From f96441b9faf769c9ecdd4d338b605ea3d0cc4010 Mon Sep 17 00:00:00 2001
From: Chris Larson <clarson@kergoth.com>
Date: Tue, 9 Nov 2004 00:36:47 +0000
Subject: Disable bk EOLN_NATIVE conversions on all files in packages
 FILESPATHs, to prevent it screwing up patches.

BKrev: 4190111fA4MuVozAqwE7xOSL9fr-TA
---
 linux/files/linux-2.4-cpufreq.patch                |    20 +
 linux/files/linux-2.4-no-short-loads.patch         |    18 +
 linux/files/linux-2.4.18-list_move.patch           |    32 +
 linux/gumstix-2.6.5-gnalm1-gum0/defconfig          |   777 +
 .../linux-2.6.5-gnalm1.patch                       | 20991 +++++
 .../defconfig-ipaqpxa                              |  1575 +
 .../defconfig-ipaqpxa                              |  1577 +
 .../defconfig-ipaqpxa                              |  1578 +
 .../defconfig-ipaqpxa                              |  1578 +
 linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6     |  1304 +
 .../defconfig-ipaq-pxa-2.6_2.6.8.1-hh0             |  1382 +
 .../defconfig-ipaqsa                               |  1505 +
 .../disable-pcmcia-probe.patch                     |    17 +
 .../ipsec.patch                                    |  1446 +
 .../mkdep.patch                                    |    16 +
 .../defconfig-ipaqsa                               |  1508 +
 linux/handhelds-sa-2.6/defconfig-jornada56x        |   877 +
 linux/linux-bast-2.4.25-vrs1-bast1/defconfig       |  1115 +
 linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch     |    16 +
 linux/linux-mtx-1-2.4.24/defconfig-mtx-1           |  1265 +
 linux/linux-mtx-1-2.4.27/defconfig-mtx-1           |  1183 +
 linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff    |    15 +
 linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch    |    11 +
 .../omap1610h2/defconfig                           |   840 +
 .../schedstats-arm.patch                           |    26 +
 linux/linux-sun4cdm-2.4.26/defconfig               |   473 +
 linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig        |   689 +
 linux/linux-xxs1500-2.4.21/Makefile                |   756 +
 linux/linux-xxs1500-2.4.21/defconfig-xxs1500       |  1199 +
 .../linux-xxs1500-2.4.21/zboot-Makefile-flags.diff |    11 +
 .../montavista-sa-2.4.17-mvl21/apm-hh-merge.patch  |   561 +
 .../montavista-sa-2.4.17-mvl21/beagle-sound.patch  |    57 +
 .../disable-pcmcia-probe.patch                     |    17 +
 linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff |   399 +
 .../iw_handlers.w13-5.diff                         |  1513 +
 .../iw_handlers.w14-5.diff                         |   838 +
 .../montavista-sa-2.4.17-mvl21/machine_name.patch  |    19 +
 linux/montavista-sa-2.4.17-mvl21/mkdep.patch       |    16 +
 .../remove-montavista-init-stupidity.patch         |    23 +
 .../ucb1x_kill-zombie.patch                        |    15 +
 .../gcc-registerparanoia.patch                     |    57 +
 linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch    |   134 +
 linux/nslu2-linksys-2.4.22/gl811e.patch            |    43 +
 .../nslu2-linksys-2.4.22/linksys_can_bite_me.patch |    34 +
 .../linux-2.4.24-attribute-used.patch              |   140 +
 linux/nslu2-linksys-2.4.22/nofpu.patch             |    18 +
 linux/nslu2-linksys-2.4.22/short_loadbytes.patch   |    18 +
 linux/nslu2-openslug-2.6.7/arm-Makefile.patch      |    13 +
 linux/nslu2-openslug-2.6.7/arm-timer.patch         |    17 +
 linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch        |     9 +
 linux/nslu2-openslug-2.6.7/x1205-rtc.patch         |   142 +
 linux/nslu2-unslung-kernel-2.3r25/able/defconfig   |   973 +
 .../able/missing_usb_ioctls.patch                  |    11 +
 .../unslung-kernel-ext3flash.patch                 |    28 +
 .../unslung-kernel-vfatdisk2.patch                 |    45 +
 .../unslung-kernel.patch                           |    11 +
 .../2.4.25-vrs2-pxa1.patch                         | 39937 +++++++++
 .../2.4.25-vrs2.patch                              | 86979 +++++++++++++++++++
 .../disable-pcmcia-probe.patch                     |    17 +
 linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch |    16 +
 .../mppe-20040216.patch                            |  1225 +
 .../scrolling-area.patch                           |    18 +
 .../simpad-apm.diff                                |   799 +
 .../simpad-backlight-if.diff                       |    97 +
 .../simpad-pm-updates.patch                        |    47 +
 .../simpad-switches-input.diff                     |   126 +
 .../simpad-ts-noninput.diff                        |    11 +
 .../sound-volume-reversed.patch                    |    16 +
 .../collie-config-2.6.7-jl2                        |   769 +
 .../husky-config-2.6.7-jl2                         |   855 +
 .../openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff |   881 +
 .../poodle-config-2.6.7-jl2                        |   708 +
 .../bluecard_cs.patch                              |    11 +
 .../bluetooth-2.4.18-mh11.patch                    | 31393 +++++++
 .../bt950_cs.patch                                 |  1174 +
 .../buffered-fbmem.patch                           |    19 +
 .../compile.patch                                  |    14 +
 .../deviceinfo.patch                               |    26 +
 .../disable-pcmcia-probe.patch                     |    17 +
 .../enable-sysrq.patch                             |    45 +
 .../idecs.patch                                    |    77 +
 .../initsh.patch                                   |    14 +
 .../irda-qos.patch                                 |   108 +
 .../iw240_we15-6.diff                              |   399 +
 .../iw_handlers.w13-5.diff                         |  1513 +
 .../iw_handlers.w14-5.diff                         |   838 +
 .../keyboard-ctrl+alt.patch                        |    79 +
 .../keymap-more-sane.patch                         |    23 +
 .../logo.patch                                     |  2598 +
 .../mkdep.patch                                    |    16 +
 .../swap-performance.patch                         |    19 +
 .../usb-storage.patch                              |  3433 +
 .../battery.patch                                  |   326 +
 .../bluetooth-patch-2.4.18-mh9.diff                | 30831 +++++++
 .../disable-pcmcia-probe.patch                     |    17 +
 .../idecs.patch                                    |    77 +
 .../initsh.patch                                   |    14 +
 .../iw240_we15-6.diff                              |   399 +
 .../iw_handlers.w13-5.diff                         |  1513 +
 .../iw_handlers.w14-5.diff                         |   838 +
 .../keymap-more-sane.patch                         |    19 +
 .../logo.patch                                     |  2598 +
 .../mkdep.patch                                    |    16 +
 .../sound-2.4.18r2.patch                           |  5602 ++
 104 files changed, 265518 insertions(+)

(limited to 'linux')

diff --git a/linux/files/linux-2.4-cpufreq.patch b/linux/files/linux-2.4-cpufreq.patch
index e69de29bb2..c3526bb30d 100644
--- a/linux/files/linux-2.4-cpufreq.patch
+++ b/linux/files/linux-2.4-cpufreq.patch
@@ -0,0 +1,20 @@
+Index: include/linux/cpufreq.h
+===================================================================
+RCS file: /cvs/linux/kernel/include/linux/cpufreq.h,v
+retrieving revision 1.4
+diff -u -r1.4 cpufreq.h
+--- linux/include/linux/cpufreq.h	23 Aug 2002 22:18:47 -0000	1.4
++++ linux/include/linux/cpufreq.h	29 Apr 2004 08:44:18 -0000
+@@ -16,9 +16,9 @@
+ #include <linux/notifier.h>
+ 
+ #ifndef CONFIG_SMP
+-#define cpufreq_current(cpu)	((void)(cpu), __cpufreq_cur)
+-#define cpufreq_max(cpu)	((void)(cpu), __cpufreq_max)
+-#define cpufreq_min(cpu)	((void)(cpu), __cpufreq_min)
++#define cpufreq_current(cpu)	(__cpufreq_cur)
++#define cpufreq_max(cpu)	(__cpufreq_max)
++#define cpufreq_min(cpu)	(__cpufreq_min)
+ #else
+ /*
+  * Should be something like:
diff --git a/linux/files/linux-2.4-no-short-loads.patch b/linux/files/linux-2.4-no-short-loads.patch
index e69de29bb2..f2d6c74224 100644
--- a/linux/files/linux-2.4-no-short-loads.patch
+++ b/linux/files/linux-2.4-no-short-loads.patch
@@ -0,0 +1,18 @@
+Index: arch/arm/Makefile
+===================================================================
+RCS file: /cvs/linux/kernel/arch/arm/Makefile,v
+retrieving revision 1.47
+diff -u -r1.47 Makefile
+--- linux/arch/arm/Makefile	9 Jul 2003 14:10:56 -0000	1.47
++++ linux/arch/arm/Makefile	28 Apr 2004 21:11:04 -0000
+@@ -60,8 +60,8 @@
+ tune-$(CONFIG_CPU_XSCALE)	:=-mtune=xscale
+ #tune-$(CONFIG_CPU_XSCALE)	:=-mtune=strongarm
+ 
+-CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+-CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
++CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -msoft-float -Uarm
++CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -msoft-float -Uarm
+ AFLAGS		+=$(apcs-y) $(arch-y) -msoft-float
+ 
+ ifeq ($(CONFIG_CPU_26),y)
diff --git a/linux/files/linux-2.4.18-list_move.patch b/linux/files/linux-2.4.18-list_move.patch
index e69de29bb2..faec56330b 100644
--- a/linux/files/linux-2.4.18-list_move.patch
+++ b/linux/files/linux-2.4.18-list_move.patch
@@ -0,0 +1,32 @@
+--- linux/include/linux/list.h~	2001-12-21 17:42:03.000000000 +0000
++++ linux/include/linux/list.h	2004-06-14 23:41:33.000000000 +0100
+@@ -105,6 +105,29 @@
+ }
+ 
+ /**
++ * list_move - delete from one list and add as another's head
++ * @list: the entry to move
++ * @head: the head that will precede our entry
++ */
++static inline void list_move(struct list_head *list, struct list_head *head)
++{
++        __list_del(list->prev, list->next);
++        list_add(list, head);
++}
++
++/**
++ * list_move_tail - delete from one list and add as another's tail
++ * @list: the entry to move
++ * @head: the head that will follow our entry
++ */
++static inline void list_move_tail(struct list_head *list,
++				  struct list_head *head)
++{
++        __list_del(list->prev, list->next);
++        list_add_tail(list, head);
++}
++
++/**
+  * list_empty - tests whether a list is empty
+  * @head: the list to test.
+  */
diff --git a/linux/gumstix-2.6.5-gnalm1-gum0/defconfig b/linux/gumstix-2.6.5-gnalm1-gum0/defconfig
index e69de29bb2..64020e2cbe 100644
--- a/linux/gumstix-2.6.5-gnalm1-gum0/defconfig
+++ b/linux/gumstix-2.6.5-gnalm1-gum0/defconfig
@@ -0,0 +1,777 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# IOP3xx Implementation Options
+#
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP321 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
+CONFIG_ARCH_GUMSTIK=y
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+
+#
+# SA11x0 Implementations
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CPU_FREQ=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+CONFIG_FPE_FASTFPE=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="root=/dev/ram0 console=tty0,115200n8"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0x00180000
+CONFIG_MTD_PHYSMAP_LEN=0x00280000
+CONFIG_MTD_PHYSMAP_BUSWIDTH=2
+CONFIG_MTD_GUMSTIK=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLKMTD=y
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=36000
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_PACKET is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q 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_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+# CONFIG_SLIP_COMPRESSED is not set
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+# CONFIG_BT_HCIUART_BCSP is not set
+# CONFIG_BT_HCIVHCI is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_TSLIBDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 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
+
+#
+# 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_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+CONFIG_SA1100_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_ALGOPXA=y
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+CONFIG_I2C_PXA2XX=y
+# CONFIG_SCx200_ACB is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_PXA=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY 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_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+# CONFIG_DEVPTS_FS_SECURITY is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+# 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 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 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_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+CONFIG_LDM_PARTITION=y
+# CONFIG_LDM_DEBUG is not set
+# CONFIG_NEC98_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_GADGET_PXA2XX=y
+CONFIG_USB_PXA2XX=y
+CONFIG_USB_PXA2XX_SMALL=y
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch b/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch
index e69de29bb2..e8ed5c9d44 100644
--- a/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch
+++ b/linux/gumstix-2.6.5-gnalm1-gum0/linux-2.6.5-gnalm1.patch
@@ -0,0 +1,20991 @@
+--- linux-2.6.5/kernel/printk.c~heh	2004-04-03 22:38:24.000000000 -0500
++++ linux-2.6.5/kernel/printk.c	2004-04-30 20:57:36.000000000 -0400
+@@ -832,3 +832,25 @@
+ 				printk_ratelimit_burst);
+ }
+ EXPORT_SYMBOL(printk_ratelimit);
++
++#include <linux/sysrq.h>
++
++static void
++show_msg_info(int key, struct pt_regs *regs, struct tty_struct *tty)
++{
++	call_console_drivers(log_end - logged_chars, log_end);
++}
++
++static struct sysrq_key_op msg_info_op = {
++	.handler	= show_msg_info,
++	.help_msg	= "Dumpmsgs",
++	.action_msg	= "Kernel Messages",
++};
++
++static int __init dbg_init(void)
++{
++	register_sysrq_key('d', &msg_info_op);
++	return 0;
++}
++
++__initcall(dbg_init);
+--- linux-2.6.5/kernel/resource.c~heh	2004-04-03 22:37:36.000000000 -0500
++++ linux-2.6.5/kernel/resource.c	2004-04-30 20:57:36.000000000 -0400
+@@ -179,6 +179,8 @@
+ {
+ 	struct resource *tmp, **p;
+ 
++	BUG_ON(old->child);
++
+ 	p = &old->parent->child;
+ 	for (;;) {
+ 		tmp = *p;
+@@ -409,6 +411,47 @@
+ EXPORT_SYMBOL(adjust_resource);
+ 
+ /*
++ * Given an existing resource, change its start and size to match the
++ * arguments.  Returns -EBUSY if it can't fit.  Existing children of
++ * the resource are assumed to be immutable.
++ */
++int reallocate_resource(struct resource *res, unsigned long start, unsigned long size)
++{
++	struct resource *tmp, *parent = res->parent;
++	unsigned long end = start + size - 1;
++	int result = -EBUSY;
++
++	write_lock(&resource_lock);
++
++	if ((start < parent->start) || (end > parent->end))
++		goto out;
++
++	for (tmp = res->child; tmp; tmp = tmp->sibling) {
++		if ((tmp->start < start) || (tmp->end > end))
++			goto out;
++	}
++
++	if (res->sibling && (res->sibling->start <= end))
++		goto out;
++
++	tmp = parent->child;
++	if (tmp != res) {
++		while (tmp->sibling != res)
++			tmp = tmp->sibling;
++		if (start <= tmp->end)
++			goto out;
++	}
++
++	res->start = start;
++	res->end = end;
++	result = 0;
++
++ out:
++	write_unlock(&resource_lock);
++	return result;
++}
++
++/*
+  * This is compatibility stuff for IO resources.
+  *
+  * Note how this, unlike the above, knows about
+--- linux-2.6.5/include/asm-arm/mach/irq.h~heh	2004-04-03 22:36:54.000000000 -0500
++++ linux-2.6.5/include/asm-arm/mach/irq.h	2004-04-30 20:57:36.000000000 -0400
+@@ -14,6 +14,19 @@
+ struct pt_regs;
+ struct seq_file;
+ 
++/*
++ * Architectures are expected to define NR_IRQ_DEVICES and
++ * NR_IRQ_DEVICE_SHIFT if they wish to use dynamic IRQs.
++ */
++#ifndef NR_IRQ_DEVICES
++#define NR_IRQ_DEVICES		1
++#endif
++#define NR_IRQ_PER_DEVICE	(1 << (NR_IRQ_DEVICE_SHIFT - 1))
++
++#define IRQ_DEVICE(i)	((i) >> NR_IRQ_DEVICE_SHIFT)
++#define IRQ_INDEX(i)	((i) & (NR_IRQ_PER_GROUP - 1))
++#define TO_IRQ(g,i)	(((g) << NR_IRQ_DEVICE_SHIFT) + (i))
++
+ typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *);
+ typedef void (*irq_control_t)(unsigned int);
+ 
+--- linux-2.6.5/include/asm-arm/arch-pxa/uncompress.h~heh	2004-04-03 22:36:17.000000000 -0500
++++ linux-2.6.5/include/asm-arm/arch-pxa/uncompress.h	2004-04-30 20:57:36.000000000 -0400
+@@ -12,6 +12,7 @@
+ #define FFUART		((volatile unsigned long *)0x40100000)
+ #define BTUART		((volatile unsigned long *)0x40200000)
+ #define STUART		((volatile unsigned long *)0x40700000)
++#define HWUART		((volatile unsigned long *)0x41600000)
+ 
+ #define UART		FFUART
+ 
+--- linux-2.6.5/include/asm-arm/arch-pxa/dma.h~heh	2004-04-03 22:38:18.000000000 -0500
++++ linux-2.6.5/include/asm-arm/arch-pxa/dma.h	2004-04-30 20:57:36.000000000 -0400
+@@ -22,11 +22,11 @@
+  * Note: this structure must always be aligned to a 16-byte boundary.
+  */
+ 
+-typedef struct {
+-	volatile u32 ddadr;	/* Points to the next descriptor + flags */
+-	volatile u32 dsadr;	/* DSADR value for the current transfer */
+-	volatile u32 dtadr;	/* DTADR value for the current transfer */
+-	volatile u32 dcmd;	/* DCMD value for the current transfer */
++typedef struct pxa_dma_desc {
++	u32 ddadr;	/* Points to the next descriptor + flags */
++	u32 dsadr;	/* DSADR value for the current transfer */
++	u32 dtadr;	/* DTADR value for the current transfer */
++	u32 dcmd;	/* DCMD value for the current transfer */
+ } pxa_dma_desc;
+ 
+ /*
+--- linux-2.6.5/include/asm-arm/arch-pxa/serial.h~heh	2004-04-03 22:37:06.000000000 -0500
++++ linux-2.6.5/include/asm-arm/arch-pxa/serial.h	2004-04-30 20:57:36.000000000 -0400
+@@ -43,6 +43,15 @@
+ 		io_type:		SERIAL_IO_MEM,	\
+ 		irq:			IRQ_BTUART,	\
+ 		flags:			STD_COM_FLAGS,	\
++	}, {	\
++		type:			PORT_PXA,	\
++		xmit_fifo_size:		64,		\
++		baud_base:		BAUD_BASE,	\
++		iomem_base:		&HWUART,	\
++		iomem_reg_shift:	2,		\
++		io_type:		SERIAL_IO_MEM,	\
++		irq:			IRQ_HWUART,	\
++		flags:			STD_COM_FLAGS,	\
+ 	}
+ 
+ #define EXTRA_SERIAL_PORT_DEFNS
+--- linux-2.6.5/include/asm-arm/arch-pxa/pxa-regs.h~heh	2004-04-03 22:37:36.000000000 -0500
++++ linux-2.6.5/include/asm-arm/arch-pxa/pxa-regs.h	2004-04-30 20:57:36.000000000 -0400
+@@ -124,26 +124,26 @@
+ #define DRCMR12		__REG(0x40000130)  /* Request to Channel Map Register for AC97 audio transmit Request */
+ #define DRCMR13		__REG(0x40000134)  /* Request to Channel Map Register for SSP receive Request */
+ #define DRCMR14		__REG(0x40000138)  /* Request to Channel Map Register for SSP transmit Request */
+-#define DRCMR15		__REG(0x4000013c)  /* Reserved */
+-#define DRCMR16		__REG(0x40000140)  /* Reserved */
++#define DRCMR15		__REG(0x4000013c)  /* Request to Channel Map Register for NSSP receive Request */
++#define DRCMR16		__REG(0x40000140)  /* Request to Channel Map Register for NSSP transmit Request */
+ #define DRCMR17		__REG(0x40000144)  /* Request to Channel Map Register for ICP receive Request */
+ #define DRCMR18		__REG(0x40000148)  /* Request to Channel Map Register for ICP transmit Request */
+ #define DRCMR19		__REG(0x4000014c)  /* Request to Channel Map Register for STUART receive Request */
+ #define DRCMR20		__REG(0x40000150)  /* Request to Channel Map Register for STUART transmit Request */
+ #define DRCMR21		__REG(0x40000154)  /* Request to Channel Map Register for MMC receive Request */
+ #define DRCMR22		__REG(0x40000158)  /* Request to Channel Map Register for MMC transmit Request */
+-#define DRCMR23		__REG(0x4000015c)  /* Reserved */
+-#define DRCMR24		__REG(0x40000160)  /* Reserved */
++#define DRCMR23		__REG(0x4000015c)  /* Request to Channel Map Register for ASSP receive Request */
++#define DRCMR24		__REG(0x40000160)  /* Request to Channel Map Register for ASSP transmit Request */
+ #define DRCMR25		__REG(0x40000164)  /* Request to Channel Map Register for USB endpoint 1 Request */
+ #define DRCMR26		__REG(0x40000168)  /* Request to Channel Map Register for USB endpoint 2 Request */
+ #define DRCMR27		__REG(0x4000016C)  /* Request to Channel Map Register for USB endpoint 3 Request */
+ #define DRCMR28		__REG(0x40000170)  /* Request to Channel Map Register for USB endpoint 4 Request */
+-#define DRCMR29		__REG(0x40000174)  /* Reserved */
++#define DRCMR29		__REG(0x40000174)  /* Request to Channel Map Register for HWUART receive Request */
+ #define DRCMR30		__REG(0x40000178)  /* Request to Channel Map Register for USB endpoint 6 Request */
+ #define DRCMR31		__REG(0x4000017C)  /* Request to Channel Map Register for USB endpoint 7 Request */
+ #define DRCMR32		__REG(0x40000180)  /* Request to Channel Map Register for USB endpoint 8 Request */
+ #define DRCMR33		__REG(0x40000184)  /* Request to Channel Map Register for USB endpoint 9 Request */
+-#define DRCMR34		__REG(0x40000188)  /* Reserved */
++#define DRCMR34		__REG(0x40000188)  /* Request to Channel Map Register for HWUART transmit Request */
+ #define DRCMR35		__REG(0x4000018C)  /* Request to Channel Map Register for USB endpoint 11 Request */
+ #define DRCMR36		__REG(0x40000190)  /* Request to Channel Map Register for USB endpoint 12 Request */
+ #define DRCMR37		__REG(0x40000194)  /* Request to Channel Map Register for USB endpoint 13 Request */
+@@ -163,12 +163,16 @@
+ #define DRCMRTXPCDR	DRCMR12
+ #define DRCMRRXSSDR	DRCMR13
+ #define DRCMRTXSSDR	DRCMR14
++#define DRCMRRXNSSPDR	DRCMR15
++#define DRCMRTXNSSPDR	DRCMR16
+ #define DRCMRRXICDR	DRCMR17
+ #define DRCMRTXICDR	DRCMR18
+ #define DRCMRRXSTRBR	DRCMR19
+ #define DRCMRTXSTTHR	DRCMR20
+ #define DRCMRRXMMC	DRCMR21
+ #define DRCMRTXMMC	DRCMR22
++#define DRCMRRXASSPDR	DRCMR23
++#define DRCMRTXASSPDR	DRCMR24
+ 
+ #define DRCMR_MAPVLD	(1 << 7)	/* Map Valid (read / write) */
+ #define DRCMR_CHLNUM	0x0f		/* mask for Channel Number (read / write) */
+@@ -303,6 +307,22 @@
+ #define BTDLL		__REG(0x40200000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
+ #define BTDLH		__REG(0x40200004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
+ 
++/* Hardware UART (HWUART) */
++#define HWUART          HWRBR
++#define HWRBR           __REG(0x41600000)  /* Receive Buffer Register (read only) */
++#define HWTHR           __REG(0x41600000)  /* Transmit Holding Register (write only) */
++#define HWIER           __REG(0x41600004)  /* Interrupt Enable Register (read/write) */
++#define HWIIR           __REG(0x41600008)  /* Interrupt ID Register (read only) */
++#define HWFCR           __REG(0x41600008)  /* FIFO Control Register (write only) */
++#define HWLCR           __REG(0x4160000C)  /* Line Control Register (read/write) */
++#define HWMCR           __REG(0x41600010)  /* Modem Control Register (read/write) */
++#define HWLSR           __REG(0x41600014)  /* Line Status Register (read only) */
++#define HWMSR           __REG(0x41600018)  /* Reserved */
++#define HWSPR           __REG(0x4160001C)  /* Scratch Pad Register (read/write) */
++#define HWISR           __REG(0x41600020)  /* Infrared Selection Register (read/write) */
++#define HWDLL           __REG(0x41600000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
++#define HWDLH           __REG(0x41600004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
++
+ /* Standard UART (STUART) */
+ #define STUART		STRBR
+ #define STRBR		__REG(0x40700000)  /* Receive Buffer Register (read only) */
+@@ -1078,6 +1098,111 @@
+ 
+ 
+ /*
++ * NSSP Serial Port Registers (Network SSP)
++ */
++
++#define NSSCR0		__REG(0x41400000)  /* NSSP Control Register 0 */
++#define NSSCR1		__REG(0x41400004)  /* NSSP Control Register 1 */
++#define NSSSR		__REG(0x41400008)  /* NSSP Status Register */
++#define NSSITR		__REG(0x4140000C)  /* NSSP Interrupt Test Register */
++#define NSSDR		__REG(0x41400010)  /* (Write / Read) NSSP Data Write Register/NSSP Data Read Register */
++#define NSSTO		__REG(0x41400028)  /* NSSP Time Out Register */
++#define NSSPSP		__REG(0x4140002C)  /* NSSP Programable Serial Port Register*/
++
++
++/*
++ * ASSP Serial Port Registers (Audio SSP)
++ */
++
++#define ASSCR0		__REG(0x41500000)  /* ASSP Control Register 0 */
++#define ASSCR1		__REG(0x41500004)  /* ASSP Control Register 1 */
++#define ASSSR		__REG(0x41500008)  /* ASSP Status Register */
++#define ASSITR		__REG(0x4150000C)  /* ASSP Interrupt Test Register */
++#define ASSDR		__REG(0x41500010)  /* (Write / Read) ASSP Data Write Register/ASSP Data Read Register */
++#define ASSTO		__REG(0x41500028)  /* ASSP Time Out Register */
++#define ASSPSP		__REG(0x4150002C)  /* ASSP Programable Serial Port Register*/
++
++
++/* 
++ * Bit definitions for SSP, NSSP and ASSP registers 
++ *  - note that some bits are only available on the NSSP and ASSP
++ */
++
++#define SSCR0_EDSS		(1 << 20)   /* ext. data size select */
++#define SSCR0_SCR_MASK		0x000fff00  /* [19:8] secrial clock rate */
++#define SSCR0_SCR(x)		(((x)<<8) & XSSCR0_SCR_MASK)
++#define SSCR0_SSE		(1 << 7)    /* sync ser port enable */
++#define SSCR0_FRF_MASK		0x00000030  /* [5:4] frame format */
++#define SSCR0_FRF(x)		(((x)<<4) & XSSCR0_FRF_MASK)
++#define SSCR0_FRF_SPI		0x00000000     /* ser peripheral i/f */
++#define SSCR0_FRF_TISSP		0x00000010     /* TI sync ser port */
++#define SSCR0_FRF_MICROWAVE	0x00000020     /* microwire */
++#define SSCR0_FRF_PSP		0x00000030     /* prog ser protocol */
++#define SSCR0_DSS_MASK		0x0000000f  /* data size select */
++#define SSCR0_DSS(x)		((x) & XSSCR0_DSS_MASK)
++
++#define SSCR1_TTELP		(1 << 31)   /* tx hi-z later phase */
++#define SSCR1_TTE		(1 << 30)   /* tx hi-z enable */
++#define SSCR1_EBCEI		(1 << 29)   /* bit count error int mask */
++#define SSCR1_SCFR		(1 << 28)   /* slave clock free running */
++#define SSCR1_SCLKDIR		(1 << 25)   /* ssp clock direction */
++#define SSCR1_SFRMDIR		(1 << 24)   /* ssp frame direction */
++#define SSCR1_RWOT		(1 << 23)   /* rx without transmit */
++#define SSCR1_TSRE		(1 << 21)   /* tx req enable */
++#define SSCR1_RSRE		(1 << 20)   /* rx req enable */
++#define SSCR1_TINTE		(1 << 19)   /* timeout int enable */
++#define SSCR1_STRF		(1 << 15)   /* select fifo for efwr */
++#define SSCR1_EFWR		(1 << 14)   /* fifo write/read enable */
++#define SSCR1_RFT_MASK		0x00003c00  /* [13:10] rx fifo threshold */
++#define SSCR1_RFT(x)		(((x)<<10) & XSSCR1_RFT_MASK)
++#define SSCR1_TFT_MASK		0x000003c0  /* [9:6] tx fifo threshold */
++#define SSCR1_TFT(x)		(((x)<<6) & XSSCR1_TFT_MASK)
++#define SSCR1_MWDS		(1 << 5)    /* microwire tx data size */
++#define SSCR1_SPH		(1 << 4)    /* SPI SSPSCLK phase */
++#define SSCR1_SPO		(1 << 3)    /* motorolla SPI polarity */
++#define SSCR1_LBM		(1 << 2)    /* loop-back mode */
++#define SSCR1_TIE		(1 << 1)    /* tx fifo int enable */
++#define SSCR1_RIE		(1 << 0)    /* rx fifo int enable */
++
++#define SSPSP_DMYSTOP_MASK	0x01800000  /* [24:23] dummy stop */
++#define SSPSP_DMYSTOP(x)	(((x)<<23) & XSSPSP_DMYSTOP_MASK)
++#define SSPSP_SFRMWDTH_MASK	0x007f0000  /* [22:16] serial frame width */
++#define SSPSP_SFRMWDTH(x)	(((x)<<16) & XSSPSP_SFRMWDTH_MASK)
++#define SSPSP_SFRMDLY_MASK	0x0000fe00  /* [15:9] serial frame delay */
++#define SSPSP_SFRMDLY(x)	(((x)<<9) & XSSPSP_SFRMDLY_MASK)
++#define SSPSP_DMYSTRT_MASK	0x00000180  /* [8:7] dummy start */
++#define SSPSP_DMYSTRT(x)	(((x)<<7) & XSSPSP_DMYSTRT_MASK)
++#define SSPSP_STRTDLY_MASK	0x00000070  /* [6:4] three-bit start delay */
++#define SSPSP_STRTDLY(x)	(((x)<<4) & XSSPSP_STRTDLY_MASK)
++#define SSPSP_ETDS		(1 << 3)    /* end of tx data state */
++#define SSPSP_SFRMP		(1 << 2)    /* serial frame polarity */
++#define SSPSP_SCMODE_MASK	0x00000003  /* bit-rate clock mode */
++#define SSPSP_SCMODE(x)		((x) & XSSPSP_SCMODE_MASK)
++
++#define SSTO_TIMEOUT_MASK	0x00ffffff  /* [23:0] timeout */
++#define SSTO_TIMEOUT(x)		((x) & XSSTO_TIMEOUT_MASK)
++
++#define SSITR_TROR		(1 << 7)    /* test rx fifo overrun */
++#define SSITR_TRFS		(1 << 6)    /* test rx fifo serv req */
++#define SSITR_TTFS		(1 << 5)    /* test tx fifo serv req */
++
++#define SSSR_BCE		(1 << 23)   /* bit count error */
++#define SSSR_CSS		(1 << 22)   /* clock sync stat */
++#define SSSR_TUR		(1 << 21)   /* tx fifo underrun */
++#define SSSR_TINT		(1 << 19)   /* rx timeout int */
++#define SSSR_RFL_MASK		0x0000f000  /* rx fifo level */
++#define SSSR_RFL(x)		(((x)<<16) & XSSSR_RFL_MASK)
++#define SSSR_TFL_MASK		0x00000f00  /* tx fifo level */
++#define SSSR_TFL(x)		(((x)<<8) & XSSSR_TFL_MASK)
++#define SSSR_ROR		(1 << 7)    /* rx fifo overrun */
++#define SSSR_RFS		(1 << 6)    /* rx fifo serv request */
++#define SSSR_TFS		(1 << 5)    /* tx fifo serv req */
++#define SSSR_BSY		(1 << 4)    /* SSP busy */
++#define SSSR_RNE		(1 << 3)    /* rx fifo not empty */
++#define SSSR_TNF		(1 << 2)    /* tx fifo not full */
++
++
++/*
+  * MultiMediaCard (MMC) controller
+  */
+ 
+@@ -1122,6 +1247,7 @@
+ #define CKEN7_BTUART	(1 << 7)	/* BTUART Unit Clock Enable */
+ #define CKEN6_FFUART	(1 << 6)	/* FFUART Unit Clock Enable */
+ #define CKEN5_STUART	(1 << 5)	/* STUART Unit Clock Enable */
++#define CKEN4_HWUART	(1 << 4)        /* HWUART Unit Clock Enable */
+ #define CKEN3_SSP	(1 << 3)	/* SSP Unit Clock Enable */
+ #define CKEN2_AC97	(1 << 2)	/* AC97 Unit Clock Enable */
+ #define CKEN1_PWM1	(1 << 1)	/* PWM1 Clock Enable */
+--- linux-2.6.5/include/asm-arm/page.h~heh	2004-04-03 22:36:25.000000000 -0500
++++ linux-2.6.5/include/asm-arm/page.h	2004-04-30 20:57:36.000000000 -0400
+@@ -92,6 +92,14 @@
+ # endif
+ #endif
+ 
++#ifdef CONFIG_CPU_COPY_V6
++# ifdef _USER
++#  define MULTI_USER 1
++# else
++#  define _USER v6
++# endif
++#endif
++
+ #ifndef _USER
+ #error Unknown user operations model
+ #endif
+--- linux-2.6.5/include/asm-arm/thread_info.h~heh	2004-04-03 22:37:06.000000000 -0500
++++ linux-2.6.5/include/asm-arm/thread_info.h	2004-04-30 20:57:36.000000000 -0400
+@@ -108,8 +108,8 @@
+ #define TI_CPU		20
+ #define TI_CPU_DOMAIN	24
+ #define TI_CPU_SAVE	28
+-#define TI_USED_MATH	76
+-#define TI_FPSTATE	(TI_USED_MATH+16)
++#define TI_USED_CP	76
++#define TI_FPSTATE	(TI_USED_CP+16)
+ 
+ #endif
+ 
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/asm-arm/rtc.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,45 @@
++/*
++ *  linux/include/asm-arm/rtc.h
++ *
++ *  Copyright (C) 2003 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef ASMARM_RTC_H
++#define ASMARM_RTC_H
++
++struct module;
++
++struct rtc_ops {
++	struct module	*owner;
++	int		(*open)(void);
++	void		(*release)(void);
++	int		(*ioctl)(unsigned int, unsigned long);
++
++	void		(*read_time)(struct rtc_time *);
++	int		(*set_time)(struct rtc_time *);
++	void		(*read_alarm)(struct rtc_wkalrm *);
++	int		(*set_alarm)(struct rtc_wkalrm *);
++	int		(*proc)(char *buf);
++};
++
++void rtc_time_to_tm(unsigned long, struct rtc_time *);
++int rtc_tm_to_time(struct rtc_time *, unsigned long *);
++void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *);
++void rtc_update(unsigned long, unsigned long);
++int register_rtc(struct rtc_ops *);
++void unregister_rtc(struct rtc_ops *);
++
++static inline int rtc_periodic_alarm(struct rtc_time *tm)
++{
++	return  (tm->tm_year == -1) ||
++		((unsigned)tm->tm_mon >= 12) ||
++		((unsigned)(tm->tm_mday - 1) >= 31) ||
++		((unsigned)tm->tm_hour > 23) ||
++		((unsigned)tm->tm_min > 59) ||
++		((unsigned)tm->tm_sec > 59);
++}
++
++#endif
+--- linux-2.6.5/include/linux/serial.h~heh	2004-04-03 22:36:26.000000000 -0500
++++ linux-2.6.5/include/linux/serial.h	2004-04-30 20:57:36.000000000 -0400
+@@ -81,17 +81,6 @@
+ #define SERIAL_IO_HUB6	1
+ #define SERIAL_IO_MEM	2
+ 
+-struct serial_uart_config {
+-	char	*name;
+-	int	dfl_xmit_fifo_size;
+-	int	flags;
+-};
+-
+-#define UART_CLEAR_FIFO		0x01
+-#define UART_USE_FIFO		0x02
+-#define UART_STARTECH		0x04
+-#define UART_NATSEMI		0x08
+-
+ /*
+  * Definitions for async_struct (and serial_struct) flags field
+  */
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/i2c-pxa.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,76 @@
++/*
++ *  i2c_pxa.h
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ * 
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ */
++#ifndef _I2C_PXA_H_
++#define _I2C_PXA_H_
++
++struct i2c_algo_pxa_data
++{
++        void (*write_byte) (u8 value);
++        u8   (*read_byte) (void);
++        void (*start) (void);
++        void (*repeat_start) (void);
++        void (*stop) (void);
++        void (*abort) (void);
++        int  (*wait_bus_not_busy) (void);
++        int  (*wait_for_interrupt) (int wait_type);
++        void (*transfer) (int lastbyte, int receive, int midbyte);
++        void (*reset) (void);
++
++	int udelay;
++	int timeout;
++};
++
++#define DEF_TIMEOUT             3
++#define BUS_ERROR               (-EREMOTEIO)
++#define ACK_DELAY               0       /* time to delay before checking bus error */
++#define MAX_MESSAGES            65536   /* maximum number of messages to send */
++
++#define I2C_SLEEP_TIMEOUT       2       /* time to sleep for on i2c transactions */
++#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
++#define I2C_TRANSMIT		1
++#define I2C_RECEIVE		0
++#define I2C_PXA_SLAVE_ADDR      0x1    /* slave pxa unit address */
++#define I2C_ICR_INIT            (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */
++/* ICR initialize bit values 
++*                       
++*  15. FM       0 (100 Khz operation)
++*  14. UR       0 (No unit reset)
++*  13. SADIE    0 (Disables the unit from interrupting on slave addresses 
++*                                       matching its slave address)
++*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration 
++*                                       in master mode)
++*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)  
++*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
++*  9.  IRFIE    1 (Enable interrupts from full buffer received)
++*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
++*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave) 
++*  6.  IUE      0 (Disable unit until we change settings)
++*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)   
++*  4.  MA       0 (Only send stop with the ICR stop bit)
++*  3.  TB       0 (We are not transmitting a byte initially)
++*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
++*  1.  STOP     0 (Do not send a STOP)
++*  0.  START    0 (Do not send a START)
++*
++*/
++
++#define I2C_ISR_INIT            0x7FF  /* status register init */
++/* I2C status register init values 
++ *
++ * 10. BED      1 (Clear bus error detected)
++ * 9.  SAD      1 (Clear slave address detected)
++ * 7.  IRF      1 (Clear IDBR Receive Full)
++ * 6.  ITE      1 (Clear IDBR Transmit Empty)
++ * 5.  ALD      1 (Clear Arbitration Loss Detected)
++ * 4.  SSD      1 (Clear Slave Stop Detected)
++ */
++
++#endif
+--- linux-2.6.5/include/linux/ioport.h~heh	2004-04-03 22:36:26.000000000 -0500
++++ linux-2.6.5/include/linux/ioport.h	2004-04-30 20:57:36.000000000 -0400
+@@ -99,6 +99,7 @@
+ 			     void (*alignf)(void *, struct resource *,
+ 					    unsigned long, unsigned long),
+ 			     void *alignf_data);
++extern int reallocate_resource(struct resource *res, unsigned long start, unsigned long size);
+ int adjust_resource(struct resource *res, unsigned long start,
+ 		    unsigned long size);
+ 
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/switches.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,74 @@
++/*
++ *  linux/include/linux/switches.h
++ *
++ *  Copyright (C) 2000 John Dorsey
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  23 October 2000 - created.
++ */
++
++#if !defined(_LINUX_SWITCHES_H)
++#define _LINUX_SWITCHES_H
++
++#define SWITCHES_MASK_SIZE  (128)
++
++typedef unsigned long switches_bitfield;
++
++#define SWITCHES_BITS            (sizeof(switches_bitfield) * 8)
++#define SWITCHES_NUM_FIELDS      (SWITCHES_MASK_SIZE /  SWITCHES_BITS)
++#define SWITCHES_FIELD_SELECT(i) ((i) / SWITCHES_BITS)
++#define SWITCHES_FIELD_MASK(i)   ((switches_bitfield)(1 << (i) % \
++                                  SWITCHES_BITS))
++
++typedef struct switches_mask_t {
++	unsigned int count;
++	switches_bitfield events[SWITCHES_NUM_FIELDS];
++	switches_bitfield states[SWITCHES_NUM_FIELDS];
++} switches_mask_t;
++
++#define SWITCHES_ZERO(m) \
++do { \
++	unsigned int sz_i; \
++	(m)->count = 0; \
++	for(sz_i = 0; sz_i < SWITCHES_NUM_FIELDS; ++sz_i) \
++		(m)->events[sz_i] = (m)->states[sz_i] = 0; \
++} while (0)
++
++/* `s' is the state of the switch, either 0 or non-zero: */
++#define SWITCHES_SET(m, i, s) \
++do { \
++	((m)->events[SWITCHES_FIELD_SELECT((i))] |= \
++         SWITCHES_FIELD_MASK((i))); \
++	if(s) \
++		((m)->states[SWITCHES_FIELD_SELECT((i))] |= \
++                 SWITCHES_FIELD_MASK((i))); \
++	else \
++		((m)->states[SWITCHES_FIELD_SELECT((i))] &= \
++                 ~SWITCHES_FIELD_MASK((i))); \
++	++((m)->count); \
++} while (0)
++
++/* Should only use to clear an event set by SWITCHES_SET(): */
++#define SWITCHES_CLEAR(m, i) \
++do { \
++	((m)->events[SWITCHES_FIELD_SELECT((i))] &= \
++         ~SWITCHES_FIELD_MASK((i))); \
++	((m)->states[SWITCHES_FIELD_SELECT((i))] &= \
++         ~SWITCHES_FIELD_MASK((i))); \
++	--((m)->count); \
++}
++
++#define SWITCHES_COUNT(m) ((m)->count)
++
++/* Returns 0 or non-zero: */
++#define SWITCHES_EVENT(m, i) \
++((m)->events[SWITCHES_FIELD_SELECT((i))] & SWITCHES_FIELD_MASK((i)))
++
++/* Returns 0 or non-zero: */
++#define SWITCHES_STATE(m, i) \
++((m)->states[SWITCHES_FIELD_SELECT((i))] & SWITCHES_FIELD_MASK((i)))
++
++#endif  /* !defined(_LINUX_SWITCHES_H) */
+--- linux-2.6.5/include/linux/serial_reg.h~heh	2004-04-03 22:37:38.000000000 -0500
++++ linux-2.6.5/include/linux/serial_reg.h	2004-04-30 20:57:36.000000000 -0400
+@@ -121,6 +121,7 @@
+ /*
+  * These are the definitions for the Modem Control Register
+  */
++#define UART_MCR_AFE	0x20	/* Enable auto-RTS/CTS (TI16C750) */
+ #define UART_MCR_LOOP	0x10	/* Enable loopback test mode */
+ #define UART_MCR_OUT2	0x08	/* Out2 complement */
+ #define UART_MCR_OUT1	0x04	/* Out1 complement */
+@@ -156,6 +157,21 @@
+ #define UART_FCR_PXAR32	0xc0	/* receive FIFO treshold = 32 */
+ 
+ /*
++ * The Intel PXA2xx chip defines those bits
++ */
++#define UART_IER_DMAE	0x80	/* DMA Requests Enable */
++#define UART_IER_UUE	0x40	/* UART Unit Enable */
++#define UART_IER_NRZE	0x20	/* NRZ coding Enable */
++#define UART_IER_RTOIE	0x10	/* Receiver Time Out Interrupt Enable */
++
++#define UART_IIR_TOD	0x08	/* Character Timeout Indication Detected */
++
++#define UART_FCR_PXAR1	0x00	/* receive FIFO treshold = 1 */ 
++#define UART_FCR_PXAR8	0x40	/* receive FIFO treshold = 8 */
++#define UART_FCR_PXAR16	0x80	/* receive FIFO treshold = 16 */
++#define UART_FCR_PXAR32	0xc0	/* receive FIFO treshold = 32 */
++
++/*
+  * These are the definitions for the Extended Features Register
+  * (StarTech 16C660 only, when DLAB=1)
+  */
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/mmc/card.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,83 @@
++/*
++ *  linux/include/linux/mmc/card.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Card driver specific definitions.
++ */
++#ifndef LINUX_MMC_CARD_H
++#define LINUX_MMC_CARD_H
++
++#include <linux/mmc/mmc.h>
++
++struct mmc_cid {
++	unsigned int		manfid;
++	unsigned int		serial;
++	char			prod_name[8];
++	unsigned char		hwrev;
++	unsigned char		fwrev;
++	unsigned char		month;
++	unsigned char		year;
++};
++
++struct mmc_csd {
++	unsigned char		mmc_prot;
++	unsigned short		cmdclass;
++	unsigned short		tacc_clks;
++	unsigned int		tacc_ns;
++	unsigned int		max_dtr;
++	unsigned int		read_blkbits;
++	unsigned int		capacity;
++};
++
++struct mmc_host;
++
++/*
++ * MMC device
++ */
++struct mmc_card {
++	struct list_head	node;		/* node in hosts devices list */
++	struct mmc_host		*host;		/* the host this device belongs to */
++	struct device		dev;		/* the device */
++	unsigned int		rca;		/* relative card address of device */
++	unsigned int		state;		/* (our) card state */
++#define MMC_STATE_PRESENT	(1<<0)
++#define MMC_STATE_DEAD		(1<<1)
++	struct mmc_cid		cid;		/* card identification */
++	struct mmc_csd		csd;		/* card specific */
++};
++
++#define mmc_card_dead(c)	((c)->state & MMC_STATE_DEAD)
++#define mmc_card_present(c)	((c)->state & MMC_STATE_PRESENT)
++
++#define mmc_card_name(c)	((c)->cid.prod_name)
++#define mmc_card_id(c)		((c)->dev.bus_id)
++
++#define mmc_list_to_card(l)	container_of(l, struct mmc_card, node)
++#define mmc_get_drvdata(c)	dev_get_drvdata(&(c)->dev)
++#define mmc_set_drvdata(c,d)	dev_set_drvdata(&(c)->dev, d)
++
++/*
++ * MMC device driver (e.g., Flash card, I/O card...)
++ */
++struct mmc_driver {
++	struct device_driver drv;
++	int (*probe)(struct mmc_card *);
++	void (*remove)(struct mmc_card *);
++	int (*suspend)(struct mmc_card *, u32);
++	int (*resume)(struct mmc_card *);
++};
++
++extern int mmc_register_driver(struct mmc_driver *);
++extern void mmc_unregister_driver(struct mmc_driver *);
++
++static inline int mmc_card_claim_host(struct mmc_card *card)
++{
++	return __mmc_claim_host(card->host, card);
++}
++
++#define mmc_card_release_host(c)	mmc_release_host((c)->host)
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/mmc/mmc.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,88 @@
++/*
++ *  linux/include/linux/mmc/mmc.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef MMC_H
++#define MMC_H
++
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++
++struct request;
++struct mmc_data;
++struct mmc_request;
++
++struct mmc_command {
++	u32			opcode;
++	u32			arg;
++	u32			resp[4];
++	unsigned int		flags;		/* expected response type */
++#define MMC_RSP_NONE	(0 << 0)
++#define MMC_RSP_SHORT	(1 << 0)
++#define MMC_RSP_LONG	(2 << 0)
++#define MMC_RSP_MASK	(3 << 0)
++#define MMC_RSP_CRC	(1 << 3)		/* expect valid crc */
++#define MMC_RSP_BUSY	(1 << 4)		/* card may send busy */
++
++	unsigned int		retries;	/* max number of retries */
++	unsigned int		error;		/* command error */
++
++#define MMC_ERR_NONE	0
++#define MMC_ERR_TIMEOUT	1
++#define MMC_ERR_BADCRC	2
++#define MMC_ERR_FIFO	3
++#define MMC_ERR_FAILED	4
++#define MMC_ERR_INVALID	5
++
++	struct mmc_data		*data;		/* data segment associated with cmd */
++	struct mmc_request	*req;		/* assoicated request */
++};
++
++struct mmc_data {
++	unsigned int		timeout_ns;	/* data timeout (in ns, max 80ms) */
++	unsigned int		timeout_clks;	/* data timeout (in clocks) */
++	unsigned int		blksz_bits;	/* data block size */
++	unsigned int		blocks;		/* number of blocks */
++	struct request		*rq;		/* request structure */
++	unsigned int		error;		/* data error */
++	unsigned int		flags;
++
++#define MMC_DATA_WRITE	(1 << 8)
++#define MMC_DATA_READ	(1 << 9)
++#define MMC_DATA_STREAM	(1 << 10)
++
++	unsigned int		bytes_xfered;
++
++	struct mmc_command	*stop;		/* stop command */
++	struct mmc_request	*req;		/* assoicated request */
++};
++
++struct mmc_request {
++	struct mmc_command	*cmd;
++	struct mmc_data		*data;
++	struct mmc_command	*stop;
++
++	void			*done_data;	/* completion data */
++	void			(*done)(struct mmc_request *);/* completion function */
++};
++
++struct mmc_host;
++struct mmc_card;
++
++extern int mmc_wait_for_req(struct mmc_host *, struct mmc_request *);
++extern int mmc_wait_for_cmd(struct mmc_host *, struct mmc_command *, int);
++
++extern int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card);
++
++static inline void mmc_claim_host(struct mmc_host *host)
++{
++	__mmc_claim_host(host, (struct mmc_card *)-1);
++}
++
++extern void mmc_release_host(struct mmc_host *host);
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/mmc/host.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,67 @@
++/*
++ *  linux/include/linux/mmc/host.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Host driver specific definitions.
++ */
++#ifndef LINUX_MMC_HOST_H
++#define LINUX_MMC_HOST_H
++
++#include <linux/mmc/mmc.h>
++
++struct mmc_ios {
++	unsigned int	clock;			/* clock rate */
++	unsigned short	vdd;			/* supply (units of 10mV) */
++	unsigned char	bus_mode;		/* command output mode */
++
++#define MMC_BUSMODE_OPENDRAIN	1
++#define MMC_BUSMODE_PUSHPULL	2
++
++	unsigned char	power_mode;		/* power supply mode */
++
++#define MMC_POWER_OFF		0
++#define MMC_POWER_UP		1
++#define MMC_POWER_ON		2
++};
++
++struct mmc_host_ops {
++	void	(*request)(struct mmc_host *host, struct mmc_request *req);
++	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
++};
++
++struct mmc_card;
++
++struct mmc_host {
++	struct device		*dev;
++	struct mmc_host_ops	*ops;
++	unsigned int		f_min;
++	unsigned int		f_max;
++	u32			ocr_avail;
++
++	/* private data */
++	unsigned int		host_num;	/* host number */
++	struct mmc_ios		ios;		/* current io bus settings */
++	u32			ocr;		/* the current OCR setting */
++
++	struct list_head	cards;		/* devices attached to this host */
++
++	wait_queue_head_t	wq;
++	spinlock_t		lock;		/* card_busy lock */
++	struct mmc_card		*card_busy;	/* the MMC card claiming host */
++	struct mmc_card		*card_selected;	/* the selected MMC card */
++};
++
++extern int mmc_init_host(struct mmc_host *);
++extern int mmc_add_host(struct mmc_host *);
++extern void mmc_remove_host(struct mmc_host *);
++extern int mmc_suspend_host(struct mmc_host *, u32);
++extern int mmc_resume_host(struct mmc_host *);
++
++extern void mmc_detect_change(struct mmc_host *);
++extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
++
++#endif
++
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/mmc/protocol.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,203 @@
++/*
++ * Header for MultiMediaCard (MMC)
++ *
++ * Copyright 2002 Hewlett-Packard Company
++ *
++ * Use consistent with the GNU GPL is permitted,
++ * provided that this copyright notice is
++ * preserved in its entirety in all copies and derived works.
++ *
++ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
++ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
++ * FITNESS FOR ANY PARTICULAR PURPOSE.
++ *
++ * Many thanks to Alessandro Rubini and Jonathan Corbet!
++ *
++ * Based strongly on code by:
++ *
++ * Author: Yong-iL Joh <tolkien@mizi.com>
++ * Date  : $Date$
++ *
++ * Author:  Andrew Christian
++ *          15 May 2002
++ */
++
++#ifndef MMC_MMC_PROTOCOL_H
++#define MMC_MMC_PROTOCOL_H
++
++/* Standard MMC commands (3.1)           type  argument     response */
++   /* class 1 */
++#define	MMC_GO_IDLE_STATE         0   /* bc                          */
++#define MMC_SEND_OP_COND          1   /* bcr  [31:0] OCR         R3  */
++#define MMC_ALL_SEND_CID          2   /* bcr                     R2  */
++#define MMC_SET_RELATIVE_ADDR     3   /* ac   [31:16] RCA        R1  */
++#define MMC_SET_DSR               4   /* bc   [31:16] RCA            */
++#define MMC_SELECT_CARD           7   /* ac   [31:16] RCA        R1  */
++#define MMC_SEND_CSD              9   /* ac   [31:16] RCA        R2  */
++#define MMC_SEND_CID             10   /* ac   [31:16] RCA        R2  */
++#define MMC_READ_DAT_UNTIL_STOP  11   /* adtc [31:0] dadr        R1  */
++#define MMC_STOP_TRANSMISSION    12   /* ac                      R1b */
++#define MMC_SEND_STATUS	         13   /* ac   [31:16] RCA        R1  */
++#define MMC_GO_INACTIVE_STATE    15   /* ac   [31:16] RCA            */
++
++  /* class 2 */
++#define MMC_SET_BLOCKLEN         16   /* ac   [31:0] block len   R1  */
++#define MMC_READ_SINGLE_BLOCK    17   /* adtc [31:0] data addr   R1  */
++#define MMC_READ_MULTIPLE_BLOCK  18   /* adtc [31:0] data addr   R1  */
++
++  /* class 3 */
++#define MMC_WRITE_DAT_UNTIL_STOP 20   /* adtc [31:0] data addr   R1  */
++
++  /* class 4 */
++#define MMC_SET_BLOCK_COUNT      23   /* adtc [31:0] data addr   R1  */
++#define MMC_WRITE_BLOCK          24   /* adtc [31:0] data addr   R1  */
++#define MMC_WRITE_MULTIPLE_BLOCK 25   /* adtc                    R1  */
++#define MMC_PROGRAM_CID          26   /* adtc                    R1  */
++#define MMC_PROGRAM_CSD          27   /* adtc                    R1  */
++
++  /* class 6 */
++#define MMC_SET_WRITE_PROT       28   /* ac   [31:0] data addr   R1b */
++#define MMC_CLR_WRITE_PROT       29   /* ac   [31:0] data addr   R1b */
++#define MMC_SEND_WRITE_PROT      30   /* adtc [31:0] wpdata addr R1  */
++
++  /* class 5 */
++#define MMC_ERASE_GROUP_START    35   /* ac   [31:0] data addr   R1  */
++#define MMC_ERASE_GROUP_END      36   /* ac   [31:0] data addr   R1  */
++#define MMC_ERASE                37   /* ac                      R1b */
++
++  /* class 9 */
++#define MMC_FAST_IO              39   /* ac   <Complex>          R4  */
++#define MMC_GO_IRQ_STATE         40   /* bcr                     R5  */
++
++  /* class 7 */
++#define MMC_LOCK_UNLOCK          42   /* adtc                    R1b */
++
++  /* class 8 */
++#define MMC_APP_CMD              55   /* ac   [31:16] RCA        R1  */
++#define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1b */
++
++/*
++  MMC status in R1
++  Type
++  	e : error bit
++	s : status bit
++	r : detected and set for the actual command response
++	x : detected and set during command execution. the host must poll
++            the card by sending status command in order to read these bits.
++  Clear condition
++  	a : according to the card state
++	b : always related to the previous command. Reception of
++            a valid command will clear it (with a delay of one command)
++	c : clear by read
++ */
++
++#define R1_OUT_OF_RANGE		(1 << 31)	/* er, c */
++#define R1_ADDRESS_ERROR	(1 << 30)	/* erx, c */
++#define R1_BLOCK_LEN_ERROR	(1 << 29)	/* er, c */
++#define R1_ERASE_SEQ_ERROR      (1 << 28)	/* er, c */
++#define R1_ERASE_PARAM		(1 << 27)	/* ex, c */
++#define R1_WP_VIOLATION		(1 << 26)	/* erx, c */
++#define R1_CARD_IS_LOCKED	(1 << 25)	/* sx, a */
++#define R1_LOCK_UNLOCK_FAILED	(1 << 24)	/* erx, c */
++#define R1_COM_CRC_ERROR	(1 << 23)	/* er, b */
++#define R1_ILLEGAL_COMMAND	(1 << 22)	/* er, b */
++#define R1_CARD_ECC_FAILED	(1 << 21)	/* ex, c */
++#define R1_CC_ERROR		(1 << 20)	/* erx, c */
++#define R1_ERROR		(1 << 19)	/* erx, c */
++#define R1_UNDERRUN		(1 << 18)	/* ex, c */
++#define R1_OVERRUN		(1 << 17)	/* ex, c */
++#define R1_CID_CSD_OVERWRITE	(1 << 16)	/* erx, c, CID/CSD overwrite */
++#define R1_WP_ERASE_SKIP	(1 << 15)	/* sx, c */
++#define R1_CARD_ECC_DISABLED	(1 << 14)	/* sx, a */
++#define R1_ERASE_RESET		(1 << 13)	/* sr, c */
++#define R1_STATUS(x)            (x & 0xFFFFE000)
++#define R1_CURRENT_STATE(x)    	((x & 0x00001E00) >> 9)	/* sx, b (4 bits) */
++#define R1_READY_FOR_DATA	(1 << 8)	/* sx, a */
++#define R1_APP_CMD		(1 << 7)	/* sr, c */
++
++/* These are unpacked versions of the actual responses */
++
++struct _mmc_csd {
++	u8  csd_structure;
++	u8  spec_vers;
++	u8  taac;
++	u8  nsac;
++	u8  tran_speed;
++	u16 ccc;
++	u8  read_bl_len;
++	u8  read_bl_partial;
++	u8  write_blk_misalign;
++	u8  read_blk_misalign;
++	u8  dsr_imp;
++	u16 c_size;
++	u8  vdd_r_curr_min;
++	u8  vdd_r_curr_max;
++	u8  vdd_w_curr_min;
++	u8  vdd_w_curr_max;
++	u8  c_size_mult;
++	union {
++		struct { /* MMC system specification version 3.1 */
++			u8  erase_grp_size;
++			u8  erase_grp_mult;
++		} v31;
++		struct { /* MMC system specification version 2.2 */
++			u8  sector_size;
++			u8  erase_grp_size;
++		} v22;
++	} erase;
++	u8  wp_grp_size;
++	u8  wp_grp_enable;
++	u8  default_ecc;
++	u8  r2w_factor;
++	u8  write_bl_len;
++	u8  write_bl_partial;
++	u8  file_format_grp;
++	u8  copy;
++	u8  perm_write_protect;
++	u8  tmp_write_protect;
++	u8  file_format;
++	u8  ecc;
++};
++
++#define MMC_VDD_145_150	0x00000001	/* VDD voltage 1.45 - 1.50 */
++#define MMC_VDD_150_155	0x00000002	/* VDD voltage 1.50 - 1.55 */
++#define MMC_VDD_155_160	0x00000004	/* VDD voltage 1.55 - 1.60 */
++#define MMC_VDD_160_165	0x00000008	/* VDD voltage 1.60 - 1.65 */
++#define MMC_VDD_165_170	0x00000010	/* VDD voltage 1.65 - 1.70 */
++#define MMC_VDD_17_18	0x00000020	/* VDD voltage 1.7 - 1.8 */
++#define MMC_VDD_18_19	0x00000040	/* VDD voltage 1.8 - 1.9 */
++#define MMC_VDD_19_20	0x00000080	/* VDD voltage 1.9 - 2.0 */
++#define MMC_VDD_20_21	0x00000100	/* VDD voltage 2.0 ~ 2.1 */
++#define MMC_VDD_21_22	0x00000200	/* VDD voltage 2.1 ~ 2.2 */
++#define MMC_VDD_22_23	0x00000400	/* VDD voltage 2.2 ~ 2.3 */
++#define MMC_VDD_23_24	0x00000800	/* VDD voltage 2.3 ~ 2.4 */
++#define MMC_VDD_24_25	0x00001000	/* VDD voltage 2.4 ~ 2.5 */
++#define MMC_VDD_25_26	0x00002000	/* VDD voltage 2.5 ~ 2.6 */
++#define MMC_VDD_26_27	0x00004000	/* VDD voltage 2.6 ~ 2.7 */
++#define MMC_VDD_27_28	0x00008000	/* VDD voltage 2.7 ~ 2.8 */
++#define MMC_VDD_28_29	0x00010000	/* VDD voltage 2.8 ~ 2.9 */
++#define MMC_VDD_29_30	0x00020000	/* VDD voltage 2.9 ~ 3.0 */
++#define MMC_VDD_30_31	0x00040000	/* VDD voltage 3.0 ~ 3.1 */
++#define MMC_VDD_31_32	0x00080000	/* VDD voltage 3.1 ~ 3.2 */
++#define MMC_VDD_32_33	0x00100000	/* VDD voltage 3.2 ~ 3.3 */
++#define MMC_VDD_33_34	0x00200000	/* VDD voltage 3.3 ~ 3.4 */
++#define MMC_VDD_34_35	0x00400000	/* VDD voltage 3.4 ~ 3.5 */
++#define MMC_VDD_35_36	0x00800000	/* VDD voltage 3.5 ~ 3.6 */
++#define MMC_CARD_BUSY	0x80000000	/* Card Power up status bit */
++
++
++/*
++ * CSD field definitions
++ */
++
++#define CSD_STRUCT_VER_1_0  0           /* Valid for system specification 1.0 - 1.2 */
++#define CSD_STRUCT_VER_1_1  1           /* Valid for system specification 1.4 - 2.2 */
++#define CSD_STRUCT_VER_1_2  2           /* Valid for system specification 3.1       */
++
++#define CSD_SPEC_VER_0      0           /* Implements system specification 1.0 - 1.2 */
++#define CSD_SPEC_VER_1      1           /* Implements system specification 1.4 */
++#define CSD_SPEC_VER_2      2           /* Implements system specification 2.0 - 2.2 */
++#define CSD_SPEC_VER_3      3           /* Implements system specification 3.1 */
++
++#endif  /* MMC_MMC_PROTOCOL_H */
++
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/l3/algo-bit.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,39 @@
++/*
++ *  linux/include/linux/l3/algo-bit.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ * L3 Bus bit-banging algorithm.  Derived from i2c-algo-bit.h by
++ * Simon G. Vogl.
++ */
++#ifndef L3_ALGO_BIT_H
++#define L3_ALGO_BIT_H 1
++
++#include <linux/l3/l3.h>
++
++struct l3_algo_bit_data {
++	void (*setdat) (void *data, int state);
++	void (*setclk) (void *data, int state);
++	void (*setmode)(void *data, int state);
++	void (*setdir) (void *data, int in);	/* set data direction */
++	int  (*getdat) (void *data);
++
++	void *data;
++
++	/* bus timings (us) */
++	int	data_hold;
++	int	data_setup;
++	int	clock_high;
++	int	mode_hold;
++	int	mode_setup;
++	int	mode;
++};
++
++int l3_bit_add_bus(struct l3_adapter *);
++int l3_bit_del_bus(struct l3_adapter *);
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/l3/l3.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,95 @@
++/*
++ *  linux/include/linux/l3/l3.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ * Derived from i2c.h by Simon G. Vogl
++ */
++#ifndef L3_H
++#define L3_H
++
++struct l3_msg {
++	unsigned char	addr;	/* slave address	*/
++	unsigned char	flags;		
++#define L3_M_RD		0x01
++#define L3_M_NOADDR	0x02
++	unsigned short	len;	/* msg length		*/
++	unsigned char	*buf;	/* pointer to msg data	*/
++};
++
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++#include <linux/list.h>
++
++struct l3_adapter;
++
++struct l3_algorithm {
++	/* textual description */
++	char name[32];
++
++	/* perform bus transactions */
++	int (*xfer)(struct l3_adapter *, struct l3_msg msgs[], int num);
++};
++
++struct semaphore;
++
++/*
++ * l3_adapter is the structure used to identify a physical L3 bus along
++ * with the access algorithms necessary to access it.
++ */
++struct l3_adapter {
++	/*
++	 * This name is used to uniquely identify the adapter.
++	 * It should be the same as the module name.
++	 */
++	char			name[32];
++
++	/*
++	 * the algorithm to access the bus
++	 */
++	struct l3_algorithm	*algo;
++
++	/*
++	 * Algorithm specific data
++	 */
++	void			*algo_data;
++
++	/*
++	 * This may be NULL, or should point to the module struct
++	 */
++	struct module		*owner;
++
++	/*
++	 * private data for the adapter
++	 */
++	void			*data;
++
++	/*
++	 * Our lock.  Unlike the i2c layer, we allow this to be used for
++	 * other stuff, like the i2c layer lock.  Some people implement
++	 * i2c stuff using the same signals as the l3 bus.
++	 */
++	struct semaphore	*lock;
++
++	/*
++	 * List of all adapters.
++	 */
++	struct list_head	adapters;
++};
++
++extern int l3_add_adapter(struct l3_adapter *);
++extern int l3_del_adapter(struct l3_adapter *);
++extern void l3_put_adapter(struct l3_adapter *);
++extern struct l3_adapter *l3_get_adapter(const char *name);
++
++extern int l3_write(struct l3_adapter *, int, const char *, int);
++extern int l3_read(struct l3_adapter *, int, char *, int);
++
++#endif
++
++#endif /* L3_H */
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/include/linux/l3/uda1341.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,61 @@
++/*
++ *  linux/include/linux/l3/uda1341.h
++ *
++ * Philips UDA1341 mixer device driver
++ *
++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++
++#define UDA1341_NAME "uda1341"
++
++struct uda1341_cfg {
++	unsigned int fs:16;
++	unsigned int format:3;
++};
++
++#define FMT_I2S		0
++#define FMT_LSB16	1
++#define FMT_LSB18	2
++#define FMT_LSB20	3
++#define FMT_MSB		4
++#define FMT_LSB16MSB	5
++#define FMT_LSB18MSB	6
++#define FMT_LSB20MSB	7
++
++#define L3_UDA1341_CONFIGURE	0x13410001
++
++struct l3_gain {
++	unsigned int	left:8;
++	unsigned int	right:8;
++	unsigned int	unused:8;
++	unsigned int	channel:8;
++};
++
++#define L3_SET_VOLUME		0x13410002
++#define L3_SET_TREBLE		0x13410003
++#define L3_SET_BASS		0x13410004
++#define L3_SET_GAIN		0x13410005
++
++struct l3_agc {
++	unsigned int	level:8;
++	unsigned int	enable:1;
++	unsigned int	attack:7;
++	unsigned int	decay:8;
++	unsigned int	channel:8;
++};
++
++#define L3_INPUT_AGC		0x13410006
++
++struct uda1341;
++
++int uda1341_configure(struct uda1341 *uda, struct uda1341_cfg *conf);
++int uda1341_mixer_ctl(struct uda1341 *uda, int cmd, void *arg);
++int uda1341_open(struct uda1341 *uda);
++void uda1341_close(struct uda1341 *uda);
++
++struct uda1341 *uda1341_attach(const char *adapter);
++void uda1341_detach(struct uda1341 *uda);
++
+--- linux-2.6.5/include/linux/i2c-id.h~heh	2004-04-03 22:36:16.000000000 -0500
++++ linux-2.6.5/include/linux/i2c-id.h	2004-04-30 20:57:36.000000000 -0400
+@@ -187,6 +187,7 @@
+ #define I2C_ALGO_BITHS	0x130000	/* enhanced bit style adapters	*/
+ #define I2C_ALGO_OCP_IOP3XX  0x140000	/* XSCALE IOP3XX On-chip I2C alg */
+ 
++#define I2C_ALGO_PXA	0x200000	/* Intel PXA I2C algorithm  */
+ #define I2C_ALGO_EXP	0x800000	/* experimental			*/
+ 
+ #define I2C_ALGO_MASK	0xff0000	/* Mask for algorithms		*/
+--- linux-2.6.5/include/linux/serial_core.h~heh	2004-04-03 22:36:18.000000000 -0500
++++ linux-2.6.5/include/linux/serial_core.h	2004-04-30 20:57:36.000000000 -0400
+@@ -17,7 +17,7 @@
+  * along with this program; if not, write to the Free Software
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  *
+- *  $Id$
++ *  $Id$
+  */
+ 
+ /*
+@@ -159,8 +159,6 @@
+ 	spinlock_t		lock;			/* port lock */
+ 	unsigned int		iobase;			/* in/out[bwl] */
+ 	char			*membase;		/* read/write[bwl] */
+-	unsigned int		irq;			/* irq number */
+-	unsigned int		uartclk;		/* base uart clock */
+ 	unsigned char		fifosize;		/* tx fifo size */
+ 	unsigned char		x_char;			/* xon/xoff char */
+ 	unsigned char		regshift;		/* reg offset shift */
+@@ -172,6 +170,7 @@
+ 
+ 	unsigned int		read_status_mask;	/* driver specific */
+ 	unsigned int		ignore_status_mask;	/* driver specific */
++
+ 	struct uart_info	*info;			/* pointer to parent info */
+ 	struct uart_icount	icount;			/* statistics */
+ 
+@@ -182,7 +181,6 @@
+ 
+ 	unsigned int		flags;
+ 
+-#define UPF_HUP_NOTIFY		(1 << 0)
+ #define UPF_FOURPORT		(1 << 1)
+ #define UPF_SAK			(1 << 2)
+ #define UPF_SPD_MASK		(0x1030)
+@@ -212,9 +210,12 @@
+ 	unsigned int		timeout;		/* character-based timeout */
+ 	unsigned int		type;			/* port type */
+ 	struct uart_ops		*ops;
++	unsigned int		uartclk;		/* base uart clock */
+ 	unsigned int		custom_divisor;
++	unsigned int		irq;			/* irq number */
+ 	unsigned int		line;			/* port index */
+ 	unsigned long		mapbase;		/* for ioremap */
++	struct device		*dev;			/* parent device */
+ 	unsigned char		hub6;			/* this should be in the 8250 driver */
+ 	unsigned char		unused[3];
+ };
+--- linux-2.6.5/include/linux/vmalloc.h~heh	2004-04-03 22:38:23.000000000 -0500
++++ linux-2.6.5/include/linux/vmalloc.h	2004-04-30 20:57:36.000000000 -0400
+@@ -35,6 +35,8 @@
+  *	Lowlevel-APIs (not for driver use!)
+  */
+ extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags);
++extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
++					unsigned long start, unsigned long end);
+ extern struct vm_struct *remove_vm_area(void *addr);
+ extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
+ 			struct page ***pages);
+--- linux-2.6.5/include/linux/mm.h~heh	2004-04-03 22:36:15.000000000 -0500
++++ linux-2.6.5/include/linux/mm.h	2004-04-30 20:57:36.000000000 -0400
+@@ -655,5 +655,12 @@
+ int in_gate_area(struct task_struct *task, unsigned long addr);
+ #endif
+ 
++#ifndef __arm__
++#define memc_update_addr(x,y,z)
++#define memc_update_mm(x)
++#define memc_clear(x,y)
++#endif
++
+ #endif /* __KERNEL__ */
+ #endif /* _LINUX_MM_H */
++
+--- linux-2.6.5/init/do_mounts.c~heh	2004-04-03 22:36:56.000000000 -0500
++++ linux-2.6.5/init/do_mounts.c	2004-04-30 20:57:36.000000000 -0400
+@@ -391,7 +391,7 @@
+ 			root_device_name += 5;
+ 	}
+ 
+-	is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
++	is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR || MAJOR(ROOT_DEV) == 31;
+ 
+ 	if (initrd_load())
+ 		goto out;
+--- linux-2.6.5/fs/binfmt_aout.c~heh	2004-04-03 22:36:26.000000000 -0500
++++ linux-2.6.5/fs/binfmt_aout.c	2004-04-30 20:57:36.000000000 -0400
+@@ -432,7 +432,11 @@
+ 		else
+ 			send_sig(SIGTRAP, current, 0);
+ 	}
++#ifndef __arm__
+ 	return 0;
++#else
++	return regs->ARM_r0;
++#endif
+ }
+ 
+ static int load_aout_library(struct file *file)
+@@ -462,8 +466,11 @@
+ 
+ 	/* For  QMAGIC, the starting address is 0x20 into the page.  We mask
+ 	   this off to get the starting address for the page */
+-
+-	start_addr =  ex.a_entry & 0xfffff000;
++#ifndef __arm__
++	start_addr = ex.a_entry & 0xfffff000;
++#else
++	start_addr = ex.a_entry & 0xffff8000;
++#endif
+ 
+ 	if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
+ 		static unsigned long error_time;
+--- linux-2.6.5/mm/slab.c~heh	2004-04-03 22:37:41.000000000 -0500
++++ linux-2.6.5/mm/slab.c	2004-04-30 20:57:36.000000000 -0400
+@@ -2115,12 +2115,12 @@
+  *
+  * Called with disabled ints.
+  */
+-static inline void __cache_free (kmem_cache_t *cachep, void* objp)
++static inline void __cache_free (kmem_cache_t *cachep, void* objp, void *caller)
+ {
+ 	struct array_cache *ac = ac_data(cachep);
+ 
+ 	check_irq_off();
+-	objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0));
++	objp = cache_free_debugcheck(cachep, objp, caller /*__builtin_return_address(0)*/);
+ 
+ 	if (likely(ac->avail < ac->limit)) {
+ 		STATS_INC_FREEHIT(cachep);
+@@ -2289,7 +2289,7 @@
+ 	unsigned long flags;
+ 
+ 	local_irq_save(flags);
+-	__cache_free(cachep, objp);
++	__cache_free(cachep, objp, __builtin_return_address(0));
+ 	local_irq_restore(flags);
+ }
+ 
+@@ -2312,7 +2312,7 @@
+ 	local_irq_save(flags);
+ 	kfree_debugcheck(objp);
+ 	c = GET_PAGE_CACHE(virt_to_page(objp));
+-	__cache_free(c, (void*)objp);
++	__cache_free(c, (void*)objp, __builtin_return_address(0));
+ 	local_irq_restore(flags);
+ }
+ 
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/Documentation/l3/structure	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,36 @@
++L3 Bus Driver
++-------------
++
++The structure of the driver is as follows:
++
++	+----------+	+----------+	+----------+
++	| client 1 |	| client 2 |	| client 3 |
++	+-----^----+	+----^-----+	+----^-----+
++	      |		     |               |
++	+-----v--------------v---------------v-----+
++	|                                          |
++	+-----^-------+              +-------^-----+
++	      |	      |     core     |       |
++	+-----v----+  |	             |  +----v-----+
++	| device   |  |	             |  | device   |
++	| driver 1 |  |              |	| driver 2 |
++	+-----^----+  |              |  +----^-----+
++	      |	      |	  services   |       |
++	+-----v-------+              +-------v-----+
++	|                                          |
++	+-----------------^----^-------------------+
++			  |    |
++			  |  +-v---------+
++			  |  | algorithm |
++			  |  |  driver   |
++			  |  +-v---------+
++			  |    |
++			+-v----v-+
++			|  bus   |
++			| driver |
++			+--------+
++
++Clients talk to the core to attach device drivers and bus adapters, and
++to instruct device drivers to perform actions.  Device drivers then talk
++to the core to perform L3 bus transactions via the algorithm driver and
++ultimately bus driver.
+--- linux-2.6.5/arch/arm/kernel/debug.S~heh	2004-04-03 22:36:55.000000000 -0500
++++ linux-2.6.5/arch/arm/kernel/debug.S	2004-04-30 20:57:36.000000000 -0400
+@@ -192,6 +192,20 @@
+ 
+ 		@ if all ports are inactive, then there is nothing we can do
+ 		moveq	pc, lr
++		ldr	r1, [\rx, #UTCR2]
++		teq	r1, #5
++		movne	r1, #0
++		strne	r1, [\rx, #UTCR3]
++		movne	r1, #8
++		strne	r1, [\rx, #UTCR0]
++		movne	r1, #5
++		strne	r1, [\rx, #UTCR2]
++		movne	r1, #0
++		strne	r1, [\rx, #UTCR1]
++		movne	r1, #3
++		strne	r1, [\rx, #UTCR3]
++		movne	r1, #255
++		strne	r1, [\rx, #UTSR0]
+ 		.endm
+ 
+ 		.macro	senduart,rd,rx
+@@ -287,7 +301,7 @@
+ 
+ #elif defined(CONFIG_ARCH_INTEGRATOR)
+ 
+-#include <asm/hardware/serial_amba.h>
++#include <asm/hardware/amba_serial.h>
+ 
+ 		.macro	addruart,rx
+ 		mrc	p15, 0, \rx, c1, c0
+@@ -298,7 +312,7 @@
+ 		.endm
+ 
+ 		.macro	senduart,rd,rx
+-		strb	\rd, [\rx, #AMBA_UARTDR]
++		strb	\rd, [\rx, #UART01x_DR]
+ 		.endm
+ 
+ 		.macro	waituart,rd,rx
+--- linux-2.6.5/arch/arm/kernel/entry-armv.S~heh	2004-04-03 22:36:54.000000000 -0500
++++ linux-2.6.5/arch/arm/kernel/entry-armv.S	2004-04-30 20:57:36.000000000 -0400
+@@ -1181,6 +1181,9 @@
+  * get out of that mode without clobbering one register.
+  */
+ vector_FIQ:	disable_fiq
++		mrs	r13, spsr
++		orr	r13, r13, #PSR_F_BIT
++		msr	spsr, r13
+ 		subs	pc, lr, #4
+ 
+ /*=============================================================================
+--- linux-2.6.5/arch/arm/kernel/irq.c~heh	2004-04-03 22:36:12.000000000 -0500
++++ linux-2.6.5/arch/arm/kernel/irq.c	2004-04-30 20:57:36.000000000 -0400
+@@ -47,12 +47,36 @@
+ #define MAX_IRQ_CNT	100000
+ 
+ static volatile unsigned long irq_err_count;
+-static spinlock_t irq_controller_lock;
+ static LIST_HEAD(irq_pending);
+ 
+ struct irqdesc irq_desc[NR_IRQS];
+ void (*init_arch_irq)(void) __initdata = NULL;
+ 
++#if NR_IRQ_DEVICES > 1
++struct irq_device {
++	spinlock_t	lock;
++	int		nr_irqs;
++	struct irq_desc	*irqs;
++};
++
++static struct irq_device irq_devices[NR_IRQ_DEVICES] = {
++	[0] = {
++		.lock		= SPIN_LOCK_UNLOCKED,
++		.nr_irqs	= NR_IRQS,
++		.irqs		= irq_desc,
++	},
++};
++#define IRQ_LOCK(irq)	(&irq_devices[IRQ_DEVICE(irq)].lock)
++#define IRQ_DESC(irq)	(&irq_devices[IRQ_DEVICE(irq)].irqs[IRQ_INDEX(irq)])
++#define IRQ_VALID(irq)	(IRQ_DEVICE(irq) < NR_IRQ_DEVICES && \
++			 IRQ_INDEX(irq) < irq_devices[IRQ_DEVICE(irq)].nr_irqs)
++#else
++static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED;
++#define IRQ_LOCK(irq)	(&irq_controller_lock)
++#define IRQ_DESC(irq)	(&irq_desc[irq])
++#define IRQ_VALID(irq)	((irq) < NR_IRQS)
++#endif
++
+ /*
+  * Dummy mask/unmask handler
+  */
+@@ -95,13 +119,13 @@
+  */
+ void disable_irq(unsigned int irq)
+ {
+-	struct irqdesc *desc = irq_desc + irq;
++	struct irqdesc *desc = IRQ_DESC(irq);
+ 	unsigned long flags;
+ 
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	desc->disable_depth++;
+ 	list_del_init(&desc->pend);
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ }
+ 
+ /**
+@@ -116,10 +140,10 @@
+  */
+ void enable_irq(unsigned int irq)
+ {
+-	struct irqdesc *desc = irq_desc + irq;
++	struct irqdesc *desc = IRQ_DESC(irq);
+ 	unsigned long flags;
+ 
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	if (unlikely(!desc->disable_depth)) {
+ 		printk("enable_irq(%u) unbalanced from %p\n", irq,
+ 			__builtin_return_address(0));
+@@ -140,7 +164,7 @@
+ 				list_add(&desc->pend, &irq_pending);
+ 		}
+ 	}
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ }
+ 
+ /*
+@@ -148,24 +172,24 @@
+  */
+ void enable_irq_wake(unsigned int irq)
+ {
+-	struct irqdesc *desc = irq_desc + irq;
++	struct irqdesc *desc = IRQ_DESC(irq);
+ 	unsigned long flags;
+ 
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	if (desc->chip->wake)
+ 		desc->chip->wake(irq, 1);
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ }
+ 
+ void disable_irq_wake(unsigned int irq)
+ {
+-	struct irqdesc *desc = irq_desc + irq;
++	struct irqdesc *desc = IRQ_DESC(irq);
+ 	unsigned long flags;
+ 
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	if (desc->chip->wake)
+ 		desc->chip->wake(irq, 0);
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ }
+ 
+ int show_interrupts(struct seq_file *p, void *v)
+@@ -175,8 +199,8 @@
+ 	unsigned long flags;
+ 
+ 	if (i < NR_IRQS) {
+-		spin_lock_irqsave(&irq_controller_lock, flags);
+-	    	action = irq_desc[i].action;
++		spin_lock_irqsave(IRQ_LOCK(irq), flags);
++	    	action = IRQ_DESC(i)->action;
+ 		if (!action)
+ 			goto unlock;
+ 
+@@ -187,7 +211,7 @@
+ 
+ 		seq_putc(p, '\n');
+ unlock:
+-		spin_unlock_irqrestore(&irq_controller_lock, flags);
++		spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ 	} else if (i == NR_IRQS) {
+ #ifdef CONFIG_ARCH_ACORN
+ 		show_fiq_list(p, v);
+@@ -259,7 +283,7 @@
+ 	unsigned int status;
+ 	int retval = 0;
+ 
+-	spin_unlock(&irq_controller_lock);
++	spin_unlock(IRQ_LOCK(irq));
+ 
+ 	if (!(action->flags & SA_INTERRUPT))
+ 		local_irq_enable();
+@@ -274,7 +298,7 @@
+ 	if (status & SA_SAMPLE_RANDOM)
+ 		add_interrupt_randomness(irq);
+ 
+-	spin_lock_irq(&irq_controller_lock);
++	spin_lock_irq(IRQ_LOCK(irq));
+ 
+ 	return retval;
+ }
+@@ -455,7 +479,7 @@
+ 		desc = &bad_irq_desc;
+ 
+ 	irq_enter();
+-	spin_lock(&irq_controller_lock);
++	spin_lock(IRQ_LOCK(irq));
+ 	desc->handle(irq, desc, regs);
+ 
+ 	/*
+@@ -464,7 +488,7 @@
+ 	if (!list_empty(&irq_pending))
+ 		do_pending_irqs(regs);
+ 
+-	spin_unlock(&irq_controller_lock);
++	spin_unlock(IRQ_LOCK(irq));
+ 	irq_exit();
+ }
+ 
+@@ -473,7 +497,7 @@
+ 	struct irqdesc *desc;
+ 	unsigned long flags;
+ 
+-	if (irq >= NR_IRQS) {
++	if (!IRQ_VALID(irq)) {
+ 		printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq);
+ 		return;
+ 	}
+@@ -481,12 +505,12 @@
+ 	if (handle == NULL)
+ 		handle = do_bad_IRQ;
+ 
+-	desc = irq_desc + irq;
++	desc = IRQ_DESC(irq);
+ 
+ 	if (is_chained && desc->chip == &bad_chip)
+ 		printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq);
+ 
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	if (handle == do_bad_IRQ) {
+ 		desc->chip->mask(irq);
+ 		desc->chip->ack(irq);
+@@ -499,7 +523,7 @@
+ 		desc->disable_depth = 0;
+ 		desc->chip->unmask(irq);
+ 	}
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ }
+ 
+ void set_irq_chip(unsigned int irq, struct irqchip *chip)
+@@ -507,7 +531,7 @@
+ 	struct irqdesc *desc;
+ 	unsigned long flags;
+ 
+-	if (irq >= NR_IRQS) {
++	if (!IRQ_VALID(irq)) {
+ 		printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq);
+ 		return;
+ 	}
+@@ -515,10 +539,10 @@
+ 	if (chip == NULL)
+ 		chip = &bad_chip;
+ 
+-	desc = irq_desc + irq;
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	desc = IRQ_DESC(irq);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	desc->chip = chip;
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ }
+ 
+ int set_irq_type(unsigned int irq, unsigned int type)
+@@ -527,16 +551,21 @@
+ 	unsigned long flags;
+ 	int ret = -ENXIO;
+ 
+-	if (irq >= NR_IRQS) {
++	if (!IRQ_VALID(irq)) {
+ 		printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
+ 		return -ENODEV;
+ 	}
+ 
+-	desc = irq_desc + irq;
++	desc = IRQ_DESC(irq);
++	if (!desc->action && desc->handle != do_bad_IRQ) {
++		printk(KERN_ERR "Setting type of unclaimed IRQ%d from ", irq);
++		print_symbol("%s\n", (unsigned long)__builtin_return_address(0));
++	}
++
+ 	if (desc->chip->type) {
+-		spin_lock_irqsave(&irq_controller_lock, flags);
++		spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 		ret = desc->chip->type(irq, type);
+-		spin_unlock_irqrestore(&irq_controller_lock, flags);
++		spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ 	}
+ 
+ 	return ret;
+@@ -547,17 +576,17 @@
+ 	struct irqdesc *desc;
+ 	unsigned long flags;
+ 
+-	if (irq >= NR_IRQS) {
++	if (!IRQ_VALID(irq)) {
+ 		printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
+ 		return;
+ 	}
+ 
+-	desc = irq_desc + irq;
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	desc = IRQ_DESC(irq);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	desc->valid = (iflags & IRQF_VALID) != 0;
+ 	desc->probe_ok = (iflags & IRQF_PROBE) != 0;
+ 	desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0;
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ }
+ 
+ int setup_irq(unsigned int irq, struct irqaction *new)
+@@ -587,13 +616,13 @@
+ 	/*
+ 	 * The following block of code has to be executed atomically
+ 	 */
+-	desc = irq_desc + irq;
+-	spin_lock_irqsave(&irq_controller_lock, flags);
++	desc = IRQ_DESC(irq);
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
+ 	p = &desc->action;
+ 	if ((old = *p) != NULL) {
+ 		/* Can't share interrupts unless both agree to */
+ 		if (!(old->flags & new->flags & SA_SHIRQ)) {
+-			spin_unlock_irqrestore(&irq_controller_lock, flags);
++			spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ 			return -EBUSY;
+ 		}
+ 
+@@ -618,7 +647,7 @@
+ 		}
+ 	}
+ 
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ 	return 0;
+ }
+ 
+@@ -659,7 +688,7 @@
+ 	unsigned long retval;
+ 	struct irqaction *action;
+ 
+-	if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler ||
++	if (!IRQ_VALID(irq) || !IRQ_DESC(irq)->valid || !handler ||
+ 	    (irq_flags & SA_SHIRQ && !dev_id))
+ 		return -EINVAL;
+ 
+@@ -700,14 +729,14 @@
+ 	struct irqaction * action, **p;
+ 	unsigned long flags;
+ 
+-	if (irq >= NR_IRQS || !irq_desc[irq].valid) {
++	if (!IRQ_VALID(irq) || !IRQ_DESC(irq)->valid) {
+ 		printk(KERN_ERR "Trying to free IRQ%d\n",irq);
+ 		dump_stack();
+ 		return;
+ 	}
+ 
+-	spin_lock_irqsave(&irq_controller_lock, flags);
+-	for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) {
++	spin_lock_irqsave(IRQ_LOCK(irq), flags);
++	for (p = &IRQ_DESC(irq)->action; (action = *p) != NULL; p = &action->next) {
+ 		if (action->dev_id != dev_id)
+ 			continue;
+ 
+@@ -715,7 +744,7 @@
+ 		*p = action->next;
+ 		break;
+ 	}
+-	spin_unlock_irqrestore(&irq_controller_lock, flags);
++	spin_unlock_irqrestore(IRQ_LOCK(irq), flags);
+ 
+ 	if (!action) {
+ 		printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
+@@ -747,19 +776,18 @@
+ 	 * first snaffle up any unassigned but
+ 	 * probe-able interrupts
+ 	 */
+-	spin_lock_irq(&irq_controller_lock);
+ 	for (i = 0; i < NR_IRQS; i++) {
+-		if (!irq_desc[i].probe_ok || irq_desc[i].action)
+-			continue;
+-
+-		irq_desc[i].probing = 1;
+-		irq_desc[i].triggered = 0;
+-		if (irq_desc[i].chip->type)
+-			irq_desc[i].chip->type(i, IRQT_PROBE);
+-		irq_desc[i].chip->unmask(i);
+-		irqs += 1;
++		spin_lock_irq(IRQ_LOCK(i));
++		if (irq_desc[i].probe_ok && !irq_desc[i].action) {
++			irq_desc[i].probing = 1;
++			irq_desc[i].triggered = 0;
++			if (irq_desc[i].chip->type)
++				irq_desc[i].chip->type(i, IRQT_PROBE);
++			irq_desc[i].chip->unmask(i);
++			irqs += 1;
++		}
++		spin_unlock_irq(IRQ_LOCK(i));
+ 	}
+-	spin_unlock_irq(&irq_controller_lock);
+ 
+ 	/*
+ 	 * wait for spurious interrupts to mask themselves out again
+@@ -770,14 +798,14 @@
+ 	/*
+ 	 * now filter out any obviously spurious interrupts
+ 	 */
+-	spin_lock_irq(&irq_controller_lock);
+ 	for (i = 0; i < NR_IRQS; i++) {
++		spin_lock_irq(IRQ_LOCK(i));
+ 		if (irq_desc[i].probing && irq_desc[i].triggered) {
+ 			irq_desc[i].probing = 0;
+ 			irqs -= 1;
+ 		}
++		spin_unlock_irq(IRQ_LOCK(i));
+ 	}
+-	spin_unlock_irq(&irq_controller_lock);
+ 
+ 	return irqs;
+ }
+@@ -788,11 +816,13 @@
+ {
+ 	unsigned int mask = 0, i;
+ 
+-	spin_lock_irq(&irq_controller_lock);
+-	for (i = 0; i < 16 && i < NR_IRQS; i++)
+-		if (irq_desc[i].probing && irq_desc[i].triggered)
++	for (i = 0; i < 16 && i < NR_IRQS; i++) {
++		struct irqdesc *desc = IRQ_DESC(i);
++		spin_lock_irq(IRQ_LOCK(i));
++		if (desc->probing && desc->triggered)
+ 			mask |= 1 << i;
+-	spin_unlock_irq(&irq_controller_lock);
++		spin_unlock_irq(IRQ_LOCK(i));
++	}
+ 
+ 	up(&probe_sem);
+ 
+@@ -813,23 +843,21 @@
+ 	 * look at the interrupts, and find exactly one
+ 	 * that we were probing has been triggered
+ 	 */
+-	spin_lock_irq(&irq_controller_lock);
+ 	for (i = 0; i < NR_IRQS; i++) {
+-		if (irq_desc[i].probing &&
+-		    irq_desc[i].triggered) {
++		struct irqdesc *desc = IRQ_DESC(i);
++
++		spin_lock_irq(IRQ_LOCK(i));
++		if (desc->probing && desc->triggered) {
+ 			if (irq_found != NO_IRQ) {
++				spin_unlock_irq(IRQ_LOCK(i));
+ 				irq_found = NO_IRQ;
+-				goto out;
++				break;
+ 			}
+ 			irq_found = i;
+ 		}
++		spin_unlock_irq(IRQ_LOCK(i));
+ 	}
+ 
+-	if (irq_found == -1)
+-		irq_found = NO_IRQ;
+-out:
+-	spin_unlock_irq(&irq_controller_lock);
+-
+ 	up(&probe_sem);
+ 
+ 	return irq_found;
+--- linux-2.6.5/arch/arm/kernel/bios32.c~heh	2004-04-03 22:36:56.000000000 -0500
++++ linux-2.6.5/arch/arm/kernel/bios32.c	2004-04-30 20:57:36.000000000 -0400
+@@ -565,8 +565,6 @@
+ 	if (hw->postinit)
+ 		hw->postinit();
+ 
+-	pci_fixup_irqs(pcibios_swizzle, pcibios_map_irq);
+-
+ 	list_for_each_entry(sys, &hw->buses, node) {
+ 		struct pci_bus *bus = sys->bus;
+ 
+@@ -581,6 +579,11 @@
+ 		pci_bus_assign_resources(bus);
+ 
+ 		/*
++		 * Fixup IRQs.
++		 */
++		pci_bus_fixup_irqs(bus, pcibios_swizzle, pcibios_map_irq);
++
++		/*
+ 		 * Tell drivers about devices found.
+ 		 */
+ 		pci_bus_add_devices(bus);
+--- linux-2.6.5/arch/arm/kernel/traps.c~heh	2004-04-03 22:36:57.000000000 -0500
++++ linux-2.6.5/arch/arm/kernel/traps.c	2004-04-30 20:57:36.000000000 -0400
+@@ -206,33 +206,43 @@
+ 	c_backtrace(fp, 0x10);
+ }
+ 
+-spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+-
+-/*
+- * This function is protected against re-entrancy.
+- */
+-NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
++static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
+ {
+-	struct task_struct *tsk = current;
++	struct task_struct *tsk = thread->task;
+ 	static int die_counter;
+ 
+-	console_verbose();
+-	spin_lock_irq(&die_lock);
+-	bust_spinlocks(1);
+-
+ 	printk("Internal error: %s: %x [#%d]\n", str, err, ++die_counter);
+ 	print_modules();
+ 	printk("CPU: %d\n", smp_processor_id());
+ 	show_regs(regs);
+ 	printk("Process %s (pid: %d, stack limit = 0x%p)\n",
+-		tsk->comm, tsk->pid, tsk->thread_info + 1);
++		tsk->comm, tsk->pid, thread + 1);
+ 
+ 	if (!user_mode(regs) || in_interrupt()) {
+ 		dump_mem("Stack: ", regs->ARM_sp, 8192+(unsigned long)tsk->thread_info);
+ 		dump_backtrace(regs, tsk);
+ 		dump_instr(regs);
+ 	}
++}
++
++void nmi_watchdog(struct thread_info *thread, struct pt_regs *regs)
++{
++	__die("NMI watchdog", 0, thread, regs);
++}
+ 
++spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
++
++/*
++ * This function is protected against re-entrancy.
++ */
++NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
++{
++	struct thread_info *thread = current_thread_info();
++
++	console_verbose();
++	spin_lock_irq(&die_lock);
++	bust_spinlocks(1);
++	__die(str, err, thread, regs);
+ 	bust_spinlocks(0);
+ 	spin_unlock_irq(&die_lock);
+ 	do_exit(SIGSEGV);
+--- linux-2.6.5/arch/arm/Kconfig~heh	2004-04-03 22:37:07.000000000 -0500
++++ linux-2.6.5/arch/arm/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -297,7 +297,7 @@
+ 
+ config CPU_FREQ
+ 	bool "Support CPU clock change (EXPERIMENTAL)"
+-	depends on (ARCH_SA1100 || ARCH_INTEGRATOR) && EXPERIMENTAL
++	depends on (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_PXA) && EXPERIMENTAL
+ 	help
+ 	  CPU clock scaling allows you to change the clock speed of the
+ 	  running CPU on the fly. This is a nice method to save battery power,
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/fastfpe/entry.S	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,294 @@
++/*
++At entry the registers contain the following information:
++
++r14	return address for undefined exception return
++r9	return address for return from exception
++r13	user registers on stack, offset 0 up to offset 4*15 contains
++	registers r0..15, then the psr
++r10	FP workspace 35 words (init, reg[8][4], fpsr, fpcr)
++ 
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.data
++fp_const:
++	.word	0, 0x00000000, 0, 0x80000000	@ 0
++	.word	0, 0x80000000, 0,          0	@ 1
++	.word	0, 0x80000000, 0,          1	@ 2
++	.word	0, 0xc0000000, 0,          1	@ 3
++	.word	0, 0x80000000, 0,          2	@ 4
++	.word	0, 0xa0000000, 0,          2	@ 5
++	.word	0, 0x80000000, 0,	  -1	@ 0.5
++	.word	0, 0xa0000000, 0,          3	@ 10
++fp_undef:
++	.word	0
++fp_cond:
++	.word	0xf0f0	@ eq
++	.word	0x0f0f	@ ne
++	.word	0xcccc	@ cs
++	.word	0x3333	@ cc
++	.word	0xff00	@ mi
++	.word	0x00ff	@ pl
++	.word	0xaaaa	@ vs
++	.word	0x5555	@ vc
++	.word	0x0c0c	@ hi
++	.word	0xf3f3	@ ls
++	.word	0xaa55	@ ge
++	.word	0x55aa	@ lt
++	.word	0x0a05	@ gt
++	.word	0xf5fa	@ le
++	.word	0xffff	@ al
++	.word	0x0000	@ nv
++	
++/*---------------------------------------------------------------------------*/
++	
++	.text
++	.globl	fastfpe_enter
++fastfpe_enter:
++	ldr	r4,=fp_undef
++	str	r14,[r4]		@ to free one register
++	add	r10,r10,#4		@ to make the code simpler
++	mov	r4, r0			@ r4=trapped instruction
++	and	r1,r4,#0x00000f00	@ r1=coprocessor << 8
++next_enter:
++	cmp	r1,#1<<8		@ copro 1 ?
++	beq	copro_1
++	cmp	r1,#2<<8
++	movne	pc,r14
++
++copro_2:
++	and	r1,r4,#0x0f000000
++	cmp	r1,#0x0c000000          @ CPDT with post indexing
++        cmpne   r1,#0x0d000000          @ CPDT with pre indexing
++        beq     CPDT_M_enter
++	mov	pc,r14
++
++copro_1:
++	and	r1,r4,#0x0f000000
++	cmp	r1,#0x0e000000		@ CPDO
++	beq	CPDO_CPRT_enter
++	cmp	r1,#0x0c000000		@ CPDT with post indexing
++	cmpne	r1,#0x0d000000		@ CPDT with pre indexing
++	beq	CPDT_1_enter
++	mov	pc,r14
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	fastfpe_next
++fastfpe_next:
++	ldr	r5,[r13,#60]
++next_after_cond:
++__x1:
++	ldrt	r4,[r5],#4
++	
++	ldr	r0,=fp_cond		@ check condition of next instruction
++	ldr	r1,[r13,#64]		@ psr containing flags
++	mov	r2,r4,lsr#28
++	mov	r1,r1,lsr#28
++	ldr	r0,[r0,r2,lsl#2]
++	mov	r0,r0,lsr r1
++	tst	r0,#1
++	beq	next_after_cond		@ must not necessarily have been an
++					@ FP instruction !
++	and	r1,r4,#0x0f000000	@ Test for copro instruction
++	cmp	r1,#0x0c000000
++	rsbgts	r0,r1,#0x0e000000	@ cmpgt #0x0e000000,r1
++	movlt	pc,r9			@ next is no copro instruction, return
++	
++	ands	r1,r4,#0x00000f00	@ r1 = coprocessor << 8
++	cmpne	r1,#3<<8
++	movge	pc,r9			@ copro = 0 or >=3, return
++		
++	str	r5,[r13,#60]		@ save updated pc
++	b	next_enter
++
++/*---------------------------------------------------------------------------*/
++
++undefined:
++	ldr	r4,=fp_undef
++	ldr	pc,[r4]	
++
++/*---------------------------------------------------------------------------*/
++
++CPDT_1_enter:
++	and	r5,r4,#0x000f0000	@ r5=base register number << 16
++	ldr	r6,[r13,r5,lsr#14]	@ r6=base address
++	cmp	r5,#0x000f0000		@ base register = pc ?
++	addeq	r6,r6,#4
++	and	r7,r4,#0x000000ff	@ r7=offset value
++
++	tst	r4,#0x00800000		@ up or down?
++	addne	r7,r6,r7,lsl#2
++	subeq	r7,r6,r7,lsl#2		@ r6=base address +/- offset
++	tst	r4,#0x01000000		@ preindexing ?
++	movne	r6,r7
++	tst	r4,#0x00200000		@ write back ?
++	cmpne	r5,#0x000f0000		@ base register = pc ?
++	strne	r7,[r13,r5,lsr#14]
++
++	and	r0,r4,#0x00007000	@ r0=fp register number << 12
++	add	r0,r10,r0,lsr#8		@ r0=address of fp register
++	mov	r1,#0
++	tst	r4,#0x00008000
++	orrne	r1,r1,#1		@ T0
++	tst	r4,#0x00400000
++	orrne	r1,r1,#2		@ T1
++	tst	r4,#0x00100000
++	orrne	r1,r1,#4		@ L/S
++
++	add	pc,pc,r1,lsl#2
++	mov	r0,r0
++	b	CPDT_store_single	@ these functions get 
++	b	CPDT_store_double	@ r0=address of fp register
++	b	CPDT_store_extended	@ r6=address of data
++	b	undefined		@ CPDT_store_decimal
++        b       CPDT_load_single
++        b       CPDT_load_double
++        b       CPDT_load_extended
++        b       undefined		@ CPDT_load_decimal
++
++/*---------------------------------------------------------------------------*/
++
++CPDT_M_enter:
++	and	r5,r4,#0x000f0000	@ r5=base register number << 16
++	ldr	r6,[r13,r5,lsr#14]	@ r6=base address
++	cmp	r5,#0x000f0000		@ base register = pc ?
++	addeq	r6,r6,#4
++	and	r7,r4,#0x000000ff	@ r7=offset value
++
++	tst	r4,#0x00800000		@ up or down?
++	addne	r7,r6,r7,lsl#2
++	subeq	r7,r6,r7,lsl#2		@ r7=base address +/- offset
++	tst	r4,#0x01000000		@ preindexing ?
++	movne	r6,r7
++	tst	r4,#0x00200000		@ write back ?
++	cmpne	r5,#0x000f0000		@ base register = pc ?
++	strne	r7,[r13,r5,lsr#14]
++
++	and	r0,r4,#0x00007000	@ r0=fp register number << 12
++	and	r1,r4,#0x00008000
++	mov	r1,r1,lsr#15		@ N0
++	and	r2,r4,#0x00400000
++	orrs	r1,r1,r2,lsr#21		@ N1
++	addeq	r1,r1,#4		@ r1=register count
++
++	tst	r4,#0x00100000		@ load/store
++	beq	CPDT_sfm
++	b	CPDT_lfm
++
++/*---------------------------------------------------------------------------*/
++
++CPDO_CPRT_enter:
++	tst	r4,#0x00000010
++	bne	CPRT_enter
++	
++	and	r0,r4,#0x00007000
++	add	r0,r10,r0,lsr#8		@ r0=address of Fd
++	and	r1,r4,#0x00070000
++	add	r1,r10,r1,lsr#12	@ r1=address of Fn
++	tst	r4,#0x00000008
++	bne	CPDO_const
++	and	r2,r4,#0x00000007
++	add	r2,r10,r2,lsl#4		@ r2=address of Fm
++	
++CPDO_constback:
++	and	r3,r4,#0x00f00000
++	tst	r4,#0x00008000
++	orrne	r3,r3,#0x01000000
++		
++	add	pc,pc,r3,lsr#18
++	mov	r0,r0
++	b	CPDO_adf
++	b	CPDO_muf
++	b	CPDO_suf
++	b	CPDO_rsf
++	b	CPDO_dvf
++	b	CPDO_rdf
++	b	undefined
++	b	undefined
++	b	undefined		@ CPDO_rmf
++	b	CPDO_muf
++	b	CPDO_dvf
++	b	CPDO_rdf
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	CPDO_mvf
++	b	CPDO_mnf
++	b	CPDO_abs
++	b	CPDO_rnd
++	b	CPDO_sqt
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	CPDO_rnd
++	b	fastfpe_next
++
++CPDO_const:
++	ldr	r2,=fp_const
++	and	r3,r4,#0x00000007
++	add	r2,r2,r3,lsl#4	
++	b	CPDO_constback
++	
++/*---------------------------------------------------------------------------*/
++
++CPRT_enter:
++	and	r0,r4,#0x0000f000	@ r0=Rd<<12
++	and	r1,r4,#0x00070000
++	add	r1,r10,r1,lsr#12	@ r1=address of Fn
++	tst	r4,#0x00000008
++	bne	CPRT_const
++	and	r2,r4,#0x00000007
++	add	r2,r10,r2,lsl#4		@ r2=address of Fm
++	
++CPRT_constback:
++	and	r3,r4,#0x00f00000
++		
++	add	pc,pc,r3,lsr#18
++	mov	r0,r0
++	b	CPRT_flt
++	b	CPRT_fix
++	b	CPRT_wfs
++	b	CPRT_rfs
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	CPRT_cmf
++	b	undefined
++	b	CPRT_cnf
++	b	undefined
++	b	CPRT_cmf
++	b	undefined
++	b	CPRT_cnf
++
++CPRT_const:
++	ldr	r2,=fp_const
++	and	r3,r4,#0x00000007
++	add	r2,r2,r3,lsl#4	
++	b	CPRT_constback
++	
++/*---------------------------------------------------------------------------*/
++
++	@ The fetch of the next instruction to emulate could fault
++
++	.section .fixup,"ax"
++	.align
++__f1:
++	mov	pc,r9
++	.previous
++	.section __ex_table,"a"
++	.align 3
++	.long	__x1,__f1
++	.previous
++	
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/fastfpe/module.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,62 @@
++/*
++    Fast Floating Point Emulator
++    (c) Peter Teichmann <mail@peter-teichmann.de>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++
++#ifndef MODULE
++#define kern_fp_enter	fp_enter
++
++extern char fpe_type[];
++#endif
++
++static void (*orig_fp_enter)(void);	/* old kern_fp_enter value */
++extern void (*kern_fp_enter)(void);	/* current FP handler */
++extern void fastfpe_enter(void);	/* forward declarations */
++
++static int __init fpe_init(void)
++{
++  if (fpe_type[0] && strcmp(fpe_type, "fastfpe"))
++    return 0;
++
++  printk("Fast Floating Point Emulator V0.9 (c) Peter Teichmann.\n");
++
++  /* Save pointer to the old FP handler and then patch ourselves in */
++  orig_fp_enter = kern_fp_enter;
++  kern_fp_enter = fastfpe_enter;
++
++  return 0;
++}
++
++static void __exit fpe_exit(void)
++{
++  /* Restore the values we saved earlier. */
++  kern_fp_enter = orig_fp_enter;
++}
++
++module_init(fpe_init);
++module_exit(fpe_exit);
++
++MODULE_AUTHOR("Peter Teichmann <mail@peter-teichmann.de>");
++MODULE_DESCRIPTION("Fast floating point emulator with full precision");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/fastfpe/CPDO.S	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,682 @@
++/*
++The FP structure has 4 words reserved for each register, the first is used just
++for the sign in bit 31, the second and third are for the mantissa (unsigned
++integer, high 32 bit first) and the fourth is the exponent (signed integer).
++The mantissa is always normalized.
++
++If the exponent is 0x80000000, that is the most negative value, the number
++represented is 0 and both mantissa words are also 0.
++
++If the exponent is 0x7fffffff, that is the biggest positive value, the number
++represented is infinity if the high 32 mantissa bit are also 0, otherwise it is
++a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
++
++Decimal and packed decimal numbers are not supported yet.
++
++The parameters to these functions are r0=destination pointer, r1 and r2
++source pointers. r4 is the instruction. They may use r0-r8 and r14. They return
++to fastfpe_next, except CPDO_rnf_core which expects the return address in r14.
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_adf
++CPDO_adf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_adf_extra
++
++	cmp	r1,r2
++	bne	CPDO_suf_s
++
++CPDO_adf_s:
++	subs	r2,r7,r8
++	bge	CPDO_adf_2nd
++	
++	mov	r7,r8
++	rsb	r2,r2,#0
++	cmp	r2,#32
++	ble	CPDO_adf_1st2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r5,r3,lsr r2
++	mov	r3,#0
++	b	CPDO_adf_add
++
++CPDO_adf_1st2:
++	rsb	r8,r2,#32
++	mov	r5,r5,lsr r2
++	orr	r5,r5,r3,lsl r8
++	mov	r3,r3,lsr r2	@ 1. op normalized
++	b	CPDO_adf_add
++
++CPDO_adf_2nd:
++	cmp	r2,#32
++	ble	CPDO_adf_2nd2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r6,r4,lsr r2
++	mov	r4,#0
++	b	CPDO_adf_add
++
++CPDO_adf_2nd2:
++	rsb	r8,r2,#32
++	mov	r6,r6,lsr r2
++	orr	r6,r6,r4,lsl r8
++	mov	r4,r4,lsr r2	@ 2. op normalized
++
++CPDO_adf_add:
++	adds	r5,r5,r6
++	adcs	r3,r3,r4	@ do addition
++	bcc	CPDO_adf_end
++
++	add	r7,r7,#1
++	movs	r3,r3,rrx
++	mov	r5,r5,rrx	@ correct for overflow
++
++CPDO_adf_end:
++	cmp	r7,#0x20000000
++	bge	CPDO_inf
++
++	stmia	r0,{r1,r3,r5,r7}
++	b	fastfpe_next
++
++CPDO_adf_extra:
++	cmp	r7,#0x7fffffff		@ was it the 1st ?
++	bne	CPDO_infnan_2		@ no it was the 2nd
++	cmp	r8,#0x7fffffff		@ if 1st, 2nd too ?
++	bne	CPDO_infnan_1		@ no only 1st
++	cmp	r3,#0
++	cmpeq	r4,#0
++	bne	CPDO_nan_12
++	b	CPDO_inf
++
++/*---------------------------------------------------------------------------*/
++
++CPDO_infnan_1:
++	stmia	r0,{r1,r3,r5,r7}
++	b	fastfpe_next
++
++CPDO_infnan_2:
++	stmia	r0,{r2,r4,r6,r8}
++	b	fastfpe_next
++	
++CPDO_nan_12:
++	orr	r2,r3,r4
++	b	CPDO_inf_1
++
++CPDO_nan:
++	mov	r2,#0x40000000		@ create non signalling NaN
++	b	CPDO_inf_1
++
++CPDO_inf:
++	mov	r2,#0
++CPDO_inf_1:
++	mov	r3,#0
++	mov	r4,#0x7fffffff
++CPDO_store_1234:
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++CPDO_zero:
++	mov	r1,#0
++CPDO_zero_1:
++	mov	r2,#0
++	mov	r3,#0
++	mov	r4,#0x80000000
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_suf
++CPDO_suf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++CPDO_suf_l:
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_suf_extra
++
++	cmp	r1,r2
++	bne	CPDO_adf_s
++
++CPDO_suf_s:
++	subs	r2,r7,r8		@ determine greater number
++	bgt	CPDO_suf_2nd		@ first number is greater
++	blt	CPDO_suf_1st		@ second number is greater
++	cmp	r3,r4			@ also mantissa is important
++	cmpeq	r5,r6
++	bhi	CPDO_suf_2nd		@ first number is greater
++	beq	CPDO_zero
++
++CPDO_suf_1st:
++	eor	r1,r1,#0x80000000	@ second number is greater, invert sign
++	mov	r7,r8
++	rsb	r2,r2,#0
++	cmp	r2,#32
++	ble	CPDO_suf_1st2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r5,r3,lsr r2
++	mov	r3,#0
++	b	CPDO_suf_1st_sub
++
++CPDO_suf_1st2:
++	rsb	r8,r2,#32
++	mov	r5,r5,lsr r2
++	orr	r5,r5,r3,lsl r8
++	mov	r3,r3,lsr r2	@ 1. op normalized
++
++CPDO_suf_1st_sub:
++	subs	r5,r6,r5	@ do subtraction
++	sbc	r3,r4,r3
++	b	CPDO_suf_norm
++
++CPDO_suf_2nd:
++	cmp	r2,#32
++	ble	CPDO_suf_2nd2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r6,r4,lsr r2
++	mov	r4,#0
++	b	CPDO_suf_2nd_sub
++
++CPDO_suf_2nd2:
++	rsb	r8,r2,#32
++	mov	r6,r6,lsr r2
++	orr	r6,r6,r4,lsl r8
++	mov	r4,r4,lsr r2	@ 2. op normalized
++
++CPDO_suf_2nd_sub:
++	subs	r5,r5,r6
++	sbc	r3,r3,r4	@ do subtraction
++
++CPDO_suf_norm:
++	teq	r3,#0		@ normalize 32bit
++	moveq	r3,r5
++	moveq	r5,#0
++	subeq	r7,r7,#32
++	
++	cmp	r3,#0x00010000	@ 16bit
++	movcc	r3,r3,lsl#16
++	orrcc	r3,r3,r5,lsr#16
++	movcc	r5,r5,lsl#16
++	subcc	r7,r7,#16
++	
++	cmp	r3,#0x01000000	@ 8bit
++	movcc	r3,r3,lsl#8
++	orrcc	r3,r3,r5,lsr#24
++	movcc	r5,r5,lsl#8
++	subcc	r7,r7,#8
++	
++	cmp	r3,#0x10000000	@ 4bit
++	movcc	r3,r3,lsl#4
++	orrcc	r3,r3,r5,lsr#28
++	movcc	r5,r5,lsl#4
++	subcc	r7,r7,#4
++	
++	cmp	r3,#0x40000000	@ 2bit
++	movcc	r3,r3,lsl#2
++	orrcc	r3,r3,r5,lsr#30
++	movcc	r5,r5,lsl#2
++	subcc	r7,r7,#2
++	
++	cmp	r3,#0x80000000	@ 1bit
++	movcc	r3,r3,lsl#1
++	orrcc	r3,r3,r5,lsr#31
++	movcc	r5,r5,lsl#1
++	subcc	r7,r7,#1
++
++	cmp	r7,#0xe0000000
++	ble	CPDO_zero_1
++
++	stmia	r0,{r1,r3,r5,r7}
++	b	fastfpe_next
++
++CPDO_suf_extra:
++	cmp	r7,#0x7fffffff		@ was it the 1st ?
++	eorne	r2,r2,#0x80000000	@ change sign, might have been INF
++	bne	CPDO_infnan_2		@ no it was the 2nd
++	cmp	r8,#0x7fffffff		@ if 1st, 2nd too ?
++	bne	CPDO_infnan_1		@ no only 1st
++	cmp	r3,#0
++	cmpeq	r4,#0
++	bne	CPDO_nan_12
++	b	CPDO_nan		@ here is difference with adf !
++
++/*---------------------------------------------------------------------------*/
++
++	.globl CPDO_rsf
++CPDO_rsf:
++	mov	r3,r2
++	ldmia	r1,{r2,r4,r6,r8}
++	ldmia	r3,{r1,r3,r5,r7}
++	b	CPDO_suf_l
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_muf
++CPDO_muf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_muf_extra
++	
++	eor	r1,r1,r2
++	adds	r8,r7,r8
++	bvs	CPDO_zero_1
++
++	umull	r7,r2,r3,r4
++	umull	r14,r3,r6,r3
++	adds	r7,r7,r3	@ r2|r7|r14 = r2|r7|#0 + #0|r3|r14
++	adc	r2,r2,#0
++	umull	r4,r3,r5,r4
++	adds	r14,r14,r4	@ r2|r7|r14 += #0|r3|r4
++	adcs	r7,r7,r3
++	adc	r2,r2,#0
++	umull	r4,r3,r5,r6
++	adds	r14,r14,r3	@ r2|r7|r14 += #0|#0|r3
++	adcs	r7,r7,#0
++	adcs	r2,r2,#0
++
++	bpl	CPDO_muf_norm
++	
++	add	r8,r8,#1
++	b	CPDO_muf_end
++	
++CPDO_muf_norm:
++	adds	r14,r14,r14
++	adcs	r7,r7,r7
++	adcs	r2,r2,r2
++
++CPDO_muf_end:
++	cmp	r8,#0x20000000
++	bge	CPDO_inf
++	cmp	r8,#0xe0000000
++	ble	CPDO_zero_1
++	stmia	r0,{r1,r2,r7,r8}
++	b	fastfpe_next
++
++CPDO_muf_extra:
++	cmp	r7,#0x7fffffff		@ was it the first?
++	bne	CPDO_muf_extra_2nd	@ no, so it was the second
++	cmp	r8,#0x7fffffff		@ yes, second too?
++	bne	CPDO_muf_extra_1st	@ no, only first
++	orr	r3,r3,r4		@ if both inf -> inf, otherwise nan
++	eor	r1,r1,r2		@ sign for the inf case
++	b	CPDO_infnan_1
++
++CPDO_muf_extra_1st:
++	cmp	r3,#0			@ is it a nan?
++	bne	CPDO_infnan_1
++	cmp	r8,#0x80000000		@ is the second 0?
++	beq	CPDO_nan
++	eor	r1,r1,r2		@ correct sign for inf
++	b	CPDO_inf
++
++CPDO_muf_extra_2nd:
++	cmp	r4,#0			@ is it a nan?
++	bne	CPDO_infnan_2
++	cmp	r7,#0x80000000		@ is the first 0?
++	beq	CPDO_nan
++	eor	r1,r1,r2		@ correct sign for inf
++	b	CPDO_inf
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_dvf
++CPDO_dvf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++CPDO_dvf_l:
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_dvf_extra
++	cmp	r8,#0x80000000
++	beq	CPDO_dvf_by0
++
++	eor	r1,r1,r2
++	cmp	r7,#0x80000000
++	beq	CPDO_zero_1
++	
++	sub	r8,r7,r8
++	
++	mov	r2,#0
++	mov	r7,#1
++
++	cmp	r3,r4
++	cmpeq	r5,r6
++	bcs	CPDO_dvf_loop_
++
++	sub	r8,r8,#1
++
++CPDO_dvf_loop:
++	adds	r5,r5,r5
++	adcs	r3,r3,r3
++	bcs	CPDO_dvf_anyway
++CPDO_dvf_loop_:
++	subs	r5,r5,r6
++	sbcs	r3,r3,r4
++	bcs	CPDO_dvf_okay
++
++	adds	r5,r5,r6
++	adc	r3,r3,r4
++	adds	r7,r7,r7
++	adcs	r2,r2,r2
++	bcc	CPDO_dvf_loop
++	b	CPDO_dvf_end
++
++CPDO_dvf_anyway:
++	adcs	r7,r7,r7
++	adcs	r2,r2,r2
++	bcs	CPDO_dvf_end
++	subs	r5,r5,r6
++	sbc	r3,r3,r4
++	b	CPDO_dvf_loop
++
++CPDO_dvf_okay:
++	adcs	r7,r7,r7
++	adcs	r2,r2,r2
++	bcc	CPDO_dvf_loop
++
++CPDO_dvf_end:
++	b	CPDO_muf_end
++
++CPDO_dvf_by0:
++	cmp	R7,#0x80000000
++	beq	CPDO_nan		@ first also 0 -> nan
++	eor	r1,r1,r2		@ otherwise calculatesign for inf
++	b	CPDO_inf
++
++CPDO_dvf_extra:
++	cmp	r7,#0x7fffffff		@ was it the first?
++	bne	CPDO_dvf_extra_2nd	@ no, so it was the second
++	cmp	r8,#0x7fffffff		@ yes, second too?
++	bne	CPDO_dvf_extra_1st	@ no, only first
++	orrs	r3,r3,r4
++	beq	CPDO_nan		@ if both inf -> create nan
++	b	CPDO_nan_12		@ otherwise keep nan
++
++CPDO_dvf_extra_1st:
++	eor	r1,r1,r2		@ correct sign for inf
++	b	CPDO_infnan_1
++
++CPDO_dvf_extra_2nd:
++	cmp	r4,#0			@ is it a nan?
++	bne	CPDO_infnan_2
++	eor	r1,r1,r2		@ correct sign for zero
++	b	CPDO_zero_1
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_rdf
++CPDO_rdf:
++	mov	r3,r2
++	ldmia	r1,{r2,r4,r6,r8}
++	ldmia	r3,{r1,r3,r5,r7}
++	b	CPDO_dvf_l
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_rmf
++CPDO_rmf:
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_mvf
++CPDO_mvf:
++	ldmia	r2,{r1,r2,r3,r4}
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_mnf
++CPDO_mnf:
++	ldmia	r2,{r1,r2,r3,r4}
++	eor	r1,r1,#0x80000000
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_abs
++CPDO_abs:
++	ldmia	r2,{r1,r2,r3,r4}
++	bic	r1,r1,#0x80000000
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++	
++	.globl	CPDO_sqt
++CPDO_sqt:
++	ldmia	r2,{r1,r2,r3,r4}
++	cmp	r1,#0
++	bne	CPDO_nan
++	cmp	r4,#0x7fffffff
++	beq	CPDO_store_1234
++
++	tst	r4,r4,lsr#1		@carry=exponent bit 0
++	bcc	CPDO_sqt_exponenteven
++	adds	r3,r3,r3
++	adcs	r2,r2,r2		@carry is needed in loop!
++CPDO_sqt_exponenteven:
++	mov	r4,r4,asr #1
++	str	r4,[r0,#12]
++
++	mov	r4,#0x80000000
++	mov	r5,#0
++	sub	r2,r2,#0x80000000
++
++	mov	r8,#0x40000000
++	mov	r14,#0x80000000
++
++	mov	r1,#1
++	b	CPDO_sqt_loop1_first
++CPDO_sqt_loop1:
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++CPDO_sqt_loop1_first:
++	add	r6,r4,r8,lsr r1		@r7 const = r5
++	bcs	CPDO_sqt_loop1_1
++	cmp	r2,r6
++	cmpeq	r3,r5			@r5 for r7
++	bcc	CPDO_sqt_loop1_0
++CPDO_sqt_loop1_1:
++	orr	r4,r4,r14,lsr r1
++	subs	r3,r3,r5		@r5 for r7
++	sbc	r2,r2,r6
++CPDO_sqt_loop1_0:
++	add	r1,r1,#1
++	cmp	r1,#30
++	ble	CPDO_sqt_loop1
++
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++	bcs	CPDO_sqt_between_1
++	adds	r7,r5,#0x80000000
++	adc	r6,r4,#0
++	cmp	r2,r6
++	cmpeq	r3,r7
++	bcc	CPDO_sqt_between_0
++CPDO_sqt_between_1:
++	orr	r4,r4,#0x00000001
++	subs	r3,r3,r5
++	sbc	r2,r2,r4
++	subs	r3,r3,#0x80000000
++	sbc	r2,r2,#0
++CPDO_sqt_between_0:
++	mov	r1,#0
++
++CPDO_sqt_loop2:
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++	bcs	CPDO_sqt_loop2_1
++	adds	r7,r5,r8,lsr r1
++	adc	r6,r4,#0
++	cmp	r2,r6
++	cmpeq	r3,r7
++	bcc	CPDO_sqt_loop2_0
++CPDO_sqt_loop2_1:
++	orr	r5,r5,r14,lsr r1
++	subs	r3,r3,r5
++	sbc	r2,r2,r4
++	subs	r3,r3,r8,lsr r1
++	sbc	r2,r2,#0
++CPDO_sqt_loop2_0:
++	add	r1,r1,#1
++	cmp	r1,#30
++	ble	CPDO_sqt_loop2
++
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++	bcs	CPDO_sqt_after_1
++	cmp	r2,r6
++	cmpeq	r3,r7
++	bcc	CPDO_sqt_after_0
++CPDO_sqt_after_1:
++	orr	r5,r5,#0x00000001
++CPDO_sqt_after_0:
++
++	mov	r1,#0
++	stmia	r0,{r1,r4,r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++	
++	.globl	CPDO_rnd
++CPDO_rnd:
++	ldmia	r2,{r1,r2,r3,r5}
++        bl      CPDO_rnd_core
++
++CPDO_rnd_store:
++	stmia	r0,{r1,r2,r3,r5}
++    	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_rnd_core
++CPDO_rnd_core:
++	and	r4,r4,#0x00000060
++	add	pc,pc,r4,lsr#3
++	mov	r0,r0
++	b	CPDO_rnd_N
++	b	CPDO_rnd_P
++	b	CPDO_rnd_M
++	b	CPDO_rnd_Z
++	
++CPDO_rnd_N:
++	cmp	r5,#-1
++	blt	CPDO_rnd_zero
++	cmp	r5,#63
++	movge	pc,r14
++	mov	r4,#0x40000000
++	cmp	r5,#31
++	bge	CPDO_rnd_N_2
++
++	adds	r2,r2,r4,lsr r5
++	bcc	CPDO_rnd_end
++	b	CPDO_rnd_end_norm
++
++CPDO_rnd_N_2:
++CPDO_rnd_P_2:
++	sub	r6,r5,#32
++	adds	r3,r3,r4,ror r6	@ror ist needed to handle a -1 correctly
++	adcs	r2,r2,#0
++	bcc	CPDO_rnd_end
++	b	CPDO_rnd_end_norm
++
++CPDO_rnd_P:
++	tst	r1,#0x80000000
++	bne	CPDO_rnd_M_entry
++CPDO_rnd_P_entry:
++	cmp	r5,#0
++	blt	CPDO_rnd_P_small
++	cmp	r5,#63
++	movge	pc,r14
++	mov	r4,#0x7fffffff
++	cmp	r5,#32
++	bge	CPDO_rnd_P_2
++
++	adds	r3,r3,#0xffffffff
++	adcs	r2,r2,r4,lsr r5
++	bcc	CPDO_rnd_end
++	b	CPDO_rnd_end_norm
++
++CPDO_rnd_P_small:
++	cmp	r5,#0x80000000
++	moveq	pc,r14
++	b	CPDO_rnd_one
++
++CPDO_rnd_M:
++	tst	r1,#0x80000000
++	bne	CPDO_rnd_P_entry
++CPDO_rnd_M_entry:
++	cmp	r5,#0
++	blt	CPDO_rnd_zero
++	cmp	r5,#63
++	movge	pc,r14
++
++	b	CPDO_rnd_end
++	
++CPDO_rnd_Z:
++	cmp	r5,#0
++	blt	CPDO_rnd_zero
++	cmp	r5,#63
++	movge	pc,r14
++	b	CPDO_rnd_end
++
++CPDO_rnd_end_norm:
++	add	r5,r5,#1
++	movs	r2,r2,rrx
++	mov	r3,r3,rrx
++CPDO_rnd_end:
++	rsbs	r4,r5,#31
++	bmi	CPDO_rnd_end_2
++	mov     r3,#0
++	mov     r2,r2,lsr r4
++	mov	r2,r2,lsl r4
++	mov	pc,r14
++
++CPDO_rnd_end_2:
++	rsb	r4,r5,#63
++	mov	r3,r3,lsr r4
++	mov	r3,r3,lsl r4
++	mov	pc,r14
++
++CPDO_rnd_one:
++	mov	r2,#0x80000000
++	mov	r3,#0
++	mov	r5,#0
++	mov	pc,r14
++	
++CPDO_rnd_zero:
++	mov	r1,#0
++	mov	r2,#0
++	mov	r3,#0
++	mov	r5,#0x80000000
++	mov	pc,r14
++
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/fastfpe/CPRT.S	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,185 @@
++/*
++The FP structure has 4 words reserved for each register, the first is used
++just
++for the sign in bit 31, the second and third are for the mantissa (unsigned
++integer, high 32 bit first) and the fourth is the exponent (signed integer).
++The mantissa is always normalized.
++
++If the exponent is 0x80000000, that is the most negative value, the number
++represented is 0 and both mantissa words are also 0.
++
++If the exponent is 0x7fffffff, that is the biggest positive value, the
++number
++represented is infinity if the high 32 mantissa bit are also 0, otherwise it
++is
++a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
++
++Decimal and packed decimal numbers are not supported yet.
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.text
++	.globl	CPRT_flt
++CPRT_flt:
++	add	r0,r13,r0,lsr#10
++	ldr	r2,[r0]
++	mov	r3,#0
++	cmp	r2,#0
++	beq	CPRT_flt_zero
++	
++	ands	r0,r2,#0x80000000
++	rsbne	r2,r2,#0
++	mov	r4,#31
++	
++	cmp	r2,#0x00010000
++	movcc	r2,r2,lsl#16
++	subcc	r4,r4,#16
++	
++	cmp	r2,#0x01000000
++	movcc	r2,r2,lsl#8
++	subcc	r4,r4,#8
++	
++	cmp	r2,#0x10000000
++	movcc	r2,r2,lsl#4
++	subcc	r4,r4,#4
++	
++	cmp	r2,#0x40000000
++	movcc	r2,r2,lsl#2
++	subcc	r4,r4,#2
++	
++	cmp	r2,#0x80000000
++	movcc	r2,r2,lsl#1
++	subcc	r4,r4,#1
++
++	stmia	r1,{r0,r2,r3,r4}
++	b	fastfpe_next
++
++CPRT_flt_zero:
++	mov	r0,#0
++	mov	r4,#0x80000000
++	stmia	r1,{r0,r2,r3,r4}
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_fix
++CPRT_fix:
++	ldmia	r2,{r1,r2,r3,r5}
++	bl	CPDO_rnd_core
++	
++CPRT_back:
++	add	r0,r13,r0,lsr#10
++	cmp	r5,#0
++	blt	CPRT_int_zero
++	cmp	r5,#30
++	bgt	CPRT_overflow
++	
++	rsb	r5,r5,#31
++	mov	r2,r2,lsr r5
++	tst	r1,#0x80000000
++	rsbne	r2,r2,#0
++	
++	str	r2,[r0]
++	b	fastfpe_next
++
++CPRT_int_zero:
++	mov	r2,#0
++	str	r2,[r0]
++	b	fastfpe_next
++
++CPRT_overflow:
++	mov	r2,#0x80000000
++	tst	r1,#0x80000000
++	subeq	r2,r2,#1
++	str	r2,[r0]
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_wfs
++CPRT_wfs:
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_rfs
++CPRT_rfs:
++	add	r0,r13,r0,lsr#10
++	mov	r1,#0x02000000		@ Software Emulation, not Acorn FPE
++	str	r1,[r0]
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_cmf
++CPRT_cmf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++CPRT_cmf_e:
++	ldr	r0,[r13,#16*4]
++	
++	cmp	r7,#0x7fffffff
++	bic	r0,r0,#0xf0000000
++
++	cmpeq	r3,#0xffffffff
++	beq	CPRT_cmf_unordered
++	cmp	r8,#0x7fffffff
++	cmpeq	r4,#0xffffffff
++	beq	CPRT_cmf_unordered
++
++	cmp	r1,r2
++	beq	CPRT_cmf_equalsign
++	b	CPRT_cmf_sign
++
++CPRT_cmf_equalsign:
++	cmp	r7,r8
++	beq	CPRT_cmf_equalexponent
++	bgt	CPRT_cmf_sign
++	b	CPRT_cmf_signb	
++
++CPRT_cmf_equalexponent:
++	cmp	r3,r4
++	cmpeq	r5,r6
++	beq	CPRT_cmf_equal
++	bhi	CPRT_cmf_sign
++	b	CPRT_cmf_signb
++
++CPRT_cmf_sign:
++	cmp     r7,#0x80000000		@ (0.0 == -0.0)?
++	cmpeq   r7,r8
++	beq     CPRT_cmf_equal
++	tst	r1,#0x80000000
++	orreq	r0,r0,#0x20000000
++	orrne	r0,r0,#0x80000000
++	str	r0,[r13,#16*4]
++	b	fastfpe_next
++
++CPRT_cmf_signb:
++	tst	r1,#0x80000000
++	orrne	r0,r0,#0x20000000
++	orreq	r0,r0,#0x80000000
++	str	r0,[r13,#16*4] 
++	b	fastfpe_next
++
++CPRT_cmf_equal:
++	orr	r0,r0,#0x60000000
++	str	r0,[r13,#16*4]
++	b	fastfpe_next
++
++CPRT_cmf_unordered:
++	orr	r0,r0,#0x10000000
++        str     r0,[r13,#16*4]
++        b       fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_cnf
++CPRT_cnf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++	eor	r2,r2,#0x80000000
++	b	CPRT_cmf_e
++
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/fastfpe/CPDT.S	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,430 @@
++/*
++The FP structure has 4 words reserved for each register, the first is used just
++for the sign in bit 31, the second and third are for the mantissa (unsigned
++integer, high 32 bit first) and the fourth is the exponent (signed integer).
++The mantissa is always normalized.
++
++If the exponent is 0x80000000, that is the most negative value, the number
++represented is 0 and both mantissa words are also 0.
++
++If the exponent is 0x7fffffff, that is the biggest positive value, the number
++represented is infinity if the high 32 mantissa bit are also 0, otherwise it is
++a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
++
++Decimal and packed decimal numbers are not supported yet.
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_single
++CPDT_load_single:
++	ldr	r1,[r6]
++	
++	and	r2,r1,#0x80000000	@ r2 = sign
++	
++	mov	r5,r1,lsr#23
++	bics	r5,r5,#0x100
++	beq	CPDT_ls_e0		@ exponent = 0; zero/denormalized
++	teq	r5,#255
++	beq	CPDT_ls_e255		@ exponent = 255; infinity/NaN
++
++	sub     r5,r5,#127		@ r5 = exponent, remove normalized bias
++
++	mov	r3,r1,lsl#8
++	orr	r3,r3,#0x80000000
++	mov	r4,#0			@ r3,r4 = mantissa
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ls_e0:
++	movs	r3,r1,lsl#9
++	beq	CPDT_load_zero
++
++	mov	r5,#-127
++
++CPDT_ls_e0_norm:
++	tst	r3,#0x80000000
++	subeq	r5,r5,#1
++	moveq	r3,r3,lsl#1
++	beq	CPDT_ls_e0_norm
++
++	mov	r4,#0
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ls_e255:
++	mov	r3,r1,lsl#9
++	mov	r4,#0
++	mov	r5,#0x7fffffff
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_load_zero:
++	mov	r3,#0
++	mov	r4,#0
++	mov	r5,#0x80000000
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_double
++CPDT_load_double:
++	ldr	r1,[r6]
++	ldr	r6,[r6,#4]
++
++	and	r2,r1,#0x80000000	@ r2 = sign
++
++	mov	r5,r1,lsr#20
++	bics	r5,r5,#0x800
++	beq	CPDT_ld_e0		@ exponent = 0; zero/denormalized
++	add	r4,r5,#1
++	teq	r4,#2048
++	beq	CPDT_ld_e2047		@ exponent = 2047; infinity/NaN
++
++	add     r5,r5,#1
++	sub	r5,r5,#1024		@ r5 = exponent, remove normalized bias
++
++	mov	r3,r1,lsl#11
++	orr	r3,r3,#0x80000000
++	orr	r3,r3,r6,lsr #21
++	mov	r4,r6,lsl#11		@ r3,r4 = mantissa
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ld_e0:
++	mov	r3,r1,lsl#12
++	orr	r3,r3,r6,lsr#20
++	movs	r4,r6,lsl#12
++	teqeq	r3,#0
++	beq	CPDT_load_zero
++	
++	mov	r5,#1
++	sub	r5,r5,#1024
++
++CPDT_ld_e0_norm:
++	tst	r3,#0x80000000
++	subeq	r5,r5,#1
++	moveqs	r4,r4,lsl#1
++	adceq	r3,r3,r3
++	beq	CPDT_ld_e0_norm
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ld_e2047:
++	mov	r3,r1,lsl#12
++	orr	r3,r3,r6,lsr#1
++	bic	r6,r6,#0x80000000
++	orr	r3,r3,r6		@ to get all fraction bits !
++	mov	r4,#0
++	mov	r5,#0x7fffffff
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_extended
++CPDT_load_extended:
++	ldr	r1,[r6]
++	ldr	r3,[r6,#4]
++	ldr	r4,[r6,#8]
++	
++	and	r2,r1,#0x80000000
++	bics	r5,r1,#0x80000000
++	beq	CPDT_le_e0
++	add	r1,r5,#1
++	teq	r4,#32768
++	beq	CPDT_le_e32767
++
++	add	r5,r5,#1
++	sub	r5,r5,#16384
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_le_e0:
++	teq	r3,#0
++	teqeq	r4,#0
++	beq	CPDT_load_zero
++	
++	mov	r5,#2
++	sub	r5,r5,#16384
++	b	CPDT_ld_e0_norm
++
++CPDT_le_e32767:
++	mov	r3,r3,lsl#1
++	orr	r3,r3,r4,lsr#1
++	bic	r4,r4,#0x80000000
++	orr	r3,r3,r4
++	mov	r5,#0x7fffffff
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_decimal
++CPDT_load_decimal:
++	
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_single
++CPDT_store_single:
++	ldmia	r0,{r1-r4}
++	
++	cmp	r4,#-127
++	ble	CPDT_ss_e0
++	cmp	r4,#128
++	bge	CPDT_ss_e255
++
++	adds	r2,r2,#1<<7		@ round to nearest
++	bcs	CPDT_ss_rnd_ovfl	@ very very seldom taken
++
++CPDT_ss_store:
++	add	r4,r4,#127
++	orr	r1,r1,r4,lsl#23
++	
++	bic	r2,r2,#0x80000000
++	orr	r1,r1,r2,lsr#8
++
++	str	r1,[r6]
++	b	fastfpe_next
++
++CPDT_ss_rnd_ovfl:
++	add	r4,r4,#1
++	cmp	r4,#128
++	bge	CPDT_ss_e255
++
++	mov	r2,#0x80000000
++	mov	r3,#0
++	b	CPDT_ss_store
++
++CPDT_ss_e0:
++	cmp	r4,#-150
++	ble	CPDT_ss_zero
++
++	add	r4,r4,#126
++CPDT_ss_unnormalize:
++	mov	r2,r2,lsr#1
++	adds	r4,r4,#1
++	bne	CPDT_ss_unnormalize
++
++	orr	r1,r1,r2,lsr#8
++
++CPDT_ss_zero:
++	str	r1,[r6]
++	b	fastfpe_next
++
++CPDT_ss_e255:
++	cmp	r4,#0x7fffffff
++	bne	CPDT_ss_inf
++	cmp	r2,#0
++	beq	CPDT_ss_inf
++
++	orr	r1,r1,#0x00200000	@ for safety so that it is not INF
++	orr	r1,r1,r2,lsr#9		@ get highest bit of mantissa
++
++CPDT_ss_inf:
++	orr	r1,r1,#0x7f000000
++	orr	r1,r1,#0x00800000
++	str	r1,[r6]
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_double
++CPDT_store_double:
++	ldmia	r0,{r1-r4}
++	
++	cmp	r4,#1024		@ this check has to be first, or
++	bge	CPDT_sd_e2047		@ overflow can occur on second !
++	add	r0,r4,#3
++	cmp	r0,#-1023+3		@ cmp with -1023
++	ble	CPDT_sd_e0
++
++	adds	r3,r3,#1<<10		@ round to nearest
++	adcs	r2,r2,#0
++	bcs	CPDT_sd_rnd_ovfl	@ very very seldom taken
++
++CPDT_sd_store:
++	sub	r4,r4,#1
++	add	r4,r4,#1024
++	orr	r1,r1,r4,lsl#20
++	
++	bic	r2,r2,#0x80000000
++	orr	r1,r1,r2,lsr#11
++
++	mov	r2,r2,lsl#21
++	orr	r2,r2,r3,lsr#11
++
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++CPDT_sd_rnd_ovfl:
++	add	r4,r4,#1
++	cmp	r4,#1024
++	bge	CPDT_sd_e2047
++
++	mov	r2,#0x80000000
++	mov	r3,#0
++	b	CPDT_sd_store
++
++CPDT_sd_e0:
++	add	r0,r4,#1075-1024
++	cmp	r0,#-1024
++	ble	CPDT_sd_zero
++
++	add	r4,r4,#1024
++	sub	r4,r4,#2
++CPDT_sd_unnormalize:
++	movs	r2,r2,lsr#1
++	mov	r3,r3,rrx
++	adds	r4,r4,#1
++	bne	CPDT_sd_unnormalize
++
++	orr	r1,r1,r2,lsr#11
++	mov	r2,r2,lsl#21
++	orr	r2,r2,r3,lsr#11
++
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++CPDT_sd_zero:
++	mov	r2,#0
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++CPDT_sd_e2047:
++	cmp	r4,#0x7fffffff
++	bne	CPDT_sd_inf
++	cmp	r2,#0
++	beq	CPDT_sd_inf
++
++	orr	r1,r1,#0x00040000	@ for safety so that it is not INF
++	orr	r1,r1,r2,lsr#12		@ get highest bit of mantissa
++
++CPDT_sd_inf:
++	orr	r1,r1,#0x7f000000
++	orr	r1,r1,#0x00f00000
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_extended
++CPDT_store_extended:
++	ldmia	r0,{r1-r4}
++	
++	cmp	r4,#16384		@ this check has to be first, or
++	bge	CPDT_se_e32767		@ overflow can occur with second !
++	add	r0,r4,#63
++	cmp	r0,#-16383+63
++	ble	CPDT_se_e0
++
++	sub	r4,r4,#1
++	add	r4,r4,#16384
++	orr	r1,r1,r4
++	
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++
++CPDT_se_e0:
++	add	r0,r4,#16446-16384
++	cmp	r0,#-16384
++	ble	CPDT_se_zero
++
++	add	r4,r4,#16384
++	sub	r4,r4,#2
++CPDT_se_unnormalize:
++	movs	r2,r2,lsr#1
++	mov	r3,r3,rrx
++	adds	r4,r4,#1
++	bne	CPDT_se_unnormalize
++
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++	
++CPDT_se_zero:
++	mov	r2,#0
++	mov	r3,#0
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++
++CPDT_se_e32767:
++	cmp	r4,#0x7fffffff
++	bne	CPDT_se_inf
++	cmp	r2,#0
++	beq	CPDT_se_inf
++
++	mov	r2,r2,lsl#1
++	orr	r2,r2,#0x20000000
++
++CPDT_se_inf:
++	orr	r1,r1,#0x00007f00
++	orr	r1,r1,#0x000000ff
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_decimal
++CPDT_store_decimal:
++
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_sfm
++CPDT_sfm:
++	add	r2,r10,r0,lsr#8
++	ldr	r4,[r2,#0]
++	ldr	r3,[r2,#4]
++	bic	r3,r3,#0x80000000
++	orr	r3,r3,r4
++	str	r3,[r6],#4
++	ldr	r3,[r2,#8]
++	str	r3,[r6],#4
++	ldr	r3,[r2,#12]
++	str	r3,[r6],#4
++
++	add	r0,r0,#1<<12
++	and	r0,r0,#7<<12
++	subs	r1,r1,#1
++	bne	CPDT_sfm
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_lfm
++CPDT_lfm:
++	add	r2,r10,r0,lsr#8
++	ldr	r4,[r6],#4
++	and	r3,r4,#0x80000000
++	str	r3,[r2,#0]
++	ldr	r3,[r6],#4
++	str	r3,[r2,#8]
++	ldr	r3,[r6],#4
++	str	r3,[r2,#12]
++
++	cmp	r3,#0x80000000		@ does the exp indicate zero?
++	biceq	r4,r4,#0x80000000	@ if so, indicate 'denormalized'
++	beq	CPDT_lfm_storer4
++	cmp	r3,#0x7fffffff		@ does the exp indicate inf or NaN?
++	biceq	r4,r4,#0x80000000	@ if so, indicate 'denormalized'
++	beq	CPDT_lfm_storer4
++	orrne	r4,r4,#0x80000000	@ otherwise, set normalized bit
++
++CPDT_lfm_storer4:
++	str	r4,[r2,#4]
++
++	add	r0,r0,#1<<12
++	and	r0,r0,#7<<12
++	subs	r1,r1,#1
++	bne	CPDT_lfm
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/fastfpe/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,14 @@
++#
++# linux/arch/arm/fastfpe/Makefile
++#
++# Copyright (C) Peter Teichmann
++#
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++fastfpe-objs := module.o entry.o CPDO.o CPRT.o CPDT.o
++
++obj-$(CONFIG_FPE_FASTFPE) += fastfpe.o
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/common/rtctime.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,482 @@
++/*
++ *  linux/arch/arm/common/rtctime.c
++ *
++ *  Copyright (C) 2003 Deep Blue Solutions Ltd.
++ *  Based on sa1100-rtc.c, Nils Faerber, CIH, Nicolas Pitre.
++ *  Based on rtc.c by Paul Gortmaker
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/time.h>
++#include <linux/rtc.h>
++#include <linux/poll.h>
++#include <linux/proc_fs.h>
++#include <linux/miscdevice.h>
++#include <linux/spinlock.h>
++#include <linux/device.h>
++
++#include <asm/rtc.h>
++#include <asm/semaphore.h>
++
++static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
++static struct fasync_struct *rtc_async_queue;
++
++/*
++ * rtc_lock protects rtc_irq_data
++ */
++static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
++static unsigned long rtc_irq_data;
++
++/*
++ * rtc_sem protects rtc_inuse and rtc_ops
++ */
++static DECLARE_MUTEX(rtc_sem);
++static unsigned long rtc_inuse;
++static struct rtc_ops *rtc_ops;
++
++#define rtc_epoch 1900UL
++
++static const unsigned char days_in_month[] = {
++	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
++};
++
++#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
++#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
++
++static int month_days(unsigned int month, unsigned int year)
++{
++	return days_in_month[month] + (LEAP_YEAR(year) && month == 1);
++}
++
++/*
++ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
++ */
++void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
++{
++	int days, month, year;
++
++	days = time / 86400;
++	time -= days * 86400;
++
++	tm->tm_wday = (days + 4) % 7;
++
++	year = 1970 + days / 365;
++	days -= (year - 1970) * 365
++	        + LEAPS_THRU_END_OF(year - 1)
++	        - LEAPS_THRU_END_OF(1970 - 1);
++	if (days < 0) {
++		year -= 1;
++		days += 365 + LEAP_YEAR(year);
++	}
++	tm->tm_year = year - 1900;
++	tm->tm_yday = days + 1;
++
++	for (month = 0; month < 11; month++) {
++		int newdays;
++
++		newdays = days - month_days(month, year);
++		if (newdays < 0)
++			break;
++		days = newdays;
++	}
++	tm->tm_mon = month;
++	tm->tm_mday = days + 1;
++
++	tm->tm_hour = time / 3600;
++	time -= tm->tm_hour * 3600;
++	tm->tm_min = time / 60;
++	tm->tm_sec = time - tm->tm_min * 60;
++}
++
++/*
++ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
++ */
++int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
++{
++	unsigned int yrs = tm->tm_year + 1900;
++
++	*time = 0;
++
++	if (yrs < 1970 ||
++	    tm->tm_mon >= 12 ||
++	    tm->tm_mday < 1 ||
++	    tm->tm_mday > month_days(tm->tm_mon, yrs) ||
++	    tm->tm_hour >= 24 ||
++	    tm->tm_min >= 60 ||
++	    tm->tm_sec >= 60)
++		return -EINVAL;
++
++	*time = mktime(yrs, tm->tm_mon + 1, tm->tm_mday,
++		       tm->tm_hour, tm->tm_min, tm->tm_sec);
++
++	return 0;
++}
++
++/*
++ * Calculate the next alarm time given the requested alarm time mask
++ * and the current time.
++ *
++ * FIXME: for now, we just copy the alarm time because we're lazy (and
++ * is therefore buggy - setting a 10am alarm at 8pm will not result in
++ * the alarm triggering.)
++ */
++void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, struct rtc_time *alrm)
++{
++	next->tm_year = now->tm_year;
++	next->tm_mon = now->tm_mon;
++	next->tm_mday = now->tm_mday;
++	next->tm_hour = alrm->tm_hour;
++	next->tm_min = alrm->tm_min;
++	next->tm_sec = alrm->tm_sec;
++}
++
++static inline void rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
++{
++	memset(tm, 0, sizeof(struct rtc_time));
++	ops->read_time(tm);
++}
++
++static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
++{
++	return ops->set_time(tm);
++}
++
++static inline void rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
++{
++	memset(alrm, 0, sizeof(struct rtc_wkalrm));
++	ops->read_alarm(alrm);
++}
++
++static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
++{
++	return ops->set_alarm(alrm);
++}
++
++void rtc_update(unsigned long num, unsigned long events)
++{
++	spin_lock(&rtc_lock);
++	rtc_irq_data = (rtc_irq_data + (num << 8)) | events;
++	spin_unlock(&rtc_lock);
++
++	wake_up_interruptible(&rtc_wait);
++	kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
++}
++
++
++static ssize_t
++rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long data;
++	ssize_t ret;
++
++	if (count < sizeof(unsigned long))
++		return -EINVAL;
++
++	add_wait_queue(&rtc_wait, &wait);
++	do {
++		__set_current_state(TASK_INTERRUPTIBLE);
++
++		spin_lock_irq(&rtc_lock);
++		data = rtc_irq_data;
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++
++		if (data != 0) {
++			ret = 0;
++			break;
++		}
++		if (file->f_flags & O_NONBLOCK) {
++			ret = -EAGAIN;
++			break;
++		}
++		if (signal_pending(current)) {
++			ret = -ERESTARTSYS;
++			break;
++		}
++		schedule();
++	} while (1);
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&rtc_wait, &wait);
++
++	if (ret == 0) {
++		ret = put_user(data, (unsigned long *)buf);
++		if (ret == 0)
++			ret = sizeof(unsigned long);
++	}
++	return ret;
++}
++
++static unsigned int rtc_poll(struct file *file, poll_table *wait)
++{
++	unsigned long data;
++
++	poll_wait(file, &rtc_wait, wait);
++
++	spin_lock_irq(&rtc_lock);
++	data = rtc_irq_data;
++	spin_unlock_irq(&rtc_lock);
++
++	return data != 0 ? POLLIN | POLLRDNORM : 0;
++}
++
++static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++		     unsigned long arg)
++{
++	struct rtc_ops *ops = file->private_data;
++	struct rtc_time tm;
++	struct rtc_wkalrm alrm;
++	int ret;
++
++	switch (cmd) {
++	case RTC_ALM_READ:
++		rtc_read_alarm(ops, &alrm);
++		ret = copy_to_user((void *)arg, &alrm.time, sizeof(tm));
++		if (ret)
++			ret = -EFAULT;
++		break;
++
++	case RTC_ALM_SET:
++		ret = copy_from_user(&alrm.time, (void *)arg, sizeof(tm));
++		alrm.enabled = 0;
++		alrm.pending = 0;
++		alrm.time.tm_mday = -1;
++		alrm.time.tm_mon = -1;
++		alrm.time.tm_year = -1;
++		alrm.time.tm_wday = -1;
++		alrm.time.tm_yday = -1;
++		alrm.time.tm_isdst = -1;
++		if (ret == 0)
++			ret = rtc_set_alarm(ops, &alrm);
++		else
++			ret = -EFAULT;
++		break;
++
++	case RTC_RD_TIME:
++		rtc_read_time(ops, &tm);
++		ret = copy_to_user((void *)arg, &tm, sizeof(tm));
++		if (ret)
++			ret = -EFAULT;
++		break;
++
++	case RTC_SET_TIME:
++		if (!capable(CAP_SYS_TIME)) {
++			ret = -EACCES;
++			break;
++		}
++		ret = copy_from_user(&tm, (void *)arg, sizeof(tm));
++		if (ret == 0)
++			ret = rtc_set_time(ops, &tm);
++		else
++			ret = -EFAULT;
++		break;
++
++#ifndef rtc_epoch
++	case RTC_EPOCH_SET:
++		/*
++		 * There were no RTC clocks before 1900.
++		 */
++		if (arg < 1900) {
++			ret = -EINVAL;
++			break;
++		}
++		if (!capable(CAP_SYS_TIME)) {
++			ret = -EACCES;
++			break;
++		}
++		rtc_epoch = arg;
++		ret = 0;
++		break;
++#endif
++
++	case RTC_EPOCH_READ:
++		ret = put_user(rtc_epoch, (unsigned long *)arg);
++		break;
++
++	case RTC_WKALM_SET:
++		ret = copy_from_user(&alrm, (void *)arg, sizeof(alrm));
++		if (ret == 0)
++			ret = rtc_set_alarm(ops, &alrm);
++		else
++			ret = -EFAULT;
++		break;
++
++	case RTC_WKALM_RD:
++		rtc_read_alarm(ops, &alrm);
++		ret = copy_to_user((void *)arg, &alrm, sizeof(alrm));
++		if (ret)
++			ret = -EFAULT;
++		break;
++
++	default:
++		ret = ops->ioctl(cmd, arg);
++	}
++	return ret;
++}
++
++static int rtc_open(struct inode *inode, struct file *file)
++{
++	int ret;
++
++	down(&rtc_sem);
++
++	if (rtc_inuse) {
++		ret = -EBUSY;
++	} else if (!rtc_ops || !try_module_get(rtc_ops->owner)) {
++		ret = -ENODEV;
++	} else {
++		file->private_data = rtc_ops;
++
++		ret = rtc_ops->open ? rtc_ops->open() : 0;
++		if (ret == 0) {
++			spin_lock_irq(&rtc_lock);
++			rtc_irq_data = 0;
++			spin_unlock_irq(&rtc_lock);
++
++			rtc_inuse = 1;
++		}
++	}
++	up(&rtc_sem);
++
++	return ret;
++}
++
++static int rtc_release(struct inode *inode, struct file *file)
++{
++	struct rtc_ops *ops = file->private_data;
++
++	if (ops->release)
++		ops->release();
++
++	spin_lock_irq(&rtc_lock);
++	rtc_irq_data = 0;
++	spin_unlock_irq(&rtc_lock);
++
++	module_put(rtc_ops->owner);
++	rtc_inuse = 0;
++
++	return 0;
++}
++
++static int rtc_fasync(int fd, struct file *file, int on)
++{
++	return fasync_helper(fd, file, on, &rtc_async_queue);
++}
++
++static struct file_operations rtc_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= no_llseek,
++	.read		= rtc_read,
++	.poll		= rtc_poll,
++	.ioctl		= rtc_ioctl,
++	.open		= rtc_open,
++	.release	= rtc_release,
++	.fasync		= rtc_fasync,
++};
++
++static struct miscdevice rtc_miscdev = {
++	.minor		= RTC_MINOR,
++	.name		= "rtc",
++	.fops		= &rtc_fops,
++};
++
++
++static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++	struct rtc_ops *ops = data;
++	struct rtc_wkalrm alrm;
++	struct rtc_time tm;
++	char *p = page;
++	int len;
++
++	rtc_read_time(ops, &tm);
++
++	p += sprintf(p,
++		"rtc_time\t: %02d:%02d:%02d\n"
++		"rtc_date\t: %04d-%02d-%02d\n"
++		"rtc_epoch\t: %04lu\n",
++		tm.tm_hour, tm.tm_min, tm.tm_sec,
++		tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
++		rtc_epoch);
++
++	rtc_read_alarm(ops, &alrm);
++	p += sprintf(p, "alrm_time\t: ");
++	if ((unsigned int)alrm.time.tm_hour <= 24)
++		p += sprintf(p, "%02d:", alrm.time.tm_hour);
++	else
++		p += sprintf(p, "**:");
++	if ((unsigned int)alrm.time.tm_min <= 59)
++		p += sprintf(p, "%02d:", alrm.time.tm_min);
++	else
++		p += sprintf(p, "**:");
++	if ((unsigned int)alrm.time.tm_sec <= 59)
++		p += sprintf(p, "%02d\n", alrm.time.tm_sec);
++	else
++		p += sprintf(p, "**\n");
++
++	p += sprintf(p, "alrm_date\t: ");
++	if ((unsigned int)alrm.time.tm_year <= 200)
++		p += sprintf(p, "%04d-", alrm.time.tm_year + 1900);
++	else
++		p += sprintf(p, "****-");
++	if ((unsigned int)alrm.time.tm_mon <= 11)
++		p += sprintf(p, "%02d-", alrm.time.tm_mon + 1);
++	else
++		p += sprintf(p, "**-");
++	if ((unsigned int)alrm.time.tm_mday <= 31)
++		p += sprintf(p, "%02d\n", alrm.time.tm_mday);
++	else
++		p += sprintf(p, "**\n");
++	p += sprintf(p, "alrm_wakeup\t: %s\n", alrm.enabled ? "yes" : "no");
++	p += sprintf(p, "alrm_pending\t: %s\n", alrm.pending ? "yes" : "no");
++
++	if (ops->proc)
++		p += ops->proc(p);
++
++	len = (p - page) - off;
++	if (len < 0)
++		len = 0;
++	*eof = len <= count;
++	*start = page + off;
++
++	return len;
++}
++
++int register_rtc(struct rtc_ops *ops)
++{
++	int ret = -EBUSY;
++
++	down(&rtc_sem);
++	if (rtc_ops == NULL) {
++		rtc_ops = ops;
++
++		ret = misc_register(&rtc_miscdev);
++		if (ret == 0)
++			create_proc_read_entry("driver/rtc", 0, 0,
++					       rtc_read_proc, ops);
++	}
++	up(&rtc_sem);
++
++	return ret;
++}
++
++void unregister_rtc(struct rtc_ops *rtc)
++{
++	down(&rtc_sem);
++	if (rtc == rtc_ops) {
++		remove_proc_entry("driver/rtc", NULL);
++		misc_deregister(&rtc_miscdev);
++		rtc_ops = NULL;
++	}
++	up(&rtc_sem);
++}
++
++EXPORT_SYMBOL(rtc_time_to_tm);
++EXPORT_SYMBOL(rtc_tm_to_time);
++EXPORT_SYMBOL(rtc_update);
++EXPORT_SYMBOL(register_rtc);
++EXPORT_SYMBOL(unregister_rtc);
+--- linux-2.6.5/arch/arm/common/Makefile~heh	2004-04-03 22:36:57.000000000 -0500
++++ linux-2.6.5/arch/arm/common/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -2,7 +2,7 @@
+ # Makefile for the linux kernel.
+ #
+ 
+-obj-y				+= platform.o
++obj-y				+= platform.o rtctime.o
+ obj-$(CONFIG_ARM_AMBA)		+= amba.o
+ obj-$(CONFIG_ICST525)		+= icst525.o
+ obj-$(CONFIG_SA1111)		+= sa1111.o sa1111-pcibuf.o
+--- linux-2.6.5/arch/arm/mach-pxa/generic.c~heh	2004-04-03 22:36:53.000000000 -0500
++++ linux-2.6.5/arch/arm/mach-pxa/generic.c	2004-04-30 20:57:36.000000000 -0400
+@@ -132,7 +132,7 @@
+  /* virtual     physical    length      type */
+   { 0xf6000000, 0x20000000, 0x01000000, MT_DEVICE }, /* PCMCIA0 IO */
+   { 0xf7000000, 0x30000000, 0x01000000, MT_DEVICE }, /* PCMCIA1 IO */
+-  { 0xf8000000, 0x40000000, 0x01400000, MT_DEVICE }, /* Devs */
++  { 0xf8000000, 0x40000000, 0x01800000, MT_DEVICE }, /* Devs */
+   { 0xfa000000, 0x44000000, 0x00100000, MT_DEVICE }, /* LCD */
+   { 0xfc000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Mem Ctl */
+   { 0xff000000, 0x00000000, 0x00100000, MT_DEVICE }  /* UNCACHED_PHYS_0 */
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-pxa/cpu-pxa.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,322 @@
++/*
++ *  linux/arch/arm/mach-pxa/cpu-pxa.c
++ *
++ *  Copyright (C) 2002,2003 Intrinsyc Software
++ *
++ * 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
++ *
++ * History:
++ *   31-Jul-2002 : Initial version [FB]
++ *   29-Jan-2003 : added PXA255 support [FB]
++ *   20-Apr-2003 : ported to v2.5 (Dustin McIntire, Sensoria Corp.)
++ * 
++ * Note:
++ *   This driver may change the memory bus clock rate, but will not do any
++ *   platform specific access timing changes... for example if you have flash
++ *   memory connected to CS0, you will need to register a platform specific
++ *   notifier which will adjust the memory access strobes to maintain a 
++ *   minimum strobe width.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++
++#include <asm/hardware.h>
++
++#define DEBUG  0
++
++#ifdef DEBUG
++  static unsigned int freq_debug = DEBUG;
++  MODULE_PARM(freq_debug, "i");
++  MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0");
++#else
++  #define freq_debug  0
++#endif  
++
++typedef struct
++{
++    unsigned int khz;
++    unsigned int membus;
++    unsigned int cccr;
++    unsigned int div2;
++} pxa_freqs_t;
++
++/* Define the refresh period in mSec for the SDRAM and the number of rows */
++#define SDRAM_TREF          64      /* standard 64ms SDRAM */
++#define SDRAM_ROWS          4096    /* 64MB=8192 32MB=4096 */ 
++#define MDREFR_DRI(x)       ((x*SDRAM_TREF)/(SDRAM_ROWS*32))
++
++#define CCLKCFG_TURBO       0x1
++#define CCLKCFG_FCS         0x2
++#define PXA25x_MIN_FREQ     99500
++#define PXA25x_MAX_FREQ     398100
++#define MDREFR_DB2_MASK     (MDREFR_K2DB2 | MDREFR_K1DB2)
++#define MDREFR_DRI_MASK     0xFFF
++
++
++/* Use the run mode frequencies for the CPUFREQ_POLICY_PERFORMANCE policy */
++static pxa_freqs_t pxa255_run_freqs[] =
++{
++    /* CPU   MEMBUS  CCCR  DIV2*/
++    { 99500,  99500, 0x121, 1}, /* run= 99, turbo= 99, PXbus=50,  SDRAM=50 */
++    {132700, 132700, 0x123, 1}, /* run=133, turbo=133, PXbus=66,  SDRAM=66 */
++    {199100,  99500, 0x141, 0}, /* run=199, turbo=199, PXbus=99,  SDRAM=99 */
++    {265400, 132700, 0x143, 1}, /* run=265, turbo=265, PXbus=133, SDRAM=66 */
++    {331800, 165900, 0x145, 1}, /* run=331, turbo=331, PXbus=166, SDRAM=83 */
++    {398100,  99500, 0x161, 0}, /* run=398, turbo=398, PXbus=196, SDRAM=99 */
++    {0,}
++};
++#define NUM_RUN_FREQS (sizeof(pxa255_run_freqs)/sizeof(pxa_freqs_t))
++
++static struct cpufreq_frequency_table pxa255_run_freq_table[NUM_RUN_FREQS+1];
++
++/* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */
++static pxa_freqs_t pxa255_turbo_freqs[] =
++{
++    /* CPU   MEMBUS  CCCR  DIV2*/
++    { 99500, 99500,  0x121, 1}, /* run=99,  turbo= 99, PXbus=50, SDRAM=50 */
++    {199100, 99500,  0x221, 0}, /* run=99,  turbo=199, PXbus=50, SDRAM=99 */
++    {298500, 99500,  0x321, 0}, /* run=99,  turbo=287, PXbus=50, SDRAM=99 */
++    {298600, 99500,  0x1c1, 0}, /* run=199, turbo=287, PXbus=99, SDRAM=99 */
++    {398100, 99500,  0x241, 0}, /* run=199, turbo=398, PXbus=99, SDRAM=99 */
++    {0,}
++};
++#define NUM_TURBO_FREQS (sizeof(pxa255_turbo_freqs)/sizeof(pxa_freqs_t))
++
++static struct cpufreq_frequency_table pxa255_turbo_freq_table[NUM_TURBO_FREQS+1];
++
++/* find a valid frequency point */
++static int pxa_verify_policy(struct cpufreq_policy *policy)
++{
++    int ret;
++    struct cpufreq_frequency_table *pxa_freqs_table;
++
++    if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
++        pxa_freqs_table = pxa255_run_freq_table;
++    } else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
++        pxa_freqs_table = pxa255_turbo_freq_table;
++    } else if (policy->policy == CPUFREQ_POLICY_GOVERNOR) {
++        pxa_freqs_table = pxa255_run_freq_table;
++    } else {
++        printk("CPU PXA: Unknown policy found. "
++               "Using CPUFREQ_POLICY_PERFORMANCE\n");
++        pxa_freqs_table = pxa255_run_freq_table;
++    } 
++	ret=cpufreq_frequency_table_verify(policy, pxa_freqs_table);
++    
++    if(freq_debug) {
++        printk("Verified CPU policy: %dKhz min to %dKhz max\n",
++            policy->min, policy->max);
++    }
++
++    return ret;
++}
++
++static int pxa_set_target(struct cpufreq_policy *policy,
++                 unsigned int target_freq,
++                 unsigned int relation)
++{
++    int idx;
++    unsigned long cpus_allowed;
++    int cpu = policy->cpu;
++    struct cpufreq_freqs freqs;
++    pxa_freqs_t *pxa_freq_settings;
++    struct cpufreq_frequency_table *pxa_freqs_table;
++    unsigned long flags;
++    unsigned int unused;
++    unsigned int preset_mdrefr, postset_mdrefr;
++
++    /*
++     * Save this threads cpus_allowed mask.
++     */
++    cpus_allowed = current->cpus_allowed;
++
++    /*
++     * Bind to the specified CPU.  When this call returns,
++     * we should be running on the right CPU.
++     */
++    set_cpus_allowed(current, 1 << cpu);
++    BUG_ON(cpu != smp_processor_id());
++
++    /* Get the current policy */
++    if(policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
++        pxa_freq_settings = pxa255_run_freqs;
++        pxa_freqs_table   = pxa255_run_freq_table;
++    }else if (policy->policy == CPUFREQ_POLICY_POWERSAVE) {
++        pxa_freq_settings = pxa255_turbo_freqs;
++        pxa_freqs_table   = pxa255_turbo_freq_table;
++    }else if (policy->policy == CPUFREQ_POLICY_GOVERNOR) {
++        pxa_freq_settings = pxa255_run_freqs;
++        pxa_freqs_table   = pxa255_run_freq_table;
++    }else {
++        printk("CPU PXA: Unknown policy found. "
++               "Using CPUFREQ_POLICY_PERFORMANCE\n");
++        pxa_freq_settings = pxa255_run_freqs;
++        pxa_freqs_table   = pxa255_run_freq_table;
++    } 
++
++    /* Lookup the next frequency */
++	if (cpufreq_frequency_table_target(policy, pxa_freqs_table, 
++	                                   target_freq, relation, &idx)) {
++		return -EINVAL;
++    }
++
++    freqs.old = policy->cur;
++    freqs.new = pxa_freq_settings[idx].khz;
++    freqs.cpu = policy->cpu;  
++    if(freq_debug) {
++        printk(KERN_INFO "Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", 
++            freqs.new/1000, (pxa_freq_settings[idx].div2) ? 
++            (pxa_freq_settings[idx].membus/2000) : 
++            (pxa_freq_settings[idx].membus/1000));
++    }
++
++    void *ramstart = phys_to_virt(0xa0000000);
++
++    /* 
++     * Tell everyone what we're about to do... 
++     * you should add a notify client with any platform specific 
++     * Vcc changing capability
++     */
++    cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
++
++    /* Calculate the next MDREFR.  If we're slowing down the SDRAM clock
++     * we need to preset the smaller DRI before the change.  If we're speeding
++     * up we need to set the larger DRI value after the change.  
++     */
++    preset_mdrefr = postset_mdrefr = MDREFR;
++    if((MDREFR & MDREFR_DRI_MASK) > MDREFR_DRI(pxa_freq_settings[idx].membus)) {    
++        preset_mdrefr = (preset_mdrefr & ~MDREFR_DRI_MASK) | 
++                        MDREFR_DRI(pxa_freq_settings[idx].membus);
++    }
++    postset_mdrefr = (postset_mdrefr & ~MDREFR_DRI_MASK) | 
++                    MDREFR_DRI(pxa_freq_settings[idx].membus);
++    
++    /* If we're dividing the memory clock by two for the SDRAM clock, this
++     * must be set prior to the change.  Clearing the divide must be done
++     * after the change.
++     */
++    if(pxa_freq_settings[idx].div2) { 
++        preset_mdrefr  |= MDREFR_DB2_MASK;
++        postset_mdrefr |= MDREFR_DB2_MASK;
++    } else { 
++        postset_mdrefr &= ~MDREFR_DB2_MASK; 
++    }
++    
++    local_irq_save(flags);
++    
++    /* Set new the CCCR */
++    CCCR = pxa_freq_settings[idx].cccr;
++
++    __asm__ __volatile__("                                  \
++        ldr r4, [%1] ;  /* load MDREFR */                   \
++        b   2f ;                                            \
++        .align  5 ;                                         \
++1:                                                          \
++        str %4, [%1] ;          /* preset the MDREFR */     \
++        mcr p14, 0, %2, c6, c0, 0 ; /* set CCLKCFG[FCS] */  \
++        str %5, [%1] ;          /* postset the MDREFR */    \
++                                                            \
++        b   3f       ;                                      \
++2:      b   1b       ;                                      \
++3:      nop          ;                                      \
++        "                                                                            
++        : "=&r" (unused)                                                             
++        : "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart), \
++          "r" (preset_mdrefr), "r" (postset_mdrefr)             
++        : "r4", "r5");
++    local_irq_restore(flags);
++
++    /*
++     * Restore the CPUs allowed mask.
++     */
++    set_cpus_allowed(current, cpus_allowed);
++
++    /* 
++     * Tell everyone what we've just done... 
++     * you should add a notify client with any platform specific 
++     * SDRAM refresh timer adjustments
++     */
++    cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
++
++    return 0;
++}
++
++static int pxa_cpufreq_init(struct cpufreq_policy *policy)
++{
++    unsigned long cpus_allowed;
++    unsigned int cpu = policy->cpu;
++    int i;
++
++	cpus_allowed = current->cpus_allowed;
++
++	set_cpus_allowed(current, 1 << cpu);
++	BUG_ON(cpu != smp_processor_id());
++
++    /* set default policy and cpuinfo */
++    policy->policy = CPUFREQ_POLICY_PERFORMANCE;
++    policy->cpuinfo.max_freq = PXA25x_MAX_FREQ;
++    policy->cpuinfo.min_freq = PXA25x_MIN_FREQ;
++    policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
++    policy->cur = get_clk_frequency_khz(0); /* current freq */
++    policy->min = policy->max = policy->cur;
++
++    /* Generate the run cpufreq_frequency_table struct */
++    for(i=0;i<NUM_RUN_FREQS;i++) {
++        pxa255_run_freq_table[i].frequency = pxa255_run_freqs[i].khz;
++        pxa255_run_freq_table[i].index = i;    
++    }
++    pxa255_run_freq_table[i].frequency = CPUFREQ_TABLE_END;
++    /* Generate the turbo cpufreq_frequency_table struct */
++    for(i=0;i<NUM_TURBO_FREQS;i++) {
++        pxa255_turbo_freq_table[i].frequency = pxa255_turbo_freqs[i].khz;
++        pxa255_turbo_freq_table[i].index = i;    
++    }
++    pxa255_turbo_freq_table[i].frequency = CPUFREQ_TABLE_END;
++    
++    set_cpus_allowed(current, cpus_allowed);
++    printk(KERN_INFO "PXA CPU frequency change support initialized\n");
++
++    return 0;
++}
++
++static struct cpufreq_driver pxa_cpufreq_driver = {
++    .verify     = pxa_verify_policy,
++    .target     = pxa_set_target,
++    .init       = pxa_cpufreq_init,
++    .name       = "PXA25x",
++};
++
++static int __init pxa_cpu_init(void)
++{
++    return cpufreq_register_driver(&pxa_cpufreq_driver);
++}
++
++static void __exit pxa_cpu_exit(void)
++{
++    cpufreq_unregister_driver(&pxa_cpufreq_driver);
++}
++
++
++MODULE_AUTHOR ("Intrinsyc Software Inc.");
++MODULE_DESCRIPTION ("CPU frequency changing driver for the PXA architecture");
++MODULE_LICENSE("GPL");
++module_init(pxa_cpu_init);
++module_exit(pxa_cpu_exit);
++
+--- linux-2.6.5/arch/arm/boot/compressed/misc.c~heh	2004-04-03 22:37:37.000000000 -0500
++++ linux-2.6.5/arch/arm/boot/compressed/misc.c	2004-04-30 20:57:36.000000000 -0400
+@@ -113,7 +113,7 @@
+  * gzip delarations
+  */
+ #define OF(args)  args
+-#define STATIC static
++#define STATIC
+ 
+ typedef unsigned char  uch;
+ typedef unsigned short ush;
+@@ -122,12 +122,12 @@
+ #define WSIZE 0x8000		/* Window size must be at least 32k, */
+ 				/* and a power of two */
+ 
+-static uch *inbuf;		/* input buffer */
+-static uch window[WSIZE];	/* Sliding window buffer */
++unsigned char *inbuf;		/* input buffer */
++unsigned char window[WSIZE];	/* Sliding window buffer */
+ 
+-static unsigned insize;		/* valid bytes in inbuf */
+-static unsigned inptr;		/* index of next byte to be processed in inbuf */
+-static unsigned outcnt;		/* bytes in output buffer */
++unsigned int insize;		/* valid bytes in inbuf */
++unsigned int inptr;		/* index of next byte to be processed in inbuf */
++unsigned int outcnt;		/* bytes in output buffer */
+ 
+ /* gzip flag byte */
+ #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+@@ -166,9 +166,9 @@
+ extern char input_data[];
+ extern char input_data_end[];
+ 
+-static uch *output_data;
+-static ulg output_ptr;
+-static ulg bytes_out;
++unsigned char *output_data;
++unsigned long output_ptr;
++unsigned long bytes_out;
+ 
+ static void *malloc(int size);
+ static void free(void *where);
+@@ -179,8 +179,8 @@
+ static void puts(const char *);
+ 
+ extern int end;
+-static ulg free_mem_ptr;
+-static ulg free_mem_ptr_end;
++unsigned long free_mem_ptr;
++unsigned long free_mem_ptr_end;
+ 
+ #define HEAP_SIZE 0x2000
+ 
+--- linux-2.6.5/arch/arm/mm/ioremap.c~heh	2004-04-03 22:37:36.000000000 -0500
++++ linux-2.6.5/arch/arm/mm/ioremap.c	2004-04-30 20:57:36.000000000 -0400
+@@ -13,15 +13,18 @@
+  * virtual space.  One should *only* use readl, writel, memcpy_toio and
+  * so on with such remapped areas.
+  *
+- * Because the ARM only has a 32-bit address space we can't address the
+- * whole of the (physical) PCI space at once.  PCI huge-mode addressing
+- * allows us to circumvent this restriction by splitting PCI space into
+- * two 2GB chunks and mapping only one at a time into processor memory.
+- * We use MMU protection domains to trap any attempt to access the bank
+- * that is not currently mapped.  (This isn't fully implemented yet.)
++ * ioremap support tweaked to allow support for large page mappings.  We
++ * have several issues that needs to be resolved first however:
++ *
++ *  1. We need set_pte, or something like set_pte to understand large
++ *     page mappings.
++ *
++ *  2. we need the unmap_* functions to likewise understand large page
++ *     mappings.
+  */
+ #include <linux/errno.h>
+ #include <linux/mm.h>
++#include <linux/slab.h>
+ #include <linux/vmalloc.h>
+ 
+ #include <asm/page.h>
+@@ -29,31 +32,162 @@
+ #include <asm/io.h>
+ #include <asm/tlbflush.h>
+ 
+-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+-	unsigned long phys_addr, pgprot_t pgprot)
++extern rwlock_t vmlist_lock;
++extern struct vm_struct *vmlist;
++
++static struct vm_struct *
++get_io_vm_area(unsigned long size, unsigned long align, unsigned long flags)
+ {
++	struct vm_struct **p, *tmp, *area;
++	unsigned long addr;
++
++	area = (struct vm_struct *)kmalloc(sizeof(*area), GFP_KERNEL);
++	if (!area)
++		return NULL;
++
++	align -= 1;
++
++	size += PAGE_SIZE;
++	addr = VMALLOC_START;
++	write_lock(&vmlist_lock);
++	for (p = &vmlist; (tmp = *p); p = &tmp->next) {
++		if ((unsigned long)tmp->addr < addr)
++			continue;
++		if ((size + addr) < addr)
++			goto out;
++		if (size + addr <= (unsigned long) tmp->addr)
++			break;
++		addr = tmp->size + (unsigned long) tmp->addr;
++		if ((addr + align) < addr)
++			goto out;
++		addr = (addr + align) & ~align;
++		if (addr > VMALLOC_END - size)
++			goto out;
++	}
++	area->flags = flags;
++	area->addr = (void *)addr;
++	area->size = size;
++	area->next = *p;
++	*p = area;
++	write_unlock(&vmlist_lock);
++	return area;
++
++out:
++	write_unlock(&vmlist_lock);
++	kfree(area);
++	return NULL;
++}
++
++static inline void unmap_area_pte(pmd_t *pmd, unsigned long address, unsigned long size)
++{
++	pte_t *ptep;
+ 	unsigned long end;
+ 
++	if (pmd_none(*pmd))
++		return;
++	if (pmd_bad(*pmd)) {
++		pmd_ERROR(*pmd);
++		pmd_clear(pmd);
++		return;
++	}
++	ptep = pte_offset_kernel(pmd, address);
+ 	address &= ~PMD_MASK;
+ 	end = address + size;
+ 	if (end > PMD_SIZE)
+ 		end = PMD_SIZE;
+-	if (address >= end)
+-		BUG();
+ 	do {
+-		if (!pte_none(*pte)) {
+-			printk("remap_area_pte: page already exists\n");
+-			BUG();
++		pte_t pte;
++		pte = ptep_get_and_clear(ptep);
++		address += PAGE_SIZE;
++		ptep++;
++		if (pte_none(pte))
++			continue;
++		if (pte_present(pte)) {
++			unsigned long pfn = pte_pfn(pte);
++			struct page *page;
++
++			if (!pfn_valid(pfn))
++				continue;
++			page = pfn_to_page(pfn);
++			if (!PageReserved(page))
++				__free_page(page);
++			continue;
+ 		}
+-		set_pte(pte, pfn_pte(phys_addr >> PAGE_SHIFT, pgprot));
++		printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");
++	} while (address < end);
++}
++
++static inline void unmap_area_pmd(pgd_t *dir, unsigned long address, unsigned long size)
++{
++	pmd_t *pmd;
++	unsigned long end;
++
++	if (pgd_none(*dir))
++		return;
++	if (pgd_bad(*dir)) {
++		pgd_ERROR(*dir);
++		pgd_clear(dir);
++		return;
++	}
++	pmd = pmd_offset(dir, address);
++	address &= ~PGDIR_MASK;
++	end = address + size;
++	if (end > PGDIR_SIZE)
++		end = PGDIR_SIZE;
++	do {
++		unmap_area_pte(pmd, address, end - address);
++		address = (address + PMD_SIZE) & PMD_MASK;
++		pmd++;
++	} while (address < end);
++}
++
++static void
++unmap_area_pages(unsigned long address, unsigned long size)
++{
++	unsigned long start = address;
++	unsigned long end = address + size;
++	pgd_t *dir;
++
++	dir = pgd_offset_k(address);
++	flush_cache_vunmap(start, end);
++	do {
++		unmap_area_pmd(dir, address, end - address);
++		address = (address + PGDIR_SIZE) & PGDIR_MASK;
++		dir++;
++	} while (address && (address < end));
++	flush_tlb_kernel_range(start, end);
++}
++
++static inline void
++remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
++	       unsigned long pfn, pgprot_t pgprot)
++{
++	unsigned long end;
++
++	address &= ~PMD_MASK;
++	end = address + size;
++	if (end > PMD_SIZE)
++		end = PMD_SIZE;
++	BUG_ON(address >= end);
++	do {
++		if (!pte_none(*pte))
++			goto bad;
++
++		set_pte(pte, pfn_pte(pfn, pgprot));
+ 		address += PAGE_SIZE;
+-		phys_addr += PAGE_SIZE;
++		pfn++;
+ 		pte++;
+ 	} while (address && (address < end));
++	return;
++
++ bad:
++	printk("remap_area_pte: page already exists\n");
++	BUG();
+ }
+ 
+-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+-	unsigned long phys_addr, unsigned long flags)
++static inline int
++remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
++	       unsigned long pfn, unsigned long flags)
+ {
+ 	unsigned long end;
+ 	pgprot_t pgprot;
+@@ -64,51 +198,53 @@
+ 	if (end > PGDIR_SIZE)
+ 		end = PGDIR_SIZE;
+ 
+-	phys_addr -= address;
+-	if (address >= end)
+-		BUG();
++	pfn -= address >> PAGE_SHIFT;
++	BUG_ON(address >= end);
+ 
+ 	pgprot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | L_PTE_WRITE | flags);
+ 	do {
+ 		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
+ 		if (!pte)
+ 			return -ENOMEM;
+-		remap_area_pte(pte, address, end - address, address + phys_addr, pgprot);
++		remap_area_pte(pte, address, end - address, pfn + (address >> PAGE_SHIFT), pgprot);
+ 		address = (address + PMD_SIZE) & PMD_MASK;
+ 		pmd++;
+ 	} while (address && (address < end));
+ 	return 0;
+ }
+ 
+-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+-				 unsigned long size, unsigned long flags)
++static int
++remap_area_pages(unsigned long start, unsigned long pfn,
++		 unsigned long size, unsigned long flags)
+ {
+-	int error;
++	unsigned long address = start;
++	unsigned long end = start + size;
++	int err = 0;
+ 	pgd_t * dir;
+-	unsigned long end = address + size;
+ 
+-	phys_addr -= address;
++	pfn -= address >> PAGE_SHIFT;
+ 	dir = pgd_offset(&init_mm, address);
+-	flush_cache_all();
+-	if (address >= end)
+-		BUG();
++	BUG_ON(address >= end);
+ 	spin_lock(&init_mm.page_table_lock);
+ 	do {
+-		pmd_t *pmd;
+-		pmd = pmd_alloc(&init_mm, dir, address);
+-		error = -ENOMEM;
+-		if (!pmd)
++		pmd_t *pmd = pmd_alloc(&init_mm, dir, address);
++		if (!pmd) {
++			err = -ENOMEM;
+ 			break;
++		}
+ 		if (remap_area_pmd(pmd, address, end - address,
+-					 phys_addr + address, flags))
++				   pfn + (address >> PAGE_SHIFT), flags)) {
++			err = -ENOMEM;
+ 			break;
+-		error = 0;
++		}
++
+ 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ 		dir++;
+ 	} while (address && (address < end));
++
+ 	spin_unlock(&init_mm.page_table_lock);
+-	flush_tlb_all();
+-	return error;
++	flush_cache_vmap(start, end);
++	return err;
+ }
+ 
+ /*
+@@ -146,11 +282,11 @@
+ 	/*
+ 	 * Ok, go for it..
+ 	 */
+-	area = get_vm_area(size, VM_IOREMAP);
++	area = get_io_vm_area(size, align, VM_IOREMAP);
+ 	if (!area)
+ 		return NULL;
+ 	addr = area->addr;
+-	if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
++	if (remap_area_pages((unsigned long) addr, phys_addr >> PAGE_SHIFT, size, flags)) {
+ 		vfree(addr);
+ 		return NULL;
+ 	}
+@@ -159,5 +295,26 @@
+ 
+ void __iounmap(void *addr)
+ {
+-	vfree((void *) (PAGE_MASK & (unsigned long) addr));
++	struct vm_struct **p, *tmp;
++
++	if (!addr)
++		return;
++
++	if ((PAGE_SIZE - 1) & (unsigned long)addr) {
++		printk(KERN_ERR "Trying to iounmap() bad address (%p)\n", addr);
++		return;
++	}
++
++	write_lock(&vmlist_lock);
++	for (p = &vmlist; (tmp = *p); p = &tmp->next) {
++		if (tmp->addr == addr) {
++			*p = tmp->next;
++			unmap_area_pages((unsigned long) tmp->addr, tmp->size);
++			write_unlock(&vmlist_lock);
++			kfree(tmp);
++			return;
++		}
++	}
++	write_unlock(&vmlist_lock);
++	printk(KERN_ERR "Trying to iounmap nonexistent area (%p)\n", addr);
+ }
+--- linux-2.6.5/arch/arm/mm/proc-xscale.S~heh	2004-04-03 22:38:05.000000000 -0500
++++ linux-2.6.5/arch/arm/mm/proc-xscale.S	2004-04-30 20:57:36.000000000 -0400
+@@ -563,11 +563,62 @@
+ 	movne	r2, #0				@ no -> fault
+ 
+ 	str	r2, [r0]			@ hardware version
++
++	@ We try to map 64K page entries when possible.  
++	@ We do that for kernel space only since the usage pattern from
++	@ the setting of VM area is quite simple.  User space is not worth
++	@ the implied complexity because of ever randomly changing PTEs 
++	@ (page aging, swapout, etc) requiring constant coherency checks.
++	@ Since PTEs are usually set in increasing order, we test the
++	@ possibility for a large page only when given the last PTE of a
++	@ 64K boundary.
++	tsteq	r1, #L_PTE_USER
++	andeq	r1, r0, #(15 << 2)
++	teqeq	r1, #(15 << 2)
++	beq	1f
++
+ 	mov	ip, #0
+ 	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
+ 	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
+ 	mov	pc, lr
+ 
++	@ See if we have 16 identical PTEs but with consecutive base addresses
++1:	bic	r3, r2, #0x0000f000
++	mov	r1, #0x0000f000
++2:	eor	r2, r2, r3
++	teq	r2, r1
++	bne	4f
++	subs	r1, r1, #0x00001000
++	ldr	r2, [r0, #-4]!
++	bne	2b
++	eors	r2, r2, r3
++	bne	4f
++
++	@ Now create our LARGE PTE from the current EXT one.
++	bic	r3, r3, #PTE_TYPE_MASK
++	orr	r3, r3, #PTE_TYPE_LARGE
++	and	r2, r3, #0x30			@ EXT_AP --> LARGE_AP0
++	orr	r2, r2, r2, lsl #2		@ add LARGE_AP1
++	orr	r2, r2, r2, lsl #4		@ add LARGE_AP3 + LARGE_AP2
++	and	r1, r3, #0x3c0			@ EXT_TEX
++	bic	r3, r3, #0x3c0
++	orr	r2, r2, r1, lsl #(12 - 6)	@ --> LARGE_TEX
++	orr	r2, r2, r3			@ add remaining bits
++
++	@ then put it in the pagetable
++	mov	r3, r2
++3:	strd	r2, [r0], #8
++	tst	r0, #(15 << 2)
++	bne	3b
++
++	@ Then sync the 2 corresponding cache lines
++	sub	r0, r0, #(16 << 2)
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++4:	orr	r0, r0, #(15 << 2)
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
+ 
+ 	.ltorg
+ 
+--- linux-2.6.5/arch/arm/mach-sa1100/Makefile~heh	2004-04-03 22:38:26.000000000 -0500
++++ linux-2.6.5/arch/arm/mach-sa1100/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -3,7 +3,7 @@
+ #
+ 
+ # Common support
+-obj-y := generic.o irq.o dma.o
++obj-y := generic.o irq.o dma.o nmi-oopser.o
+ obj-m :=
+ obj-n :=
+ obj-  :=
+@@ -88,7 +88,7 @@
+ obj-$(CONFIG_LEDS) += $(led-y)
+ 
+ # SA1110 USB client support
+-#obj-$(CONFIG_SA1100_USB)		+= usb/
++obj-$(CONFIG_SA1100_USB)		+= usb/
+ 
+ # Miscelaneous functions
+ obj-$(CONFIG_PM)			+= pm.o sleep.o
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/strings.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,43 @@
++/*
++ * usb/strings.h
++ *
++ * Copyright (C) 2002 Russell King.
++ *
++ * USB device string handling, built upon usb buffers.
++ */
++#ifndef USBDEV_STRINGS_H
++#define USBDEV_STRINGS_H
++
++#include <linux/spinlock.h>
++
++struct usb_buf;
++
++#define NR_STRINGS 8
++
++struct usb_string_descriptor;
++
++struct usbc_strs {
++	spinlock_t lock;
++	struct usb_buf *buf[NR_STRINGS];
++};
++
++#define usbc_string_desc(buf)	((struct usb_string_descriptor *)(buf)->data)
++
++void usbc_string_from_cstr(struct usb_buf *buf, const char *str);
++struct usb_buf *usbc_string_alloc(int len);
++void usbc_string_free(struct usb_buf *buf);
++
++int usbc_string_add(struct usbc_strs *table, struct usb_buf *buf);
++void usbc_string_del(struct usbc_strs *table, int nr);
++
++/*
++ * Note: usbc_string_find() increments the buffer use count.
++ * You must call usbb_put() after use.
++ */
++struct usb_buf *
++usbc_string_find(struct usbc_strs *table, unsigned int lang, unsigned int idx);
++
++void usbc_string_free_all(struct usbc_strs *table);
++void usbc_string_init(struct usbc_strs *table);
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_ctl.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,114 @@
++/*
++ *	Copyright (C)  Compaq Computer Corporation, 1998, 1999
++ *	Copyright (C)  Extenex Corporation 2001
++ *
++ *  usb_ctl.h
++ *
++ *  PRIVATE interface used to share info among components of the SA-1100 USB
++ *  core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core
++ *  should use sa1100_usb.h.
++ *
++ */
++
++#ifndef _USB_CTL_H
++#define _USB_CTL_H
++
++#include <asm/dma.h>  /* dmach_t */
++
++struct usb_client;
++
++struct usb_stats_t {
++	 unsigned long ep0_fifo_write_failures;
++	 unsigned long ep0_bytes_written;
++	 unsigned long ep0_fifo_read_failures;
++	 unsigned long ep0_bytes_read;
++};
++
++struct usb_info_t
++{
++	struct usb_client *client;
++	dma_regs_t *dmach_tx, *dmach_rx;
++	int state;
++	unsigned char address;
++	struct usb_stats_t stats;
++};
++
++/* in usb_ctl.c */
++extern struct usb_info_t usbd_info;
++
++/*
++ * Function Prototypes
++ */
++enum { kError=-1, kEvSuspend=0, kEvReset=1,
++	   kEvResume=2, kEvAddress=3, kEvConfig=4, kEvDeConfig=5 };
++int usbctl_next_state_on_event( int event );
++
++/* endpoint zero */
++void ep0_reset(void);
++void ep0_int_hndlr(void);
++
++/* receiver */
++int  ep1_recv(void);
++int  ep1_init(dma_regs_t *dma);
++void ep1_int_hndlr(int status);
++void ep1_reset(void);
++void ep1_stall(void);
++
++/* xmitter */
++void ep2_reset(void);
++int  ep2_init(dma_regs_t *dma);
++void ep2_int_hndlr(int status);
++void ep2_stall(void);
++
++#define UDC_write(reg, val) { \
++	int i = 10000; \
++	do { \
++	  	(reg) = (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: write %#x to %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while((reg) != (val)); \
++}
++
++#define UDC_set(reg, val) { \
++	int i = 10000; \
++	do { \
++		(reg) |= (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: set %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while(!((reg) & (val))); \
++}
++
++#define UDC_clear(reg, val) { \
++	int i = 10000; \
++	do { \
++		(reg) &= ~(val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: clear %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while((reg) & (val)); \
++}
++
++#define UDC_flip(reg, val) { \
++	int i = 10000; \
++	(reg) = (val); \
++	do { \
++		(reg) = (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: flip %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while(((reg) & (val))); \
++}
++
++
++#define CHECK_ADDRESS { if ( Ser0UDCAR == 1 ) { printk("%s:%d I lost my address!!!\n",__FUNCTION__, __LINE__);}}
++#endif /* _USB_CTL_H */
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_send.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,302 @@
++/*
++ * Generic xmit layer for the SA1100 USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This is still work in progress...
++ *
++ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ * 15/03/2001 - ep2_start now sets UDCAR to overcome something that is hardware
++ * 		bug, I think. green@iXcelerator.com
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <linux/delay.h>	// for the massive_attack hack 28Feb01ww
++#include <linux/usb_ch9.h>
++
++#include <asm/dma.h>
++
++#include "usbdev.h"
++#include "sa1100_usb.h"
++#include "sa1100usb.h"
++
++static unsigned int ep2_curdmalen;
++static unsigned int ep2_remain;
++
++static struct sausb_dev *ep2_dev;
++
++static void udc_set_cs2(u32 val, u32 mask, u32 check)
++{
++	int i = 0;
++
++	do {
++		Ser0UDCCS2 = val;
++		udelay(1);
++		if ((Ser0UDCCS2 & mask) == check)
++			return;
++	} while (i++ < 10000);
++
++	printk("UDC: UDCCS2 write timed out: val=0x%08x\n", val);
++}
++
++/* set feature stall executing, async */
++static void ep2_start(struct sausb_dev *usb)
++{
++	ep2_curdmalen = min(ep2_remain, usb->ep[1].maxpktsize);
++	if (ep2_curdmalen == 0)
++		return;
++
++	/*
++	 * must do this _before_ queue buffer..
++	 * stop NAKing IN tokens
++	 */
++	udc_set_cs2(usb->ep[1].udccs | UDCCS2_TPC, UDCCS2_TPC, 0);
++
++	UDC_write(Ser0UDCIMP, ep2_curdmalen - 1);
++
++	/* Remove if never seen...8Mar01ww */
++	{
++		int massive_attack = 20;
++		while (Ser0UDCIMP != ep2_curdmalen - 1 && massive_attack--) {
++			printk("usbsnd: Oh no you don't! Let me spin...");
++			udelay(500);
++			printk("and try again...\n");
++			UDC_write(Ser0UDCIMP, ep2_curdmalen - 1);
++		}
++		if (massive_attack != 20) {
++			if (Ser0UDCIMP != ep2_curdmalen - 1)
++				printk("usbsnd: Massive attack FAILED. %d\n",
++				     20 - massive_attack);
++			else
++				printk("usbsnd: Massive attack WORKED. %d\n",
++				     20 - massive_attack);
++		}
++	}
++	/* End remove if never seen... 8Mar01ww */
++
++	/*
++	 * fight stupid silicon bug
++	 */
++	Ser0UDCAR = usb->ctl->address;
++
++	sa1100_start_dma(usb->ep[1].dmach, usb->ep[1].pktdma, ep2_curdmalen);
++}
++
++static void udc_ep2_done(struct sausb_dev *usb, int flag)
++{
++	int size = usb->ep[1].buflen - ep2_remain;
++
++	if (!usb->ep[1].buflen)
++		return;
++
++	dma_unmap_single(usb->dev, usb->ep[1].bufdma, usb->ep[1].buflen,
++			 DMA_TO_DEVICE);
++
++	usb->ep[1].bufdma = 0;
++	usb->ep[1].buflen = 0;
++	usb->ep[1].pktdma = 0;
++
++	if (usb->ep[1].cb_func)
++		usb->ep[1].cb_func(usb->ep[1].cb_data, flag, size);
++}
++
++/*
++ * Initialisation.  Clear out the status.
++ */
++void udc_ep2_init(struct sausb_dev *usb)
++{
++	ep2_dev = usb;
++
++	usb->ep[1].udccs = UDCCS2_FST;
++
++	BUG_ON(usb->ep[1].buflen);
++	BUG_ON(usb->ep[1].pktlen);
++
++	sa1100_reset_dma(usb->ep[1].dmach);
++}
++
++/*
++ * Note: rev A0-B2 chips don't like FST
++ */
++void udc_ep2_halt(struct sausb_dev *usb, int halt)
++{
++	usb->ep[1].host_halt = halt;
++
++	if (halt) {
++		usb->ep[1].udccs |= UDCCS2_FST;
++		udc_set_cs2(UDCCS2_FST, UDCCS2_FST, UDCCS2_FST);
++	} else {
++		sa1100_clear_dma(usb->ep[1].dmach);
++
++		udc_set_cs2(UDCCS2_FST, UDCCS2_FST, UDCCS2_FST);
++		udc_set_cs2(0, UDCCS2_FST, 0);
++		udc_set_cs2(UDCCS2_SST, UDCCS2_SST, 0);
++
++		usb->ep[1].udccs &= ~UDCCS2_FST;
++
++		udc_ep2_done(usb, -EINTR);
++	}
++}
++
++/*
++ * This gets called when we receive a SET_CONFIGURATION packet to EP0.
++ * We were configured.  We can now send packets to the host.
++ */
++void udc_ep2_config(struct sausb_dev *usb, unsigned int maxpktsize)
++{
++	/*
++	 * We shouldn't be transmitting anything...
++	 */
++	BUG_ON(usb->ep[1].buflen);
++	BUG_ON(usb->ep[1].pktlen);
++
++	/*
++	 * Set our configuration.
++	 */
++	usb->ep[1].maxpktsize = maxpktsize;
++	usb->ep[1].configured = 1;
++
++	/*
++	 * Clear any pending TPC status.
++	 */
++	udc_set_cs2(UDCCS2_TPC, UDCCS2_TPC, 0);
++
++	/*
++	 * Enable EP2 interrupts.
++	 */
++	usb->udccr &= ~UDCCR_TIM;
++	UDC_write(Ser0UDCCR, usb->udccr);
++
++	usb->ep[1].udccs = 0;
++}
++
++/*
++ * We saw a reset from the attached hub, or were deconfigured.
++ * This means we are no longer configured.
++ */
++void udc_ep2_reset(struct sausb_dev *usb)
++{
++	/*
++	 * Disable EP2 interrupts.
++	 */
++	usb->udccr |= UDCCR_TIM;
++	UDC_write(Ser0UDCCR, usb->udccr);
++
++	usb->ep[1].configured = 0;
++	usb->ep[1].maxpktsize = 0;
++
++	sa1100_reset_dma(usb->ep[1].dmach);
++	udc_ep2_done(usb, -EINTR);
++}
++
++void udc_ep2_int_hndlr(struct sausb_dev *usb)
++{
++	u32 status = Ser0UDCCS2;
++
++	// check for stupid silicon bug.
++	if (Ser0UDCAR != usb->ctl->address)
++		Ser0UDCAR = usb->ctl->address;
++
++	udc_set_cs2(usb->ep[1].udccs | UDCCS2_SST, UDCCS2_SST, 0);
++
++	if (!(status & UDCCS2_TPC)) {
++		printk("usb_send: Not TPC: UDCCS2 = %x\n", status);
++		return;
++	}
++
++	sa1100_stop_dma(usb->ep[1].dmach);
++
++	if (status & (UDCCS2_TPE | UDCCS2_TUR)) {
++		printk("usb_send: transmit error %x\n", status);
++		usb->ep[1].fifo_errs ++;
++		udc_ep2_done(usb, -EIO);
++	} else {
++		unsigned int imp;
++#if 1		// 22Feb01ww/Oleg
++		imp = ep2_curdmalen;
++#else
++		// this is workaround for case when setting
++		// of Ser0UDCIMP was failed
++		imp = Ser0UDCIMP + 1;
++#endif
++		usb->ep[1].pktdma += imp;
++		ep2_remain -= imp;
++
++		usb->ep[1].bytes += imp;
++		usb->ep[1].packets++;
++
++		sa1100_clear_dma(usb->ep[1].dmach);
++
++		if (ep2_remain != 0) {
++			ep2_start(usb);
++		} else {
++			udc_ep2_done(usb, 0);
++		}
++	}
++}
++
++int udc_ep2_send(struct sausb_dev *usb, char *buf, int len)
++{
++	unsigned long flags;
++	dma_addr_t dma;
++	int ret;
++
++	if (!buf || len == 0)
++		return -EINVAL;
++
++	dma = dma_map_single(usb->dev, buf, len, DMA_TO_DEVICE);
++
++	spin_lock_irqsave(&usb->lock, flags);
++	do {
++		if (!usb->ep[1].configured) {
++			ret = -ENODEV;
++			break;
++		}
++
++		if (usb->ep[1].buflen) {
++			ret = -EBUSY;
++			break;
++		}
++
++		usb->ep[1].bufdma = dma;
++		usb->ep[1].buflen = len;
++		usb->ep[1].pktdma = dma;
++		ep2_remain = len;
++
++		sa1100_clear_dma(usb->ep[1].dmach);
++
++		ep2_start(usb);
++		ret = 0;
++	} while (0);
++	spin_unlock_irqrestore(&usb->lock, flags);
++
++	if (ret)
++		dma_unmap_single(usb->dev, dma, len, DMA_TO_DEVICE);
++
++	return ret;
++}
++
++void udc_ep2_send_reset(struct sausb_dev *usb)
++{
++	sa1100_reset_dma(usb->ep[1].dmach);
++	udc_ep2_done(usb, -EINTR);
++}
++
++int udc_ep2_idle(struct sausb_dev *usb)
++{
++	if (!usb->ep[1].configured)
++		return -ENODEV;
++
++	if (usb->ep[1].buflen)
++		return -EBUSY;
++
++	return 0;
++}
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-char.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,709 @@
++/*
++ * (C) Copyright 2000-2001 Extenex 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *  usb-char.c
++ *
++ *  Miscellaneous character device interface for SA1100 USB function
++ *	driver.
++ *
++ *  Background:
++ *  The SA1100 function driver ported from the Compaq Itsy project
++ *  has an interface, usb-eth.c, to feed network packets over the
++ *  usb wire and into the Linux TCP/IP stack.
++ *
++ *  This file replaces that one with a simple character device
++ *  interface that allows unstructured "byte pipe" style reads and
++ *  writes over the USB bulk endpoints by userspace programs.
++ *
++ *  A new define, CONFIG_SA1100_USB_NETLINK, has been created that,
++ *  when set, (the default) causes the ethernet interface to be used.
++ *  When not set, this more pedestrian character interface is linked
++ *  in instead.
++ *
++ *  Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ *
++ *  ward.willats@extenex.com
++ *
++ *  To do:
++ *  - Can't dma into ring buffer directly with dma_map/unmap usb_recv
++ *    uses and get bytes out at the same time DMA is going on. Investigate:
++ *    a) changing usb_recv to use alloc_consistent() at client request; or
++ *    b) non-ring-buffer based data structures. In the meantime, I am using
++ *    a bounce buffer. Simple, but wasteful.
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/cache.h>
++#include <linux/poll.h>
++#include <linux/circ_buf.h>
++#include <linux/timer.h>
++#include <linux/usb_ch9.h>
++
++#include <asm/io.h>
++#include <asm/semaphore.h>
++#include <asm/page.h>
++#include <asm/mach-types.h>
++
++#include "usb-char.h"
++#include "client.h"
++
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Driver  Options
++//////////////////////////////////////////////////////////////////////////////
++
++#define VERSION 	"0.4"
++
++
++#define VERBOSITY 1
++
++#if VERBOSITY
++# define	PRINTK(x, a...)	printk (x, ## a)
++#else
++# define	PRINTK(x, a...)	/**/
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals - Macros - Enums - Structures
++//////////////////////////////////////////////////////////////////////////////
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++typedef int bool; enum { false = 0, true = 1 };
++
++static const char pszMe[] = "usbchr: ";
++
++static wait_queue_head_t wq_read;
++static wait_queue_head_t wq_write;
++static wait_queue_head_t wq_poll;
++
++/* Serialze multiple writers onto the transmit hardware
++.. since we sleep the writer during transmit to stay in
++.. sync. (Multiple writers don't make much sense, but..) */
++static DECLARE_MUTEX( xmit_sem );
++
++// size of usb DATA0/1 packets. 64 is standard maximum
++// for bulk transport, though most hosts seem to be able
++// to handle larger.
++#define TX_PACKET_SIZE 64
++#define RX_PACKET_SIZE 64
++#define RBUF_SIZE  (4*PAGE_SIZE)
++
++static struct wcirc_buf {
++  char *buf;
++  int in;
++  int out;
++} rx_ring = { NULL, 0, 0 };
++
++static struct {
++	 unsigned long  cnt_rx_complete;
++	 unsigned long  cnt_rx_errors;
++	 unsigned long  bytes_rx;
++	 unsigned long  cnt_tx_timeouts;
++	 unsigned long  cnt_tx_errors;
++	 unsigned long  bytes_tx;
++} charstats;
++
++
++static char * tx_buf = NULL;
++static char * packet_buffer = NULL;
++static int sending = 0;
++static int usb_ref_count = 0;
++static int last_tx_result = 0;
++static int last_rx_result = 0;
++static int last_tx_size = 0;
++static struct timer_list tx_timer;
++
++//////////////////////////////////////////////////////////////////////////////
++// Prototypes
++//////////////////////////////////////////////////////////////////////////////
++static char * 	what_the_f( int e );
++static void 	free_txrx_buffers( void );
++static void     twiddle_descriptors(struct usb_client *client);
++static int      usbc_open( struct inode *pInode, struct file *pFile );
++static void     rx_done_callback_packet_buffer(void *data, int flag, int size );
++
++static void     tx_timeout( unsigned long );
++static void     tx_done_callback(void *data, int flag, int size );
++
++static ssize_t  usbc_read( struct file *, char *, size_t, loff_t * );
++static ssize_t  usbc_write( struct file *, const char *, size_t, loff_t * );
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait );
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++                       unsigned int nCmd, unsigned long argument );
++static int      usbc_close( struct inode *pInode, struct file *pFile );
++
++#ifdef CONFIG_SA1100_EXTENEX1
++static void     extenex_configured_notify_proc( void );
++#endif
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++static char * what_the_f( int e )
++{
++	 char * p;
++	 switch( e ) {
++	 case 0:
++		  p = "noErr";
++		  break;
++	 case -ENODEV:
++		  p = "ENODEV - usb not in config state";
++		  break;
++	 case -EBUSY:
++		  p = "EBUSY - another request on the hardware";
++		  break;
++	 case -EAGAIN:
++		  p = "EAGAIN";
++		  break;
++	 case -EINTR:
++		  p = "EINTR - interrupted\n";
++		  break;
++	 case -EPIPE:
++		  p = "EPIPE - zero length xfer\n";
++		  break;
++	 default:
++		  p = "????";
++		  break;
++	 }
++	 return p;
++}
++
++static void free_txrx_buffers( void )
++{
++	 if ( rx_ring.buf != NULL ) {
++		  kfree( rx_ring.buf );
++		  rx_ring.buf = NULL;
++	 }
++	 if ( packet_buffer != NULL ) {
++		  kfree( packet_buffer );
++		  packet_buffer = NULL;
++	 }
++	 if ( tx_buf != NULL ) {
++		  kfree( tx_buf );
++		  tx_buf = NULL;
++	 }
++}
++
++/* twiddle_descriptors()
++ * It is between open() and start(). Setup descriptors.
++ */
++static void twiddle_descriptors(struct usb_client *client)
++{
++	struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
++
++	cdb->ep1.wMaxPacketSize = cpu_to_le16(RX_PACKET_SIZE);
++	cdb->ep2.wMaxPacketSize = cpu_to_le16(TX_PACKET_SIZE);
++
++#ifdef CONFIG_SA1100_EXTENEX1
++	if (machine_is_extenex1()) {
++		int nr;
++
++		cdb->cfg.bmAttributes = USB_CONFIG_SELFPOWERED;
++		cdb->cfg.MaxPower = 0;
++
++		nr = sa1100_usb_add_string(client->ctl, "HHT Bulk Transfer");
++
++		if (nr > 0)
++			cdb->intf.iInterface = nr;
++	}
++#endif
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// ASYNCHRONOUS
++//////////////////////////////////////////////////////////////////////////////
++static  void kick_start_rx( void )
++{
++	 if ( usb_ref_count ) {
++		  int total_space  = CIRC_SPACE( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  if ( total_space >= RX_PACKET_SIZE ) {
++		           sa1100_usb_recv_set_callback(rx_done_callback_packet_buffer, NULL);
++			   sa1100_usb_recv( packet_buffer, RX_PACKET_SIZE);
++		  }
++	 }
++}
++/*
++ * rx_done_callback_packet_buffer()
++ * We have completed a DMA xfer into the temp packet buffer.
++ * Move to ring.
++ *
++ * flag values:
++ * on init,  -EAGAIN
++ * on reset, -EINTR
++ * on RPE, -EIO
++ * on short packet -EPIPE
++ */
++static void
++rx_done_callback_packet_buffer(void *data, int flag, int size )
++{
++	 charstats.cnt_rx_complete++;
++
++	 if ( flag == 0 || flag == -EPIPE ) {
++		  size_t n;
++
++		  charstats.bytes_rx += size;
++
++		  n = CIRC_SPACE_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  n = MIN( n, size );
++		  size -= n;
++
++		  memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer, n );
++		  rx_ring.in = (rx_ring.in + n) & (RBUF_SIZE-1);
++		  memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer + n, size );
++		  rx_ring.in = (rx_ring.in + size) & (RBUF_SIZE-1);
++
++		  wake_up_interruptible( &wq_read );
++		  wake_up_interruptible( &wq_poll );
++
++		  last_rx_result = 0;
++
++		  kick_start_rx();
++
++	 } else if ( flag != -EAGAIN ) {
++		  charstats.cnt_rx_errors++;
++		  last_rx_result = flag;
++		  wake_up_interruptible( &wq_read );
++		  wake_up_interruptible( &wq_poll );
++	 }
++	 else  /* init, start a read */
++		  kick_start_rx();
++}
++
++
++static void tx_timeout( unsigned long unused )
++{
++	printk( "%stx timeout\n", pszMe );
++	sa1100_usb_send_reset();
++	charstats.cnt_tx_timeouts++;
++}
++
++
++// on init, -EAGAIN
++// on reset, -EINTR
++// on TPE, -EIO
++static void tx_done_callback(void *data, int flags, int size )
++{
++	 if ( flags == 0 )
++		  charstats.bytes_tx += size;
++	 else
++		  charstats.cnt_tx_errors++;
++	 last_tx_size = size;
++	 last_tx_result = flags;
++	 sending = 0;
++	 wake_up_interruptible( &wq_write );
++	 wake_up_interruptible( &wq_poll );
++}
++
++
++static struct usb_client usbc_client = {
++	.name		= "usb-char",
++
++	/*
++	 * USB client identification for host use in CPU endian.
++	 */
++	.vendor		= 0,
++	.product	= 0,
++	.version	= 0,
++	.class		= 0xff,
++	.subclass	= 0,
++	.protocol	= 0,
++};
++
++#ifdef CONFIG_SA1100_EXTENEX1
++#include "../../../drivers/char/ex_gpio.h"
++static void extenex_state_change(void *data, int state, int oldstate)
++{
++	if (exgpio_play_string( "440,1:698,1") == -EAGAIN)
++		printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe );
++}
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Workers
++//////////////////////////////////////////////////////////////////////////////
++
++static int usbc_open(struct inode *pInode, struct file *pFile)
++{
++	int retval = 0;
++
++	PRINTK( KERN_DEBUG "%sopen()\n", pszMe );
++
++#ifdef CONFIG_SA1100_EXTENEX1
++	if (machine_is_extenex1()) {
++		usbc_client.vendor           = 0x0c9f;
++		usbc_client.product          = 0x0100;
++		usbc_client.version          = 0x0001;
++		usbc_client.manufacturer_str = "Extenex";
++		usbc_client.product_str      = "Handheld Theater";
++		usbc_client.serial_str       = "00000000";
++		usbc_client.state_change     = extenex_state_change;
++	}
++#endif
++
++	 /* start usb core */
++	 retval = usbctl_open(&usbc_client);
++	 if (retval)
++		return retval;
++
++	 /* allocate memory */
++	 if ( usb_ref_count == 0 ) {
++		  tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA );
++		  if ( tx_buf == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++		  rx_ring.buf =
++			(char*) kmalloc( RBUF_SIZE, GFP_KERNEL );
++
++		  if ( rx_ring.buf == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++
++		  packet_buffer =
++			(char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA  );
++
++		  if ( packet_buffer == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++		  rx_ring.in = rx_ring.out = 0;
++		  memset( &charstats, 0, sizeof( charstats ) );
++		  sending = 0;
++		  last_tx_result = 0;
++		  last_tx_size = 0;
++	 }
++
++	 /* modify default descriptors */
++	 twiddle_descriptors(&usbc_client);
++
++	 retval = usbctl_start(&usbc_client);
++	 if ( retval ) {
++		  printk( "%sAGHH! Could not USB core\n", pszMe );
++		  free_txrx_buffers();
++		  return retval;
++	 }
++	 usb_ref_count++;   /* must do _before_ kick_start() */
++	 MOD_INC_USE_COUNT;
++	 kick_start_rx();
++	 return 0;
++
++ malloc_fail:
++	 free_txrx_buffers();
++	 return -ENOMEM;
++}
++
++/*
++ * Read endpoint. Note that you can issue a read to an
++ * unconfigured endpoint. Eventually, the host may come along
++ * and configure underneath this module and data will appear.
++ */
++static ssize_t usbc_read( struct file *pFile, char *pUserBuffer,
++                        size_t stCount, loff_t *pPos )
++{
++	 ssize_t retval;
++	 unsigned long flags;
++	 DECLARE_WAITQUEUE( wait, current );
++
++	 PRINTK( KERN_DEBUG "%sread()\n", pszMe );
++
++	 local_irq_save(flags);
++	 if ( last_rx_result == 0 ) {
++		  local_irq_restore( flags );
++	 } else {  /* an error happended and receiver is paused */
++		  local_irq_restore( flags );
++		  last_rx_result = 0;
++		  kick_start_rx();
++	 }
++
++	 add_wait_queue( &wq_read, &wait );
++	 while( 1 ) {
++		  ssize_t bytes_avail;
++		  ssize_t bytes_to_end;
++
++		  set_current_state( TASK_INTERRUPTIBLE );
++
++		  /* snap ring buf state */
++		  local_irq_save( flags );
++		  bytes_avail  = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  local_irq_restore( flags );
++
++		  if ( bytes_avail != 0 ) {
++			   ssize_t bytes_to_move = MIN( stCount, bytes_avail );
++			   retval = 0;		// will be bytes transfered
++			   if ( bytes_to_move != 0 ) {
++					size_t n = MIN( bytes_to_end, bytes_to_move );
++					if ( copy_to_user( pUserBuffer,
++									   &rx_ring.buf[ rx_ring.out ],
++									   n ) ) {
++						 retval = -EFAULT;
++						 break;
++					}
++					bytes_to_move -= n;
++ 					retval += n;
++					// might go 1 char off end, so wrap
++					rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1);
++					if ( copy_to_user( pUserBuffer + n,
++									   &rx_ring.buf[ rx_ring.out ],
++									   bytes_to_move )
++						 ) {
++						 retval = -EFAULT;
++						 break;
++					}
++					rx_ring.out += bytes_to_move;		// cannot wrap
++					retval += bytes_to_move;
++					kick_start_rx();
++			   }
++			   break;
++		  }
++		  else if ( last_rx_result ) {
++			   retval = last_rx_result;
++			   break;
++		  }
++		  else if ( pFile->f_flags & O_NONBLOCK ) {  // no data, can't sleep
++			   retval = -EAGAIN;
++			   break;
++		  }
++		  else if ( signal_pending( current ) ) {   // no data, can sleep, but signal
++			   retval = -ERESTARTSYS;
++			   break;
++		  }
++		  schedule();					   			// no data, can sleep
++	 }
++	 set_current_state( TASK_RUNNING );
++	 remove_wait_queue( &wq_read, &wait );
++
++	 if ( retval < 0 )
++		  printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) );
++	 return retval;
++}
++
++/*
++ * Write endpoint. This routine attempts to break the passed in buffer
++ * into usb DATA0/1 packet size chunks and send them to the host.
++ * (The lower-level driver tries to do this too, but easier for us
++ * to manage things here.)
++ *
++ * We are at the mercy of the host here, in that it must send an IN
++ * token to us to pull this data back, so hopefully some higher level
++ * protocol is expecting traffic to flow in that direction so the host
++ * is actually polling us. To guard against hangs, a 5 second timeout
++ * is used.
++ *
++ * This routine takes some care to only report bytes sent that have
++ * actually made it across the wire. Thus we try to stay in lockstep
++ * with the completion routine and only have one packet on the xmit
++ * hardware at a time. Multiple simultaneous writers will get
++ * "undefined" results.
++ *
++  */
++static ssize_t  usbc_write( struct file *pFile, const char * pUserBuffer,
++							 size_t stCount, loff_t *pPos )
++{
++	 ssize_t retval = 0;
++	 ssize_t stSent = 0;
++
++	 DECLARE_WAITQUEUE( wait, current );
++
++	 PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount );
++
++	 down( &xmit_sem );  // only one thread onto the hardware at a time
++
++	 while( stCount != 0 && retval == 0 ) {
++		  int nThisTime  = MIN( TX_PACKET_SIZE, stCount );
++		  copy_from_user( tx_buf, pUserBuffer, nThisTime );
++		  sending = nThisTime;
++		  sa1100_usb_send_set_callback(tx_done_callback, NULL);
++ 		  retval = sa1100_usb_send( tx_buf, nThisTime);
++		  if ( retval < 0 ) {
++			   char * p = what_the_f( retval );
++			   printk( "%sCould not queue xmission. rc=%d - %s\n",
++					   pszMe, retval, p );
++			   sending = 0;
++			   break;
++		  }
++		  /* now have something on the diving board */
++		  add_wait_queue( &wq_write, &wait );
++		  tx_timer.expires = jiffies + ( HZ * 5 );
++		  add_timer( &tx_timer );
++		  while( 1 ) {
++			   set_current_state( TASK_INTERRUPTIBLE );
++			   if ( sending == 0 ) {  /* it jumped into the pool */
++					del_timer( &tx_timer );
++					retval = last_tx_result;
++					if ( retval == 0 ) {
++						 stSent		 += last_tx_size;
++						 pUserBuffer += last_tx_size;
++						 stCount     -= last_tx_size;
++					}
++					else
++						 printk( "%sxmission error rc=%d - %s\n",
++								 pszMe, retval, what_the_f(retval) );
++					break;
++			   }
++			   else if ( signal_pending( current ) ) {
++					del_timer( &tx_timer );
++					printk( "%ssignal\n", pszMe  );
++					retval = -ERESTARTSYS;
++					break;
++			   }
++			   schedule();
++		  }
++		  set_current_state( TASK_RUNNING );
++		  remove_wait_queue( &wq_write, &wait );
++	 }
++
++	 up( &xmit_sem );
++
++	 if ( 0 == retval )
++		  retval = stSent;
++	 return retval;
++}
++
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait )
++{
++	 unsigned int retval = 0;
++
++	 PRINTK( KERN_DEBUG "%poll()\n", pszMe );
++
++	 poll_wait( pFile, &wq_poll, pWait );
++
++	 if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) )
++		  retval |= POLLIN | POLLRDNORM;
++	 if ( sa1100_usb_xmitter_avail() )
++		  retval |= POLLOUT | POLLWRNORM;
++	 return retval;
++}
++
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++                       unsigned int nCmd, unsigned long argument )
++{
++	 int retval = 0;
++
++	 switch( nCmd ) {
++
++	 case USBC_IOC_FLUSH_RECEIVER:
++		  sa1100_usb_recv_reset();
++		  rx_ring.in = rx_ring.out = 0;
++		  break;
++
++	 case USBC_IOC_FLUSH_TRANSMITTER:
++		  sa1100_usb_send_reset();
++		  break;
++
++	 case USBC_IOC_FLUSH_ALL:
++		  sa1100_usb_recv_reset();
++		  rx_ring.in = rx_ring.out = 0;
++		  sa1100_usb_send_reset();
++		  break;
++
++	 default:
++		  retval = -ENOIOCTLCMD;
++		  break;
++
++	 }
++	 return retval;
++}
++
++
++static int usbc_close( struct inode *pInode, struct file * pFile )
++{
++	PRINTK( KERN_DEBUG "%sclose()\n", pszMe );
++	if ( --usb_ref_count == 0 ) {
++		 down( &xmit_sem );
++		 usbctl_stop(&usbc_client);
++		 free_txrx_buffers();
++		 del_timer( &tx_timer );
++		 usbctl_close(&usbc_client);
++		 up(&xmit_sem);
++	}
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Initialization
++//////////////////////////////////////////////////////////////////////////////
++
++static struct file_operations usbc_fops = {
++	owner:		THIS_MODULE,
++	open:		usbc_open,
++	read:		usbc_read,
++	write:		usbc_write,
++	poll:		usbc_poll,
++	ioctl:		usbc_ioctl,
++	release:	usbc_close,
++};
++
++static struct miscdevice usbc_misc_device = {
++	USBC_MINOR,
++	"usb_char",
++	&usbc_fops
++};
++
++/*
++ * usbc_init()
++ */
++
++static int __init usbc_init( void )
++{
++	 int rc;
++
++#if !defined( CONFIG_ARCH_SA1100 )
++	 return -ENODEV;
++#endif
++
++	 if ( (rc = misc_register( &usbc_misc_device )) != 0 ) {
++		  printk( KERN_WARNING "%sCould not register device 10, "
++				  "%d. (%d)\n", pszMe, USBC_MINOR, rc );
++		  return -EBUSY;
++	 }
++
++	 // initialize wait queues
++	 init_waitqueue_head( &wq_read );
++	 init_waitqueue_head( &wq_write );
++	 init_waitqueue_head( &wq_poll );
++
++	 // initialize tx timeout timer
++	 init_timer( &tx_timer );
++	 tx_timer.function = tx_timeout;
++
++	  printk( KERN_INFO "USB Function Character Driver Interface"
++				  " - %s, (C) 2001, Extenex Corp.\n", VERSION
++		   );
++
++	 return rc;
++}
++
++static void __exit usbc_exit( void )
++{
++}
++
++module_init(usbc_init);
++module_exit(usbc_exit);
++
++// end: usb-char.c
++
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-eth.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,535 @@
++/*
++ * Network driver for the SA1100 USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original initial ethernet test driver
++ * Copyright (c) Compaq Computer Corporation, 1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Issues:
++ *  - DMA needs 8 byte aligned buffer, but causes inefficiencies
++ *    in the IP code.
++ *  - stall endpoint operations appeared to be very unstable.
++ */
++
++/*
++ * Define RX_NO_COPY if you want data to arrive directly into the
++ * receive network buffers, instead of arriving into bounce buffer
++ * and then get copied to network buffer.
++ *
++ * Since the SA1100 DMA engine is unable to cope with unaligned
++ * buffer addresses, we need to use bounce buffers or suffer the
++ * alignment trap performance hit.
++ */
++#undef RX_NO_COPY
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++#include <linux/usb_ch9.h>
++
++#include "client.h"
++
++
++#define ETHERNET_VENDOR_ID  0x049f
++#define ETHERNET_PRODUCT_ID 0x505A
++#define MAX_PACKET 32768
++
++/*
++ * This is our usb "packet size", and must match the host "packet size".
++ */
++static int usb_rsize = 64;
++static int usb_wsize = 64;
++
++struct usbe_info {
++	struct net_device	dev;
++	struct usb_client	client;
++	struct sk_buff		*cur_tx_skb;
++	struct sk_buff		*next_tx_skb;
++	struct sk_buff		*cur_rx_skb;
++	struct sk_buff		*next_rx_skb;
++#ifndef RX_NO_COPY
++	char *dmabuf;	// dma expects it's buffers to be aligned on 8 bytes boundary
++#endif
++	struct net_device_stats	stats;
++};
++
++
++static int usbeth_change_mtu(struct net_device *dev, int new_mtu)
++{
++	if (new_mtu <= sizeof(struct ethhdr) || new_mtu > MAX_PACKET)
++		return -EINVAL;
++
++	// no second zero-length packet read wanted after mtu-sized packets
++	if (((new_mtu + sizeof(struct ethhdr)) % usb_rsize) == 0)
++		return -EDOM;
++
++	dev->mtu = new_mtu;
++	return 0;
++}
++
++static struct sk_buff *usb_new_recv_skb(struct usbe_info *usbe)
++{
++	struct sk_buff *skb;
++
++	skb = alloc_skb(2 + sizeof(struct ethhdr) + usbe->dev.mtu,
++			GFP_ATOMIC);
++
++	if (skb)
++		skb_reserve(skb, 2);
++
++	return skb;
++}
++
++static void usbeth_recv_callback(void *data, int flag, int len)
++{
++	struct usbe_info *usbe = data;
++	struct sk_buff *skb;
++	unsigned int size;
++	char *buf;
++
++	skb = usbe->cur_rx_skb;
++
++	/* flag validation */
++	if (flag != 0)
++		goto error;
++
++	/*
++	 * Make sure we have enough room left in the buffer.
++	 */
++	if (len > skb_tailroom(skb)) {
++		usbe->stats.rx_over_errors++;
++		usbe->stats.rx_errors++;
++		goto oversize;
++	}
++
++	/*
++	 * If the packet is smaller than usb_rsize bytes, the packet
++	 * is complete, and we need to use the next receive buffer.
++	 */
++	if (len != usb_rsize)
++		usbe->cur_rx_skb = usbe->next_rx_skb;
++
++	/*
++	 * Put the data onto the socket buffer and resume USB receive.
++	 */
++#ifndef RX_NO_COPY
++	memcpy(skb_put(skb, len), usbe->dmabuf, len);
++	buf = usbe->dmabuf;
++	size = usb_rsize;
++#else
++	skb_put(skb, len);
++	buf = usbe->cur_rx_skb->tail;
++	size = skb_tailroom(usbe->cur_rx_skb);
++#endif
++	usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size);
++
++	if (len == usb_rsize)
++		return;
++
++	/*
++	 * A frame must contain at least an ethernet header.
++	 */
++	if (skb->len < sizeof(struct ethhdr)) {
++		usbe->stats.rx_length_errors++;
++		usbe->stats.rx_errors++;
++		goto recycle;
++	}
++
++	/*
++	 * MAC must match our address or the broadcast address.
++	 * Really, we should let any packet through, otherwise
++	 * things that rely on multicast won't work.
++	 */
++	if (memcmp(skb->data, usbe->dev.dev_addr, ETH_ALEN) &&
++	    memcmp(skb->data, usbe->dev.broadcast, ETH_ALEN)) {
++		usbe->stats.rx_frame_errors++;
++		usbe->stats.rx_errors++;
++		goto recycle;
++	}
++
++	/*
++	 * We're going to consume this SKB.  Get a new skb to
++	 * replace it with.  IF this fails, we'd better recycle
++	 * the one we have.
++	 */
++	usbe->next_rx_skb = usb_new_recv_skb(usbe);
++	if (!usbe->next_rx_skb) {
++		if (net_ratelimit())
++			printk(KERN_ERR "%s: can't allocate new rx skb\n",
++				usbe->dev.name);
++		usbe->stats.rx_dropped++;
++		goto recycle;
++	}
++
++// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
++
++	usbe->stats.rx_packets++;
++	usbe->stats.rx_bytes += skb->len;
++	usbe->dev.last_rx = jiffies;
++
++	skb->dev = &usbe->dev;
++	skb->protocol = eth_type_trans(skb, &usbe->dev);
++	skb->ip_summed = CHECKSUM_NONE;
++
++	if (netif_rx(skb) == NET_RX_DROP)
++		usbe->stats.rx_dropped++;
++	return;
++
++ error:
++	/*
++	 * Oops, IO error, or stalled.
++	 */
++	switch (flag) {
++	case -EIO:	/* aborted transfer */
++		usbe->stats.rx_errors++;
++		break;
++
++	case -EPIPE:	/* fifo screwed/no data */
++		usbe->stats.rx_fifo_errors++;
++		usbe->stats.rx_errors++;
++		break;
++
++	case -EINTR:	/* reset */
++		break;
++
++	case -EAGAIN:	/* initialisation */
++		break;
++	}
++
++ oversize:
++	skb_trim(skb, 0);
++
++#ifndef RX_NO_COPY
++	buf = usbe->dmabuf;
++	size = usb_rsize;
++#else
++	buf = skb->tail;
++	size = skb_tailroom(skb);
++#endif
++	usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size);
++	return;
++
++ recycle:
++	skb_trim(skb, 0);
++	usbe->next_rx_skb = skb;
++	return;
++}
++
++/*
++ * Send a skb.
++ *
++ * Note that the receiver expects the last packet to be a non-multiple
++ * of its rsize.  If the packet length is a muliple of wsize (and
++ * therefore the remote rsize) tweak the length.
++ */
++static void usbeth_send(struct sk_buff *skb, struct usbe_info *usbe)
++{
++	unsigned int len = skb->len;
++	int ret;
++
++	if ((len % usb_wsize) == 0)
++		len++;
++
++	ret = usbctl_ep_queue_buffer(usbe->client.ctl, 2, skb->data, len);
++	if (ret) {
++		printk(KERN_ERR "%s: tx dropping packet: %d\n",
++		       usbe->dev.name, ret);
++
++		/*
++		 * If the USB core can't accept the packet, we drop it.
++		 */
++		dev_kfree_skb_irq(skb);
++
++		usbe->cur_tx_skb = NULL;
++		usbe->stats.tx_carrier_errors++;
++	} else {
++		usbe->dev.trans_start = jiffies;
++	}
++}
++
++static void usbeth_send_callback(void *data, int flag, int size)
++{
++	struct usbe_info *usbe = data;
++	struct sk_buff *skb = usbe->cur_tx_skb;
++
++	switch (flag) {
++	case 0:
++		usbe->stats.tx_packets++;
++		usbe->stats.tx_bytes += skb->len;
++		break;
++	case -EIO:
++		usbe->stats.tx_errors++;
++		break;
++	default:
++		usbe->stats.tx_dropped++;
++		break;
++	}
++
++	dev_kfree_skb_irq(skb);
++
++	skb = usbe->cur_tx_skb = usbe->next_tx_skb;
++	usbe->next_tx_skb = NULL;
++
++	if (skb)
++		usbeth_send(skb, usbe);
++
++	netif_wake_queue(&usbe->dev);
++}
++
++static int usbeth_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct usbe_info *usbe = dev->priv;
++	unsigned long flags;
++
++	if (usbe->next_tx_skb) {
++		printk(KERN_ERR "%s: called with next_tx_skb != NULL\n",
++		       usbe->dev.name);
++		return 1;
++	}
++
++	local_irq_save(flags);
++	if (usbe->cur_tx_skb) {
++		usbe->next_tx_skb = skb;
++		netif_stop_queue(dev);
++	} else {
++		usbe->cur_tx_skb = skb;
++
++		usbeth_send(skb, usbe);
++	}
++	local_irq_restore(flags);
++	return 0;
++}
++
++/*
++ * Transmit timed out.  Reset the endpoint, and re-queue the pending
++ * packet.  If we have a free transmit slot, wake the transmit queue.
++ */
++static void usbeth_xmit_timeout(struct net_device *dev)
++{
++	struct usbe_info *usbe = dev->priv;
++	unsigned long flags;
++
++	usbctl_ep_reset(usbe->client.ctl, 2);
++
++	local_irq_save(flags);
++	if (usbe->cur_tx_skb)
++		usbeth_send(usbe->cur_tx_skb, usbe);
++
++	if (usbe->next_tx_skb == NULL)
++		netif_wake_queue(dev);
++
++	usbe->stats.tx_errors++;
++	local_irq_restore(flags);
++}
++
++static int usbeth_open(struct net_device *dev)
++{
++	struct usbe_info *usbe = dev->priv;
++	unsigned char *buf;
++	unsigned int size;
++
++	usbctl_ep_set_callback(usbe->client.ctl, 2, usbeth_send_callback, usbe);
++	usbctl_ep_set_callback(usbe->client.ctl, 1, usbeth_recv_callback, usbe);
++
++	usbe->cur_tx_skb = usbe->next_tx_skb = NULL;
++	usbe->cur_rx_skb = usb_new_recv_skb(usbe);
++	usbe->next_rx_skb = usb_new_recv_skb(usbe);
++	if (!usbe->cur_rx_skb || !usbe->next_rx_skb) {
++		printk(KERN_ERR "%s: can't allocate new skb\n",
++			usbe->dev.name);
++		if (usbe->cur_rx_skb)
++			kfree_skb(usbe->cur_rx_skb);
++		if (usbe->next_rx_skb)
++			kfree_skb(usbe->next_rx_skb);
++		return -ENOMEM;;
++	}
++#ifndef RX_NO_COPY
++	buf =  usbe->dmabuf;
++	size = usb_rsize;
++#else
++	buf = usbe->cur_rx_skb->tail;
++	size = skb_tailroom(usbe->cur_rx_skb);
++#endif
++	usbctl_ep_queue_buffer(usbe->client.ctl, 1, buf, size);
++
++	if (netif_carrier_ok(dev))
++		netif_start_queue(dev);
++
++	return 0;
++}
++
++static int usbeth_close(struct net_device *dev)
++{
++	struct usbe_info *usbe = dev->priv;
++
++	netif_stop_queue(dev);
++
++	usbctl_ep_set_callback(usbe->client.ctl, 2, NULL, NULL);
++	usbctl_ep_set_callback(usbe->client.ctl, 1, NULL, NULL);
++	usbctl_ep_reset(usbe->client.ctl, 2);
++	usbctl_ep_reset(usbe->client.ctl, 1);
++
++	if (usbe->cur_tx_skb)
++		kfree_skb(usbe->cur_tx_skb);
++	if (usbe->next_tx_skb)
++		kfree_skb(usbe->next_tx_skb);
++	if (usbe->cur_rx_skb)
++		kfree_skb(usbe->cur_rx_skb);
++	if (usbe->next_rx_skb)
++		kfree_skb(usbe->next_rx_skb);
++
++	return 0;
++}
++
++static struct net_device_stats *usbeth_stats(struct net_device *dev)
++{
++	struct usbe_info *usbe = dev->priv;
++
++	return &usbe->stats;
++}
++
++static int __init usbeth_probe(struct net_device *dev)
++{
++	u8 node_id[ETH_ALEN];
++
++	SET_MODULE_OWNER(dev);
++
++	/*
++	 * Assign the hardware address of the board:
++	 * generate it randomly, as there can be many such
++	 * devices on the bus.
++	 */
++	get_random_bytes(node_id, sizeof node_id);
++	node_id[0] &= 0xfe;	// clear multicast bit
++	memcpy(dev->dev_addr, node_id, sizeof node_id);
++
++	ether_setup(dev);
++	dev->flags &= ~IFF_MULTICAST;
++	dev->flags &= ~IFF_BROADCAST;
++	//dev->flags |= IFF_NOARP;
++
++	return 0;
++}
++
++/*
++ * This is called when something in the upper usb client layers
++ * changes that affects the endpoint connectivity state (eg,
++ * connection or disconnection from the host.)  We probably want
++ * to do some more handling here, like kicking off a pending
++ * transmission if we're running?
++ */
++static void usbeth_state_change(void *data, int state, int oldstate)
++{
++	struct usbe_info *usbe = data;
++
++	if (state == USB_STATE_CONFIGURED) {
++		netif_carrier_on(&usbe->dev);
++		if (netif_running(&usbe->dev))
++			netif_wake_queue(&usbe->dev);
++	} else {
++		if (netif_running(&usbe->dev))
++			netif_stop_queue(&usbe->dev);
++		netif_carrier_off(&usbe->dev);
++	}
++}
++
++static struct usbe_info usbe_info = {
++	.dev	= {
++		.name			= "usbf",
++		.init			= usbeth_probe,
++		.get_stats		= usbeth_stats,
++		.watchdog_timeo		= 1 * HZ,
++		.open			= usbeth_open,
++		.stop			= usbeth_close,
++		.hard_start_xmit	= usbeth_xmit,
++		.change_mtu		= usbeth_change_mtu,
++		.tx_timeout		= usbeth_xmit_timeout,
++		.priv			= &usbe_info,
++	},
++	.client	= {
++		.name			= "usbeth",
++		.priv			= &usbe_info,
++		.state_change		= usbeth_state_change,
++
++		/*
++		 * USB client identification for host use in CPU endian.
++		 */
++		.vendor			= ETHERNET_VENDOR_ID,
++		.product		= ETHERNET_PRODUCT_ID,
++		.version		= 0,
++		.class			= 0xff,	/* vendor specific */
++		.subclass		= 0,
++		.protocol		= 0,
++
++		.product_str		= "SA1100 USB NIC",
++	},
++};
++
++static int __init usbeth_init(void)
++{
++	int rc;
++
++#ifndef RX_NO_COPY
++	usbe_info.dmabuf = kmalloc(usb_rsize, GFP_KERNEL | GFP_DMA);
++	if (!usbe_info.dmabuf)
++		return -ENOMEM;
++#endif
++
++	if (register_netdev(&usbe_info.dev) != 0) {
++#ifndef RX_NO_COPY
++		kfree(usbe_info.dmabuf);
++#endif
++		return -EIO;
++	}
++
++	rc = usbctl_open(&usbe_info.client);
++	if (rc == 0) {
++		struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
++
++		cdb->ep1.wMaxPacketSize = cpu_to_le16(usb_rsize);
++		cdb->ep2.wMaxPacketSize = cpu_to_le16(usb_wsize);
++
++		rc = usbctl_start(&usbe_info.client);
++		if (rc)
++			usbctl_close(&usbe_info.client);
++	}
++
++	if (rc) {
++		unregister_netdev(&usbe_info.dev);
++#ifndef RX_NO_COPY
++		kfree(usbe_info.dmabuf);
++#endif
++	}
++
++	return rc;
++}
++
++static void __exit usbeth_cleanup(void)
++{
++	usbctl_stop(&usbe_info.client);
++	usbctl_close(&usbe_info.client);
++
++	unregister_netdev(&usbe_info.dev);
++#ifndef RX_NO_COPY
++	kfree(usbe_info.dmabuf);
++#endif
++}
++
++module_init(usbeth_init);
++module_exit(usbeth_cleanup);
++
++MODULE_DESCRIPTION("USB client ethernet driver");
++MODULE_PARM(usb_rsize, "1i");
++MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to sa11x0");
++MODULE_PARM(usb_wsize, "1i");
++MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from sa11x0 to host");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_recv.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,318 @@
++/*
++ * Generic receive layer for the SA1100 USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This is still work in progress...
++ *
++ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <linux/usb_ch9.h>
++
++#include <asm/byteorder.h>
++#include <asm/dma.h>
++
++#include "sa1100_usb.h"
++#include "sa1100usb.h"
++
++static int naking;
++
++#if 1
++static void dump_buf(struct sausb_dev *usb, const char *prefix)
++{
++	printk("%s: buf [dma=%08x len=%3d] pkt [cpu=%08x dma=%08x len=%3d rem=%3d]\n",
++		prefix,
++		usb->ep[0].bufdma,
++		usb->ep[0].buflen,
++		(unsigned int)usb->ep[0].pktcpu,
++		usb->ep[0].pktdma,
++		usb->ep[0].pktlen,
++		usb->ep[0].pktrem);
++}
++#endif
++
++static void udc_ep1_done(struct sausb_dev *usb, int flag, int size)
++{
++//	printk("UDC: rxd: %3d %3d\n", flag, size);
++	dump_buf(usb, "UDC: rxd");
++
++	if (!usb->ep[0].buflen)
++		return;
++
++	dma_unmap_single(usb->dev, usb->ep[0].bufdma, usb->ep[0].buflen,
++			 DMA_FROM_DEVICE);
++
++	usb->ep[0].bufdma = 0;
++	usb->ep[0].buflen = 0;
++	usb->ep[0].pktcpu = NULL;
++	usb->ep[0].pktdma = 0;
++	usb->ep[0].pktlen = 0;
++	usb->ep[0].pktrem = 0;
++
++	if (usb->ep[0].cb_func)
++		usb->ep[0].cb_func(usb->ep[0].cb_data, flag, size);
++}
++
++/*
++ * Initialisation.  Clear out the status, and set FST.
++ */
++void udc_ep1_init(struct sausb_dev *usb)
++{
++	sa1100_reset_dma(usb->ep[0].dmach);
++
++	UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC);
++
++	BUG_ON(usb->ep[0].buflen);
++	BUG_ON(usb->ep[0].pktlen);
++}
++
++void udc_ep1_halt(struct sausb_dev *usb, int halt)
++{
++	if (halt) {
++		/* force stall at UDC */
++		UDC_set(Ser0UDCCS1, UDCCS1_FST);
++	} else {
++		sa1100_reset_dma(usb->ep[0].dmach);
++
++		UDC_clear(Ser0UDCCS1, UDCCS1_FST);
++
++		udc_ep1_done(usb, -EINTR, 0);
++	}
++}
++
++/*
++ * This gets called when we receive a SET_CONFIGURATION packet to EP0.
++ * We were configured.  We can now accept packets from the host.
++ */
++void udc_ep1_config(struct sausb_dev *usb, unsigned int maxpktsize)
++{
++	usb->ep[0].maxpktsize = maxpktsize;
++	usb->ep[0].configured = 1;
++
++	Ser0UDCOMP = maxpktsize - 1;
++
++	sa1100_reset_dma(usb->ep[0].dmach);
++	udc_ep1_done(usb, -EINTR, 0);
++
++	/*
++	 * Enable EP1 interrupts.
++	 */
++	usb->udccr &= ~UDCCR_RIM;
++	UDC_write(Ser0UDCCR, usb->udccr);
++}
++
++/*
++ * We saw a reset from the attached hub.  This means we are no
++ * longer configured, and as far as the rest of the world is
++ * concerned, we don't exist.
++ */
++void udc_ep1_reset(struct sausb_dev *usb)
++{
++	/*
++	 * Disable EP1 interrupts.
++	 */
++	usb->udccr |= UDCCR_RIM;
++	UDC_write(Ser0UDCCR, usb->udccr);
++
++	usb->ep[0].configured = 0;
++	usb->ep[0].maxpktsize = 0;
++
++	sa1100_reset_dma(usb->ep[0].dmach);
++	udc_ep1_done(usb, -EINTR, 0);
++}
++
++void udc_ep1_int_hndlr(struct sausb_dev *usb)
++{
++	dma_addr_t dma_addr;
++	unsigned int len;
++	u32 status = Ser0UDCCS1;
++
++	dump_buf(usb, "UDC: int");
++
++	if (naking) {
++		printk("UDC: usbrx: in ISR but naking [0x%02x]\n", status);
++		return;
++	}
++
++	if (!(status & UDCCS1_RPC))
++		/* you can get here if we are holding NAK */
++		return;
++
++	if (!usb->ep[0].buflen) {
++		printk("UDC: usb_recv: RPC for non-existent buffer [0x%02x]\n", status);
++		naking = 1;
++		return;
++	}
++
++	sa1100_stop_dma(usb->ep[0].dmach);
++
++	dma_addr = sa1100_get_dma_pos(usb->ep[0].dmach);
++
++	/*
++	 * We've finished with the DMA for this packet.
++	 */
++	sa1100_clear_dma(usb->ep[0].dmach);
++
++	if (status & UDCCS1_SST) {
++		printk("UDC: usb_recv: stall sent\n");
++		UDC_flip(Ser0UDCCS1, UDCCS1_SST);
++
++		/*
++		 * UDC aborted current transfer, so we do.
++		 *
++		 * It would be better to re-queue this buffer IMHO.  It
++		 * hasn't gone anywhere yet. --rmk
++		 */
++		UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++		udc_ep1_done(usb, -EIO, 0);
++		return;
++	}
++
++	if (status & UDCCS1_RPE) {
++		printk("UDC: usb_recv: RPError %x\n", status);
++		UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++		udc_ep1_done(usb, -EIO, 0);
++		return;
++	}
++
++	len = dma_addr - usb->ep[0].pktdma;
++	if (len < 0) {
++		printk("UDC: usb_recv: dma_addr (%x) < pktdma (%x)\n",
++			dma_addr, usb->ep[0].pktdma);
++		len = 0;
++	}
++
++	if (len > usb->ep[0].pktlen)
++		len = usb->ep[0].pktlen;
++
++	/*
++	 * If our transfer was smaller, and we have bytes left in
++	 * the FIFO, we need to read them out manually.
++	 */
++	if (len < usb->ep[0].pktlen && (Ser0UDCCS1 & UDCCS1_RNE)) {
++		char *buf;
++
++		dma_sync_single(usb->dev, usb->ep[0].pktdma + len,
++				usb->ep[0].pktlen - len, DMA_FROM_DEVICE);
++
++		buf = (char *)usb->ep[0].pktcpu + len;
++
++		do {
++			*buf++ = Ser0UDCDR;
++			len++;
++		} while (len < usb->ep[0].pktlen && (Ser0UDCCS1 & UDCCS1_RNE));
++
++		/*
++		 * Note: knowing the internals of this macro is BAD, but we
++		 * need this to cause the data to be written back to memory.
++		 */
++		dma_sync_single(usb->dev, usb->ep[0].pktdma + len,
++				usb->ep[0].pktlen - len, DMA_TO_DEVICE);
++	}
++
++	/*
++	 * If the FIFO still contains data, something's definitely wrong.
++	 */
++	if (Ser0UDCCS1 & UDCCS1_RNE) {
++		printk("UDC: usb_recv: fifo screwed, shouldn't contain data\n");
++		usb->ep[0].fifo_errs++;
++		naking = 1;
++		udc_ep1_done(usb, -EPIPE, 0);
++		return;
++	}
++
++	/*
++	 * Do statistics.
++	 */
++	if (len) {
++		usb->ep[0].bytes += len;
++		usb->ep[0].packets ++;
++	}
++
++	/*
++	 * Update remaining byte count for this buffer.
++	 */
++	usb->ep[0].pktrem -= len;
++
++	/*
++	 * If we received a full-sized packet, and there's more
++	 * data remaining, th, queue up another receive.
++	 */
++	if (len == usb->ep[0].pktlen && usb->ep[0].pktrem != 0) {
++		usb->ep[0].pktcpu += len;
++		usb->ep[0].pktdma += len;
++		usb->ep[0].pktlen = min(usb->ep[0].pktrem, usb->ep[0].maxpktsize);
++		sa1100_start_dma(usb->ep[0].dmach, usb->ep[0].pktdma, usb->ep[0].pktlen);
++		/*
++		 * Clear RPC to receive next packet.
++		 */
++		UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++		dump_buf(usb, "UDC: req");
++		return;
++	}
++
++	naking = 1;
++	udc_ep1_done(usb, 0, usb->ep[0].buflen - usb->ep[0].pktrem);
++}
++
++int udc_ep1_queue_buffer(struct sausb_dev *usb, char *buf, unsigned int len)
++{
++	unsigned long flags;
++	dma_addr_t dma;
++	int ret;
++
++	if (!buf || len == 0)
++		return -EINVAL;
++
++	dma = dma_map_single(usb->dev, buf, len, DMA_FROM_DEVICE);
++
++	spin_lock_irqsave(&usb->lock, flags);
++	do {
++		if (usb->ep[0].buflen) {
++			ret = -EBUSY;
++			break;
++		}
++
++		sa1100_clear_dma(usb->ep[0].dmach);
++
++		usb->ep[0].bufdma = dma;
++		usb->ep[0].buflen = len;
++		usb->ep[0].pktcpu = buf;
++		usb->ep[0].pktdma = dma;
++		usb->ep[0].pktlen = min(len, usb->ep[0].maxpktsize);
++		usb->ep[0].pktrem = len;
++
++		sa1100_start_dma(usb->ep[0].dmach, usb->ep[0].bufdma, usb->ep[0].buflen);
++		dump_buf(usb, "UDC: que");
++
++		if (naking) {
++			/* turn off NAK of OUT packets, if set */
++			UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++			naking = 0;
++		}
++
++		ret = 0;
++	} while (0);
++	spin_unlock_irqrestore(&usb->lock, flags);
++
++	if (ret)
++		dma_unmap_single(usb->dev, dma, len, DMA_FROM_DEVICE);
++
++	return 0;
++}
++
++void udc_ep1_recv_reset(struct sausb_dev *usb)
++{
++	sa1100_reset_dma(usb->ep[0].dmach);
++	udc_ep1_done(usb, -EINTR, 0);
++}
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/buffer.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,63 @@
++/*
++ * usb/buffer.c
++ *
++ * Copyright (C) 2002 Russell King.
++ */
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++
++#include "buffer.h"
++
++static LIST_HEAD(buffers);
++
++struct usb_buf *usbb_alloc(int size, int gfp)
++{
++	unsigned long flags;
++	struct usb_buf *buf;
++
++	buf = kmalloc(sizeof(struct usb_buf) + size, gfp);
++	if (buf) {
++		atomic_set(&buf->users, 1);
++		local_irq_save(flags);
++		list_add(&buf->list, &buffers);
++		local_irq_restore(flags);
++		buf->len  = 0;
++		buf->data = (unsigned char *) (buf + 1);
++		buf->head = (unsigned char *) (buf + 1);
++	}
++
++	return buf;
++}
++
++void __usbb_free(struct usb_buf *buf)
++{
++	unsigned long flags;
++	local_irq_save(flags);
++	list_del(&buf->list);
++	local_irq_restore(flags);
++	kfree(buf);
++}
++
++EXPORT_SYMBOL(usbb_alloc);
++EXPORT_SYMBOL(__usbb_free);
++
++static void __exit usbb_exit(void)
++{
++	if (!list_empty(&buffers)) {
++		struct list_head *l, *n;
++		printk("usbb: buffers not freed:\n");
++
++		list_for_each_safe(l, n, &buffers) {
++			struct usb_buf *b = list_entry(l, struct usb_buf, list);
++
++			printk(" %p: alloced from %p count %d\n",
++				b, b->alloced_by, atomic_read(&b->users));
++
++			__usbb_free(b);
++		}
++	}
++}
++
++module_exit(usbb_exit);
++
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb-char.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2001 Extenex Corporation
++ *
++ * usb-char.h
++ *
++ * Character device emulation client for SA-1100 client usb core.
++ *
++ *
++ *
++ */
++#ifndef _USB_CHAR_H
++#define _USB_CHAR_H
++
++#define USBC_MAJOR 10      /* miscellaneous character device */
++#define USBC_MINOR 240     /* in the "reserved for local use" range */
++
++#define USBC_MAGIC 0x8E
++
++/* zap everything in receive ring buffer */
++#define USBC_IOC_FLUSH_RECEIVER    _IO( USBC_MAGIC, 0x01 )
++
++/* reset transmitter */
++#define USBC_IOC_FLUSH_TRANSMITTER _IO( USBC_MAGIC, 0x02 )
++
++/* do both of above */
++#define USBC_IOC_FLUSH_ALL         _IO( USBC_MAGIC, 0x03 )
++
++
++
++
++
++
++#endif /* _USB_CHAR_H */
++
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/buffer.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,45 @@
++/*
++ * usb/buffer.h: USB client buffers
++ *
++ * Copyright (C) 2002 Russell King.
++ *
++ * Loosely based on linux/skbuff.h
++ */
++#ifndef USBDEV_BUFFER_H
++#define USBDEV_BUFFER_H
++
++#include <linux/list.h>
++
++struct usb_buf {
++	atomic_t	users;
++	struct list_head list;
++	void		*alloced_by;
++	unsigned char	*data;
++	unsigned char	*head;
++	unsigned int	len;
++};
++
++extern struct usb_buf *usbb_alloc(int size, int gfp);
++extern void __usbb_free(struct usb_buf *);
++
++static inline struct usb_buf *usbb_get(struct usb_buf *buf)
++{
++	atomic_inc(&buf->users);
++	return buf;
++}
++
++static inline void usbb_put(struct usb_buf *buf)
++{
++	if (atomic_dec_and_test(&buf->users))
++		__usbb_free(buf);
++}
++
++static inline void *usbb_push(struct usb_buf *buf, int len)
++{
++	unsigned char *b = buf->head;
++	buf->head += len;
++	buf->len += len;
++	return b;
++}
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100usb.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,1160 @@
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/usb_ch9.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/spinlock.h>
++#include <linux/device.h>
++
++#include <asm/mach-types.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/irq.h>
++
++#include "buffer.h"
++#include "usbdev.h"
++#include "sa1100_usb.h"
++#include "sa1100usb.h"
++
++#ifdef DEBUG
++#define DPRINTK(fmt, args...) printk( fmt , ## args)
++#else
++#define DPRINTK(fmt, args...)
++#endif
++
++static inline void pcs(const char *prefix)
++{
++#ifdef DEBUG
++	__u32 foo = Ser0UDCCS0;
++
++	DPRINTK("%s UDCAR: %d\n", prefix, Ser0UDCAR);
++
++	printk("UDC: %s: %08x [ %s%s%s%s%s%s]\n", prefix,
++	       foo,
++	       foo & UDCCS0_SE ? "SE " : "",
++	       foo & UDCCS0_DE ? "DE " : "",
++	       foo & UDCCS0_FST ? "FST " : "",
++	       foo & UDCCS0_SST ? "SST " : "",
++	       foo & UDCCS0_IPR ? "IPR " : "",
++	       foo & UDCCS0_OPR ? "OPR " : "");
++#endif
++}
++
++/*
++ * soft_connect_hook()
++ *
++ * Some devices have platform-specific circuitry to make USB
++ * not seem to be plugged in, even when it is. This allows
++ * software to control when a device 'appears' on the USB bus
++ * (after Linux has booted and this driver has loaded, for
++ * example). If you have such a circuit, control it here.
++ */
++static inline void soft_connect_hook(int enable)
++{
++#ifdef CONFIG_SA1100_EXTENEX1
++	if (machine_is_extenex1()) {
++		if (enable) {
++			PPDR |= PPC_USB_SOFT_CON;
++			PPSR |= PPC_USB_SOFT_CON;
++		} else {
++			PPSR &= ~PPC_USB_SOFT_CON;
++			PPDR &= ~PPC_USB_SOFT_CON;
++		}
++	}
++#endif
++}
++
++/*
++ * disable the UDC at the source
++ */
++static inline void udc_disable(struct sausb_dev *usb)
++{
++	soft_connect_hook(0);
++
++	usb->udccr = UDCCR_UDD | UDCCR_SUSIM;
++
++	UDC_write(Ser0UDCCR, usb->udccr);
++}
++
++/*
++ * Clear any pending write from the EP0 write buffer.
++ */
++static void ep0_clear_write(struct sausb_dev *usb)
++{
++	struct usb_buf *buf;
++
++	buf = usb->wrbuf;
++	usb->wrint = NULL;
++	usb->wrbuf = NULL;
++	usb->wrptr = NULL;
++	usb->wrlen = 0;
++
++	if (buf)
++		usbb_put(buf);
++}
++
++static int udc_start(void *priv)
++{
++	struct sausb_dev *usb = priv;
++
++	usb->ep[0].maxpktsize = 0;
++	usb->ep[1].maxpktsize = 0;
++
++	/*
++	 * start UDC internal machinery running, but mask interrupts.
++	 */
++	usb->udccr = UDCCR_SUSIM | UDCCR_TIM | UDCCR_RIM | UDCCR_EIM |
++		     UDCCR_RESIM;
++	UDC_write(Ser0UDCCR, usb->udccr);
++
++	udelay(100);
++
++	/*
++	 * clear all interrupt sources
++	 */
++	Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR |
++		    UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR;
++
++	/*
++	 * flush DMA and fire through some -EAGAINs
++	 */
++	udc_ep1_init(usb);
++	udc_ep2_init(usb);
++
++	/*
++	 * enable any platform specific hardware
++	 */
++	soft_connect_hook(1);
++
++	/*
++	 * Enable resume, suspend and endpoint 0 interrupts.  Leave
++	 * endpoint 1 and 2 interrupts masked.
++	 *
++	 * If you are unplugged you will immediately get a suspend
++	 * interrupt.  If you are plugged and have a soft connect-circuit,
++	 * you will get a reset.  If you are plugged without a soft-connect,
++	 * I think you also get suspend.
++	 */
++	usb->udccr &= ~(UDCCR_SUSIM | UDCCR_EIM | UDCCR_RESIM);
++	UDC_write(Ser0UDCCR, usb->udccr);
++
++	return 0;
++}
++
++static int udc_stop(void *priv)
++{
++	struct sausb_dev *usb = priv;
++
++	ep0_clear_write(usb);
++
++	/* mask everything */
++	Ser0UDCCR = 0xFC;
++
++	udc_ep1_reset(usb);
++	udc_ep2_reset(usb);
++
++	udc_disable(usb);
++
++	return 0;
++}
++
++
++
++
++
++/*
++ * some voodo I am adding, since the vanilla macros just aren't doing it
++ * 1Mar01ww
++ */
++
++#define ABORT_BITS	(UDCCS0_SST | UDCCS0_SE)
++#define OK_TO_WRITE	(!(Ser0UDCCS0 & ABORT_BITS))
++#define BOTH_BITS	(UDCCS0_IPR | UDCCS0_DE)
++
++static void set_de(void)
++{
++	int i = 1;
++
++	while (1) {
++		if (OK_TO_WRITE) {
++			Ser0UDCCS0 |= UDCCS0_DE;
++		} else {
++			DPRINTK("UDC: quitting set DE because SST or SE set\n");
++			break;
++		}
++		if (Ser0UDCCS0 & UDCCS0_DE)
++			break;
++		udelay(i);
++		if (++i == 50) {
++			printk("UDC: Dangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8X)\n",
++			       UDCCS0_DE, Ser0UDCCS0);
++			break;
++		}
++	}
++}
++
++static void set_ipr(void)
++{
++	int i = 1;
++
++	while (1) {
++		if (OK_TO_WRITE) {
++			Ser0UDCCS0 |= UDCCS0_IPR;
++		} else {
++			DPRINTK("UDC: Quitting set IPR because SST or SE set\n");
++			break;
++		}
++		if (Ser0UDCCS0 & UDCCS0_IPR)
++			break;
++		udelay(i);
++		if (++i == 50) {
++			printk("UDC: Dangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8X)\n",
++			       UDCCS0_IPR, Ser0UDCCS0);
++			break;
++		}
++	}
++}
++
++static void set_ipr_and_de(void)
++{
++	int i = 1;
++
++	while (1) {
++		if (OK_TO_WRITE) {
++			Ser0UDCCS0 |= BOTH_BITS;
++		} else {
++			DPRINTK("UDC: Quitting set IPR/DE because SST or SE set\n");
++			break;
++		}
++		if ((Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS)
++			break;
++		udelay(i);
++		if (++i == 50) {
++			printk("UDC: Dangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8X)\n",
++			       UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0);
++			break;
++		}
++	}
++}
++
++static inline void set_cs_bits(__u32 bits)
++{
++	if (bits & (UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST | UDCCS0_SST))
++		Ser0UDCCS0 = bits;
++	else if ((bits & BOTH_BITS) == BOTH_BITS)
++		set_ipr_and_de();
++	else if (bits & UDCCS0_IPR)
++		set_ipr();
++	else if (bits & UDCCS0_DE)
++		set_de();
++}
++
++/*
++ * udc_ep0_write_fifo()
++ *
++ * Stick bytes in the 8 bytes endpoint zero FIFO.  This version uses a
++ * variety of tricks to make sure the bytes are written correctly:
++ *  1. The count register is checked to see if the byte went in,
++ *     and the write is attempted again if not.
++ *  2. An overall counter is used to break out so we don't hang in
++ *     those (rare) cases where the UDC reverses direction of the
++ *     FIFO underneath us without notification (in response to host
++ *     aborting a setup transaction early).
++ */
++static void udc_ep0_write_fifo(struct sausb_dev *usb)
++{
++	unsigned int bytes_this_time = min(usb->wrlen, 8U);
++	int bytes_written = 0;
++
++	DPRINTK("WF=%d: ", bytes_this_time);
++
++	while (bytes_this_time--) {
++		unsigned int cwc;
++		int i;
++
++		DPRINTK("%2.2X ", *usb->wrptr);
++
++		cwc = Ser0UDCWC & 15;
++
++		i = 10;
++		do {
++			Ser0UDCD0 = *usb->wrptr;
++			udelay(20);	/* voodo 28Feb01ww */
++		} while ((Ser0UDCWC & 15) == cwc && --i);
++
++		if (i == 0) {
++			printk("UDC: udc_ep0_write_fifo: write failure\n");
++			usb->ep0_wr_fifo_errs++;
++		}
++
++		usb->wrptr++;
++		bytes_written++;
++	}
++	usb->wrlen -= bytes_written;
++
++	/* following propagation voodo so maybe caller writing IPR in
++	   ..a moment might actually get it to stick 28Feb01ww */
++	udelay(300);
++
++	usb->ep0_wr_bytes += bytes_written;
++	DPRINTK("L=%d WCR=%8.8X\n", usb->wrlen, Ser0UDCWC);
++}
++
++/*
++ * read_fifo()
++ *
++ * Read 1-8 bytes out of FIFO and put in request.  Called to do the
++ * initial read of setup requests from the host. Return number of
++ * bytes read.
++ *
++ * Like write fifo above, this driver uses multiple reads checked
++ * against the count register with an overall timeout.
++ */
++static int
++udc_ep0_read_fifo(struct sausb_dev *usb, struct usb_ctrlrequest *request, int sz)
++{
++	unsigned char *pOut = (unsigned char *) request;
++	unsigned int fifo_count, bytes_read = 0;
++
++	fifo_count = Ser0UDCWC & 15;
++
++	DPRINTK("RF=%d ", fifo_count);
++	BUG_ON(fifo_count > sz);
++
++	while (fifo_count--) {
++		unsigned int cwc;
++		int i;
++
++		cwc = Ser0UDCWC & 15;
++
++		i = 10;
++		do {
++			*pOut = (unsigned char) Ser0UDCD0;
++			udelay(20);
++		} while ((Ser0UDCWC & 15) == cwc && --i);
++
++		if (i == 0) {
++			printk(KERN_ERR "UDC: udc_ep0_read_fifo: read failure\n");
++			usb->ep0_rd_fifo_errs++;
++			break;
++		}
++		pOut++;
++		bytes_read++;
++	}
++
++	DPRINTK("fc=%d\n", bytes_read);
++	usb->ep0_rd_bytes += bytes_read;
++	usb->ep0_rd_packets ++;
++	return bytes_read;
++}
++
++static void ep0_sh_write_data(struct sausb_dev *usb)
++{
++	/*
++	 * If bytes left is zero, we are coming in on the
++	 * interrupt after the last packet went out. And
++	 * we know we don't have to empty packet this
++	 * transfer so just set DE and we are done
++	 */
++	set_cs_bits(UDCCS0_DE);
++}
++
++static void ep0_sh_write_with_empty_packet(struct sausb_dev *usb)
++{
++	/*
++	 * If bytes left is zero, we are coming in on the
++	 * interrupt after the last packet went out.
++	 * We must do short packet suff, so set DE and IPR
++	 */
++	set_cs_bits(UDCCS0_IPR | UDCCS0_DE);
++	DPRINTK("UDC: sh_write_empty: Sent empty packet\n");
++}
++
++static int udc_clear_opr(void)
++{
++	int i = 10000;
++	int is_clear;
++
++	/*FIXME*/
++	do {
++		Ser0UDCCS0 = UDCCS0_SO;
++		is_clear = !(Ser0UDCCS0 & UDCCS0_OPR);
++		if (i-- <= 0)
++			break;
++	} while (!is_clear);
++
++	return is_clear;
++}
++
++static int udc_ep0_queue(void *priv, struct usb_buf *buf,
++			 unsigned int req_len)
++{
++	struct sausb_dev *usb = priv;
++	__u32 cs_reg_bits = UDCCS0_IPR;
++
++	DPRINTK("a=%d r=%d\n", buf->len, req_len);
++
++	/*
++	 * thou shalt not enter data phase until
++	 * Out Packet Ready is clear
++	 */
++	if (!udc_clear_opr()) {
++		printk("UDC: SO did not clear OPR\n");
++		set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++		usbb_put(buf);
++		return 1;
++	}
++
++	usb->ep0_wr_packets++;
++
++	usb->wrbuf = buf;
++	usb->wrptr = buf->data;
++	usb->wrlen = min(buf->len, req_len);
++
++	udc_ep0_write_fifo(usb);
++
++	if (usb->wrlen == 0) {
++		/*
++		 * out in one, so data end
++		 */
++		cs_reg_bits |= UDCCS0_DE;
++		ep0_clear_write(usb);
++	} else if (buf->len < req_len) {
++		/*
++		 * we are going to short-change host
++		 * so need nul to not stall
++		 */
++		usb->wrint = ep0_sh_write_with_empty_packet;
++	} else {
++		/*
++		 * we have as much or more than requested
++		 */
++		usb->wrint = ep0_sh_write_data;
++	}
++
++	/*
++	 * note: IPR was set uncondtionally at start of routine
++	 */
++	set_cs_bits(cs_reg_bits);
++	return 0;
++}
++
++/*
++ * When SO and DE sent, UDC will enter status phase and ack, propagating
++ * new address to udc core.  Next control transfer will be on the new
++ * address.
++ *
++ * You can't see the change in a read back of CAR until then (about 250us
++ * later, on my box).  The original Intel driver sets S0 and DE and code
++ * to check that address has propagated here.  I tried this, but it would
++ * only sometimes work!  The rest of the time it would never propagate and
++ * we'd spin forever.  So now I just set it and pray...
++ */
++static void udc_set_address(void *priv, unsigned int addr)
++{
++	Ser0UDCAR = addr;
++}
++
++static void udc_set_config(void *priv, struct cdb *cdb)
++{
++	struct sausb_dev *usb = priv;
++
++	if (cdb) {
++		udc_ep1_config(usb, le16_to_cpu(cdb->ep1.wMaxPacketSize));
++		udc_ep2_config(usb, le16_to_cpu(cdb->ep2.wMaxPacketSize));
++	} else {
++		udc_ep1_reset(usb);
++		udc_ep2_reset(usb);
++	}
++}
++
++static unsigned int udc_ep_get_status(void *priv, unsigned int ep)
++{
++	unsigned int status;
++
++	switch (ep) {
++	case 0:
++		status = (Ser0UDCCS0 & UDCCS0_FST) ? 1 : 0;
++		break;
++
++	case 1:
++		status = (Ser0UDCCS1 & UDCCS1_FST) ? 1 : 0;
++		break;
++
++	case 2:
++		status = (Ser0UDCCS2 & UDCCS2_FST) ? 1 : 0;
++		break;
++
++	default:
++		printk(KERN_ERR "UDC: get_status: bad end point %d\n", ep);
++		status = 0;
++		break;
++	}
++
++	return status;
++}
++
++static void udc_ep_halt(void *priv, unsigned int ep, int halt)
++{
++	struct sausb_dev *usb = priv;
++
++	printk("UDC: ep%d %s halt\n", ep, halt ? "set" : "clear");
++
++	switch (ep) {
++	case 1:
++		udc_ep1_halt(usb, halt);
++		break;
++
++	case 2:
++		udc_ep2_halt(usb, halt);
++		break;
++	}
++}
++
++static int udc_ep_queue(void *priv, unsigned int ep, char *buf, unsigned int len)
++{
++	struct sausb_dev *usb = priv;
++	int ret = -EINVAL;
++
++	switch (ep) {
++	case 1:
++		ret = udc_ep1_queue_buffer(usb, buf, len);
++		break;
++	case 2:
++		ret = udc_ep2_send(usb, buf, len);
++		break;
++	}
++
++	return ret;
++}
++
++static void udc_ep_reset(void *priv, unsigned int ep)
++{
++	struct sausb_dev *usb = priv;
++
++	switch (ep) {
++	case 1:
++		udc_ep1_recv_reset(usb);
++		break;
++	case 2:
++		udc_ep2_send_reset(usb);
++		break;
++	}
++}
++
++static void udc_ep_callback(void *priv, unsigned int ep, usb_callback_t cb, void *data)
++{
++	struct sausb_dev *usb = priv;
++	unsigned long flags;
++
++	if (ep == 1 || ep == 2) {
++		ep -= 1;
++
++		spin_lock_irqsave(&usb->lock, flags);
++		usb->ep[ep].cb_func = cb;
++		usb->ep[ep].cb_data = data;
++		spin_unlock_irqrestore(&usb->lock, flags);
++	}
++}
++
++static int udc_ep_idle(void *priv, unsigned int ep)
++{
++	struct sausb_dev *usb = priv;
++	int ret = -EINVAL;
++
++	switch (ep) {
++	case 1:
++		break;
++	case 2:
++		ret = udc_ep2_idle(usb);
++		break;
++	}
++
++	return ret;
++}
++
++static struct usbc_driver usb_sa1100_drv = {
++	.owner		= THIS_MODULE,
++	.name		= "SA1100",
++	.start		= udc_start,
++	.stop		= udc_stop,
++	.ep0_queue	= udc_ep0_queue,
++	.set_address	= udc_set_address,
++	.set_config	= udc_set_config,
++	.ep_get_status	= udc_ep_get_status,
++	.ep_halt	= udc_ep_halt,
++	.ep_queue	= udc_ep_queue,
++	.ep_reset	= udc_ep_reset,
++	.ep_callback	= udc_ep_callback,
++	.ep_idle	= udc_ep_idle,
++};
++
++
++/*
++ * udc_ep0_read_packet()
++ *
++ * This setup handler is the "idle" state of endpoint zero. It looks for
++ * OPR (OUT packet ready) to see if a setup request has been been received
++ * from the host. Requests without a return data phase are immediately
++ * handled. Otherwise, the handler may be set to one of the sh_write_xxxx
++ * data pumpers if more than 8 bytes need to get back to the host.
++ */
++static void udc_ep0_read_packet(struct sausb_dev *usb, u32 cs_reg_in)
++{
++	struct usb_ctrlrequest req;
++	int n, ret = RET_NOACTION;
++
++	/*
++	 * A control request has been received by EP0.
++	 * Read the request.
++	 */
++	n = udc_ep0_read_fifo(usb, &req, sizeof(req));
++
++	if (n == sizeof(req)) {
++		ret = usbctl_parse_request(usb->ctl, &req);
++	} else {
++		/*
++		 * The request wasn't fully received.  Force a
++		 * stall.
++		 */
++		set_cs_bits(UDCCS0_FST | UDCCS0_SO);
++		printk("UDC: fifo read error: wanted %d bytes got %d\n",
++		       sizeof(req), n);
++	}
++
++	switch (ret) {
++	case RET_ERROR:
++	case RET_NOACTION:
++		break;
++
++	case RET_ACK:
++		set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++		break;
++
++	case RET_REQERROR:
++		/*
++		 * Send stall PID to host.
++		 */
++		set_cs_bits(UDCCS0_DE | UDCCS0_SO | UDCCS0_FST);
++		break;
++	}
++}
++
++/*
++ * HACK DEBUG  3Mar01ww
++ * Well, maybe not, it really seems to help!  08Mar01ww
++ */
++static void core_kicker(struct sausb_dev *usb)
++{
++	__u32 car = Ser0UDCAR;
++	__u32 imp = Ser0UDCIMP;
++	__u32 omp = Ser0UDCOMP;
++
++	UDC_set(Ser0UDCCR, UDCCR_UDD);
++	udelay(300);
++	UDC_clear(Ser0UDCCR, UDCCR_UDD);
++
++	Ser0UDCAR = car;
++	Ser0UDCIMP = imp;
++	Ser0UDCOMP = omp;
++}
++
++static void enable_resume_mask_suspend(struct sausb_dev *usb)
++{
++	int i;
++
++	usb->udccr |= UDCCR_SUSIM;
++
++	i = 1;
++	do {
++		Ser0UDCCR = usb->udccr;
++		udelay(i);
++		if (Ser0UDCCR == usb->udccr)
++			break;
++		if (Ser0UDCSR & UDCSR_RSTIR)
++			break;
++	} while (i++ < 50);
++
++	if (i == 50)
++		printk("UDC: enable_resume: could not set SUSIM 0x%08x\n",
++		       Ser0UDCCR);
++
++	usb->udccr &= ~UDCCR_RESIM;
++
++	i = 1;	
++	do {
++		Ser0UDCCR = usb->udccr;
++		udelay(i);
++		if (Ser0UDCCR == usb->udccr)
++			break;
++		if (Ser0UDCSR & UDCSR_RSTIR)
++			break;
++	} while (i++ < 50);
++
++	if (i == 50)
++		printk("UDC: enable_resume: could not clear RESIM 0x%08x\n",
++		       Ser0UDCCR);
++}
++
++static void enable_suspend_mask_resume(struct sausb_dev *usb)
++{
++	int i;
++
++	usb->udccr |= UDCCR_RESIM;
++
++	i = 1;
++	do {
++		Ser0UDCCR = usb->udccr;
++		udelay(i);
++		if (Ser0UDCCR == usb->udccr)
++			break;
++		if (Ser0UDCSR & UDCSR_RSTIR)
++			break;
++	} while (i++ < 50);
++
++	if (i == 50)
++		printk("UDC: enable_resume: could not set RESIM 0x%08x\n",
++		       Ser0UDCCR);
++
++	usb->udccr &= ~UDCCR_SUSIM;
++
++	i = 1;	
++	do {
++		Ser0UDCCR = usb->udccr;
++		udelay(i);
++		if (Ser0UDCCR == usb->udccr)
++			break;
++		if (Ser0UDCSR & UDCSR_RSTIR)
++			break;
++	} while (i++ < 50);
++
++	if (i == 50)
++		printk("UDC: enable_resume: could not clear SUSIM 0x%08x\n",
++		       Ser0UDCCR);
++}
++
++/*
++ * Reset received from HUB (or controller just went nuts and reset by
++ * itself!) so UDC core has been reset, track this state here
++ */
++static void udc_reset(struct sausb_dev *usb)
++{
++	if (usbctl_reset(usb->ctl)) {
++		ep0_clear_write(usb);
++
++		/*
++		 * Clean up endpoints.
++		 */
++		udc_ep1_reset(usb);
++		udc_ep2_reset(usb);
++	}
++
++	/*
++	 * mask reset ints, they flood during sequence, enable
++	 * suspend and resume
++	 */
++	usb->udccr = (usb->udccr & ~(UDCCR_SUSIM | UDCCR_RESIM)) | UDCCR_REM;
++	Ser0UDCCR = usb->udccr;
++}
++
++/*
++ * handle interrupt for endpoint zero
++ */
++static void udc_ep0_int_hndlr(struct sausb_dev *usb)
++{
++	u32 cs_reg_in;
++
++	pcs("-->");
++
++	cs_reg_in = Ser0UDCCS0;
++
++	/*
++	 * If "setup end" has been set, the usb controller has terminated
++	 * a setup transaction before we set DE. This happens during
++	 * enumeration with some hosts. For example, the host will ask for
++	 * our device descriptor and specify a return of 64 bytes. When we
++	 * hand back the first 8, the host will know our max packet size
++	 * and turn around and issue a new setup immediately. This causes
++	 * the UDC to auto-ack the new setup and set SE. We must then
++	 * "unload" (process) the new setup, which is what will happen
++	 * after this preamble is finished executing.
++	 */
++	if (cs_reg_in & UDCCS0_SE) {
++		DPRINTK("UDC: early termination of setup\n");
++
++		/*
++		 * Clear setup end
++		 */
++		set_cs_bits(UDCCS0_SSE);
++
++		/*
++		 * Clear any pending write.
++		 */
++		ep0_clear_write(usb);
++	}
++
++	/*
++	 * UDC sent a stall due to a protocol violation.
++	 */
++	if (cs_reg_in & UDCCS0_SST) {
++		usb->ep0_stall_sent++;
++
++		DPRINTK("UDC: write_preamble: UDC sent stall\n");
++
++		/*
++		 * Clear sent stall
++		 */
++		set_cs_bits(UDCCS0_SST);
++
++		/*
++		 * Clear any pending write.
++		 */
++		ep0_clear_write(usb);
++	}
++
++	switch (cs_reg_in & (UDCCS0_OPR | UDCCS0_IPR)) {
++	case UDCCS0_OPR | UDCCS0_IPR:
++		DPRINTK("UDC: write_preamble: see OPR. Stopping write to "
++			"handle new SETUP\n");
++
++		/*
++		 * very rarely, you can get OPR and
++		 * leftover IPR. Try to clear
++		 */
++		UDC_clear(Ser0UDCCS0, UDCCS0_IPR);
++
++		/*
++		 * Clear any pending write.
++		 */
++		ep0_clear_write(usb);
++
++		/*FALLTHROUGH*/
++	case UDCCS0_OPR:
++		/*
++		 * A new setup request is pending.  Handle
++		 * it. Note that we don't try to read a
++		 * packet if SE was set and OPR is clear.
++		 */
++		udc_ep0_read_packet(usb, cs_reg_in);
++		break;
++
++	case 0:
++		if (usb->wrint) {
++			if (usb->wrlen != 0) {
++				/*
++				 * More data to go
++				 */
++				udc_ep0_write_fifo(usb);
++				set_ipr();
++			}
++
++			if (usb->wrlen == 0) {
++				/*
++				 * All data sent.
++				 */
++				usb->wrint(usb);
++
++				ep0_clear_write(usb);
++			}
++		}
++		break;
++
++	case UDCCS0_IPR:
++		DPRINTK("UDC: IPR set, not writing\n");
++		usb->ep0_early_irqs++;
++		break;
++	}
++
++	pcs("<--");
++}
++
++static irqreturn_t udc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct sausb_dev *usb = dev_id;
++	u32 status = Ser0UDCSR;
++
++	/*
++	 * ReSeT Interrupt Request - UDC has been reset
++	 */
++	if (status & UDCSR_RSTIR) {
++		udc_reset(usb);
++
++		/*
++		 * clear all pending sources
++		 */
++		UDC_flip(Ser0UDCSR, status);
++		return IRQ_HANDLED;
++	}
++
++	/*
++	 * else we have done something other than reset,
++	 * so be sure reset enabled
++	 */
++	usb->udccr &= ~UDCCR_REM;
++	UDC_write(Ser0UDCCR, usb->udccr);
++
++	/*
++	 * RESume Interrupt Request
++	 */
++	if (status & UDCSR_RESIR) {
++		usbctl_resume(usb->ctl);
++		core_kicker(usb);
++		enable_suspend_mask_resume(usb);
++	}
++
++	/*
++	 * SUSpend Interrupt Request
++	 */
++	if (status & UDCSR_SUSIR) {
++		usbctl_suspend(usb->ctl);
++		enable_resume_mask_suspend(usb);
++	}
++
++	/*
++	 * clear all pending sources
++	 */
++	UDC_flip(Ser0UDCSR, status);
++
++	if (status & UDCSR_EIR)
++		udc_ep0_int_hndlr(usb);
++
++	if (status & UDCSR_RIR)
++		udc_ep1_int_hndlr(usb);
++
++	if (status & UDCSR_TIR)
++		udc_ep2_int_hndlr(usb);
++
++	return IRQ_HANDLED;
++}
++
++#ifdef CONFIG_PROC_FS
++
++#define SAY( fmt, args... )  p += sprintf(p, fmt, ## args )
++#define SAYV(  num )         p += sprintf(p, num_fmt, "Value", num )
++#define SAYC( label, yn )    p += sprintf(p, yn_fmt, label, yn )
++#define SAYS( label, v )     p += sprintf(p, cnt_fmt, label, v )
++
++static int
++udc_read_proc(char *page, char **start, off_t off, int cnt, int *eof,
++	      void *data)
++{
++	struct sausb_dev *usb = data;
++	char *p = page;
++	u32 v;
++	int len, i;
++
++	p += usbctl_proc_info(usb->ctl, p);
++	p += sprintf(p, "\nUDC:\n");
++	v = Ser0UDCAR;
++	p += sprintf(p, "Address\t: %d (0x%02x)\n", v, v);
++	v = Ser0UDCIMP;
++	p += sprintf(p, "IN max\t: %d (0x%02x)\n", v + 1, v);
++	v = Ser0UDCOMP;
++	p += sprintf(p, "OUT max\t: %d (0x%02x)\n", v + 1, v);
++	v = Ser0UDCCR;
++	p += sprintf(p, "UDCCR\t: 0x%02x "
++			"[ %cSUSIM %cTIM %cRIM %cEIM %cRESIM %cUDA %cUDD ] "
++			"(0x%02x)\n",
++			v,
++			v & UDCCR_SUSIM ? '+' : '-', v & UDCCR_TIM ? '+' : '-',
++			v & UDCCR_RIM   ? '+' : '-', v & UDCCR_EIM ? '+' : '-',
++			v & UDCCR_RESIM ? '+' : '-', v & UDCCR_UDA ? '+' : '-',
++			v & UDCCR_UDD   ? '+' : '-', usb->udccr);
++	v = Ser0UDCCS0;
++	p += sprintf(p, "UDCCS0\t: 0x%02x "
++			"[ %cSO    %cSE  %cDE  %cFST %cSST   %cIPR %cOPR ]\n",
++			v,
++			v & UDCCS0_SO  ? '+' : '-', v & UDCCS0_SE  ? '+' : '-',
++			v & UDCCS0_DE  ? '+' : '-', v & UDCCS0_FST ? '+' : '-',
++			v & UDCCS0_SST ? '+' : '-', v & UDCCS0_IPR ? '+' : '-',
++			v & UDCCS0_OPR ? '+' : '-');
++	v = Ser0UDCCS1;
++	p += sprintf(p, "UDCCS1\t: 0x%02x "
++			"[         %cRNE %cFST %cSST %cRPE   %cRPC %cRFS ]\n",
++			v,
++			v & UDCCS1_RNE ? '+' : '-', v & UDCCS1_FST ? '+' : '-',
++			v & UDCCS1_SST ? '+' : '-', v & UDCCS1_RPE ? '+' : '-',
++			v & UDCCS1_RPC ? '+' : '-', v & UDCCS1_RFS ? '+' : '-');
++	v = Ser0UDCCS2;
++	p += sprintf(p, "UDCCS2\t: 0x%02x "
++			"[         %cFST %cSST %cTUR %cTPE   %cTPC %cTFS ]\n",
++			v,
++			v & UDCCS2_FST ? '+' : '-', v & UDCCS2_SST ? '+' : '-',
++			v & UDCCS2_TUR ? '+' : '-', v & UDCCS2_TPE ? '+' : '-',
++			v & UDCCS2_TPC ? '+' : '-', v & UDCCS2_TFS ? '+' : '-');
++
++	p += sprintf(p, "\n");
++	p += sprintf(p, "             Bytes    Packets  FIFO errs Max Sz\n");
++	p += sprintf(p, "EP0 Rd: %10ld %10ld %10ld      -\n",
++		     usb->ep0_rd_bytes,
++		     usb->ep0_rd_packets,
++		     usb->ep0_rd_fifo_errs);
++	p += sprintf(p, "EP0 Wr: %10ld %10ld %10ld      -\n",
++		     usb->ep0_wr_bytes,
++		     usb->ep0_wr_packets,
++		     usb->ep0_wr_fifo_errs);
++
++	for (i = 0; i < 2; i++)
++		p += sprintf(p, "EP%d   : %10ld %10ld %10ld %6d\n",
++			     i + 1,
++			     usb->ep[i].bytes,
++			     usb->ep[i].packets,
++			     usb->ep[i].fifo_errs,
++			     usb->ep[i].maxpktsize);
++
++	p += sprintf(p, "Stalls sent\t: %ld\n", usb->ep0_stall_sent);
++	p += sprintf(p, "Early ints\t: %ld\n", usb->ep0_early_irqs);
++
++#if 0
++	v = Ser0UDCSR;
++	SAY("\nUDC Interrupt Request Register\n");
++	SAYV(v);
++	SAYC("Reset pending", (v & UDCSR_RSTIR) ? yes : no);
++	SAYC("Suspend pending", (v & UDCSR_SUSIR) ? yes : no);
++	SAYC("Resume pending", (v & UDCSR_RESIR) ? yes : no);
++	SAYC("ep0 pending", (v & UDCSR_EIR) ? yes : no);
++	SAYC("receiver pending", (v & UDCSR_RIR) ? yes : no);
++	SAYC("tramsitter pending", (v & UDCSR_TIR) ? yes : no);
++
++#ifdef CONFIG_SA1100_EXTENEX1
++	SAYC("\nSoft connect",
++	     (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden");
++#endif
++#endif
++
++	len = (p - page) - off;
++	if (len < 0)
++		len = 0;
++	*eof = (len <= cnt) ? 1 : 0;
++	*start = page + off;
++
++	return len;
++}
++
++#endif
++
++extern struct usbctl usbctl;
++
++static int __devinit udc_probe(struct device *dev)
++{
++	struct sausb_dev *usb;
++	int retval;
++
++	if (!request_mem_region(0x80000000, 0x10000, "sa11x0-udc"))
++		return -EBUSY;
++
++	usb = kmalloc(sizeof(struct sausb_dev), GFP_KERNEL);
++	if (!usb)
++		return -ENOMEM;
++
++	memset(usb, 0, sizeof(struct sausb_dev));
++	dev_set_drvdata(dev, usb);
++
++	usb_sa1100_drv.priv = usb;
++
++	usb->dev = dev;
++	usb->ctl = &usbctl;
++
++	spin_lock_init(&usb->lock);
++
++	udc_disable(usb);
++
++	usbctl_init(usb->ctl, &usb_sa1100_drv);
++
++#ifdef CONFIG_PROC_FS
++	create_proc_read_entry("sausb", 0, NULL, udc_read_proc, usb);
++#endif
++
++	/* setup rx dma */
++	retval = sa1100_request_dma(DMA_Ser0UDCRd, "USB receive",
++				    NULL, NULL, &usb->ep[0].dmach);
++	if (retval) {
++		printk("UDC: unable to register for rx dma rc=%d\n",
++		       retval);
++		goto err;
++	}
++
++	/* setup tx dma */
++	retval = sa1100_request_dma(DMA_Ser0UDCWr, "USB transmit",
++				    NULL, NULL, &usb->ep[1].dmach);
++	if (retval) {
++		printk("UDC: unable to register for tx dma rc=%d\n",
++		       retval);
++		goto err;
++	}
++
++	/* now allocate the IRQ. */
++	retval = request_irq(IRQ_Ser0UDC, udc_interrupt, SA_INTERRUPT,
++			     "SA USB core", usb);
++	if (retval) {
++		printk("UDC: couldn't request USB irq rc=%d\n", retval);
++		goto err;
++	}
++
++	return retval;
++
++ err:
++	if (usb->ep[2].dmach) {
++		sa1100_free_dma(usb->ep[2].dmach);
++		usb->ep[2].dmach = NULL;
++	}
++	if (usb->ep[1].dmach) {
++		sa1100_free_dma(usb->ep[1].dmach);
++		usb->ep[1].dmach = NULL;
++	}
++#ifdef CONFIG_PROC_FS
++	remove_proc_entry("sausb", NULL);
++#endif
++	release_mem_region(0x80000000, 0x10000);
++	return retval;
++}
++
++/*
++ * Release DMA and interrupt resources
++ */
++static int __devexit udc_remove(struct device *dev)
++{
++	struct sausb_dev *usb = dev_get_drvdata(dev);
++
++	dev_set_drvdata(dev, NULL);
++
++#ifdef CONFIG_PROC_FS
++	remove_proc_entry("sausb", NULL);
++#endif
++
++	udc_disable(usb);
++
++	free_irq(IRQ_Ser0UDC, usb);
++	sa1100_free_dma(usb->ep[1].dmach);
++	sa1100_free_dma(usb->ep[0].dmach);
++
++	usbctl_exit(usb->ctl);
++
++	release_mem_region(0x80000000, 0x10000);
++
++	return 0;
++}
++
++static struct device_driver sa11x0usb_driver = {
++	.name		= "sa11x0-udc",
++	.bus		= &platform_bus_type,
++	.probe		= udc_probe,
++	.remove		= __devexit_p(udc_remove),
++};
++
++static int __init udc_init(void)
++{
++	return driver_register(&sa11x0usb_driver);
++}
++
++static void __exit udc_exit(void)
++{
++	driver_unregister(&sa11x0usb_driver);
++}
++
++module_init(udc_init);
++module_exit(udc_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("SA1100 USB Gadget driver");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/control.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,933 @@
++/*
++ * usb/control.c
++ *
++ * This parses and handles all the control messages to/from endpoint 0.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/usb_ch9.h>
++#include <linux/gfp.h>
++#include <linux/init.h>
++
++#include "buffer.h"
++#include "client.h"
++#include "usbdev.h"
++
++#include "sa1100_usb.h"
++
++#define USB_ENDPOINT_HALT		0
++#define USB_DEVICE_REMOTE_WAKEUP	1
++
++#undef DEBUG
++
++#ifdef DEBUG
++#define DPRINTK(fmt, args...) printk(KERN_DEBUG fmt , ## args)
++#else
++#define DPRINTK(fmt, args...)
++#endif
++
++/*
++ * print string descriptor
++ */
++static char * __attribute__((unused))
++psdesc(char *str, int len, struct usb_string_descriptor *desc)
++{
++	char *start = str;
++	int nchars = (desc->bLength - 2) / sizeof(__u16) + 2;
++	int i;
++
++	if (nchars >= len)
++		nchars = len - 1;
++
++	nchars -= 2;
++
++	*str++ = '"';
++	for(i = 0; i < nchars; i++)
++	 	*str++ = le16_to_cpu(desc->wData[i]);
++	*str++ = '"';
++	*str = '\0';
++
++	return start;
++}
++
++enum {
++	kError		= -1,
++	kEvSuspend	= 0,
++	kEvReset	= 1,
++	kEvResume	= 2,
++	kEvAddress	= 3,
++	kEvConfig	= 4,
++	kEvDeConfig	= 5
++};
++
++enum {
++	kStateZombie		= 0,
++	kStateZombieSuspend	= 1,
++	kStateDefault		= 2,
++	kStateDefaultSuspend	= 3,
++	kStateAddr		= 4,
++	kStateAddrSuspend	= 5,
++	kStateConfig		= 6,
++	kStateConfigSuspend	= 7
++};
++
++#define kE	kError
++#define kSZ	kStateZombie
++#define kSZS	kStateZombieSuspend
++#define kSD	kStateDefault
++#define kSDS	kStateDefaultSuspend
++#define kSA	kStateAddr
++#define kSAS	kStateAddrSuspend
++#define kSC	kStateConfig
++#define kSCS	kStateConfigSuspend
++
++/*
++ * Fig 9-1 P192
++ *  Zombie == Attached | Powered
++ */
++static int device_state_machine[8][6] = {
++// 	suspend	reset	resume	addr	config	deconfig
++{	kSZS, 	kSD,	kE,	kE,	kE,	kE  }, /* zombie */
++{	kE,	kSD,	kSZ,	kE,	kE,	kE  }, /* zom sus */ 
++{	kSDS,	kError,	kSD,	kSA,	kE,	kE  }, /* default */
++{	kE,	kSD,	kSD,	kE,	kE,	kE  }, /* def sus */
++{	kSAS,	kSD,	kE,	kE,	kSC,	kE  }, /* addr */
++{	kE,	kSD,	kSA,	kE,	kE,	kE  }, /* addr sus */
++{	kSCS,	kSD,	kE,	kE,	kE,	kSA }, /* config */
++{	kE,	kSD, 	kSC,	kE,	kE,	kE  }  /* cfg sus */
++};
++
++/*
++ * "device state" is the usb device framework state, as opposed to the
++ * "state machine state" which is whatever the driver needs and is much
++ * more fine grained
++ */
++static int sm_state_to_device_state[8] = {
++	USB_STATE_POWERED,	/* zombie */
++	USB_STATE_SUSPENDED,	/* zombie suspended */
++	USB_STATE_DEFAULT,	/* default */
++	USB_STATE_SUSPENDED,	/* default suspended */
++	USB_STATE_ADDRESS,	/* address */
++	USB_STATE_SUSPENDED,	/* address suspended */
++	USB_STATE_CONFIGURED,	/* config */
++	USB_STATE_SUSPENDED	/* config suspended */
++};
++
++static char * state_names[8] = {
++	"zombie",
++	"zombie suspended",
++	"default",
++	"default suspended",
++	"address",
++	"address suspended",
++	"configured",
++	"config suspended"
++};
++
++static char * event_names[6] = {
++	"suspend",
++	"reset",
++	"resume",
++	"address assigned",
++	"configure",
++	"de-configure"
++};
++
++static char * device_state_names[] = {
++	"not attached",
++	"attached",
++	"powered",
++	"default",
++	"address",
++	"configured",
++	"suspended"
++};
++
++static void usbctl_callbacks(struct usbctl *ctl, int state, int oldstate)
++{
++	struct usb_client *clnt = ctl->clnt;
++
++	/*
++	 * Inform any clients currently attached
++	 * that the connectivity state changed.
++	 */
++	if (clnt && clnt->state_change)
++		clnt->state_change(clnt->priv, state, oldstate);
++}
++
++/*
++ * called by the interrupt handler here and the two endpoint
++ * files when interesting .."events" happen
++ */
++static int usbctl_next_state_on_event(struct usbctl *ctl, int event)
++{
++	int next_state, next_dev_state, old_dev_state;
++
++	printk(KERN_DEBUG "usbctl: %s --[%s]--> ", state_names[ctl->sm_state],
++		event_names[event]);
++
++	next_state = device_state_machine[ctl->sm_state][event];
++	if (next_state != kError) {
++		next_dev_state = sm_state_to_device_state[next_state];
++
++		printk("%s. Device in %s state.\n",
++			state_names[next_state],
++			device_state_names[next_dev_state]);
++
++		old_dev_state = ctl->state;
++		ctl->sm_state = next_state;
++		ctl->state = next_dev_state;
++
++		if (old_dev_state != next_dev_state)
++			usbctl_callbacks(ctl, next_dev_state, old_dev_state);
++	} else
++		printk("(error)\n");
++
++	return next_state;
++}
++
++/*
++ * Driver detected USB HUB reset.
++ */
++int usbctl_reset(struct usbctl *ctl)
++{
++	int ret;
++
++	ret = usbctl_next_state_on_event(ctl, kEvReset) == kError;
++
++	if (!ret) {
++		ctl->address = 0;
++	}
++	return ret;
++}
++
++EXPORT_SYMBOL(usbctl_reset);
++
++void usbctl_suspend(struct usbctl *ctl)
++{
++	usbctl_next_state_on_event(ctl, kEvSuspend);
++}
++
++EXPORT_SYMBOL(usbctl_suspend);
++
++void usbctl_resume(struct usbctl *ctl)
++{
++	usbctl_next_state_on_event(ctl, kEvResume);
++}
++
++EXPORT_SYMBOL(usbctl_resume);
++
++static struct usb_interface_descriptor *
++usbctl_get_interface_descriptor(struct usbctl *ctl, unsigned int interface)
++{
++	/*FIXME*/
++	struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
++
++	return (struct usb_interface_descriptor *)&cdb->intf;
++}
++
++static inline int
++__usbctl_queue(struct usbctl *ctl, struct usb_ctrlrequest *req,
++	       struct usb_buf *buf)
++{
++	unsigned int reqlen = le16_to_cpu(req->wLength);
++
++	return ctl->driver->ep0_queue(ctl->driver->priv, buf, reqlen) ?
++		RET_ERROR : RET_QUEUED;
++}
++
++static int
++usbctl_queue(struct usbctl *ctl, struct usb_ctrlrequest *req,
++	     void *data, unsigned int len)
++{
++	struct usb_buf *buf;
++
++	buf = usbb_alloc(len, GFP_ATOMIC);
++	if (!buf) {
++		printk(KERN_ERR "usb: out of memory\n");
++		return RET_ERROR;
++	}
++
++	if (data)
++		memcpy(usbb_push(buf, len), data, len);
++
++	return __usbctl_queue(ctl, req, buf);
++}
++
++/*
++ * 9.4.5: Get Status (device)
++ */
++static int
++usbctl_parse_dev_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	u16 status;
++
++	status = /* self_powered_hook() ? 1 : 0 */1;
++
++	status = cpu_to_le16(status);
++
++	return usbctl_queue(ctl, req, &status, 2);
++}
++
++/*
++ * Send USB device description to the host.
++ */
++static int
++usbctl_desc_device(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	return __usbctl_queue(ctl, req, usbb_get(ctl->dev_desc_buf));
++}
++
++/*
++ * Send USB configuration information to the host.
++ */
++static int
++usbctl_desc_config(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	/*FIXME*/
++	struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
++
++	return usbctl_queue(ctl, req, cdb, sizeof(struct cdb));
++}
++
++/*
++ * Send a string to the host from the string table.
++ */
++static int
++usbctl_desc_string(struct usbctl *ctl, struct usb_ctrlrequest *req,
++		   unsigned int idx)
++{
++	struct usb_buf *buf;
++	unsigned int lang = le16_to_cpu(req->wIndex);
++	char string[32] __attribute__((unused));
++	int ret;
++
++	DPRINTK("usbctl: desc_string (index %u, lang 0x%04x): ", idx, lang);
++
++	buf = usbc_string_find(&ctl->strings, lang, idx);
++	if (buf) {
++		DPRINTK("%s\n", idx == 0 ? "language" :
++			 psdesc(string, sizeof(string), usbc_string_desc(buf)));
++
++		ret = __usbctl_queue(ctl, req, buf);
++	} else {
++		DPRINTK("not found -> stall\n");
++		ret = RET_REQERROR;
++	}
++	return ret;
++}
++
++/*
++ * Send an interface description (and endpoints) to the host.
++ */
++static int
++usbctl_desc_interface(struct usbctl *ctl, struct usb_ctrlrequest *req,
++		      unsigned int idx)
++{
++	struct usb_interface_descriptor *desc;
++	int ret;
++
++	DPRINTK("usbctl: desc_interface (index %d)\n", idx);
++
++	desc = usbctl_get_interface_descriptor(ctl, idx);
++
++	if (desc) {
++		ret = usbctl_queue(ctl, req, desc, desc->bLength);
++	} else {
++		printk("usbctl: unknown interface %d\n", idx);
++		ret = RET_REQERROR;
++	}
++
++	return ret;
++}
++
++/*
++ * Send an endpoint (1 .. n) to the host.
++ */
++static int
++usbctl_desc_endpoint(struct usbctl *ctl, struct usb_ctrlrequest *req,
++		     unsigned int idx)
++{
++	int ret;
++
++	DPRINTK("usbctl: desc_endpoint (index %d)\n", idx);
++
++	if (idx >= 1 && idx <= ctl->nr_ep) {
++		struct usb_endpoint_descriptor *ep = ctl->ep_desc[idx - 1];
++
++		ret = usbctl_queue(ctl, req, ep, ep->bLength);
++	} else {
++		printk("usbctl: unknown endpoint %d\n", idx);
++		ret = RET_REQERROR;
++	}
++
++	return ret;
++}
++
++/*
++ * 9.4.3: Parse a request for a descriptor.
++ *  Unspecified conditions:
++ *   None
++ *  Valid states: default, address, configured.
++ */
++static int
++usbctl_parse_dev_descriptor(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int idx = le16_to_cpu(req->wValue) & 255;
++	unsigned int type = le16_to_cpu(req->wValue) >> 8;
++	int ret;
++
++	switch (type) {
++	case USB_DT_DEVICE:		/* check if idx matters */
++		ret = usbctl_desc_device(ctl, req);
++		break;
++
++	case USB_DT_CONFIG:		/* check if idx matters */
++		ret = usbctl_desc_config(ctl, req);
++		break;
++
++	case USB_DT_STRING:
++		ret = usbctl_desc_string(ctl, req, idx);
++		break;
++
++	case USB_DT_INTERFACE:
++		ret = usbctl_desc_interface(ctl, req, idx);
++		break;
++
++	case USB_DT_ENDPOINT:
++		ret = usbctl_desc_endpoint(ctl, req, idx);
++		break;
++
++	case USB_DT_DEVICE_QUALIFIER:
++	case USB_DT_OTHER_SPEED_CONFIG:
++	case USB_DT_INTERFACE_POWER:
++	default:
++		printk(KERN_ERR "usbctl: unknown descriptor: "
++			"wValue = 0x%04x wIndex = 0x%04x\n",
++			le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex));
++		ret = RET_REQERROR;
++		break;
++	}
++
++	return ret;
++}
++
++/*
++ * 9.4.6: Set Address
++ * The USB1.1 spec says the response to SetAddress() with value 0
++ * is undefined.  It then goes on to define the response.  We
++ * acknowledge addresses of zero, but take no further action.
++ */
++static int
++usbctl_parse_dev_set_address(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int address = le16_to_cpu(req->wValue) & 0x7f;
++
++	if (ctl->state == USB_STATE_CONFIGURED)
++		return RET_REQERROR;
++
++	if (address != 0) {
++		ctl->address = address;
++
++		usbctl_next_state_on_event(ctl, kEvAddress);
++
++		ctl->driver->set_address(ctl->driver->priv, address);
++	}
++
++	return RET_ACK;
++}
++
++/*
++ * 9.4.2: Get Configuration.
++ *  Unspecified conditions:
++ *   - non-zero wIndex, wValue or wLength (ignored)
++ *   - default state (request error)
++ *  Valid states: address, configured.
++ */
++static int
++usbctl_parse_dev_get_config(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	u8 status = 0;
++
++	if (ctl->state == USB_STATE_CONFIGURED)
++		status = 1;
++
++	return usbctl_queue(ctl, req, &status, 1);
++}
++
++/*
++ * 9.4.7: Set Configuration.
++ *  Unspecified conditions:
++ *   - default state (request error)
++ */
++static int
++usbctl_parse_dev_set_config(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int cfg = le16_to_cpu(req->wValue);
++	int ret = RET_REQERROR;
++
++	if (ctl->state == USB_STATE_DEFAULT)
++		return ret;
++
++	if (cfg == 0) {
++		/* enter address state, or remain in address state */
++		usbctl_next_state_on_event(ctl, kEvDeConfig);
++
++		ctl->driver->set_config(ctl->driver->priv, NULL);
++
++		ret = RET_ACK;
++	} else if (cfg == 1) {
++		/* enter configured state, and set configuration */
++		/*FIXME*/
++		struct cdb *cdb = sa1100_usb_get_descriptor_ptr();
++
++		usbctl_next_state_on_event(ctl, kEvConfig);
++
++		ctl->driver->set_config(ctl->driver->priv, cdb);
++		ret = RET_ACK;
++	}
++
++	return ret;
++}
++
++/*
++ * Interface handling
++ */
++
++/*
++ * 9.4.5: Get Status (interface)
++ */
++static int
++usbctl_parse_int_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int interface = le16_to_cpu(req->wIndex) & 255;
++	u16 status;
++
++	switch (ctl->state) {
++	case USB_STATE_DEFAULT:
++		return RET_REQERROR;
++
++	case USB_STATE_ADDRESS:
++		if (interface != 0)
++			return RET_REQERROR;
++		break;
++
++	case USB_STATE_CONFIGURED:
++		if (interface != 1)
++			return RET_REQERROR;
++		break;
++	}
++
++	status = cpu_to_le16(0);
++
++	return usbctl_queue(ctl, req, &status, 2);
++}
++
++/*
++ * 9.4.4: Get Interface
++ *  Unspecified conditions:
++ *   - 
++ *  States: Default (unspecified), Address (Request Error), Configured (ok)
++ */
++static int
++usbctl_parse_int_get_interface(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int interface = le16_to_cpu(req->wIndex) & 255;
++	u8 null = 0;
++
++	if (ctl->state != USB_STATE_CONFIGURED)
++		return RET_REQERROR;
++
++	/*
++	 * If the interface doesn't exist, respond with request error
++	 */
++	if (interface != 1)
++		return RET_REQERROR;
++
++	printk("usbctl: get interface %d not supported\n", interface);
++
++	return usbctl_queue(ctl, req, &null, 1);
++}
++
++static int
++usbctl_parse_int_set_interface(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int interface = le16_to_cpu(req->wIndex) & 255;
++
++	if (interface != 0)
++		printk("usbctl: set interface %d not supported (ignored)\n",
++			interface);
++
++	return RET_ACK;
++}
++
++/*
++ * Endpoint handling
++ */
++
++/*
++ * 9.4.5: Get Status (endpoint)
++ */
++static int
++usbctl_parse_ep_get_status(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int ep = le16_to_cpu(req->wIndex) & 15;
++	u16 status;
++
++	if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) ||
++	    ep <= ctl->nr_ep)
++		return RET_REQERROR;
++
++	status = ctl->driver->ep_get_status(ctl->driver->priv, ep);
++	status = cpu_to_le16(status);
++
++	return usbctl_queue(ctl, req, &status, 2);
++}
++
++/*
++ * 9.4.1: Clear an endpoint feature.  We only support ENDPOINT_HALT.
++ *  Unspecified conditions:
++ *   - non-zero wLength is not specified (ignored)
++ *  Valid states: Address, Configured.
++ */
++static int
++usbctl_parse_ep_clear_feature(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int feature = le16_to_cpu(req->wValue);
++	unsigned int ep = le16_to_cpu(req->wIndex) & 15;
++	int ret;
++
++	if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) ||
++	    ep <= ctl->nr_ep)
++		return RET_REQERROR;
++
++	if (feature == USB_ENDPOINT_HALT) {
++		ctl->driver->ep_halt(ctl->driver->priv, ep, 0);
++		ret = RET_ACK;
++	} else {
++		printk(KERN_ERR "usbctl: unsupported clear feature: "
++			"wValue = 0x%04x wIndex = 0x%04x\n",
++			feature, ep);
++
++		ret = RET_REQERROR;
++	}
++	return ret;
++}
++
++/*
++ * 9.4.9: Set Feature (endpoint)
++ */
++static int
++usbctl_parse_ep_set_feature(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int feature = le16_to_cpu(req->wValue);
++	unsigned int ep = le16_to_cpu(req->wIndex) & 15;
++	int ret;
++
++	if ((ep != 0 && ctl->state != USB_STATE_CONFIGURED) ||
++	    ep <= ctl->nr_ep)
++		return RET_REQERROR;
++
++	if (feature == USB_ENDPOINT_HALT) {
++		ctl->driver->ep_halt(ctl->driver->priv, ep, 1);
++		ret = RET_ACK;
++	} else {
++		printk(KERN_ERR "usbctl: unsupported set feature "
++			"wValue = 0x%04x wIndex = 0x%04x\n",
++			feature, ep);
++
++		ret = RET_REQERROR;
++	}
++	return ret;
++}
++
++/*
++ * This reflects Table 9.3 (p186) in the USB1.1 spec.
++ *
++ * Some notes:
++ *  - USB1.1 specifies remote wakeup feature, so we don't implement
++ *    USB_RECIP_DEVICE USB_REQ_{SET,CLEAR}_FEATURE
++ *  - USB1.1 doesn't actually specify any interface features, so we
++ *    don't implement USB_RECIP_INTERFACE USB_REQ_{SET,CLEAR}_FEATURE
++ */
++static int (*request_fns[4][16])(struct usbctl *, struct usb_ctrlrequest *) = {
++	[USB_RECIP_DEVICE] = {
++		[USB_REQ_GET_STATUS]	    = usbctl_parse_dev_get_status,
++		[USB_REQ_CLEAR_FEATURE]	    = NULL,
++		[USB_REQ_SET_FEATURE]	    = NULL,
++		[USB_REQ_SET_ADDRESS]	    = usbctl_parse_dev_set_address,
++		[USB_REQ_GET_DESCRIPTOR]    = usbctl_parse_dev_descriptor,
++		[USB_REQ_SET_DESCRIPTOR]    = NULL,
++		[USB_REQ_GET_CONFIGURATION] = usbctl_parse_dev_get_config,
++		[USB_REQ_SET_CONFIGURATION] = usbctl_parse_dev_set_config,
++	},
++
++	[USB_RECIP_INTERFACE] = {
++		[USB_REQ_GET_STATUS]	    = usbctl_parse_int_get_status,
++		[USB_REQ_CLEAR_FEATURE]	    = NULL,
++		[USB_REQ_SET_FEATURE]	    = NULL,
++		[USB_REQ_GET_INTERFACE]	    = usbctl_parse_int_get_interface,
++		[USB_REQ_SET_INTERFACE]	    = usbctl_parse_int_set_interface,
++	},
++
++	[USB_RECIP_ENDPOINT] = {
++		[USB_REQ_GET_STATUS]	    = usbctl_parse_ep_get_status,
++		[USB_REQ_CLEAR_FEATURE]	    = usbctl_parse_ep_clear_feature,
++		[USB_REQ_SET_FEATURE]	    = usbctl_parse_ep_set_feature,
++	},
++};
++
++static void __attribute__((unused))
++usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req)
++{
++	printk("%sbRequestType=0x%02x bRequest=0x%02x "
++		"wValue=0x%04x wIndex=0x%04x wLength=0x%04x\n",
++		prefix, req->bRequestType, req->bRequest,
++		le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex),
++		le16_to_cpu(req->wLength));
++}
++
++int usbctl_parse_request(struct usbctl *ctl, struct usb_ctrlrequest *req)
++{
++	unsigned int type;
++	int (*fn)(struct usbctl *, struct usb_ctrlrequest *) = NULL;
++	int ret = RET_REQERROR;
++
++	//usbctl_dump_request("usbctl: ", req);
++
++	type = req->bRequestType & USB_TYPE_MASK;
++	if (type == USB_TYPE_STANDARD) {
++		unsigned int recip;
++
++		recip = req->bRequestType & USB_RECIP_MASK;
++		if (recip < ARRAY_SIZE(request_fns) &&
++		    req->bRequest < ARRAY_SIZE(request_fns[0]))
++			fn = request_fns[recip][req->bRequest];
++	}
++
++	if (fn)
++		ret = fn(ctl, req);
++	else
++		usbctl_dump_request(KERN_ERR "usbctl: unknown request: ",
++				    req);
++
++	/*
++	 * Make sure we're doing the right thing.
++	 */
++	if (req->bRequestType & USB_DIR_IN) {
++		if (ret != RET_QUEUED && ret != RET_REQERROR)
++			printk("Error: device to host transfer expected\n");
++	} else {
++		if (ret == RET_QUEUED)
++			printk("Error: no device to host transfer expected\n");
++	}
++
++	return ret;
++}
++
++EXPORT_SYMBOL(usbctl_parse_request);
++
++/* Start running. Must have called usb_open (above) first */
++int usbctl_start(struct usb_client *client)
++{
++	struct usbctl *ctl = client->ctl;
++
++	if (ctl == NULL || ctl->clnt != client) {
++		printk("usbctl: start: no client registered\n");
++		return -EPERM;
++	}
++
++	ctl->sm_state = kStateZombie;
++	ctl->state = USB_STATE_POWERED;
++
++	/*
++	 * Notify the client as to our state.
++	 */
++	usbctl_callbacks(ctl, USB_STATE_POWERED, USB_STATE_SUSPENDED);
++
++	return ctl->driver->start(ctl->driver->priv);
++}
++
++EXPORT_SYMBOL(usbctl_start);
++
++/*
++ * Stop USB core from running
++ */
++void usbctl_stop(struct usb_client *client)
++{
++	struct usbctl *ctl = client->ctl;
++
++	if (ctl == NULL || ctl->clnt != client) {
++		printk("USBDEV: stop: no client/driver registered\n");
++		return;
++	}
++
++	ctl->driver->stop(ctl->driver->priv);
++}
++
++EXPORT_SYMBOL(usbctl_stop);
++
++struct usbctl usbctl;
++
++EXPORT_SYMBOL(usbctl);
++
++/* Open SA usb core on behalf of a client, but don't start running */
++
++int usbctl_open(struct usb_client *client)
++{
++	struct usbctl *ctl = &usbctl;
++	int ret;
++printk("usbctl_open: ctl %p driver %p\n", ctl, ctl->driver);
++	if (!ctl->driver || !try_module_get(ctl->driver->owner))
++		return -ENODEV;
++
++	if (ctl->clnt != NULL) {
++		ret = -EBUSY;
++		goto err;
++	}
++
++	ctl->clnt     = client;
++	ctl->state    = USB_STATE_SUSPENDED;
++	ctl->nr_ep    = 2;
++	/* start in zombie suspended state */
++	ctl->sm_state = kStateZombieSuspend;
++	ctl->state    = USB_STATE_SUSPENDED;
++	client->ctl   = ctl;
++
++	ctl->dev_desc_buf = usbb_alloc(sizeof(struct usb_device_descriptor),
++				       GFP_KERNEL);
++	if (!ctl->dev_desc_buf) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ctl->dev_desc = usbb_push(ctl->dev_desc_buf,
++				  sizeof(struct usb_device_descriptor));
++
++	/* create descriptors for enumeration */
++	initialize_descriptors(ctl);
++
++	return 0;
++
++ err:
++	module_put(ctl->driver->owner);
++	return ret;
++}
++
++EXPORT_SYMBOL(usbctl_open);
++
++/* Tell SA core client is through using it */
++void usbctl_close(struct usb_client *client)
++{
++	struct usbctl *ctl = client->ctl;
++
++	if (ctl == NULL || ctl->clnt != client) {
++		printk("usbctl: close: no client registered\n");
++		return;
++	}
++
++	usbb_put(ctl->dev_desc_buf);
++
++	client->ctl       = NULL;
++	ctl->clnt         = NULL;
++	ctl->dev_desc     = NULL;
++	ctl->dev_desc_buf = NULL;
++	/* reset to zombie suspended state */
++	ctl->sm_state     = kStateZombieSuspend;
++	ctl->state        = USB_STATE_SUSPENDED;
++
++	usbc_string_free_all(&ctl->strings);
++
++	if (ctl->driver->owner)
++		module_put(ctl->driver->owner);
++}
++
++EXPORT_SYMBOL(usbctl_close);
++
++int usbctl_proc_info(struct usbctl *ctl, char *buf)
++{
++	char *p = buf;
++
++	p += sprintf(p, "USB Gadget Core:\n");
++	p += sprintf(p, "Driver\t: %s\n",
++		ctl->driver ? ctl->driver->name : "none");
++	p += sprintf(p, "Client\t: %s\n",
++		ctl->clnt ? ctl->clnt->name : "none");
++	p += sprintf(p, "State\t: %s (%s) %d\n",
++		device_state_names[sm_state_to_device_state[ctl->sm_state]],
++		state_names[ctl->sm_state],
++		ctl->sm_state);
++	p += sprintf(p, "Address\t: %d\n", ctl->address);
++
++	return p - buf;
++}
++
++EXPORT_SYMBOL(usbctl_proc_info);
++
++int
++usbctl_ep_queue_buffer(struct usbctl *ctl, unsigned int ep,
++		       char *buf, unsigned int len)
++{
++	return ctl->driver->ep_queue(ctl->driver->priv, ep, buf, len);
++}
++
++EXPORT_SYMBOL(usbctl_ep_queue_buffer);
++
++void usbctl_ep_reset(struct usbctl *ctl, unsigned int ep)
++{
++	return ctl->driver->ep_reset(ctl->driver->priv, ep);
++}
++
++EXPORT_SYMBOL(usbctl_ep_reset);
++
++void
++usbctl_ep_set_callback(struct usbctl *ctl, unsigned int ep,
++		       usb_callback_t callback, void *data)
++{
++	ctl->driver->ep_callback(ctl->driver->priv, ep, callback, data);
++}
++
++EXPORT_SYMBOL(usbctl_ep_set_callback);
++
++int usbctl_ep_idle(struct usbctl *ctl, unsigned int ep)
++{
++	return ctl->driver->ep_idle(ctl->driver->priv, ep);
++}
++
++EXPORT_SYMBOL(usbctl_ep_idle);
++
++/*
++ * usbctl_init()
++ * Module load time. Allocate dma and interrupt resources. Setup /proc fs
++ * entry. Leave UDC disabled.
++ */
++int usbctl_init(struct usbctl *ctl, struct usbc_driver *drv)
++{
++	usbc_string_init(&ctl->strings);
++printk("usbctl_init: %p %p\n", ctl, drv);
++	/*
++	 * start in zombie suspended state
++	 */
++	ctl->sm_state	= kStateZombieSuspend;
++	ctl->state	= USB_STATE_SUSPENDED;
++	ctl->driver	= drv;
++
++	return 0;
++}
++
++/*
++ * usbctl_exit()
++ */
++void usbctl_exit(struct usbctl *ctl)
++{
++	usbc_string_free_all(&ctl->strings);
++
++	ctl->driver	= NULL;
++}
++
++EXPORT_SYMBOL(usbctl_init);
++EXPORT_SYMBOL(usbctl_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("USB gadget core");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/client.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,40 @@
++#ifndef USBDEV_CLIENT_H
++#define USBDEV_CLIENT_H
++
++#include "sa1100_usb.h" /* grr */
++
++struct usbctl;
++
++struct usb_client {
++	struct usbctl	*ctl;
++	const char	*name;		/* Client name		*/
++	void		*priv;		/* Client-private data	*/
++	void		(*state_change)(void *priv, int state, int oldstate);
++	__u16		vendor;		/* USB vendor ID	*/
++	__u16		product;	/* USB product ID	*/
++	__u16		version;	/* USB version ID	*/
++	__u8		class;		/* USB class		*/
++	__u8		subclass;	/* USB subclass		*/
++	__u8		protocol;	/* USB protocol		*/
++	__u8		unused1;
++	__u16		unused2;
++	const char	*manufacturer_str;
++	const char	*product_str;
++	const char	*serial_str;
++};
++
++int usbctl_start(struct usb_client *client);
++void usbctl_stop(struct usb_client *client);
++int usbctl_open(struct usb_client *client);
++void usbctl_close(struct usb_client *client);
++
++int
++usbctl_ep_queue_buffer(struct usbctl *ctl, unsigned int ep,
++		       char *buf, unsigned int len);
++void usbctl_ep_reset(struct usbctl *ctl, unsigned int ep);
++void
++usbctl_ep_set_callback(struct usbctl *ctl, unsigned int ep,
++		       usb_callback_t callback, void *data);
++int usbctl_ep_idle(struct usbctl *ctl, unsigned int ep);
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100_usb.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,50 @@
++/*
++ * sa1100_usb.h
++ *
++ * Public interface to the sa1100 USB core. For use by client modules
++ * like usb-eth and usb-char.
++ *
++ */
++#ifndef _SA1100_USB_H
++#define _SA1100_USB_H
++
++typedef void (*usb_callback_t)(void *data, int flag, int size);
++
++/* in usb_send.c */
++int sa1100_usb_xmitter_avail( void );
++int sa1100_usb_send(char *buf, int len);
++void sa1100_usb_send_set_callback(usb_callback_t callback, void *data);
++void sa1100_usb_send_reset(void);
++
++/* in usb_recev.c */
++int sa1100_usb_recv(char *buf, int len);
++void sa1100_usb_recv_set_callback(usb_callback_t callback, void *data);
++void sa1100_usb_recv_reset(void);
++
++//////////////////////////////////////////////////////////////////////////////
++// Descriptor Management
++//////////////////////////////////////////////////////////////////////////////
++
++// MaxPower:
++#define USB_POWER(x)  ((x)>>1) /* convert mA to descriptor units of A for MaxPower */
++
++/* "config descriptor buffer" - that is, one config,
++   ..one interface and 2 endpoints */
++struct cdb {
++	 struct usb_config_descriptor	 	cfg;
++	 struct usb_interface_descriptor	intf;
++	 struct usb_endpoint_descriptor		ep1, ep2;
++} __attribute__ ((packed));
++
++
++/*=======================================================
++ * Descriptor API
++ */
++
++/* Get the address of the statically allocated desc_t structure
++   in the usb core driver. Clients can modify this between
++   the time they call sa1100_usb_open() and sa1100_usb_start()
++*/
++struct cdb *sa1100_usb_get_descriptor_ptr(void);
++
++#endif /* _SA1100_USB_H */
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/sa1100usb.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,136 @@
++/*
++ *	Copyright (C)  Compaq Computer Corporation, 1998, 1999
++ *	Copyright (C)  Extenex Corporation 2001
++ *
++ *  usb_ctl.h
++ *
++ *  PRIVATE interface used to share info among components of the SA-1100 USB
++ *  core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core
++ *  should use sa1100_usb.h.
++ *
++ */
++#ifndef SA1100USB_H
++#define SA1100USB_H
++
++struct usbctl;
++
++struct sausb_dev {
++	struct device	*dev;
++	struct usbctl	*ctl;
++	spinlock_t	lock;
++
++	u32		udccr;
++
++	/*
++	 * EP0 write thread.
++	 */
++	void		(*wrint)(struct sausb_dev *);
++	struct usb_buf	*wrbuf;
++	unsigned char	*wrptr;
++	unsigned int	wrlen;
++
++	/*
++	 * EP0 statistics.
++	 */
++	unsigned long	ep0_wr_fifo_errs;
++	unsigned long	ep0_wr_bytes;
++	unsigned long	ep0_wr_packets;
++	unsigned long	ep0_rd_fifo_errs;
++	unsigned long	ep0_rd_bytes;
++	unsigned long	ep0_rd_packets;
++	unsigned long	ep0_stall_sent;
++	unsigned long	ep0_early_irqs;
++
++	/*
++	 * EP1 .. n
++	 */
++	struct {
++		dma_regs_t	*dmach;
++
++		dma_addr_t	bufdma;
++		unsigned int	buflen;
++		void		*pktcpu;
++		dma_addr_t	pktdma;
++		unsigned int	pktlen;
++		unsigned int	pktrem;
++
++		void		*cb_data;
++		void		(*cb_func)(void *data, int flag, int size);
++
++		u32		udccs;
++		unsigned int	maxpktsize;
++		unsigned int	configured;
++		unsigned int	host_halt;
++		unsigned long	fifo_errs;
++		unsigned long	bytes;
++		unsigned long	packets;
++	} ep[2];
++};
++
++/* receiver */
++int  ep1_recv(void);
++void udc_ep1_init(struct sausb_dev *);
++void udc_ep1_halt(struct sausb_dev *, int);
++void udc_ep1_reset(struct sausb_dev *);
++void udc_ep1_config(struct sausb_dev *, unsigned int);
++void udc_ep1_int_hndlr(struct sausb_dev *);
++
++/* xmitter */
++void udc_ep2_init(struct sausb_dev *);
++void udc_ep2_halt(struct sausb_dev *, int);
++void udc_ep2_reset(struct sausb_dev *);
++void udc_ep2_config(struct sausb_dev *, unsigned int);
++void udc_ep2_int_hndlr(struct sausb_dev *);
++
++#define UDC_write(reg, val) do { \
++	int i = 10000; \
++	do { \
++	  	(reg) = (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: write %#x to %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while((reg) != (val)); \
++} while (0)
++
++#define UDC_set(reg, val) do { \
++	int i = 10000; \
++	do { \
++		(reg) |= (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: set %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while(!((reg) & (val))); \
++} while (0)
++
++#define UDC_clear(reg, val) do { \
++	int i = 10000; \
++	do { \
++		(reg) &= ~(val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: clear %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while((reg) & (val)); \
++} while (0)
++
++#define UDC_flip(reg, val) do { \
++	int i = 10000; \
++	(reg) = (val); \
++	do { \
++		(reg) = (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: flip %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while(((reg) & (val))); \
++} while (0)
++
++#define CHECK_ADDRESS { if ( Ser0UDCAR == 1 ) { printk("%s:%d I lost my address!!!\n",__FUNCTION__, __LINE__);}}
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/strings.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,117 @@
++/*
++ * usb/strings.c
++ *
++ * Copyright (C) 2002 Russell King.
++ */
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/spinlock.h>
++#include <linux/string.h>
++#include <linux/usb_ch9.h>
++
++#include "buffer.h"
++#include "strings.h"
++
++struct usb_buf *usbc_string_alloc(int len)
++{
++	struct usb_buf *buf;
++	int tot_len;
++
++	tot_len = sizeof(struct usb_descriptor_header) + sizeof(u16) * len;
++
++	buf = usbb_alloc(tot_len, GFP_KERNEL);
++
++	if (buf) {
++		struct usb_string_descriptor *desc = usbb_push(buf, tot_len);
++
++		desc->bLength = tot_len;
++		desc->bDescriptorType = USB_DT_STRING;
++	}
++	return buf;
++}
++
++void usbc_string_free(struct usb_buf *buf)
++{
++	if (buf)
++		usbb_put(buf);
++}
++
++void usbc_string_from_cstr(struct usb_buf *buf, const char *str)
++{
++	struct usb_string_descriptor *desc = usbc_string_desc(buf);
++	int i, len;
++
++	len = strlen(str);
++	BUG_ON((sizeof(__u16) * len) > desc->bLength - sizeof(struct usb_descriptor_header));
++
++	for (i = 0; i < len; i++)
++		desc->wData[i] = cpu_to_le16(str[i]);
++}
++
++int usbc_string_add(struct usbc_strs *table, struct usb_buf *buf)
++{
++	int nr, i;
++	
++	nr = -ENOSPC;
++	spin_lock_irq(&table->lock);
++	for (i = 0; i < NR_STRINGS; i++)
++		if (table->buf[i] == NULL) {
++			table->buf[i] = buf;
++			nr = i;
++			break;
++		}
++	spin_unlock_irq(&table->lock);
++
++	return nr;
++}
++
++void usbc_string_del(struct usbc_strs *table, int nr)
++{
++	if (nr < NR_STRINGS) {
++		spin_lock_irq(&table->lock);
++		table->buf[nr] = NULL;
++		spin_unlock_irq(&table->lock);
++	}
++}
++
++struct usb_buf *
++usbc_string_find(struct usbc_strs *table, unsigned int lang, unsigned int idx)
++{
++	struct usb_buf *buf = NULL;
++
++	if (idx < NR_STRINGS) {
++		spin_lock_irq(&table->lock);
++		buf = usbb_get(table->buf[idx]);
++		spin_unlock_irq(&table->lock);
++	}
++
++	return buf;
++}
++
++void usbc_string_free_all(struct usbc_strs *table)
++{
++	int i;
++
++	spin_lock_irq(&table->lock);
++	for (i = 0; i < NR_STRINGS; i++) {
++		usbc_string_free(table->buf[i]);
++		table->buf[i] = NULL;
++	}
++	spin_unlock_irq(&table->lock);
++}
++
++void usbc_string_init(struct usbc_strs *table)
++{
++	memset(table, 0, sizeof(struct usbc_strs));
++	spin_lock_init(&table->lock);
++}
++
++EXPORT_SYMBOL(usbc_string_from_cstr);
++EXPORT_SYMBOL(usbc_string_alloc);
++EXPORT_SYMBOL(usbc_string_free);
++EXPORT_SYMBOL(usbc_string_add);
++EXPORT_SYMBOL(usbc_string_del);
++EXPORT_SYMBOL(usbc_string_find);
++EXPORT_SYMBOL(usbc_string_free_all);
++EXPORT_SYMBOL(usbc_string_init);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usb_ctl.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,171 @@
++ /*
++ *	Copyright (C) Compaq Computer Corporation, 1998, 1999
++ *  Copyright (C) Extenex Corporation, 2001
++ *
++ *  usb_ctl.c
++ *
++ *  SA1100 USB controller core driver.
++ *
++ *  This file provides interrupt routing and overall coordination
++ *  of the three endpoints in usb_ep0, usb_receive (1),  and usb_send (2).
++ *
++ *  Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ *
++ */
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/usb.h>
++
++#include "buffer.h"
++#include "client.h"
++#include "usbdev.h"
++#include "sa1100_usb.h"
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals
++//////////////////////////////////////////////////////////////////////////////
++
++/* device descriptors */
++static struct cdb cdb;
++
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++int sa1100_usb_add_string(struct usbctl *ctl, const char *str)
++{
++	int nr = 0;
++
++	if (str) {
++		struct usb_buf *buf;
++		int len;
++
++		len = strlen(str);
++
++		nr = -ENOMEM;
++		buf = usbc_string_alloc(len);
++		if (buf) {
++			usbc_string_from_cstr(buf, str);
++			nr = usbc_string_add(&ctl->strings, buf);
++
++			if (nr < 0)
++				usbc_string_free(buf);
++		}
++	}
++
++	return nr;
++}
++
++EXPORT_SYMBOL(sa1100_usb_add_string);
++
++static int sa1100_usb_add_language(struct usbctl *ctl, unsigned int lang)
++{
++	struct usb_buf *buf;
++	int nr = -ENOMEM;
++
++	buf = usbc_string_alloc(1);
++	if (buf) {
++		usbc_string_desc(buf)->wData[0] = cpu_to_le16(lang); /* American English */
++		nr = usbc_string_add(&ctl->strings, buf);
++
++		if (nr < 0)
++			usbc_string_free(buf);
++	}
++
++	return nr;
++}
++
++/* setup default descriptors */
++
++void initialize_descriptors(struct usbctl *ctl)
++{
++	struct usb_client *clnt = ctl->clnt;
++	int r;
++
++	ctl->ep_desc[0] = (struct usb_endpoint_descriptor *)&cdb.ep1;
++	ctl->ep_desc[1] = (struct usb_endpoint_descriptor *)&cdb.ep2;
++
++	cdb.cfg.bLength             = USB_DT_CONFIG_SIZE;
++	cdb.cfg.bDescriptorType     = USB_DT_CONFIG;
++	cdb.cfg.wTotalLength        = cpu_to_le16(sizeof(struct cdb));
++	cdb.cfg.bNumInterfaces      = 1;
++	cdb.cfg.bConfigurationValue = 1;
++	cdb.cfg.iConfiguration      = 0;
++	cdb.cfg.bmAttributes        = USB_CONFIG_ATT_ONE;
++	cdb.cfg.bMaxPower           = USB_POWER( 500 );
++
++	cdb.intf.bLength            = USB_DT_INTERFACE_SIZE;
++	cdb.intf.bDescriptorType    = USB_DT_INTERFACE;
++	cdb.intf.bInterfaceNumber   = 0;     /* unique intf index*/
++	cdb.intf.bAlternateSetting  = 0;
++	cdb.intf.bNumEndpoints      = 2;
++	cdb.intf.bInterfaceClass    = 0xff;  /* vendor specific */
++	cdb.intf.bInterfaceSubClass = 0;
++	cdb.intf.bInterfaceProtocol = 0;
++	cdb.intf.iInterface         = 0;
++
++	cdb.ep1.bLength             = USB_DT_INTERFACE_SIZE;
++	cdb.ep1.bDescriptorType     = USB_DT_ENDPOINT;
++	cdb.ep1.bEndpointAddress    = USB_DIR_OUT | 1;
++	cdb.ep1.bmAttributes        = USB_ENDPOINT_XFER_BULK;
++	cdb.ep1.wMaxPacketSize      = cpu_to_le16(64);
++	cdb.ep1.bInterval           = 0;
++
++	cdb.ep2.bLength             = USB_DT_INTERFACE_SIZE;
++	cdb.ep2.bDescriptorType     = USB_DT_ENDPOINT;
++	cdb.ep2.bEndpointAddress    = USB_DIR_IN | 2;
++	cdb.ep2.bmAttributes        = USB_ENDPOINT_XFER_BULK;
++	cdb.ep2.wMaxPacketSize      = cpu_to_le16(64);
++	cdb.ep2.bInterval           = 0;
++
++	ctl->dev_desc->bLength            = USB_DT_DEVICE_SIZE;
++	ctl->dev_desc->bDescriptorType    = USB_DT_DEVICE;
++	ctl->dev_desc->bcdUSB             = cpu_to_le16(0x100); /* 1.0 */
++	ctl->dev_desc->bDeviceClass       = clnt->class;
++	ctl->dev_desc->bDeviceSubClass    = clnt->subclass;
++	ctl->dev_desc->bDeviceProtocol    = clnt->protocol;
++	ctl->dev_desc->bMaxPacketSize0    = 8;	/* ep0 max fifo size */
++	ctl->dev_desc->idVendor           = cpu_to_le16(clnt->vendor);
++	ctl->dev_desc->idProduct          = cpu_to_le16(clnt->product);
++	ctl->dev_desc->bcdDevice          = cpu_to_le16(clnt->version);
++	ctl->dev_desc->bNumConfigurations = 1;
++
++	/* set language */
++	/* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */
++	r = sa1100_usb_add_language(ctl, 0x409);
++	if (r < 0)
++		printk(KERN_ERR "usbc: couldn't add language\n");
++
++	r = sa1100_usb_add_string(ctl, clnt->manufacturer_str);
++	if (r < 0)
++		printk(KERN_ERR "usbc: couldn't add manufacturer string\n");
++
++	ctl->dev_desc->iManufacturer = r > 0 ? r : 0;
++
++	r = sa1100_usb_add_string(ctl, clnt->product_str);
++	if (r < 0)
++		printk(KERN_ERR "usbc: couldn't add product string\n");
++
++	ctl->dev_desc->iProduct      = r > 0 ? r : 0;
++
++	r = sa1100_usb_add_string(ctl, clnt->serial_str);
++	if (r < 0)
++		printk(KERN_ERR "usbc: couldn't add serial string\n");
++
++	ctl->dev_desc->iSerialNumber = r > 0 ? r : 0;
++}
++
++
++/*====================================================
++ * Descriptor Manipulation.
++ * Use these between open() and start() above to setup
++ * the descriptors for your device.
++ */
++
++/* get pointer to static default descriptor */
++struct cdb *sa1100_usb_get_descriptor_ptr(void)
++{
++	return &cdb;
++}
++
++EXPORT_SYMBOL(sa1100_usb_get_descriptor_ptr);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,12 @@
++#
++# Makefile for the USB client
++#
++
++usbdevcore-objs	:= buffer.o control.o strings.o usb_ctl.o
++
++sa1100-objs := sa1100usb.o usb_recv.o usb_send.o
++
++obj-$(CONFIG_SA1100_USB)	 += usbdevcore.o sa1100.o
++obj-$(CONFIG_SA1100_USB_NETLINK) += usb-eth.o
++obj-$(CONFIG_SA1100_USB_CHAR)	 += usb-char.o
++
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/usb/usbdev.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,91 @@
++#ifndef USBDEV_H
++#define USBDEV_H
++
++#include "strings.h"
++
++struct usb_buf;
++struct module;
++struct cdb;
++struct usb_client;
++
++struct usbc_driver {
++	struct module	*owner;
++	const char	*name;
++	void		*priv;
++	int		(*start)(void *);
++	int		(*stop)(void *);
++
++	int		(*ep0_queue)(void *, struct usb_buf *buf, unsigned int req_len);
++	void		(*set_address)(void *, unsigned int addr);
++	void		(*set_config)(void *, struct cdb *config);
++
++	/*
++	 * Get specified endpoint status, as defined in 9.4.5.
++	 */
++	unsigned int	(*ep_get_status)(void *, unsigned int ep);
++	void		(*ep_halt)(void *, unsigned int ep, int halt);
++
++	/*
++	 * Client
++	 */
++	int		(*ep_queue)(void *, unsigned int, char *, unsigned int);
++	void		(*ep_reset)(void *, unsigned int);
++	void		(*ep_callback)(void *, unsigned int, void (*)(void *, int, int), void *);
++	int		(*ep_idle)(void *, unsigned int);
++};
++
++struct usbc_endpoint {
++	struct usb_endpoint_descriptor	*desc;
++};
++
++struct usbc_interface {
++	struct usb_interface_descriptor	*desc;
++	unsigned int			nr_ep;
++	struct usbc_endpoint		*ep[0];
++};
++
++struct usbc_config {
++	struct usb_config_descriptor	*desc;
++	unsigned int			nr_interface;
++	struct usbc_interface		*interface[0];
++};
++
++struct usbctl {
++	struct usb_client		*clnt;
++	const struct usbc_driver	*driver;
++
++	/* Internal state */
++	unsigned int			address;	/* host assigned address */
++	unsigned int			state;		/* our device state */
++	unsigned int			sm_state;	/* state machine state */
++
++	struct usbc_config		*config;	/* active configuration */
++	struct usbc_strs		strings;
++
++	/* Descriptors */
++	struct usb_device_descriptor	*dev_desc;	/* device descriptor */
++	struct usb_buf			*dev_desc_buf;	/* device descriptor buffer */
++
++
++	int				nr_ep;
++	struct usb_endpoint_descriptor	*ep_desc[2];
++};
++
++/*
++ * Function Prototypes
++ */
++
++#define RET_ERROR	(-1)
++#define RET_NOACTION	(0)
++#define RET_QUEUED	(1)
++#define RET_ACK		(2)
++#define RET_REQERROR	(3)
++
++int usbctl_parse_request(struct usbctl *ctl, struct usb_ctrlrequest *req);
++
++int usbctl_reset(struct usbctl *ctl);
++void usbctl_suspend(struct usbctl *ctl);
++void usbctl_resume(struct usbctl *ctl);
++
++#endif
++
+--- linux-2.6.5/arch/arm/mach-sa1100/pm.c~heh	2004-04-03 22:36:27.000000000 -0500
++++ linux-2.6.5/arch/arm/mach-sa1100/pm.c	2004-04-30 20:57:36.000000000 -0400
+@@ -150,6 +150,7 @@
+  */
+ static int sa11x0_pm_prepare(u32 state)
+ {
++	nmi_watchdog_disable();
+ 	return 0;
+ }
+ 
+@@ -158,6 +159,7 @@
+  */
+ static int sa11x0_pm_finish(u32 state)
+ {
++	nmi_watchdog_enable();
+ 	return 0;
+ }
+ 
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/arch/arm/mach-sa1100/nmi-oopser.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,104 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/gfp.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++
++#include <asm/ptrace.h>
++#include <asm/domain.h>
++#include <asm/hardware.h>
++
++static void *nmi_stack;
++
++asm("						\n\
++nmi_start:					\n\
++	mrs	r8, spsr			\n\
++	ldr	r9, .Lstack			\n\
++	ldr	sp, [r9]			\n\
++	sub	sp, sp, #18 * 4			\n\
++	str	r8, [sp, #16 * 4]		\n\
++	str	lr, [sp, #15 * 4]		\n\
++	stmia	sp, {r0 - r7}			\n\
++	add	r0, sp, #8 * 4			\n\
++	mrs	r2, cpsr			\n\
++	bic	r1, r2, #0x1f			\n\
++	orr	r1, r1, #0x13			\n\
++	msr	cpsr_c, r1			\n\
++	mov	r0, r0				\n\
++	stmia	r0, {r8 - lr}			\n\
++	mov	r0, r0				\n\
++	msr	cpsr_c, r2			\n\
++	mov	r0, r0				\n\
++	mov	r0, sp				\n\
++	mov	lr, pc				\n\
++	ldr	pc, .Lfn			\n\
++	ldmia	sp, {r0 - r7}			\n\
++	ldr	r8, [sp, #16 * 4]		\n\
++	ldr	lr, [sp, #15 * 4]		\n\
++	add	sp, sp, #18 * 4			\n\
++	msr	spsr, r8			\n\
++	movs	pc, lr				\n\
++						\n\
++.Lstack: .long nmi_stack			\n\
++.Lfn:	.long	nmi_fn				\n\
++nmi_end:");
++
++extern unsigned char nmi_start, nmi_end;
++
++static void __attribute__((unused)) nmi_fn(struct pt_regs *regs)
++{
++	struct thread_info *thread;
++	unsigned long osmr0, osmr1, oscr, ossr, icmr, icip;
++
++	oscr = OSCR;
++	osmr0 = OSMR0;
++	osmr1 = OSMR1;
++	ossr = OSSR;
++	icmr = ICMR;
++	icip = ICIP;
++
++	OSSR = OSSR_M1;
++	ICMR &= ~IC_OST1;
++
++	thread = (struct thread_info *)(regs->ARM_sp & ~8191);
++
++	bust_spinlocks(1);
++	printk("OSMR0:%08lx OSMR1:%08lx OSCR:%08lx OSSR:%08lx ICMR:%08lx ICIP:%08lx\n",
++		osmr0, osmr1, oscr, ossr, icmr, icip);
++	nmi_watchdog(thread, regs);
++	bust_spinlocks(0);
++
++	OSSR = OSSR_M1;
++	OSMR1 = OSSR + 36864000;
++	ICMR |= IC_OST1;
++}
++
++static int nmi_init(void)
++{
++	unsigned char *vec_base = (unsigned char *)vectors_base();
++return 0;
++	nmi_stack = (void *)__get_free_page(GFP_KERNEL);
++	if (!nmi_stack)
++		return -ENOMEM;
++
++	nmi_stack += PAGE_SIZE;
++
++	modify_domain(DOMAIN_USER, DOMAIN_MANAGER);
++	memcpy(vec_base + 0x1c, &nmi_start, &nmi_end - &nmi_start);
++	modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
++
++	/*
++	 * Ensure timer 1 is set to FIQ, and enabled.
++	 */
++	OSMR1 = OSCR - 1;
++	OSSR = OSSR_M1;
++	OIER |= OIER_E1;
++	ICLR |= IC_OST1;
++	ICMR |= IC_OST1;
++
++	return 0;
++}
++
++__initcall(nmi_init);
+--- linux-2.6.5/drivers/media/Kconfig~heh	2004-04-03 22:36:51.000000000 -0500
++++ linux-2.6.5/drivers/media/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -32,6 +32,8 @@
+ 
+ source "drivers/media/common/Kconfig"
+ 
++source "drivers/media/mmc/Kconfig"
++
+ config VIDEO_TUNER
+ 	tristate
+ 	default y if VIDEO_BT848=y || VIDEO_SAA7134=y || VIDEO_MXB=y || VIDEO_CX88=y
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,52 @@
++#
++# MMC subsystem configuration
++#
++
++menu "MMC/SD Card support"
++
++config MMC
++	tristate "MMC support"
++	help
++	  MMC is the "multi-media card" bus protocol.
++
++	  If you want MMC support, you should say Y here and also
++	  to the specific driver for your MMC interface.
++
++config MMC_DEBUG
++	bool "MMC debugging"
++	depends on MMC != n
++	help
++	  This is an option for use by developers; most people should
++	  say N here.  This enables MMC core and driver debugging.
++
++config MMC_BLOCK
++	tristate "MMC block device driver"
++	depends on MMC
++	default y
++	help
++	  Say Y here to enable the MMC block device driver support.
++	  This provides a block device driver, which you can use to
++	  mount the filesystem. Almost everyone wishing MMC support
++	  should say Y or M here.
++
++config MMC_ARMMMCI
++	tristate "ARM AMBA Multimedia Card Interface support"
++	depends on ARM_AMBA && MMC
++	help
++	  This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card
++	  Interface (PL180 and PL181) support.  If you have an ARM(R)
++	  platform with a Multimedia Card slot, say Y or M here.
++
++	  If unsure, say N.
++
++config MMC_PXA
++	tristate "Intel PXA255 Multimedia Card Interface support"
++	depends on ARCH_PXA && MMC
++	help
++	  This selects the Intel(R) PXA(R) Multimedia card Interface.
++	  If you have a PXA(R) platform with a Multimedia Card slot,
++	  say Y or M here.
++
++	  If unsure, say N.
++
++endmenu
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmc_queue.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,171 @@
++/*
++ *  linux/drivers/media/mmc/mmc_queue.c
++ *
++ *  Copyright (C) 2003 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#include <linux/module.h>
++#include <linux/blkdev.h>
++
++#include <linux/mmc/card.h>
++#include <linux/mmc/host.h>
++#include "mmc_queue.h"
++
++/*
++ * Prepare a MMC request.  Essentially, this means passing the
++ * preparation off to the media driver.  The media driver will
++ * create a mmc_io_request in req->special.
++ */
++static int mmc_prep_request(struct request_queue *q, struct request *req)
++{
++	struct mmc_queue *mq = q->queuedata;
++	int ret = BLKPREP_KILL;
++
++	if (req->flags & REQ_SPECIAL) {
++		/*
++		 * Special commands already have the command
++		 * blocks already setup in req->special.
++		 */
++		BUG_ON(!req->special);
++
++		ret = BLKPREP_OK;
++	} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
++		/*
++		 * Block I/O requests need translating according
++		 * to the protocol.
++		 */
++		ret = mq->prep_fn(mq, req);
++	} else {
++		/*
++		 * Everything else is invalid.
++		 */
++		blk_dump_rq_flags(req, "MMC bad request");
++	}
++
++	if (ret == BLKPREP_OK)
++		req->flags |= REQ_DONTPREP;
++
++	return ret;
++}
++
++static int mmc_queue_thread(void *d)
++{
++	struct mmc_queue *mq = d;
++	struct request_queue *q = mq->queue;
++	DECLARE_WAITQUEUE(wait, current);
++	int ret;
++
++	/*
++	 * Set iothread to ensure that we aren't put to sleep by
++	 * the process freezing.  We handle suspension ourselves.
++	 */
++	current->flags |= PF_MEMALLOC|PF_IOTHREAD;
++
++	daemonize("mmcqd");
++
++	spin_lock_irq(&current->sighand->siglock);
++	sigfillset(&current->blocked);
++	recalc_sigpending();
++	spin_unlock_irq(&current->sighand->siglock);
++
++	mq->thread = current;
++	complete(&mq->thread_complete);
++
++	add_wait_queue(&mq->thread_wq, &wait);
++	spin_lock_irq(q->queue_lock);
++	do {
++		struct request *req = NULL;
++
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (!blk_queue_plugged(q))
++			mq->req = req = elv_next_request(q);
++		spin_unlock(q->queue_lock);
++
++		if (!req) {
++			if (!mq->thread)
++				break;
++			schedule();
++			continue;
++		}
++		set_current_state(TASK_RUNNING);
++
++		ret = mq->issue_fn(mq, req);
++
++		spin_lock_irq(q->queue_lock);
++		end_request(req, ret);
++	} while (1);
++	remove_wait_queue(&mq->thread_wq, &wait);
++
++	complete_and_exit(&mq->thread_complete, 0);
++	return 0;
++}
++
++/*
++ * Generic MMC request handler.  This is called for any queue on a
++ * particular host.  When the host is not busy, we look for a request
++ * on any queue on this host, and attempt to issue it.  This may
++ * not be the queue we were asked to process.
++ */
++static void mmc_request(request_queue_t *q)
++{
++	struct mmc_queue *mq = q->queuedata;
++
++	if (!mq->req && !blk_queue_plugged(q))
++		wake_up(&mq->thread_wq);
++}
++
++/**
++ * mmc_init_queue - initialise a queue structure.
++ * @mq: mmc queue
++ * @card: mmc card to attach this queue
++ * @lock: queue lock
++ *
++ * Initialise a MMC card request queue.
++ */
++int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock)
++{
++	u64 limit = BLK_BOUNCE_HIGH;
++	int ret;
++
++	if (card->host->dev->dma_mask)
++		limit = *card->host->dev->dma_mask;
++
++	mq->card = card;
++	mq->queue = blk_init_queue(mmc_request, lock);
++	blk_queue_prep_rq(mq->queue, mmc_prep_request);
++	blk_queue_bounce_limit(mq->queue, limit);
++
++	mq->queue->queuedata = mq;
++	mq->req = NULL;
++
++	init_completion(&mq->thread_complete);
++	init_waitqueue_head(&mq->thread_wq);
++
++	ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
++	if (ret < 0) {
++		blk_cleanup_queue(mq->queue);
++	} else {
++		wait_for_completion(&mq->thread_complete);
++		init_completion(&mq->thread_complete);
++	}
++
++	return ret;
++}
++
++EXPORT_SYMBOL(mmc_init_queue);
++
++void mmc_cleanup_queue(struct mmc_queue *mq)
++{
++	mq->thread = NULL;
++	wake_up(&mq->thread_wq);
++	wait_for_completion(&mq->thread_complete);
++	blk_cleanup_queue(mq->queue);
++
++	mq->card = NULL;
++}
++
++EXPORT_SYMBOL(mmc_cleanup_queue);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/pxamci.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,587 @@
++/*
++ *  linux/drivers/media/mmc/pxa.c - PXA MMCI driver
++ *
++ *  Copyright (C) 2003 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  This hardware is really sick.  No way to clear interrupts.  Have
++ *  to turn off the clock whenever we touch the device.  Yuck!
++ *
++ *	1 and 3 byte data transfers not supported
++ *	max block length up to 1023
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/blkdev.h>
++#include <linux/dma-mapping.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/protocol.h>
++
++#include <asm/dma.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/sizes.h>
++
++#include "pxamci.h"
++
++#ifdef CONFIG_MMC_DEBUG
++#define DBG(x...)	printk(KERN_DEBUG x)
++#else
++#define DBG(x...)	do { } while (0)
++#endif
++
++struct pxamci_host {
++	struct mmc_host		mmc;
++	spinlock_t		lock;
++	struct resource		*res;
++	void			*base;
++	int			irq;
++	int			dma;
++	unsigned int		clkrt;
++	unsigned int		cmdat;
++	unsigned int		imask;
++	unsigned int		power_mode;
++
++	struct mmc_request	*req;
++	struct mmc_command	*cmd;
++	struct mmc_data		*data;
++
++	dma_addr_t		sg_dma;
++	struct pxa_dma_desc	*sg_cpu;
++
++	dma_addr_t		dma_buf;
++	unsigned int		dma_size;
++	unsigned int		dma_dir;
++};
++
++#define to_pxamci_host(x)	container_of(x, struct pxamci_host, mmc)
++
++/*
++ * The base MMC clock rate
++ */
++#define CLOCKRATE	20000000
++
++static inline unsigned int ns_to_clocks(unsigned int ns)
++{
++	return (ns * (CLOCKRATE / 1000000) + 999) / 1000;
++}
++
++static void pxamci_stop_clock(struct pxamci_host *host)
++{
++	if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
++		unsigned long flags;
++		unsigned int v;
++
++		writel(STOP_CLOCK, host->base + MMC_STRPCL);
++
++		/*
++		 * Wait for the "clock has stopped" interrupt.
++		 * We need to unmask the interrupt to receive
++		 * the notification.  Sigh.
++		 */
++		spin_lock_irqsave(&host->lock, flags);
++		writel(host->imask & ~CLK_IS_OFF, host->base + MMC_I_MASK);
++		do {
++			v = readl(host->base + MMC_I_REG);
++		} while (!(v & CLK_IS_OFF));
++		writel(host->imask, host->base + MMC_I_MASK);
++		spin_unlock_irqrestore(&host->lock, flags);
++	}
++}
++
++static void pxamci_enable_irq(struct pxamci_host *host, unsigned int mask)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&host->lock, flags);
++	host->imask &= ~mask;
++	writel(host->imask, host->base + MMC_I_MASK);
++	spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&host->lock, flags);
++	host->imask |= mask;
++	writel(host->imask, host->base + MMC_I_MASK);
++	spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
++{
++	unsigned int nob = data->blocks;
++	unsigned int timeout, size;
++	dma_addr_t dma;
++	u32 dcmd;
++	int i;
++
++	host->data = data;
++
++	if (data->flags & MMC_DATA_STREAM)
++		nob = 0xffff;
++
++	writel(nob, host->base + MMC_NOB);
++	writel(1 << data->blksz_bits, host->base + MMC_BLKLEN);
++
++	timeout = ns_to_clocks(data->timeout_ns) + data->timeout_clks;
++	writel((timeout + 255) / 256, host->base + MMC_RDTO);
++
++	if (data->flags & MMC_DATA_READ) {
++		host->dma_dir = DMA_FROM_DEVICE;
++		dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
++		DRCMRTXMMC = 0;
++		DRCMRRXMMC = host->dma | DRCMR_MAPVLD;
++	} else {
++		host->dma_dir = DMA_TO_DEVICE;
++		dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
++		DRCMRRXMMC = 0;
++		DRCMRTXMMC = host->dma | DRCMR_MAPVLD;
++	}
++
++	dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
++
++	host->dma_size = data->blocks << data->blksz_bits;
++	host->dma_buf = dma_map_single(host->mmc.dev, data->rq->buffer,
++				       host->dma_size, host->dma_dir);
++
++	for (i = 0, size = host->dma_size, dma = host->dma_buf; size; i++) {
++		u32 len = size;
++
++		if (len > DCMD_LENGTH)
++			len = 0x1000;
++
++		if (data->flags & MMC_DATA_READ) {
++			host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
++			host->sg_cpu[i].dtadr = dma;
++		} else {
++			host->sg_cpu[i].dsadr = dma;
++			host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
++		}
++		host->sg_cpu[i].dcmd = dcmd | len;
++
++		dma += len;
++		size -= len;
++
++		if (size) {
++			host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
++						 sizeof(struct pxa_dma_desc);
++		} else {
++			host->sg_cpu[i].ddadr = DDADR_STOP;
++		}
++	}
++	wmb();
++
++	DDADR(host->dma) = host->sg_dma;
++	DCSR(host->dma) = DCSR_RUN;
++}
++
++static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd, unsigned int cmdat)
++{
++	WARN_ON(host->cmd != NULL);
++	host->cmd = cmd;
++
++	if (cmd->flags & MMC_RSP_BUSY)
++		cmdat |= CMDAT_BUSY;
++
++	switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) {
++	case MMC_RSP_SHORT | MMC_RSP_CRC:
++		cmdat |= CMDAT_RESP_SHORT;
++		break;
++	case MMC_RSP_SHORT:
++		cmdat |= CMDAT_RESP_R3;
++		break;
++	case MMC_RSP_LONG | MMC_RSP_CRC:
++		cmdat |= CMDAT_RESP_R2;
++		break;
++	default:
++		break;
++	}
++
++	writel(cmd->opcode, host->base + MMC_CMD);
++	writel(cmd->arg >> 16, host->base + MMC_ARGH);
++	writel(cmd->arg & 0xffff, host->base + MMC_ARGL);
++	writel(cmdat, host->base + MMC_CMDAT);
++	writel(host->clkrt, host->base + MMC_CLKRT);
++
++	writel(START_CLOCK, host->base + MMC_STRPCL);
++
++	pxamci_enable_irq(host, END_CMD_RES);
++}
++
++static void pxamci_finish_request(struct pxamci_host *host, struct mmc_request *req)
++{
++	DBG("PXAMCI: request done\n");
++	host->req = NULL;
++	host->cmd = NULL;
++	host->data = NULL;
++	mmc_request_done(&host->mmc, req);
++}
++
++static int pxamci_cmd_done(struct pxamci_host *host, unsigned int stat)
++{
++	struct mmc_command *cmd = host->cmd;
++	int i;
++	u32 v;
++
++	if (!cmd)
++		return 0;
++
++	host->cmd = NULL;
++
++	/*
++	 * Did I mention this is Sick.  We always need to
++	 * discard the upper 8 bits of the first 16-bit word.
++	 */
++	v = readl(host->base + MMC_RES) & 0xffff;
++	for (i = 0; i < 4; i++) {
++		u32 w1 = readl(host->base + MMC_RES) & 0xffff;
++		u32 w2 = readl(host->base + MMC_RES) & 0xffff;
++		cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8;
++		v = w2;
++	}
++
++	if (stat & STAT_TIME_OUT_RESPONSE) {
++		cmd->error = MMC_ERR_TIMEOUT;
++	} else if (stat & STAT_RES_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
++		cmd->error = MMC_ERR_BADCRC;
++	}
++
++	pxamci_disable_irq(host, END_CMD_RES);
++	if (host->data && cmd->error == MMC_ERR_NONE) {
++		pxamci_enable_irq(host, DATA_TRAN_DONE);
++	} else {
++		pxamci_finish_request(host, host->req);
++	}
++
++	return 1;
++}
++
++static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
++{
++	struct mmc_data *data = host->data;
++
++	if (!data)
++		return 0;
++
++	DCSR(host->dma) = 0;
++	dma_unmap_single(host->mmc.dev, host->dma_buf, host->dma_size,
++			 host->dma_dir);
++
++	if (stat & STAT_READ_TIME_OUT)
++		data->error = MMC_ERR_TIMEOUT;
++	else if (stat & (STAT_CRC_READ_ERROR|STAT_CRC_WRITE_ERROR))
++		data->error = MMC_ERR_BADCRC;
++
++	data->bytes_xfered = (data->blocks - readl(host->base + MMC_NOB))
++			       << data->blksz_bits;
++
++	pxamci_disable_irq(host, DATA_TRAN_DONE);
++
++	host->data = NULL;
++	if (host->req->stop && data->error == MMC_ERR_NONE) {
++		pxamci_stop_clock(host);
++		pxamci_start_cmd(host, host->req->stop, 0);
++	} else {
++		pxamci_finish_request(host, host->req);
++	}
++
++	return 1;
++}
++
++static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs)
++{
++	struct pxamci_host *host = devid;
++	unsigned int ireg;
++	int handled = 0;
++
++	ireg = readl(host->base + MMC_I_REG);
++
++	DBG("PXAMCI: irq %08x\n", ireg);
++
++	if (ireg) {
++		unsigned stat = readl(host->base + MMC_STAT);
++
++		DBG("PXAMCI: stat %08x\n", stat);
++
++		if (ireg & END_CMD_RES)
++			handled |= pxamci_cmd_done(host, stat);
++		if (ireg & DATA_TRAN_DONE)
++			handled |= pxamci_data_done(host, stat);
++	}
++
++	return IRQ_RETVAL(handled);
++}
++
++static void pxamci_request(struct mmc_host *mmc, struct mmc_request *req)
++{
++	struct pxamci_host *host = to_pxamci_host(mmc);
++	unsigned int cmdat;
++
++	WARN_ON(host->req != NULL);
++
++	host->req = req;
++
++	pxamci_stop_clock(host);
++
++	cmdat = host->cmdat;
++	host->cmdat &= ~CMDAT_INIT;
++
++	if (req->data) {
++		pxamci_setup_data(host, req->data);
++
++		cmdat &= ~CMDAT_BUSY;
++		cmdat |= CMDAT_DATAEN | CMDAT_DMAEN;
++		if (req->data->flags & MMC_DATA_WRITE)
++			cmdat |= CMDAT_WRITE;
++
++		if (req->data->flags & MMC_DATA_STREAM)
++			cmdat |= CMDAT_STREAM;
++	}
++
++	pxamci_start_cmd(host, req->cmd, cmdat);
++}
++
++static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++	struct pxamci_host *host = to_pxamci_host(mmc);
++
++	DBG("pxamci_set_ios: clock %u power %u vdd %u.%02u\n",
++	    ios->clock, ios->power_mode, ios->vdd / 100,
++	    ios->vdd % 100);
++
++	if (ios->clock) {
++		unsigned int clk = CLOCKRATE / ios->clock;
++		if (CLOCKRATE / clk > ios->clock)
++			clk <<= 1;
++		host->clkrt = fls(clk) - 1;
++
++		/*
++		 * we write clkrt on the next command
++		 */
++	} else if (readl(host->base + MMC_STAT) & STAT_CLK_EN) {
++		/*
++		 * Ensure that the clock is off.
++		 */
++		writel(STOP_CLOCK, host->base + MMC_STRPCL);
++	}
++
++	if (host->power_mode != ios->power_mode) {
++		host->power_mode = ios->power_mode;
++
++		/*
++		 * power control?  none on the lubbock.
++		 */
++
++		if (ios->power_mode == MMC_POWER_ON)
++			host->cmdat |= CMDAT_INIT;
++	}
++
++	DBG("pxamci_set_ios: clkrt = %x cmdat = %x\n",
++	    host->clkrt, host->cmdat);
++}
++
++static struct mmc_host_ops pxamci_ops = {
++	.request	= pxamci_request,
++	.set_ios	= pxamci_set_ios,
++};
++
++static struct resource *platform_device_resource(struct platform_device *dev, unsigned int mask, int nr)
++{
++	int i;
++
++	for (i = 0; i < dev->num_resources; i++)
++		if (dev->resource[i].flags == mask && nr-- == 0)
++			return &dev->resource[i];
++	return NULL;
++}
++
++static int platform_device_irq(struct platform_device *dev, int nr)
++{
++	int i;
++
++	for (i = 0; i < dev->num_resources; i++)
++		if (dev->resource[i].flags == IORESOURCE_IRQ && nr-- == 0)
++			return dev->resource[i].start;
++	return NO_IRQ;
++}
++
++static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs)
++{
++	printk(KERN_ERR "DMA%d: IRQ???\n", dma);
++	DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
++}
++
++static int pxamci_probe(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	struct pxamci_host *host;
++	struct resource *r;
++	int ret, irq;
++
++	r = platform_device_resource(pdev, IORESOURCE_MEM, 0);
++	irq = platform_device_irq(pdev, 0);
++	if (!r || irq == NO_IRQ)
++		return -ENXIO;
++
++	r = request_mem_region(r->start, SZ_4K, "PXAMCI");
++	if (!r)
++		return -EBUSY;
++
++	host = kmalloc(sizeof(struct pxamci_host), GFP_KERNEL);
++	if (!host) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	memset(host, 0, sizeof(struct pxamci_host));
++	host->dma = -1;
++
++	host->sg_cpu = dma_alloc_coherent(dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL);
++	if (!host->sg_cpu) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	ret = mmc_init_host(&host->mmc);
++	if (ret)
++		goto out;
++
++	spin_lock_init(&host->lock);
++	host->res = r;
++	host->irq = irq;
++	host->imask = TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
++		      END_CMD_RES|PRG_DONE|DATA_TRAN_DONE;
++	host->mmc.dev = dev;
++	host->mmc.ops = &pxamci_ops;
++	host->mmc.f_min	= 312500;
++	host->mmc.f_max	= 20000000;
++	host->mmc.ocr_avail = MMC_VDD_32_33;
++
++	host->base = ioremap(r->start, SZ_4K);
++	if (!host->base) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	/*
++	 * Ensure that the host controller is shut down, and setup
++	 * with our defaults.
++	 */
++	pxamci_stop_clock(host);
++	writel(0, host->base + MMC_SPI);
++	writel(64, host->base + MMC_RESTO);
++
++#ifdef CONFIG_PREEMPT
++#error Not Preempt-safe
++#endif
++	pxa_gpio_mode(GPIO6_MMCCLK_MD);
++	pxa_gpio_mode(GPIO8_MMCCS0_MD);
++	CKEN |= CKEN12_MMC;
++
++	host->dma = pxa_request_dma("PXAMCI", DMA_PRIO_LOW, pxamci_dma_irq, host);
++	if (host->dma < 0)
++		goto out;
++
++	ret = request_irq(host->irq, pxamci_irq, 0, "PXAMCI", host);
++	if (ret)
++		goto out;
++
++	dev_set_drvdata(dev, host);
++
++	mmc_add_host(&host->mmc);
++
++	return 0;
++
++ out:
++	if (host) {
++		if (host->dma >= 0)
++			pxa_free_dma(host->dma);
++		if (host->base)
++			iounmap(host->base);
++		if (host->sg_cpu)
++			dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
++		kfree(host);
++	}
++	release_resource(r);
++	return ret;
++}
++
++static int pxamci_remove(struct device *dev)
++{
++	struct pxamci_host *host = dev_get_drvdata(dev);
++
++	dev_set_drvdata(dev, NULL);
++
++	if (host) {
++		mmc_remove_host(&host->mmc);
++
++		pxamci_stop_clock(host);
++		writel(TXFIFO_WR_REQ|RXFIFO_RD_REQ|CLK_IS_OFF|STOP_CMD|
++		       END_CMD_RES|PRG_DONE|DATA_TRAN_DONE,
++		       host->base + MMC_I_MASK);
++
++		free_irq(host->irq, host);
++		pxa_free_dma(host->dma);
++		iounmap(host->base);
++		dma_free_coherent(dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
++
++		release_resource(host->res);
++
++		kfree(host);
++	}
++	return 0;
++}
++
++static int pxamci_suspend(struct device *dev, u32 state, u32 level)
++{
++	struct pxamci_host *host = dev_get_drvdata(dev);
++	int ret = 0;
++
++	if (host && level == SUSPEND_DISABLE)
++		ret = mmc_suspend_host(&host->mmc, state);
++	return ret;
++}
++
++static int pxamci_resume(struct device *dev, u32 level)
++{
++	struct pxamci_host *host = dev_get_drvdata(dev);
++	int ret = 0;
++
++	if (host && level == RESUME_ENABLE)
++		ret = mmc_resume_host(&host->mmc);
++	return ret;
++}
++
++static struct device_driver pxamci_driver = {
++	.name		= "pxamci",
++	.bus		= &platform_bus_type,
++	.probe		= pxamci_probe,
++	.remove		= pxamci_remove,
++	.suspend	= pxamci_suspend,
++	.resume		= pxamci_resume,
++};
++
++static int __init pxamci_init(void)
++{
++	return driver_register(&pxamci_driver);
++}
++
++static void __exit pxamci_exit(void)
++{
++	driver_unregister(&pxamci_driver);
++}
++
++module_init(pxamci_init);
++module_exit(pxamci_exit);
++
++MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmc.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,15 @@
++/*
++ *  linux/drivers/media/mmc/mmc.h
++ *
++ *  Copyright (C) 2003 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef _MMC_H
++/* core-internal functions */
++void mmc_init_card(struct mmc_card *card, struct mmc_host *host);
++int mmc_register_card(struct mmc_card *card);
++void mmc_remove_card(struct mmc_card *card);
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmc_sysfs.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,231 @@
++/*
++ *  linux/drivers/media/mmc/mmc_sysfs.c
++ *
++ *  Copyright (C) 2003 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  MMC sysfs/driver model support.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/device.h>
++
++#include <linux/mmc/card.h>
++#include <linux/mmc/host.h>
++
++#include "mmc.h"
++
++#define dev_to_mmc_card(d)	container_of(d, struct mmc_card, dev)
++#define to_mmc_driver(d)	container_of(d, struct mmc_driver, drv)
++
++static void mmc_release_card(struct device *dev)
++{
++	struct mmc_card *card = dev_to_mmc_card(dev);
++
++	kfree(card);
++}
++
++/*
++ * This currently matches any MMC driver to any MMC card - drivers
++ * themselves make the decision whether to drive this card in their
++ * probe method.
++ */
++static int mmc_bus_match(struct device *dev, struct device_driver *drv)
++{
++	return 1;
++}
++
++static int
++mmc_bus_hotplug(struct device *dev, char **envp, int num_envp, char *buf,
++		int buf_size)
++{
++	struct mmc_card *card = dev_to_mmc_card(dev);
++	char ccc[13];
++	int i = 0;
++
++#define add_env(fmt,val)						\
++	({								\
++		int len, ret = -ENOMEM;					\
++		if (i < num_envp) {					\
++			envp[i++] = buf;				\
++			len = snprintf(buf, buf_size, fmt, val) + 1;	\
++			buf_size -= len;				\
++			buf += len;					\
++			if (buf_size >= 0)				\
++				ret = 0;				\
++		}							\
++		ret;							\
++	})
++
++	for (i = 0; i < 12; i++)
++		ccc[i] = card->csd.cmdclass & (1 << i) ? '1' : '0';
++	ccc[12] = '\0';
++
++	i = 0;
++	add_env("MMC_CCC=%s", ccc);
++	add_env("MMC_MANFID=%03x", card->cid.manfid);
++	add_env("MMC_SLOT_NAME=%s", card->dev.bus_id);
++
++	return 0;
++}
++
++static int mmc_bus_suspend(struct device *dev, u32 state)
++{
++	struct mmc_driver *drv = to_mmc_driver(dev->driver);
++	struct mmc_card *card = dev_to_mmc_card(dev);
++	int ret = 0;
++
++	if (dev->driver && drv->suspend)
++		ret = drv->suspend(card, state);
++	return ret;
++}
++
++static int mmc_bus_resume(struct device *dev)
++{
++	struct mmc_driver *drv = to_mmc_driver(dev->driver);
++	struct mmc_card *card = dev_to_mmc_card(dev);
++	int ret = 0;
++
++	if (dev->driver && drv->resume)
++		ret = drv->resume(card);
++	return ret;
++}
++
++static struct bus_type mmc_bus_type = {
++	.name		= "mmc",
++	.match		= mmc_bus_match,
++	.hotplug	= mmc_bus_hotplug,
++	.suspend	= mmc_bus_suspend,
++	.resume		= mmc_bus_resume,
++};
++
++
++static int mmc_drv_probe(struct device *dev)
++{
++	struct mmc_driver *drv = to_mmc_driver(dev->driver);
++	struct mmc_card *card = dev_to_mmc_card(dev);
++
++	return drv->probe(card);
++}
++
++static int mmc_drv_remove(struct device *dev)
++{
++	struct mmc_driver *drv = to_mmc_driver(dev->driver);
++	struct mmc_card *card = dev_to_mmc_card(dev);
++
++	drv->remove(card);
++
++	return 0;
++}
++
++
++/**
++ *	mmc_register_driver - register a media driver
++ *	@drv: MMC media driver
++ */
++int mmc_register_driver(struct mmc_driver *drv)
++{
++	drv->drv.bus = &mmc_bus_type;
++	drv->drv.probe = mmc_drv_probe;
++	drv->drv.remove = mmc_drv_remove;
++	return driver_register(&drv->drv);
++}
++
++EXPORT_SYMBOL(mmc_register_driver);
++
++/**
++ *	mmc_unregister_driver - unregister a media driver
++ *	@drv: MMC media driver
++ */
++void mmc_unregister_driver(struct mmc_driver *drv)
++{
++	drv->drv.bus = &mmc_bus_type;
++	driver_unregister(&drv->drv);
++}
++
++EXPORT_SYMBOL(mmc_unregister_driver);
++
++
++#define MMC_ATTR(name, fmt, args...)					\
++static ssize_t mmc_dev_show_##name (struct device *dev, char *buf)	\
++{									\
++	struct mmc_card *card = dev_to_mmc_card(dev);			\
++	return sprintf(buf, fmt, args);					\
++}									\
++static DEVICE_ATTR(name, S_IRUGO, mmc_dev_show_##name, NULL)
++
++MMC_ATTR(date, "%02d/%04d\n", card->cid.month, 1997 + card->cid.year);
++MMC_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
++MMC_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
++MMC_ATTR(manfid, "0x%03x\n", card->cid.manfid);
++MMC_ATTR(serial, "0x%06x\n", card->cid.serial);
++MMC_ATTR(name, "%s\n", card->cid.prod_name);
++
++static struct device_attribute *mmc_dev_attributes[] = {
++	&dev_attr_date,
++	&dev_attr_fwrev,
++	&dev_attr_hwrev,
++	&dev_attr_manfid,
++	&dev_attr_serial,
++	&dev_attr_name,
++};
++
++/*
++ * Internal function.  Initialise a MMC card structure.
++ */
++void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
++{
++	memset(card, 0, sizeof(struct mmc_card));
++	card->host = host;
++	device_initialize(&card->dev);
++	card->dev.parent = card->host->dev;
++	card->dev.bus = &mmc_bus_type;
++	card->dev.release = mmc_release_card;
++}
++
++/*
++ * Internal function.  Register a new MMC card with the driver model.
++ */
++int mmc_register_card(struct mmc_card *card)
++{
++	int ret, i;
++
++	snprintf(card->dev.bus_id, sizeof(card->dev.bus_id),
++		 "mmc%02x:%04x", card->host->host_num, card->rca);
++
++	ret = device_add(&card->dev);
++	if (ret == 0)
++		for (i = 0; i < ARRAY_SIZE(mmc_dev_attributes); i++)
++			device_create_file(&card->dev, mmc_dev_attributes[i]);
++
++	return ret;
++}
++
++/*
++ * Internal function.  Unregister a new MMC card with the
++ * driver model, and (eventually) free it.
++ */
++void mmc_remove_card(struct mmc_card *card)
++{
++	if (mmc_card_present(card))
++		device_del(&card->dev);
++
++	put_device(&card->dev);
++}
++
++
++static int __init mmc_init(void)
++{
++	return bus_register(&mmc_bus_type);
++}
++
++static void __exit mmc_exit(void)
++{
++	bus_unregister(&mmc_bus_type);
++}
++
++module_init(mmc_init);
++module_exit(mmc_exit);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmci.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,445 @@
++/*
++ *  linux/drivers/media/mmc/mmci.c - ARM PrimeCell MMCI PL180/1 driver
++ *
++ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/blkdev.h>
++#include <linux/delay.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/protocol.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/hardware/amba.h>
++
++#include "mmci.h"
++
++#define DRIVER_NAME "mmci-pl18x"
++
++#ifdef CONFIG_MMC_DEBUG
++#define DBG(x...)	printk(KERN_DEBUG x)
++#else
++#define DBG(x...)	do { } while (0)
++#endif
++
++static int fmax = 515633;
++
++static void
++mmci_request_end(struct mmci_host *host, struct mmc_request *req)
++{
++	writel(0, host->base + MMCICOMMAND);
++	host->req = NULL;
++	host->cmd = NULL;
++	host->data = NULL;
++
++	if (req->data)
++		req->data->bytes_xfered = host->data_xfered;
++
++	mmc_request_done(&host->mmc, req);
++}
++
++static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
++{
++	unsigned int datactrl;
++
++	DBG("MMCI: data: blksz %04x blks %04x flags %08x\n",
++	    1 << data->blksz_bits, data->blocks, data->flags);
++
++	datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
++
++	if (data->flags & MMC_DATA_READ)
++		datactrl |= MCI_DPSM_DIRECTION;
++
++	host->data = data;
++	host->buffer = data->rq->buffer;
++	host->size = data->blocks << data->blksz_bits;
++	host->data_xfered = 0;
++
++	writel(0x800000, host->base + MMCIDATATIMER);
++	writel(host->size, host->base + MMCIDATALENGTH);
++	writel(datactrl, host->base + MMCIDATACTRL);
++}
++
++static void
++mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
++{
++	DBG("MMCI: cmd: op %02x arg %08x flags %08x\n",
++	    cmd->opcode, cmd->arg, cmd->flags);
++
++	if (readl(host->base + MMCICOMMAND) & MCI_CPSM_ENABLE) {
++		writel(0, host->base + MMCICOMMAND);
++		udelay(1);
++	}
++
++	c |= cmd->opcode | MCI_CPSM_ENABLE;
++	switch (cmd->flags & MMC_RSP_MASK) {
++	case MMC_RSP_NONE:
++	default:
++		break;
++	case MMC_RSP_LONG:
++		c |= MCI_CPSM_LONGRSP;
++	case MMC_RSP_SHORT:
++		c |= MCI_CPSM_RESPONSE;
++		break;
++	}
++	if (/*interrupt*/0)
++		c |= MCI_CPSM_INTERRUPT;
++
++	host->cmd = cmd;
++
++	writel(cmd->arg, host->base + MMCIARGUMENT);
++	writel(c, host->base + MMCICOMMAND);
++}
++
++static void
++mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
++	      unsigned int status)
++{
++	if (status & MCI_DATABLOCKEND) {
++		host->data_xfered += 1 << data->blksz_bits;
++	}
++	if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
++		if (status & MCI_DATACRCFAIL)
++			data->error = MMC_ERR_BADCRC;
++		else if (status & MCI_DATATIMEOUT)
++			data->error = MMC_ERR_TIMEOUT;
++		else if (status & (MCI_TXUNDERRUN|MCI_RXOVERRUN))
++			data->error = MMC_ERR_FIFO;
++		status |= MCI_DATAEND;
++	}
++	if (status & MCI_DATAEND) {
++		host->data = NULL;
++		if (!data->stop) {
++			mmci_request_end(host, data->req);
++		} else /*if (readl(host->base + MMCIDATACNT) > 6)*/ {
++			mmci_start_command(host, data->stop, 0);
++		}
++	}
++}
++
++static void
++mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
++	     unsigned int status)
++{
++	host->cmd = NULL;
++
++	cmd->resp[0] = readl(host->base + MMCIRESPONSE0);
++	cmd->resp[1] = readl(host->base + MMCIRESPONSE1);
++	cmd->resp[2] = readl(host->base + MMCIRESPONSE2);
++	cmd->resp[3] = readl(host->base + MMCIRESPONSE3);
++
++	if (status & MCI_CMDTIMEOUT) {
++		cmd->error = MMC_ERR_TIMEOUT;
++	} else if (status & MCI_CMDCRCFAIL && cmd->flags & MMC_RSP_CRC) {
++		cmd->error = MMC_ERR_BADCRC;
++	}
++
++	if (!cmd->data || cmd->error != MMC_ERR_NONE) {
++		mmci_request_end(host, cmd->req);
++	} else if (!(cmd->data->flags & MMC_DATA_READ)) {
++		mmci_start_data(host, cmd->data);
++	}
++}
++
++static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct mmci_host *host = dev_id;
++	u32 status;
++	int ret = 0;
++
++	do {
++		struct mmc_command *cmd;
++		struct mmc_data *data;
++
++		status = readl(host->base + MMCISTATUS);
++		writel(status, host->base + MMCICLEAR);
++
++		if (!(status & MCI_IRQMASK))
++			break;
++
++		DBG("MMCI: irq %08x\n", status);
++
++		if (status & (MCI_RXDATAAVLBL|MCI_RXFIFOHALFFULL)) {
++			int count = host->size - (readl(host->base + MMCIFIFOCNT) << 2);
++			if (count < 0)
++				count = 0;
++			if (count && host->buffer) {
++				readsl(host->base + MMCIFIFO, host->buffer, count >> 2);
++				host->buffer += count;
++				host->size -= count;
++				if (host->size == 0)
++					host->buffer = NULL;
++			} else {
++				static int first = 1;
++				if (first) {
++					first = 0;
++					printk(KERN_ERR "MMCI: sinking excessive data\n");
++				}
++				readl(host->base + MMCIFIFO);
++			}
++		}
++		if (status & (MCI_TXFIFOEMPTY|MCI_TXFIFOHALFEMPTY)) {
++			int count = host->size;
++			if (count > MCI_FIFOHALFSIZE)
++				count = MCI_FIFOHALFSIZE;
++			if (count && host->buffer) {
++				writesl(host->base + MMCIFIFO, host->buffer, count >> 2);
++				host->buffer += count;
++				host->size -= count;
++				if (host->size == 0)
++					host->buffer = NULL;
++			} else {
++				static int first = 1;
++				if (first) {
++					first = 0;
++					printk(KERN_ERR "MMCI: ran out of source data\n");
++				}
++			}
++		}
++
++		data = host->data;
++		if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|
++			      MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND))
++			mmci_data_irq(host, data, status);
++
++		cmd = host->cmd;
++		if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
++			mmci_cmd_irq(host, cmd, status);
++
++		ret = 1;
++	} while (status);
++
++	return IRQ_RETVAL(ret);
++}
++
++static void mmci_request(struct mmc_host *mmc, struct mmc_request *req)
++{
++	struct mmci_host *host = to_mmci_host(mmc);
++
++	WARN_ON(host->req != NULL);
++
++	host->req = req;
++
++	if (req->data && req->data->flags & MMC_DATA_READ)
++		mmci_start_data(host, req->data);
++
++	mmci_start_command(host, req->cmd, 0);
++}
++
++static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++	struct mmci_host *host = to_mmci_host(mmc);
++	u32 clk = 0, pwr = 0;
++
++	DBG("MMCI: set_ios: clock %dHz busmode %d powermode %d Vdd %d.%02d\n",
++	    ios->clock, ios->bus_mode, ios->power_mode,
++	    ios->vdd / 100, ios->vdd % 100);
++
++	if (ios->clock) {
++		clk = host->mclk / (2 * ios->clock) - 1;
++		if (clk > 256)
++			clk = 255;
++		clk |= MCI_CLK_ENABLE;
++	}
++
++	switch (ios->power_mode) {
++	case MMC_POWER_OFF:
++		break;
++	case MMC_POWER_UP:
++		pwr |= MCI_PWR_UP;
++		break;
++	case MMC_POWER_ON:
++		pwr |= MCI_PWR_ON;
++		break;
++	}
++
++	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
++		pwr |= MCI_ROD;
++
++	writel(clk, host->base + MMCICLOCK);
++
++	if (host->pwr != pwr) {
++		host->pwr = pwr;
++		writel(pwr, host->base + MMCIPOWER);
++	}
++}
++
++static struct mmc_host_ops mmci_ops = {
++	.request	= mmci_request,
++	.set_ios	= mmci_set_ios,
++};
++
++static int mmci_probe(struct amba_device *dev, void *id)
++{
++	struct mmci_host *host;
++	int ret;
++//	void *tmp;
++
++	/* enable the interrupt via the VIC */
++//	tmp = ioremap(0xc3000000, SZ_4K);
++//	if (tmp) {
++//		u32 val = readl(tmp + 0x10);
++//		writel(val | 0x180, tmp + 0x10);
++//		iounmap(tmp);
++//	}
++
++	if (!request_mem_region(dev->res.start, SZ_4K, DRIVER_NAME))
++		return -EBUSY;
++
++	host = kmalloc(sizeof(struct mmci_host), GFP_KERNEL);
++	if (!host) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	memset(host, 0, sizeof(struct mmci_host));
++
++	ret = mmc_init_host(&host->mmc);
++	if (ret)
++		goto out;
++
++	host->base = ioremap(dev->res.start, SZ_4K);
++	if (!host->base) {
++		ret = -ENOMEM;
++		goto out;
++	}
++
++	host->irq = dev->irq;
++	host->mclk = 33000000;	/* impd1 */
++	host->mmc.dev = &dev->dev;
++	host->mmc.ops = &mmci_ops;
++	host->mmc.f_min = (host->mclk + 511) / 512;
++	host->mmc.f_max = host->mclk / 2;
++	if (host->mmc.f_max > fmax)
++		host->mmc.f_max = fmax;
++
++	host->mmc.ocr_avail = MMC_VDD_35_36;
++
++	writel(0, host->base + MMCIMASK0);
++	writel(0, host->base + MMCIMASK1);
++	writel(0xfff, host->base + MMCICLEAR);
++
++	ret = request_irq(host->irq, mmci_irq, SA_SHIRQ, DRIVER_NAME, host);
++	if (ret)
++		goto out;
++
++	writel(MCI_IRQENABLE, host->base + MMCIMASK0);
++
++	amba_set_drvdata(dev, host);
++
++	mmc_add_host(&host->mmc);
++
++	return 0;
++
++ out:
++	if (host) {
++		if (host->base)
++			iounmap(host->base);
++		kfree(host);
++	}
++	release_mem_region(dev->res.start, SZ_4K);
++	return ret;
++}
++
++static int mmci_remove(struct amba_device *dev)
++{
++	struct mmci_host *host = amba_get_drvdata(dev);
++
++	amba_set_drvdata(dev, NULL);
++
++	if (host) {
++		mmc_remove_host(&host->mmc);
++
++		writel(0, host->base + MMCIMASK0);
++		writel(0, host->base + MMCIMASK1);
++
++		writel(0, host->base + MMCICOMMAND);
++		writel(0, host->base + MMCIDATACTRL);
++
++		free_irq(host->irq, host);
++
++		iounmap(host->base);
++
++		kfree(host);
++
++		release_mem_region(dev->res.start, SZ_4K);
++	}
++
++	return 0;
++}
++
++#ifdef CONFIG_PM
++static int mmci_suspend(struct amba_device *dev, u32 state)
++{
++	struct mmci_host *host = amba_get_drvdata(dev);
++
++	return host ? mmc_suspend_host(&host->mmc, state) : 0;
++}
++
++static int mmci_resume(struct amba_device *dev)
++{
++	struct mmci_host *host = amba_get_drvdata(dev);
++	int ret = 0;
++
++	if (host) {
++		writel(MCI_IRQENABLE, host->base + MMCIMASK0);
++		ret = mmc_resume_host(&host->mmc);
++	}
++
++	return ret;
++}
++#else
++#define mmci_suspend	NULL
++#define mmci_resume	NULL
++#endif
++
++static struct amba_id mmci_ids[] = {
++	{
++		.id	= 0x00041180,
++		.mask	= 0x000fffff,
++	},
++	{
++		.id	= 0x00041181,
++		.mask	= 0x000fffff,
++	},
++	{ 0, 0 },
++};
++
++static struct amba_driver mmci_driver = {
++	.drv		= {
++		.name	= DRIVER_NAME,
++	},
++	.probe		= mmci_probe,
++	.remove		= mmci_remove,
++	.suspend	= mmci_suspend,
++	.resume		= mmci_resume,
++	.id_table	= mmci_ids,
++};
++
++static int __init mmci_init(void)
++{
++	return amba_driver_register(&mmci_driver);
++}
++
++static void __exit mmci_exit(void)
++{
++	amba_driver_unregister(&mmci_driver);
++}
++
++module_init(mmci_init);
++module_exit(mmci_exit);
++module_param(fmax, int, 0444);
++
++MODULE_DESCRIPTION("ARM PrimeCell PL180/181 Multimedia Card Interface driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmc_queue.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,29 @@
++#ifndef MMC_QUEUE_H
++#define MMC_QUEUE_H
++
++struct request;
++struct task_struct;
++
++struct mmc_queue {
++	struct mmc_card		*card;
++	struct completion	thread_complete;
++	wait_queue_head_t	thread_wq;
++	struct task_struct	*thread;
++	struct request		*req;
++	int			(*prep_fn)(struct mmc_queue *, struct request *);
++	int			(*issue_fn)(struct mmc_queue *, struct request *);
++	void			*data;
++	struct request_queue	*queue;
++};
++
++struct mmc_io_request {
++	struct request		*rq;
++	int			num;
++	struct mmc_command	selcmd;		/* mmc_queue private */
++	struct mmc_command	cmd[4];		/* max 4 commands */
++};
++
++extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *);
++extern void mmc_cleanup_queue(struct mmc_queue *);
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmc_block.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,482 @@
++/*
++ * Block driver for media (i.e., flash cards)
++ *
++ * Copyright 2002 Hewlett-Packard Company
++ *
++ * Use consistent with the GNU GPL is permitted,
++ * provided that this copyright notice is
++ * preserved in its entirety in all copies and derived works.
++ *
++ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
++ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
++ * FITNESS FOR ANY PARTICULAR PURPOSE.
++ *
++ * Many thanks to Alessandro Rubini and Jonathan Corbet!
++ *
++ * Author:  Andrew Christian
++ *          28 May 2002
++ */
++#include <linux/moduleparam.h>
++#include <linux/module.h>
++#include <linux/init.h>
++
++#include <linux/sched.h>
++#include <linux/kernel.h>	/* printk() */
++#include <linux/fs.h>		/* everything... */
++#include <linux/errno.h>	/* error codes */
++#include <linux/hdreg.h>	/* HDIO_GETGEO */
++#include <linux/kdev_t.h>
++#include <linux/blkdev.h>
++#include <linux/devfs_fs_kernel.h>
++
++#include <linux/mmc/card.h>
++#include <linux/mmc/protocol.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include "mmc_queue.h"
++
++#define MMC_SHIFT	3	/* max 8 partitions per card */
++
++static int mmc_major;
++static int maxsectors = 8;
++
++/*
++ * There is one mmc_blk_data per slot.
++ */
++struct mmc_blk_data {
++	spinlock_t	lock;
++	struct gendisk	*disk;
++	struct mmc_queue queue;
++
++	unsigned int	usage;
++	unsigned int	block_bits;
++	unsigned int	suspended;
++};
++
++static DECLARE_MUTEX(open_lock);
++
++static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
++{
++	struct mmc_blk_data *md;
++
++	down(&open_lock);
++	md = disk->private_data;
++	if (md && md->usage == 0)
++		md = NULL;
++	if (md)
++		md->usage++;
++	up(&open_lock);
++
++	return md;
++}
++
++static void mmc_blk_put(struct mmc_blk_data *md)
++{
++	down(&open_lock);
++	md->usage--;
++	if (md->usage == 0) {
++		put_disk(md->disk);
++		mmc_cleanup_queue(&md->queue);
++		kfree(md);
++	}
++	up(&open_lock);
++}
++
++static int mmc_blk_open(struct inode *inode, struct file *filp)
++{
++	struct mmc_blk_data *md;
++	int ret = -ENXIO;
++
++	md = mmc_blk_get(inode->i_bdev->bd_disk);
++	if (md) {
++		if (md->usage == 2)
++			check_disk_change(inode->i_bdev);
++		ret = 0;
++	}
++
++	return ret;
++}
++
++static int mmc_blk_release(struct inode *inode, struct file *filp)
++{
++	struct mmc_blk_data *md = inode->i_bdev->bd_disk->private_data;
++
++	mmc_blk_put(md);
++	return 0;
++}
++
++static int
++mmc_blk_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++	struct block_device *bdev = inode->i_bdev;
++
++	if (cmd == HDIO_GETGEO) {
++		struct hd_geometry geo;
++
++		memset(&geo, 0, sizeof(struct hd_geometry));
++
++		geo.cylinders	= get_capacity(bdev->bd_disk) / (4 * 16);
++		geo.heads	= 4;
++		geo.sectors	= 16;
++		geo.start	= get_start_sect(bdev);
++
++		return copy_to_user((void *)arg, &geo, sizeof(geo))
++			? -EFAULT : 0;
++	}
++
++	return -ENOTTY;
++}
++
++static struct block_device_operations mmc_bdops = {
++	.open			= mmc_blk_open,
++	.release		= mmc_blk_release,
++	.ioctl			= mmc_blk_ioctl,
++	.owner			= THIS_MODULE,
++};
++
++struct mmc_blk_request {
++	struct mmc_request	req;
++	struct mmc_command	cmd;
++	struct mmc_command	stop;
++	struct mmc_data		data;
++};
++
++static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
++{
++	struct mmc_blk_data *md = mq->data;
++
++	/*
++	 * If we have no device, we haven't finished initialising.
++	 */
++	if (!md || !mq->card) {
++		printk("killing request - no device/host\n");
++		goto kill;
++	}
++
++	if (md->suspended) {
++		blk_plug_device(md->queue.queue);
++		goto defer;
++	}
++
++	/*
++	 * Check for excessive requests.
++	 */
++	if (req->sector + req->nr_sectors > get_capacity(req->rq_disk)) {
++		printk("bad request size\n");
++		goto kill;
++	}
++
++	return BLKPREP_OK;
++
++ defer:
++	return BLKPREP_DEFER;
++ kill:
++	return BLKPREP_KILL;
++}
++
++static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
++{
++	struct mmc_blk_data *md = mq->data;
++	struct mmc_card *card = md->queue.card;
++	int err, sz = 0;
++
++	err = mmc_card_claim_host(card);
++	if (err)
++		goto cmd_err;
++
++	do {
++		struct mmc_blk_request rq;
++		struct mmc_command cmd;
++
++		memset(&rq, 0, sizeof(struct mmc_blk_request));
++		rq.req.cmd = &rq.cmd;
++		rq.req.data = &rq.data;
++
++		rq.cmd.arg = req->sector << 9;
++		rq.cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
++		rq.data.rq = req;
++		rq.data.timeout_ns = card->csd.tacc_ns * 10;
++		rq.data.timeout_clks = card->csd.tacc_clks * 10;
++		rq.data.blksz_bits = md->block_bits;
++		rq.data.blocks = req->current_nr_sectors >> (md->block_bits - 9);
++		rq.stop.opcode = MMC_STOP_TRANSMISSION;
++		rq.stop.arg = 0;
++		rq.stop.flags = MMC_RSP_SHORT | MMC_RSP_CRC | MMC_RSP_BUSY;
++
++		if (rq_data_dir(req) == READ) {
++			rq.cmd.opcode = rq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
++			rq.data.flags |= MMC_DATA_READ;
++		} else {
++			rq.cmd.opcode = MMC_WRITE_BLOCK;
++			rq.cmd.flags |= MMC_RSP_BUSY;
++			rq.data.flags |= MMC_DATA_WRITE;
++			rq.data.blocks = 1;
++		}
++		rq.req.stop = rq.data.blocks > 1 ? &rq.stop : NULL;
++
++		mmc_wait_for_req(card->host, &rq.req);
++		if (rq.cmd.error) {
++			err = rq.cmd.error;
++			printk("error %d sending read/write command\n", err);
++			goto cmd_err;
++		}
++
++		if (rq_data_dir(req) == READ) {
++			sz = rq.data.bytes_xfered;
++		} else {
++			sz = 0;
++		}
++
++		if (rq.data.error) {
++			err = rq.data.error;
++			printk("error %d transferring data\n", err);
++			goto cmd_err;
++		}
++
++		if (rq.stop.error) {
++			err = rq.stop.error;
++			printk("error %d sending stop command\n", err);
++			goto cmd_err;
++		}
++
++		do {
++			cmd.opcode = MMC_SEND_STATUS;
++			cmd.arg = card->rca << 16;
++			cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
++			err = mmc_wait_for_cmd(card->host, &cmd, 5);
++			if (err) {
++				printk("error %d requesting status\n", err);
++				goto cmd_err;
++			}
++		} while (!(cmd.resp[0] & R1_READY_FOR_DATA));
++
++#if 0
++		if (cmd.resp[0] & ~0x00000900)
++			printk("status = %08x\n", cmd.resp[0]);
++		err = mmc_decode_status(cmd.resp);
++		if (err)
++			goto cmd_err;
++#endif
++
++		sz = rq.data.bytes_xfered;
++	} while (end_that_request_chunk(req, 1, sz));
++
++	mmc_card_release_host(card);
++
++	return 1;
++
++ cmd_err:
++	mmc_card_release_host(card);
++
++	end_that_request_chunk(req, 1, sz);
++	req->errors = err;
++
++	return 0;
++}
++
++#define MMC_NUM_MINORS	(256 >> MMC_SHIFT)
++
++static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))];
++
++static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
++{
++	struct mmc_blk_data *md;
++	int devidx;
++
++	devidx = find_first_zero_bit(dev_use, MMC_NUM_MINORS);
++	if (devidx >= MMC_NUM_MINORS)
++		return NULL;
++	__set_bit(devidx, dev_use);
++
++	md = kmalloc(sizeof(struct mmc_blk_data), GFP_KERNEL);
++	if (md) {
++		memset(md, 0, sizeof(struct mmc_blk_data));
++
++		md->disk = alloc_disk(1 << MMC_SHIFT);
++		if (md->disk == NULL) {
++			kfree(md);
++			md = NULL;
++			goto out;
++		}
++
++		spin_lock_init(&md->lock);
++		md->usage = 1;
++
++		mmc_init_queue(&md->queue, card, &md->lock);
++		md->queue.prep_fn = mmc_blk_prep_rq;
++		md->queue.issue_fn = mmc_blk_issue_rq;
++		md->queue.data = md;
++
++		md->disk->major	= mmc_major;
++		md->disk->first_minor = devidx << MMC_SHIFT;
++		md->disk->fops = &mmc_bdops;
++		md->disk->private_data = md;
++		md->disk->queue = md->queue.queue;
++		md->disk->driverfs_dev = &card->dev;
++
++		sprintf(md->disk->disk_name, "mmcblk%d", devidx);
++		sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
++
++		md->block_bits = md->queue.card->csd.read_blkbits;
++
++		blk_queue_max_sectors(md->queue.queue, maxsectors);
++		blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
++		set_capacity(md->disk, md->queue.card->csd.capacity);
++	}
++ out:
++	return md;
++}
++
++static int
++mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
++{
++	struct mmc_command cmd;
++	int err;
++
++	mmc_card_claim_host(card);
++	cmd.opcode = MMC_SET_BLOCKLEN;
++	cmd.arg = 1 << card->csd.read_blkbits;
++	cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
++	err = mmc_wait_for_cmd(card->host, &cmd, 5);
++	mmc_card_release_host(card);
++
++	if (err) {
++		printk(KERN_ERR "%s: unable to set block size to %d: %d\n",
++			md->disk->disk_name, cmd.arg, err);
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static int mmc_blk_probe(struct mmc_card *card)
++{
++	struct mmc_blk_data *md;
++	int err;
++
++	if (card->csd.cmdclass & ~0x1ff)
++		return -ENODEV;
++
++	if (card->csd.read_blkbits < 9) {
++		printk(KERN_WARNING "%s: read blocksize too small (%u)\n",
++			mmc_card_id(card), 1 << card->csd.read_blkbits);
++		return -ENODEV;
++	}
++
++	md = mmc_blk_alloc(card);
++	if (md == NULL)
++		return -ENOMEM;
++
++	err = mmc_blk_set_blksize(md, card);
++	if (err)
++		goto out;
++
++	printk(KERN_INFO "%s: %s %s %dKiB\n",
++		md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
++		(card->csd.capacity << card->csd.read_blkbits) / 1024);
++
++	mmc_set_drvdata(card, md);
++	add_disk(md->disk);
++	return 0;
++
++ out:
++	mmc_blk_put(md);
++
++	return err;
++}
++
++static void mmc_blk_remove(struct mmc_card *card)
++{
++	struct mmc_blk_data *md = mmc_get_drvdata(card);
++
++	if (md) {
++		int devidx;
++
++		del_gendisk(md->disk);
++
++		/*
++		 * I think this is needed.
++		 */
++		md->disk->queue = NULL;
++
++		devidx = md->disk->first_minor >> MMC_SHIFT;
++		__clear_bit(devidx, dev_use);
++
++		mmc_blk_put(md);
++	}
++	mmc_set_drvdata(card, NULL);
++}
++
++#ifdef CONFIG_PM
++static int mmc_blk_suspend(struct mmc_card *card, u32 state)
++{
++	struct mmc_blk_data *md = mmc_get_drvdata(card);
++
++	if (md) {
++		blk_stop_queue(md->queue.queue);
++	}
++	return 0;
++}
++
++static int mmc_blk_resume(struct mmc_card *card)
++{
++	struct mmc_blk_data *md = mmc_get_drvdata(card);
++
++	if (md) {
++		mmc_blk_set_blksize(md, md->queue.card);
++		blk_start_queue(md->queue.queue);
++	}
++	return 0;
++}
++#else
++#define	mmc_blk_suspend	NULL
++#define mmc_blk_resume	NULL
++#endif
++
++static struct mmc_driver mmc_driver = {
++	.drv		= {
++		.name	= "mmcblk",
++	},
++	.probe		= mmc_blk_probe,
++	.remove		= mmc_blk_remove,
++	.suspend	= mmc_blk_suspend,
++	.resume		= mmc_blk_resume,
++};
++
++static int __init mmc_blk_init(void)
++{
++	int res = -ENOMEM;
++
++	res = register_blkdev(mmc_major, "mmc");
++	if (res < 0) {
++		printk(KERN_WARNING "Unable to get major %d for MMC media: %d\n",
++		       mmc_major, res);
++		goto out;
++	}
++	if (mmc_major == 0)
++		mmc_major = res;
++
++	devfs_mk_dir("mmc");
++	return mmc_register_driver(&mmc_driver);
++
++ out:
++	return res;
++}
++
++static void __exit mmc_blk_exit(void)
++{
++	mmc_unregister_driver(&mmc_driver);
++	devfs_remove("mmc");
++	unregister_blkdev(mmc_major, "mmc");
++}
++
++module_init(mmc_blk_init);
++module_exit(mmc_blk_exit);
++module_param(maxsectors, int, 0444);
++
++MODULE_PARM_DESC(maxsectors, "Maximum number of sectors for a single request");
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Multimedia Card (MMC) block device driver");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/pxamci.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,94 @@
++#undef MMC_STRPCL
++#undef MMC_STAT
++#undef MMC_CLKRT
++#undef MMC_SPI
++#undef MMC_CMDAT
++#undef MMC_RESTO
++#undef MMC_RDTO
++#undef MMC_BLKLEN
++#undef MMC_NOB
++#undef MMC_PRTBUF
++#undef MMC_I_MASK
++#undef END_CMD_RES
++#undef PRG_DONE
++#undef DATA_TRAN_DONE
++#undef MMC_I_REG
++#undef MMC_CMD
++#undef MMC_ARGH
++#undef MMC_ARGL
++#undef MMC_RES
++#undef MMC_RXFIFO
++#undef MMC_TXFIFO
++
++#define MMC_STRPCL	0x0000
++#define STOP_CLOCK		(1 << 0)
++#define START_CLOCK		(2 << 0)
++
++#define MMC_STAT	0x0004
++#define STAT_END_CMD_RES		(1 << 13)
++#define STAT_PRG_DONE			(1 << 12)
++#define STAT_DATA_TRAN_DONE		(1 << 11)
++#define STAT_CLK_EN			(1 << 8)
++#define STAT_RECV_FIFO_FULL		(1 << 7)
++#define STAT_XMIT_FIFO_EMPTY		(1 << 6)
++#define STAT_RES_CRC_ERR		(1 << 5)
++#define STAT_SPI_READ_ERROR_TOKEN	(1 << 4)
++#define STAT_CRC_READ_ERROR		(1 << 3)
++#define STAT_CRC_WRITE_ERROR		(1 << 2)
++#define STAT_TIME_OUT_RESPONSE		(1 << 1)
++#define STAT_READ_TIME_OUT		(1 << 0)
++
++#define MMC_CLKRT	0x0008		/* 3 bit */
++
++#define MMC_SPI		0x000c
++#define SPI_CS_ADDRESS		(1 << 3)
++#define SPI_CS_EN		(1 << 2)
++#define CRC_ON			(1 << 1)
++#define SPI_EN			(1 << 0)
++
++#define MMC_CMDAT	0x0010
++#define CMDAT_DMAEN		(1 << 7)
++#define CMDAT_INIT		(1 << 6)
++#define CMDAT_BUSY		(1 << 5)
++#define CMDAT_STREAM		(1 << 4)	/* 1 = stream */
++#define CMDAT_WRITE		(1 << 3)	/* 1 = write */
++#define CMDAT_DATAEN		(1 << 2)
++#define CMDAT_RESP_NONE		(0 << 0)
++#define CMDAT_RESP_SHORT	(1 << 0)
++#define CMDAT_RESP_R2		(2 << 0)
++#define CMDAT_RESP_R3		(3 << 0)
++
++#define MMC_RESTO	0x0014	/* 7 bit */
++
++#define MMC_RDTO	0x0018	/* 16 bit */
++
++#define MMC_BLKLEN	0x001c	/* 10 bit */
++
++#define MMC_NOB		0x0020	/* 16 bit */
++
++#define MMC_PRTBUF	0x0024
++#define BUF_PART_FULL		(1 << 0)
++
++#define MMC_I_MASK	0x0028
++#define TXFIFO_WR_REQ		(1 << 6)
++#define RXFIFO_RD_REQ		(1 << 5)
++#define CLK_IS_OFF		(1 << 4)
++#define STOP_CMD		(1 << 3)
++#define END_CMD_RES		(1 << 2)
++#define PRG_DONE		(1 << 1)
++#define DATA_TRAN_DONE		(1 << 0)
++
++#define MMC_I_REG	0x002c
++/* same as MMC_I_MASK */
++
++#define MMC_CMD		0x0030
++
++#define MMC_ARGH	0x0034	/* 16 bit */
++
++#define MMC_ARGL	0x0038	/* 16 bit */
++
++#define MMC_RES		0x003c	/* 16 bit */
++
++#define MMC_RXFIFO	0x0040	/* 8 bit */
++
++#define MMC_TXFIFO	0x0044	/* 8 bit */
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmci.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,147 @@
++/*
++ *  linux/drivers/media/mmc/mmci.h - ARM PrimeCell MMCI PL180/1 driver
++ *
++ *  Copyright (C) 2003 Deep Blue Solutions, Ltd, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#define MMCIPOWER		0x000
++#define MCI_PWR_OFF		0x00
++#define MCI_PWR_UP		0x02
++#define MCI_PWR_ON		0x03
++#define MCI_OD			(1 << 6)
++#define MCI_ROD			(1 << 7)
++
++#define MMCICLOCK		0x004
++#define MCI_CLK_ENABLE		(1 << 8)
++#define MCI_PWRSAVE		(1 << 9)
++#define MCI_BYPASS		(1 << 10)
++
++#define MMCIARGUMENT		0x008
++#define MMCICOMMAND		0x00c
++#define MCI_CPSM_RESPONSE	(1 << 6)
++#define MCI_CPSM_LONGRSP	(1 << 7)
++#define MCI_CPSM_INTERRUPT	(1 << 8)
++#define MCI_CPSM_PENDING	(1 << 9)
++#define MCI_CPSM_ENABLE		(1 << 10)
++
++#define MMCIRESPCMD		0x010
++#define MMCIRESPONSE0		0x014
++#define MMCIRESPONSE1		0x018
++#define MMCIRESPONSE2		0x01c
++#define MMCIRESPONSE3		0x020
++#define MMCIDATATIMER		0x024
++#define MMCIDATALENGTH		0x028
++#define MMCIDATACTRL		0x02c
++#define MCI_DPSM_ENABLE		(1 << 0)
++#define MCI_DPSM_DIRECTION	(1 << 1)
++#define MCI_DPSM_MODE		(1 << 2)
++#define MCI_DPSM_DMAENABLE	(1 << 3)
++
++#define MMCIDATACNT		0x030
++#define MMCISTATUS		0x034
++#define MCI_CMDCRCFAIL		(1 << 0)
++#define MCI_DATACRCFAIL		(1 << 1)
++#define MCI_CMDTIMEOUT		(1 << 2)
++#define MCI_DATATIMEOUT		(1 << 3)
++#define MCI_TXUNDERRUN		(1 << 4)
++#define MCI_RXOVERRUN		(1 << 5)
++#define MCI_CMDRESPEND		(1 << 6)
++#define MCI_CMDSENT		(1 << 7)
++#define MCI_DATAEND		(1 << 8)
++#define MCI_DATABLOCKEND	(1 << 10)
++#define MCI_CMDACTIVE		(1 << 11)
++#define MCI_TXACTIVE		(1 << 12)
++#define MCI_RXACTIVE		(1 << 13)
++#define MCI_TXFIFOHALFEMPTY	(1 << 14)
++#define MCI_RXFIFOHALFFULL	(1 << 15)
++#define MCI_TXFIFOFULL		(1 << 16)
++#define MCI_RXFIFOFULL		(1 << 17)
++#define MCI_TXFIFOEMPTY		(1 << 18)
++#define MCI_RXFIFOEMPTY		(1 << 19)
++#define MCI_TXDATAAVLBL		(1 << 20)
++#define MCI_RXDATAAVLBL		(1 << 21)
++
++#define MMCICLEAR		0x038
++#define MCI_CMDCRCFAILCLR	(1 << 0)
++#define MCI_DATACRCFAILCLR	(1 << 1)
++#define MCI_CMDTIMEOUTCLR	(1 << 2)
++#define MCI_DATATIMEOUTCLR	(1 << 3)
++#define MCI_TXUNDERRUNCLR	(1 << 4)
++#define MCI_RXOVERRUNCLR	(1 << 5)
++#define MCI_CMDRESPENDCLR	(1 << 6)
++#define MCI_CMDSENTCLR		(1 << 7)
++#define MCI_DATAENDCLR		(1 << 8)
++#define MCI_DATABLOCKENDCLR	(1 << 10)
++
++#define MMCIMASK0		0x03c
++#define MCI_CMDCRCFAILMASK	(1 << 0)
++#define MCI_DATACRCFAILMASK	(1 << 1)
++#define MCI_CMDTIMEOUTMASK	(1 << 2)
++#define MCI_DATATIMEOUTMASK	(1 << 3)
++#define MCI_TXUNDERRUNMASK	(1 << 4)
++#define MCI_RXOVERRUNMASK	(1 << 5)
++#define MCI_CMDRESPENDMASK	(1 << 6)
++#define MCI_CMDSENTMASK		(1 << 7)
++#define MCI_DATAENDMASK		(1 << 8)
++#define MCI_DATABLOCKENDMASK	(1 << 10)
++#define MCI_CMDACTIVEMASK	(1 << 11)
++#define MCI_TXACTIVEMASK	(1 << 12)
++#define MCI_RXACTIVEMASK	(1 << 13)
++#define MCI_TXFIFOHALFEMPTYMASK	(1 << 14)
++#define MCI_RXFIFOHALFFULLMASK	(1 << 15)
++#define MCI_TXFIFOFULLMASK	(1 << 16)
++#define MCI_RXFIFOFULLMASK	(1 << 17)
++#define MCI_TXFIFOEMPTYMASK	(1 << 18)
++#define MCI_RXFIFOEMPTYMASK	(1 << 19)
++#define MCI_TXDATAAVLBLMASK	(1 << 20)
++#define MCI_RXDATAAVLBLMASK	(1 << 21)
++
++#define MMCIMASK1		0x040
++#define MMCIFIFOCNT		0x048
++#define MMCIFIFO		0x080 /* to 0x0bc */
++
++#define MCI_IRQMASK	\
++	(MCI_CMDCRCFAIL|MCI_DATACRCFAIL|MCI_CMDTIMEOUT|MCI_DATATIMEOUT|	\
++	MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_CMDRESPEND|MCI_CMDSENT|	\
++	MCI_DATAEND|MCI_DATABLOCKEND|					\
++	MCI_TXFIFOHALFEMPTY|MCI_RXFIFOHALFFULL|				\
++	MCI_TXFIFOEMPTY|MCI_RXDATAAVLBL)
++
++#define MCI_IRQENABLE	\
++	(MCI_CMDCRCFAILMASK|MCI_DATACRCFAILMASK|MCI_CMDTIMEOUTMASK|	\
++	MCI_DATATIMEOUTMASK|MCI_TXUNDERRUNMASK|MCI_RXOVERRUNMASK|	\
++	MCI_CMDRESPENDMASK|MCI_CMDSENTMASK|MCI_DATAENDMASK|		\
++	MCI_DATABLOCKENDMASK|MCI_TXFIFOHALFEMPTYMASK|			\
++	MCI_RXFIFOHALFFULLMASK)
++
++#define MCI_FIFOSIZE	16
++	
++#define MCI_FIFOHALFSIZE (MCI_FIFOSIZE / 2)
++
++struct mmci_host {
++	struct mmc_host		mmc;
++	void			*base;
++	int			irq;
++	unsigned int		mclk;
++	u32			pwr;
++
++	struct mmc_request	*req;
++	struct mmc_command	*cmd;
++	struct mmc_data		*data;
++
++	unsigned int		data_xfered;
++
++	/* pio stuff */
++	void			*buffer;
++	unsigned int		size;
++
++	/* dma stuff */
++//	struct scatterlist	*sg_list;
++//	int			sg_len;
++//	int			sg_dir;
++};
++
++#define to_mmci_host(mmc)	container_of(mmc, struct mmci_host, mmc)
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/mmc.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,801 @@
++/*
++ *  linux/drivers/media/mmc/mmc.c
++ *
++ *  Copyright (C) 2003 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/completion.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++
++#include <linux/mmc/card.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/protocol.h>
++
++#include "mmc.h"
++
++#ifdef CONFIG_MMC_DEBUG
++#define DBG(x...)	printk(KERN_DEBUG x)
++#else
++#define DBG(x...)	do { } while (0)
++#endif
++
++#define CMD_RETRIES	3
++
++/*
++ * OCR Bit positions to 10s of Vdd mV.
++ */
++static const unsigned short mmc_ocr_bit_to_vdd[] = {
++	150,	155,	160,	165,	170,	180,	190,	200,
++	210,	220,	230,	240,	250,	260,	270,	280,
++	290,	300,	310,	320,	330,	340,	350,	360
++};
++
++static const unsigned int tran_exp[] = {
++	10000,		100000,		1000000,	10000000,
++	0,		0,		0,		0
++};
++
++static const unsigned char tran_mant[] = {
++	0,	10,	12,	13,	15,	20,	25,	30,
++	35,	40,	45,	50,	55,	60,	70,	80,
++};
++
++static const unsigned int tacc_exp[] = {
++	1,	10,	100,	1000,	10000,	100000,	1000000, 10000000,
++};
++
++static const unsigned int tacc_mant[] = {
++	0,	10,	12,	13,	15,	20,	25,	30,
++	35,	40,	45,	50,	55,	60,	70,	80,
++};
++
++
++/**
++ *	mmc_request_done - finish processing an MMC command
++ *	@host: MMC host which completed command
++ *	@cmd: MMC command which completed
++ *	@err: MMC error code
++ *
++ *	MMC drivers should call this function when they have completed
++ *	their processing of a command.  This should be called before the
++ *	data part of the command has completed.
++ */
++void mmc_request_done(struct mmc_host *host, struct mmc_request *req)
++{
++	struct mmc_command *cmd = req->cmd;
++	int err = req->cmd->error;
++	DBG("MMC: req done (%02x): %d: %08x %08x %08x %08x\n", cmd->opcode,
++	    err, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
++
++	if (err && cmd->retries) {
++		cmd->retries--;
++		cmd->error = 0;
++		host->ops->request(host, req);
++	} else if (req->done) {
++		req->done(req);
++	}
++}
++
++EXPORT_SYMBOL(mmc_request_done);
++
++/**
++ *	mmc_start_request - start a command on a host
++ *	@host: MMC host to start command on
++ *	@cmd: MMC command to start
++ *
++ *	Queue a command on the specified host.  We expect the
++ *	caller to be holding the host lock with interrupts disabled.
++ */
++void
++mmc_start_request(struct mmc_host *host, struct mmc_request *req)
++{
++	DBG("MMC: starting cmd %02x arg %08x flags %08x\n",
++	    req->cmd->opcode, req->cmd->arg, req->cmd->flags);
++
++	req->cmd->error = 0;
++	req->cmd->req = req;
++	if (req->data) {
++		req->cmd->data = req->data;
++		req->data->error = 0;
++		req->data->req = req;
++		if (req->stop) {
++			req->data->stop = req->stop;
++			req->stop->error = 0;
++			req->stop->req = req;
++		}
++	}
++	host->ops->request(host, req);
++}
++
++EXPORT_SYMBOL(mmc_start_request);
++
++static void mmc_wait_done(struct mmc_request *req)
++{
++	complete(req->done_data);
++}
++
++int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *req)
++{
++	DECLARE_COMPLETION(complete);
++
++	req->done_data = &complete;
++	req->done = mmc_wait_done;
++
++	mmc_start_request(host, req);
++
++	wait_for_completion(&complete);
++
++	return 0;
++}
++
++EXPORT_SYMBOL(mmc_wait_for_req);
++
++/**
++ *	mmc_wait_for_cmd - start a command and wait for completion
++ *	@host: MMC host to start command
++ *	@cmd: MMC command to start
++ *	@retries: maximum number of retries
++ *
++ *	Start a new MMC command for a host, and wait for the command
++ *	to complete.  Return any error that occurred while the command
++ *	was executing.  Do not attempt to parse the response.
++ */
++int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
++{
++	struct mmc_request req;
++
++	BUG_ON(host->card_busy == NULL);
++
++	memset(&req, 0, sizeof(struct mmc_request));
++
++	memset(cmd->resp, 0, sizeof(cmd->resp));
++	cmd->retries = retries;
++
++	req.cmd = cmd;
++	cmd->data = NULL;
++
++	mmc_wait_for_req(host, &req);
++
++	return cmd->error;
++}
++
++EXPORT_SYMBOL(mmc_wait_for_cmd);
++
++
++
++/**
++ *	__mmc_claim_host - exclusively claim a host
++ *	@host: mmc host to claim
++ *	@card: mmc card to claim host for
++ *
++ *	Claim a host for a set of operations.  If a valid card
++ *	is passed and this wasn't the last card selected, select
++ *	the card before returning.
++ *
++ *	Note: you should use mmc_card_claim_host or mmc_claim_host.
++ */
++int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long flags;
++	int err = 0;
++
++	add_wait_queue(&host->wq, &wait);
++	spin_lock_irqsave(&host->lock, flags);
++	while (1) {
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		if (host->card_busy == NULL)
++			break;
++		spin_unlock_irqrestore(&host->lock, flags);
++		schedule();
++		spin_lock_irqsave(&host->lock, flags);
++	}
++	set_current_state(TASK_RUNNING);
++	host->card_busy = card;
++	spin_unlock_irqrestore(&host->lock, flags);
++	remove_wait_queue(&host->wq, &wait);
++
++	if (card != (void *)-1 && host->card_selected != card) {
++		struct mmc_command cmd;
++
++		host->card_selected = card;
++
++		cmd.opcode = MMC_SELECT_CARD;
++		cmd.arg = card->rca << 16;
++		cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
++
++		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
++	}
++
++	return err;
++}
++
++EXPORT_SYMBOL(__mmc_claim_host);
++
++/**
++ *	mmc_release_host - release a host
++ *	@host: mmc host to release
++ *
++ *	Release a MMC host, allowing others to claim the host
++ *	for their operations.
++ */
++void mmc_release_host(struct mmc_host *host)
++{
++	unsigned long flags;
++
++	BUG_ON(host->card_busy == NULL);
++
++	spin_lock_irqsave(&host->lock, flags);
++	host->card_busy = NULL;
++	spin_unlock_irqrestore(&host->lock, flags);
++
++	wake_up(&host->wq);
++}
++
++EXPORT_SYMBOL(mmc_release_host);
++
++static void mmc_deselect_cards(struct mmc_host *host)
++{
++	struct mmc_command cmd;
++
++	/*
++	 * Ensure that no card is selected.
++	 */
++	if (host->card_selected) {
++		host->card_selected = NULL;
++
++		cmd.opcode = MMC_SELECT_CARD;
++		cmd.arg = 0;
++		cmd.flags = MMC_RSP_NONE;
++
++		mmc_wait_for_cmd(host, &cmd, 0);
++	}
++}
++
++
++static inline void mmc_delay(unsigned int ms)
++{
++	if (ms < HZ / 1000) {
++		yield();
++		mdelay(ms);
++	} else {
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(ms * HZ / 1000);
++	}
++}
++
++static u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
++{
++	int bit;
++
++	/*
++	 * Mask off any voltages we don't support
++	 */
++	ocr &= host->ocr_avail;
++
++	/*
++	 * Select the lowest voltage
++	 */
++	bit = ffs(ocr);
++	if (bit) {
++		bit -= 1;
++
++		ocr = 1 << bit;
++
++		host->ios.vdd = mmc_ocr_bit_to_vdd[bit];
++		host->ops->set_ios(host, &host->ios);
++	} else {
++		ocr = 0;
++	}
++
++	return ocr;
++}
++
++static void mmc_decode_cid(struct mmc_cid *cid, u32 *resp)
++{
++	memset(cid, 0, sizeof(struct mmc_cid));
++
++	cid->manfid	  = resp[0] >> 8;
++	cid->prod_name[0] = resp[0];
++	cid->prod_name[1] = resp[1] >> 24;
++	cid->prod_name[2] = resp[1] >> 16;
++	cid->prod_name[3] = resp[1] >> 8;
++	cid->prod_name[4] = resp[1];
++	cid->prod_name[5] = resp[2] >> 24;
++	cid->prod_name[6] = resp[2] >> 16;
++	cid->prod_name[7] = '\0';
++	cid->hwrev	  = (resp[2] >> 12) & 15;
++	cid->fwrev	  = (resp[2] >> 8) & 15;
++	cid->serial	  = (resp[2] & 255) << 16 | (resp[3] >> 16);
++	cid->month	  = (resp[3] >> 12) & 15;
++	cid->year	  = (resp[3] >> 8) & 15;
++}
++
++static void mmc_decode_csd(struct mmc_csd *csd, u32 *resp)
++{
++	unsigned int e, m;
++
++	csd->mmc_prot	 = (resp[0] >> 26) & 15;
++	m = (resp[0] >> 19) & 15;
++	e = (resp[0] >> 16) & 7;
++	csd->tacc_ns	 = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
++	csd->tacc_clks	 = ((resp[0] >> 8) & 255) * 100;
++
++	m = (resp[0] >> 3) & 15;
++	e = resp[0] & 7;
++	csd->max_dtr	  = tran_exp[e] * tran_mant[m];
++	csd->cmdclass	  = (resp[1] >> 20) & 0xfff;
++
++	e = (resp[2] >> 15) & 7;
++	m = (resp[1] << 2 | resp[2] >> 30) & 0x3fff;
++	csd->capacity	  = (1 + m) << (e + 2);
++
++	csd->read_blkbits = (resp[1] >> 16) & 15;
++}
++
++/*
++ * Locate a MMC card on this MMC host given a CID.
++ */
++static struct mmc_card *
++mmc_find_card(struct mmc_host *host, struct mmc_cid *cid)
++{
++	struct mmc_card *card;
++
++	list_for_each_entry(card, &host->cards, node) {
++		if (memcmp(&card->cid, cid, sizeof(struct mmc_cid)) == 0)
++			return card;
++	}
++	return NULL;
++}
++
++/*
++ * Allocate a new MMC card, and assign a unique RCA.
++ */
++static struct mmc_card *
++mmc_alloc_card(struct mmc_host *host, struct mmc_cid *cid, unsigned int *frca)
++{
++	struct mmc_card *card, *c;
++	unsigned int rca = *frca;
++
++	card = kmalloc(sizeof(struct mmc_card), GFP_KERNEL);
++	if (!card)
++		return ERR_PTR(-ENOMEM);
++
++	mmc_init_card(card, host);
++	memcpy(&card->cid, cid, sizeof(struct mmc_cid));
++
++ again:
++	list_for_each_entry(c, &host->cards, node)
++		if (c->rca == rca) {
++			rca++;
++			goto again;
++		}
++
++	card->rca = rca;
++
++	*frca = rca;
++
++	return card;
++}
++
++/*
++ * Apply power to the MMC stack.
++ */
++static void mmc_power_up(struct mmc_host *host)
++{
++	struct mmc_command cmd;
++	int bit = fls(host->ocr_avail) - 1;
++
++	host->ios.vdd = mmc_ocr_bit_to_vdd[bit];
++	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
++	host->ios.power_mode = MMC_POWER_UP;
++	host->ops->set_ios(host, &host->ios);
++
++	mmc_delay(1);
++
++	host->ios.clock = host->f_min;
++	host->ios.power_mode = MMC_POWER_ON;
++	host->ops->set_ios(host, &host->ios);
++
++	mmc_delay(2);
++
++	cmd.opcode = MMC_GO_IDLE_STATE;
++	cmd.arg = 0;
++	cmd.flags = MMC_RSP_NONE;
++
++	mmc_wait_for_cmd(host, &cmd, 0);
++}
++
++static void mmc_power_off(struct mmc_host *host)
++{
++	host->ios.clock = 0;
++	host->ios.vdd = 0;
++	host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
++	host->ios.power_mode = MMC_POWER_OFF;
++	host->ops->set_ios(host, &host->ios);
++}
++
++static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
++{
++	struct mmc_command cmd;
++	int i, err = 0;
++
++	cmd.opcode = MMC_SEND_OP_COND;
++	cmd.arg = ocr;
++	cmd.flags = MMC_RSP_SHORT;
++
++	for (i = 100; i; i--) {
++		err = mmc_wait_for_cmd(host, &cmd, 0);
++		if (err != MMC_ERR_NONE)
++			break;
++
++		if (cmd.resp[0] & MMC_CARD_BUSY || ocr == 0)
++			break;
++
++		err = MMC_ERR_TIMEOUT;
++	}
++
++	if (rocr)
++		*rocr = cmd.resp[0];
++
++	return err;
++}
++
++/*
++ * Discover cards by requesting their CID.  If this command
++ * times out, it is not an error; there are no further cards
++ * to be discovered.  Add new cards to the list.
++ *
++ * Create a mmc_card entry for each discovered card, assigning
++ * it an RCA, and save the CID.
++ */
++static void mmc_discover_cards(struct mmc_host *host)
++{
++	struct mmc_card *card;
++	unsigned int first_rca = 1, err;
++
++	while (1) {
++		struct mmc_command cmd;
++		struct mmc_cid cid;
++
++		/*
++		 * Read CID
++		 */
++		cmd.opcode = MMC_ALL_SEND_CID;
++		cmd.arg = 0;
++		cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
++
++		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
++		if (err == MMC_ERR_TIMEOUT) {
++			err = MMC_ERR_NONE;
++			break;
++		}
++		if (err != MMC_ERR_NONE) {
++			printk(KERN_ERR "MMC: mmc%d error requesting CID: %d\n",
++				host->host_num, err);
++			break;
++		}
++
++		mmc_decode_cid(&cid, cmd.resp);
++
++		card = mmc_find_card(host, &cid);
++		if (!card) {
++			card = mmc_alloc_card(host, &cid, &first_rca);
++			if (IS_ERR(card)) {
++				err = PTR_ERR(card);
++				break;
++			}
++			list_add(&card->node, &host->cards);
++		}
++
++		card->state &= ~MMC_STATE_DEAD;
++
++		cmd.opcode = MMC_SET_RELATIVE_ADDR;
++		cmd.arg = card->rca << 16;
++		cmd.flags = MMC_RSP_SHORT | MMC_RSP_CRC;
++
++		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
++		if (err != MMC_ERR_NONE)
++			card->state |= MMC_STATE_DEAD;
++	}
++}
++
++static void mmc_read_csds(struct mmc_host *host)
++{
++	struct mmc_card *card;
++
++	list_for_each_entry(card, &host->cards, node) {
++		struct mmc_command cmd;
++		int err;
++
++		if (card->state & (MMC_STATE_DEAD|MMC_STATE_PRESENT))
++			continue;
++
++		cmd.opcode = MMC_SEND_CSD;
++		cmd.arg = card->rca << 16;
++		cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
++
++		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
++		if (err != MMC_ERR_NONE) {
++			card->state |= MMC_STATE_DEAD;
++			continue;
++		}
++
++		mmc_decode_csd(&card->csd, cmd.resp);
++	}
++}
++
++static unsigned int mmc_calculate_clock(struct mmc_host *host)
++{
++	struct mmc_card *card;
++	unsigned int max_dtr = host->f_max;
++
++	list_for_each_entry(card, &host->cards, node)
++		if (!mmc_card_dead(card) && max_dtr > card->csd.max_dtr)
++			max_dtr = card->csd.max_dtr;
++
++	DBG("MMC: selected %d.%03dMHz transfer rate\n",
++	    max_dtr / 1000000, (max_dtr / 1000) % 1000);
++
++	return max_dtr;
++}
++
++/*
++ * Check whether cards we already know about are still present.
++ * We do this by requesting status, and checking whether a card
++ * responds.
++ *
++ * A request for status does not cause a state change in data
++ * transfer mode.
++ */
++static void mmc_check_cards(struct mmc_host *host)
++{
++	struct list_head *l, *n;
++
++	mmc_deselect_cards(host);
++
++	list_for_each_safe(l, n, &host->cards) {
++		struct mmc_card *card = mmc_list_to_card(l);
++		struct mmc_command cmd;
++		int err;
++
++		cmd.opcode = MMC_SEND_STATUS;
++		cmd.arg = card->rca << 16;
++		cmd.flags = MMC_RSP_LONG | MMC_RSP_CRC;
++
++		err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
++		if (err == MMC_ERR_NONE)
++			continue;
++
++		/*
++		 * Ok, we believe this card has been removed.
++		 */
++		card->state |= MMC_STATE_DEAD;
++	}
++}
++
++static void mmc_setup(struct mmc_host *host)
++{
++	if (host->ios.power_mode != MMC_POWER_ON) {
++		int err;
++		u32 ocr;
++
++		mmc_power_up(host);
++
++		err = mmc_send_op_cond(host, 0, &ocr);
++		if (err != MMC_ERR_NONE)
++			return;
++
++		host->ocr = mmc_select_voltage(host, ocr);
++	} else {
++		host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
++		host->ios.clock = host->f_min;
++		host->ops->set_ios(host, &host->ios);
++
++		/*
++		 * We should remember the OCR mask from the existing
++		 * cards, and detect the new cards OCR mask, combine
++		 * the two and re-select the VDD.  However, if we do
++		 * change VDD, we should do an idle, and then do a
++		 * full re-initialisation.  We would need to notify
++		 * drivers so that they can re-setup the cards as
++		 * well, while keeping their queues at bay.
++		 *
++		 * For the moment, we take the easy way out - if the
++		 * new cards don't like our currently selected VDD,
++		 * they drop off the bus.
++		 */
++	}
++
++	if (host->ocr == 0)
++		return;
++
++	/*
++	 * Send the selected OCR multiple times... until the cards
++	 * all get the idea that they should be ready for CMD2.
++	 * (My SanDisk card seems to need this.)
++	 */
++	mmc_send_op_cond(host, host->ocr, NULL);
++
++	mmc_discover_cards(host);
++
++	/*
++	 * Ok, now switch to push-pull mode.
++	 */
++	host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
++	host->ops->set_ios(host, &host->ios);
++
++	mmc_read_csds(host);
++}
++
++
++/**
++ *	mmc_detect_change - process change of state on a MMC socket
++ *	@host: host which changed state.
++ *
++ *	All we know is that card(s) have been inserted or removed
++ *	from the socket(s).  We don't know which socket or cards.
++ */
++void mmc_detect_change(struct mmc_host *host)
++{
++	struct list_head *l, *n;
++
++	mmc_claim_host(host);
++
++	if (host->ios.power_mode == MMC_POWER_ON)
++		mmc_check_cards(host);
++
++	mmc_setup(host);
++
++	if (!list_empty(&host->cards)) {
++		/*
++		 * (Re-)calculate the fastest clock rate which the
++		 * attached cards and the host support.
++		 */
++		host->ios.clock = mmc_calculate_clock(host);
++		host->ops->set_ios(host, &host->ios);
++	}
++
++	mmc_release_host(host);
++
++	list_for_each_safe(l, n, &host->cards) {
++		struct mmc_card *card = mmc_list_to_card(l);
++
++		/*
++		 * If this is a new and good card, register it.
++		 */
++		if (!mmc_card_present(card) && !mmc_card_dead(card)) {
++			if (mmc_register_card(card))
++				card->state |= MMC_STATE_DEAD;
++			else
++				card->state |= MMC_STATE_PRESENT;
++		}
++
++		/*
++		 * If this card is dead, destroy it.
++		 */
++		if (mmc_card_dead(card)) {
++			list_del(&card->node);
++			mmc_remove_card(card);
++		}
++	}
++
++	/*
++	 * If we discover that there are no cards on the
++	 * bus, turn off the clock and power down.
++	 */
++	if (list_empty(&host->cards))
++		mmc_power_off(host);
++}
++
++EXPORT_SYMBOL(mmc_detect_change);
++
++
++/**
++ *	mmc_init_host - initialise the per-host structure.
++ *	@host: mmc host
++ *
++ *	Initialise the per-host structure.
++ */
++int mmc_init_host(struct mmc_host *host)
++{
++	static unsigned int host_num;
++
++	memset(host, 0, sizeof(struct mmc_host));
++
++	host->host_num = host_num++;
++
++	spin_lock_init(&host->lock);
++	init_waitqueue_head(&host->wq);
++	INIT_LIST_HEAD(&host->cards);
++
++	return 0;
++}
++
++EXPORT_SYMBOL(mmc_init_host);
++
++/**
++ *	mmc_add_host - initialise host hardware
++ *	@host: mmc host
++ */
++int mmc_add_host(struct mmc_host *host)
++{
++	mmc_power_off(host);
++	mmc_detect_change(host);
++
++	return 0;
++}
++
++EXPORT_SYMBOL(mmc_add_host);
++
++/**
++ *	mmc_remove_host - remove host hardware
++ *	@host: mmc host
++ *
++ *	Unregister and remove all cards associated with this host,
++ *	and power down the MMC bus.
++ */
++void mmc_remove_host(struct mmc_host *host)
++{
++	struct list_head *l, *n;
++
++	list_for_each_safe(l, n, &host->cards) {
++		struct mmc_card *card = mmc_list_to_card(l);
++
++		mmc_remove_card(card);
++	}
++
++	mmc_power_off(host);
++}
++
++EXPORT_SYMBOL(mmc_remove_host);
++
++#ifdef CONFIG_PM
++
++/**
++ *	mmc_suspend_host - suspend a host
++ *	@host: mmc host
++ *	@state: suspend mode (PM_SUSPEND_xxx)
++ */
++int mmc_suspend_host(struct mmc_host *host, u32 state)
++{
++	mmc_claim_host(host);
++	mmc_deselect_cards(host);
++	mmc_power_off(host);
++	mmc_release_host(host);
++
++	return 0;
++}
++
++/**
++ *	mmc_resume_host - resume a previously suspended host
++ *	@host: mmc host
++ */
++int mmc_resume_host(struct mmc_host *host)
++{
++	mmc_detect_change(host);
++
++	return 0;
++}
++
++
++#else /* CONFIG_PM is not set */
++
++int mmc_suspend_host(struct mmc_host *host, u32 state) { return 0; }
++int mmc_resume_host(struct mmc_host *host) { return 0; }
++
++#endif
++
++EXPORT_SYMBOL(mmc_suspend_host);
++EXPORT_SYMBOL(mmc_resume_host);
++
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/media/mmc/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,21 @@
++#
++# Makefile for the kernel mmc device drivers.
++#
++
++#
++# Core
++#
++obj-$(CONFIG_MMC)		+= mmc_core.o
++
++#
++# Media drivers
++#
++obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o
++
++#
++# Host drivers
++#
++obj-$(CONFIG_MMC_ARMMMCI)	+= mmci.o
++obj-$(CONFIG_MMC_PXA)		+= pxamci.o
++
++mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
+--- linux-2.6.5/drivers/media/Makefile~heh	2004-04-03 22:38:15.000000000 -0500
++++ linux-2.6.5/drivers/media/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -3,3 +3,6 @@
+ #
+ 
+ obj-y        := video/ radio/ dvb/ common/
++
++obj-$(CONFIG_MMC)	+= mmc/
++
+--- linux-2.6.5/drivers/serial/Kconfig~heh	2004-04-03 22:38:15.000000000 -0500
++++ linux-2.6.5/drivers/serial/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -315,6 +315,29 @@
+ 	  your boot loader (lilo or loadlin) about how to pass options to the
+ 	  kernel at boot time.)
+ 
++config SERIAL_PXA
++	bool "PXA serial port support"
++	depends on ARM && ARCH_PXA
++	select SERIAL_CORE
++	help
++	  If you have a machine based on an Intel XScale PXA2xx CPU you
++	  can enable its onboard serial ports by enabling this option.
++
++config SERIAL_PXA_CONSOLE
++	bool "Console on PXA serial port"
++	depends on SERIAL_PXA
++	select SERIAL_CORE_CONSOLE
++	help
++	  If you have enabled the serial port on the Intel XScale PXA
++	  CPU you can make it the console by answering Y to this option.
++
++	  Even if you say Y here, the currently visible virtual console
++	  (/dev/tty0) will still be used as the system console by default, but
++	  you can alter that using a kernel command line option such as
++	  "console=ttySA0". (Try "man bootparam" or see the documentation of
++	  your boot loader (lilo or loadlin) about how to pass options to the
++	  kernel at boot time.)
++
+ config SERIAL_SA1100
+ 	bool "SA1100 serial port support"
+ 	depends on ARM && ARCH_SA1100
+--- linux-2.6.5/drivers/serial/pxa.c~heh	2004-04-03 22:38:16.000000000 -0500
++++ linux-2.6.5/drivers/serial/pxa.c	2004-04-30 20:57:36.000000000 -0400
+@@ -294,7 +294,6 @@
+ 	unsigned char status;
+ 	unsigned int ret;
+ 
+-return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+ 	spin_lock_irqsave(&up->port.lock, flags);
+ 	status = serial_in(up, UART_MSR);
+ 	spin_unlock_irqrestore(&up->port.lock, flags);
+@@ -800,6 +799,21 @@
+ 		.ops		= &serial_pxa_pops,
+ 		.line		= 2,
+ 	},
++  }, {  /* HWUART */
++	.name	= "HWUART",
++	.cken	= CKEN4_HWUART,
++	.port = {
++		.type		= PORT_PXA,
++		.iotype		= SERIAL_IO_MEM,
++		.membase	= (void *)&HWUART,
++		.mapbase	= __PREG(HWUART),
++		.irq		= IRQ_HWUART,
++		.uartclk	= 921600 * 16,
++		.fifosize	= 64,
++		.flags		= ASYNC_SKIP_TEST,
++		.ops		= &serial_pxa_pops,
++		.line		= 3,
++	},
+   }
+ };
+ 
+--- linux-2.6.5/drivers/serial/sa1100.c~heh	2004-04-03 22:36:24.000000000 -0500
++++ linux-2.6.5/drivers/serial/sa1100.c	2004-04-30 20:57:36.000000000 -0400
+@@ -448,6 +448,15 @@
+ 	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+ 
+ 	/*
++	 * If we don't support modem control lines, don't allow
++	 * these to be set.
++	 */
++	if (0) {
++		termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR);
++		termios->c_cflag |= CLOCAL;
++	}
++
++	/*
+ 	 * We only support CS7 and CS8.
+ 	 */
+ 	while ((termios->c_cflag & CSIZE) != CS7 &&
+@@ -894,6 +903,7 @@
+ 			if (sa1100_ports[i].port.mapbase != res->start)
+ 				continue;
+ 
++			sa1100_ports[i].port.dev = _dev;
+ 			uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
+ 			dev_set_drvdata(_dev, &sa1100_ports[i]);
+ 			break;
+--- linux-2.6.5/drivers/mtd/mtd_blkdevs.c~heh	2004-04-03 22:36:14.000000000 -0500
++++ linux-2.6.5/drivers/mtd/mtd_blkdevs.c	2004-04-30 20:57:36.000000000 -0400
+@@ -81,7 +81,7 @@
+ 	struct request_queue *rq = tr->blkcore_priv->rq;
+ 
+ 	/* we might get involved when memory gets low, so use PF_MEMALLOC */
+-	current->flags |= PF_MEMALLOC;
++	current->flags |= PF_MEMALLOC|PF_IOTHREAD;
+ 
+ 	daemonize("%sd", tr->name);
+ 
+--- linux-2.6.5/drivers/mtd/devices/doc1000.c~heh	2004-04-03 22:37:36.000000000 -0500
++++ linux-2.6.5/drivers/mtd/devices/doc1000.c	2004-04-30 20:57:36.000000000 -0400
+@@ -1,6 +1,6 @@
+ /*======================================================================
+ 
+-  $Id$
++  $Id$
+ 
+ ======================================================================*/
+ 
+@@ -20,6 +20,7 @@
+ #include <linux/ioctl.h>
+ #include <asm/io.h>
+ #include <asm/system.h>
++#include <asm/segment.h>
+ #include <stdarg.h>
+ #include <linux/delay.h>
+ #include <linux/init.h>
+@@ -482,7 +483,7 @@
+ 			else
+ 				priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
+ 		}
+-		else if (erase->time + erase_timeout < jiffies)
++		else if (time_after(jiffies, erase->time + erase_timeout))
+ 		{
+ 			printk("Flash erase timed out. The world is broken.\n");
+ 
+--- linux-2.6.5/drivers/mtd/mtdconcat.c~heh	2004-04-03 22:37:37.000000000 -0500
++++ linux-2.6.5/drivers/mtd/mtdconcat.c	2004-04-30 20:57:36.000000000 -0400
+@@ -7,7 +7,7 @@
+  *
+  * This code is GPL
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/module.h>
+@@ -26,7 +26,7 @@
+  */
+ struct mtd_concat {
+ 	struct mtd_info mtd;
+-	int             num_subdev;
++	int num_subdev;
+ 	struct mtd_info **subdev;
+ };
+ 
+@@ -37,21 +37,20 @@
+ #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev)	\
+ 	((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
+ 
+-
+ /*
+  * Given a pointer to the MTD object in the mtd_concat structure,
+  * we can retrieve the pointer to that structure with this macro.
+  */
+ #define CONCAT(x)  ((struct mtd_concat *)(x))
+ 
+-	
+ /* 
+  * MTD methods which look up the relevant subdevice, translate the
+  * effective address and pass through to the subdevice.
+  */
+ 
+-static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, 
+-			size_t *retlen, u_char *buf)
++static int
++concat_read(struct mtd_info *mtd, loff_t from, size_t len,
++	    size_t * retlen, u_char * buf)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int err = -EINVAL;
+@@ -59,43 +58,43 @@
+ 
+ 	*retlen = 0;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size, retsize;
+ 
+-		if (from >= subdev->size)
+-		{   /* Not destined for this subdev */
+-			size  = 0;
++		if (from >= subdev->size) {
++			/* Not destined for this subdev */
++			size = 0;
+ 			from -= subdev->size;
++			continue;
+ 		}
++		if (from + len > subdev->size)
++			/* First part goes into this subdev */
++			size = subdev->size - from;
+ 		else
+-		{
+-			if (from + len > subdev->size)
+-				size = subdev->size - from; /* First part goes into this subdev */
+-			else
+-				size = len; /* Entire transaction goes into this subdev */
++			/* Entire transaction goes into this subdev */
++			size = len;
+ 
+-			err = subdev->read(subdev, from, size, &retsize, buf);
++		err = subdev->read(subdev, from, size, &retsize, buf);
+ 
+-			if(err)
+-				break;
++		if (err)
++			break;
+ 
+-			*retlen += retsize;
+-			len -= size;
+-			if(len == 0)
+-				break;
++		*retlen += retsize;
++		len -= size;
++		if (len == 0)
++			break;
+ 
+-			err = -EINVAL;
+-			buf += size;
+-			from = 0;
+-		}
++		err = -EINVAL;
++		buf += size;
++		from = 0;
+ 	}
+ 	return err;
+ }
+ 
+-static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
+-			size_t *retlen, const u_char *buf)
++static int
++concat_write(struct mtd_info *mtd, loff_t to, size_t len,
++	     size_t * retlen, const u_char * buf)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int err = -EINVAL;
+@@ -106,46 +105,44 @@
+ 
+ 	*retlen = 0;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size, retsize;
+ 
+-		if (to >= subdev->size)
+-		{
+-			size  = 0;
++		if (to >= subdev->size) {
++			size = 0;
+ 			to -= subdev->size;
++			continue;
+ 		}
++		if (to + len > subdev->size)
++			size = subdev->size - to;
+ 		else
+-		{
+-			if (to + len > subdev->size)
+-				size = subdev->size - to;
+-			else
+-				size = len;
++			size = len;
+ 
+-			if (!(subdev->flags & MTD_WRITEABLE))
+-				err = -EROFS;
+-			else
+-				err = subdev->write(subdev, to, size, &retsize, buf);
++		if (!(subdev->flags & MTD_WRITEABLE))
++			err = -EROFS;
++		else
++			err = subdev->write(subdev, to, size, &retsize, buf);
+ 
+-			if(err)
+-				break;
++		if (err)
++			break;
+ 
+-			*retlen += retsize;
+-			len -= size;
+-			if(len == 0)
+-				break;
++		*retlen += retsize;
++		len -= size;
++		if (len == 0)
++			break;
+ 
+-			err = -EINVAL;
+-			buf += size;
+-			to = 0;
+-		}
++		err = -EINVAL;
++		buf += size;
++		to = 0;
+ 	}
+ 	return err;
+ }
+ 
+-static int concat_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+-            size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
++static int
++concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
++		size_t * retlen, u_char * buf, u_char * eccbuf,
++		struct nand_oobinfo *oobsel)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int err = -EINVAL;
+@@ -153,53 +150,56 @@
+ 
+ 	*retlen = 0;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size, retsize;
+-        
+-		if (from >= subdev->size)
+-		{   /* Not destined for this subdev */
+-			size  = 0;
++
++		if (from >= subdev->size) {
++			/* Not destined for this subdev */
++			size = 0;
+ 			from -= subdev->size;
++			continue;
+ 		}
++
++		if (from + len > subdev->size)
++			/* First part goes into this subdev */
++			size = subdev->size - from;
+ 		else
+-		{
+-			if (from + len > subdev->size)
+-				size = subdev->size - from; /* First part goes into this subdev */
+-			else
+-				size = len; /* Entire transaction goes into this subdev */
+-            
+-            if (subdev->read_ecc)
+-    			err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel);
+-            else
+-                err = -EINVAL;
++			/* Entire transaction goes into this subdev */
++			size = len;
+ 
+-			if(err)
+-				break;
++		if (subdev->read_ecc)
++			err = subdev->read_ecc(subdev, from, size,
++					       &retsize, buf, eccbuf, oobsel);
++		else
++			err = -EINVAL;
+ 
+-			*retlen += retsize;
+-			len -= size;
+-			if(len == 0)
+-				break;
++		if (err)
++			break;
+ 
+-			err = -EINVAL;
+-			buf += size;
+-            if (eccbuf)
+-            {
+-                eccbuf += subdev->oobsize;
+-                /* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus',
+-                   we must account for these */
+-                eccbuf += 2 * (sizeof(int)); 
+-            }
+-			from = 0;
++		*retlen += retsize;
++		len -= size;
++		if (len == 0)
++			break;
++
++		err = -EINVAL;
++		buf += size;
++		if (eccbuf) {
++			eccbuf += subdev->oobsize;
++			/* in nand.c at least, eccbufs are
++			   tagged with 2 (int)eccstatus'; we
++			   must account for these */
++			eccbuf += 2 * (sizeof (int));
+ 		}
++		from = 0;
+ 	}
+ 	return err;
+ }
+ 
+-static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
+-            size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel)
++static int
++concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
++		 size_t * retlen, const u_char * buf, u_char * eccbuf,
++		 struct nand_oobinfo *oobsel)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int err = -EINVAL;
+@@ -210,50 +210,48 @@
+ 
+ 	*retlen = 0;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size, retsize;
+-        
+-		if (to >= subdev->size)
+-		{
+-			size  = 0;
++
++		if (to >= subdev->size) {
++			size = 0;
+ 			to -= subdev->size;
++			continue;
+ 		}
++		if (to + len > subdev->size)
++			size = subdev->size - to;
+ 		else
+-		{
+-			if (to + len > subdev->size)
+-				size = subdev->size - to;
+-			else
+-				size = len;
++			size = len;
+ 
+-			if (!(subdev->flags & MTD_WRITEABLE))
+-				err = -EROFS;
+-			else if (subdev->write_ecc)
+-				err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel);
+-            else
+-                err = -EINVAL;
++		if (!(subdev->flags & MTD_WRITEABLE))
++			err = -EROFS;
++		else if (subdev->write_ecc)
++			err = subdev->write_ecc(subdev, to, size,
++						&retsize, buf, eccbuf, oobsel);
++		else
++			err = -EINVAL;
+ 
+-			if(err)
+-				break;
++		if (err)
++			break;
+ 
+-			*retlen += retsize;
+-			len -= size;
+-			if(len == 0)
+-				break;
++		*retlen += retsize;
++		len -= size;
++		if (len == 0)
++			break;
+ 
+-			err = -EINVAL;
+-			buf += size;
+-            if (eccbuf)
+-                eccbuf += subdev->oobsize;
+-			to = 0;
+-		}
++		err = -EINVAL;
++		buf += size;
++		if (eccbuf)
++			eccbuf += subdev->oobsize;
++		to = 0;
+ 	}
+ 	return err;
+ }
+ 
+-static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len,
+-            size_t *retlen, u_char *buf)
++static int
++concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
++		size_t * retlen, u_char * buf)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int err = -EINVAL;
+@@ -261,46 +259,47 @@
+ 
+ 	*retlen = 0;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size, retsize;
+-        
+-		if (from >= subdev->size)
+-		{   /* Not destined for this subdev */
+-			size  = 0;
++
++		if (from >= subdev->size) {
++			/* Not destined for this subdev */
++			size = 0;
+ 			from -= subdev->size;
++			continue;
+ 		}
++		if (from + len > subdev->size)
++			/* First part goes into this subdev */
++			size = subdev->size - from;
+ 		else
+-		{
+-			if (from + len > subdev->size)
+-				size = subdev->size - from; /* First part goes into this subdev */
+-			else
+-				size = len; /* Entire transaction goes into this subdev */
+-            
+-            if (subdev->read_oob)
+-    			err = subdev->read_oob(subdev, from, size, &retsize, buf);
+-            else
+-                err = -EINVAL;
++			/* Entire transaction goes into this subdev */
++			size = len;
+ 
+-			if(err)
+-				break;
++		if (subdev->read_oob)
++			err = subdev->read_oob(subdev, from, size,
++					       &retsize, buf);
++		else
++			err = -EINVAL;
+ 
+-			*retlen += retsize;
+-			len -= size;
+-			if(len == 0)
+-				break;
++		if (err)
++			break;
+ 
+-			err = -EINVAL;
+-			buf += size;
+-			from = 0;
+-		}
++		*retlen += retsize;
++		len -= size;
++		if (len == 0)
++			break;
++
++		err = -EINVAL;
++		buf += size;
++		from = 0;
+ 	}
+ 	return err;
+ }
+ 
+-static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len, 
+-            size_t *retlen, const u_char *buf)
++static int
++concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len,
++		 size_t * retlen, const u_char * buf)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int err = -EINVAL;
+@@ -311,50 +310,46 @@
+ 
+ 	*retlen = 0;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size, retsize;
+-        
+-		if (to >= subdev->size)
+-		{
+-			size  = 0;
++
++		if (to >= subdev->size) {
++			size = 0;
+ 			to -= subdev->size;
++			continue;
+ 		}
++		if (to + len > subdev->size)
++			size = subdev->size - to;
+ 		else
+-		{
+-			if (to + len > subdev->size)
+-				size = subdev->size - to;
+-			else
+-				size = len;
++			size = len;
+ 
+-			if (!(subdev->flags & MTD_WRITEABLE))
+-				err = -EROFS;
+-			else if (subdev->write_oob)
+-				err = subdev->write_oob(subdev, to, size, &retsize, buf);
+-            else
+-                err = -EINVAL;
++		if (!(subdev->flags & MTD_WRITEABLE))
++			err = -EROFS;
++		else if (subdev->write_oob)
++			err = subdev->write_oob(subdev, to, size, &retsize,
++						buf);
++		else
++			err = -EINVAL;
+ 
+-			if(err)
+-				break;
++		if (err)
++			break;
+ 
+-			*retlen += retsize;
+-			len -= size;
+-			if(len == 0)
+-				break;
++		*retlen += retsize;
++		len -= size;
++		if (len == 0)
++			break;
+ 
+-			err = -EINVAL;
+-			buf += size;
+-			to = 0;
+-		}
++		err = -EINVAL;
++		buf += size;
++		to = 0;
+ 	}
+ 	return err;
+ }
+ 
+-
+-static void concat_erase_callback (struct erase_info *instr)
++static void concat_erase_callback(struct erase_info *instr)
+ {
+-	wake_up((wait_queue_head_t *)instr->priv);
++	wake_up((wait_queue_head_t *) instr->priv);
+ }
+ 
+ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
+@@ -370,18 +365,18 @@
+ 
+ 	erase->mtd = mtd;
+ 	erase->callback = concat_erase_callback;
+-	erase->priv = (unsigned long)&waitq;
+-			
++	erase->priv = (unsigned long) &waitq;
++
+ 	/*
+ 	 * FIXME: Allow INTERRUPTIBLE. Which means
+ 	 * not having the wait_queue head on the stack.
+ 	 */
+ 	err = mtd->erase(mtd, erase);
+-	if (!err)
+-	{
++	if (!err) {
+ 		set_current_state(TASK_UNINTERRUPTIBLE);
+ 		add_wait_queue(&waitq, &wait);
+-		if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
++		if (erase->state != MTD_ERASE_DONE
++		    && erase->state != MTD_ERASE_FAILED)
+ 			schedule();
+ 		remove_wait_queue(&waitq, &wait);
+ 		set_current_state(TASK_RUNNING);
+@@ -391,7 +386,7 @@
+ 	return err;
+ }
+ 
+-static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
++static int concat_erase(struct mtd_info *mtd, struct erase_info *instr)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	struct mtd_info *subdev;
+@@ -402,10 +397,10 @@
+ 	if (!(mtd->flags & MTD_WRITEABLE))
+ 		return -EROFS;
+ 
+-	if(instr->addr > concat->mtd.size)
++	if (instr->addr > concat->mtd.size)
+ 		return -EINVAL;
+ 
+-	if(instr->len + instr->addr > concat->mtd.size)
++	if (instr->len + instr->addr > concat->mtd.size)
+ 		return -EINVAL;
+ 
+ 	/*
+@@ -414,23 +409,22 @@
+ 	 * region info rather than looking at each particular sub-device
+ 	 * in turn.
+ 	 */
+-	if (!concat->mtd.numeraseregions)
+-	{	/* the easy case: device has uniform erase block size */
+-		if(instr->addr & (concat->mtd.erasesize - 1))
++	if (!concat->mtd.numeraseregions) {
++		/* the easy case: device has uniform erase block size */
++		if (instr->addr & (concat->mtd.erasesize - 1))
+ 			return -EINVAL;
+-		if(instr->len & (concat->mtd.erasesize - 1))
++		if (instr->len & (concat->mtd.erasesize - 1))
+ 			return -EINVAL;
+-	}
+-	else
+-	{	/* device has variable erase size */
+-		struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
++	} else {
++		/* device has variable erase size */
++		struct mtd_erase_region_info *erase_regions =
++		    concat->mtd.eraseregions;
+ 
+ 		/*
+ 		 * Find the erase region where the to-be-erased area begins:
+ 		 */
+-		for(i = 0; i < concat->mtd.numeraseregions && 
+-		           instr->addr >= erase_regions[i].offset; i++)
+-			;
++		for (i = 0; i < concat->mtd.numeraseregions &&
++		     instr->addr >= erase_regions[i].offset; i++) ;
+ 		--i;
+ 
+ 		/*
+@@ -438,25 +432,26 @@
+ 		 * to-be-erased area begins. Verify that the starting
+ 		 * offset is aligned to this region's erase size:
+ 		 */
+-		if (instr->addr & (erase_regions[i].erasesize-1))
++		if (instr->addr & (erase_regions[i].erasesize - 1))
+ 			return -EINVAL;
+ 
+ 		/*
+ 		 * now find the erase region where the to-be-erased area ends:
+ 		 */
+-		for(; i < concat->mtd.numeraseregions && 
+-		      (instr->addr + instr->len) >=  erase_regions[i].offset ; ++i)
+-			;
++		for (; i < concat->mtd.numeraseregions &&
++		     (instr->addr + instr->len) >= erase_regions[i].offset;
++		     ++i) ;
+ 		--i;
+ 		/*
+ 		 * check if the ending offset is aligned to this region's erase size
+ 		 */
+-		if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
++		if ((instr->addr + instr->len) & (erase_regions[i].erasesize -
++						  1))
+ 			return -EINVAL;
+ 	}
+ 
+ 	/* make a local copy of instr to avoid modifying the caller's struct */
+-	erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
++	erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL);
+ 
+ 	if (!erase)
+ 		return -ENOMEM;
+@@ -468,39 +463,40 @@
+ 	 * find the subdevice where the to-be-erased area begins, adjust
+ 	 * starting offset to be relative to the subdevice start
+ 	 */
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		subdev = concat->subdev[i];
+-		if(subdev->size <= erase->addr)
++		if (subdev->size <= erase->addr)
+ 			erase->addr -= subdev->size;
+ 		else
+ 			break;
+-    }
+-	if(i >= concat->num_subdev)	/* must never happen since size */
+-		BUG();					/* limit has been verified above */
++	}
++
++	/* must never happen since size limit has been verified above */
++	if (i >= concat->num_subdev)
++		BUG();
+ 
+ 	/* now do the erase: */
+ 	err = 0;
+-	for(;length > 0; i++)	/* loop for all subevices affected by this request */
+-	{
+-		subdev = concat->subdev[i];		/* get current subdevice */
++	for (; length > 0; i++) {
++		/* loop for all subdevices affected by this request */
++		subdev = concat->subdev[i];	/* get current subdevice */
+ 
+ 		/* limit length to subdevice's size: */
+-		if(erase->addr + length > subdev->size)
++		if (erase->addr + length > subdev->size)
+ 			erase->len = subdev->size - erase->addr;
+ 		else
+ 			erase->len = length;
+ 
+-		if (!(subdev->flags & MTD_WRITEABLE))
+-		{
++		if (!(subdev->flags & MTD_WRITEABLE)) {
+ 			err = -EROFS;
+ 			break;
+ 		}
+ 		length -= erase->len;
+-		if ((err = concat_dev_erase(subdev, erase)))
+-		{
+-			if(err == -EINVAL)	/* sanity check: must never happen since */
+-				BUG();			/* block alignment has been checked above */
++		if ((err = concat_dev_erase(subdev, erase))) {
++			/* sanity check: should never happen since
++			 * block alignment has been checked above */
++			if (err == -EINVAL)
++				BUG();
+ 			break;
+ 		}
+ 		/*
+@@ -523,85 +519,79 @@
+ 	return 0;
+ }
+ 
+-static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
++static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int i, err = -EINVAL;
+ 
+-	if ((len + ofs) > mtd->size) 
++	if ((len + ofs) > mtd->size)
+ 		return -EINVAL;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size;
+ 
+-		if (ofs >= subdev->size)
+-		{
+-			size  = 0;
++		if (ofs >= subdev->size) {
++			size = 0;
+ 			ofs -= subdev->size;
++			continue;
+ 		}
++		if (ofs + len > subdev->size)
++			size = subdev->size - ofs;
+ 		else
+-		{
+-			if (ofs + len > subdev->size)
+-				size = subdev->size - ofs;
+-			else
+-				size = len;
++			size = len;
+ 
+-			err = subdev->lock(subdev, ofs, size);
++		err = subdev->lock(subdev, ofs, size);
+ 
+-			if(err)
+-				break;
++		if (err)
++			break;
+ 
+-			len -= size;
+-			if(len == 0)
+-				break;
++		len -= size;
++		if (len == 0)
++			break;
+ 
+-			err = -EINVAL;
+-			ofs = 0;
+-		}
++		err = -EINVAL;
++		ofs = 0;
+ 	}
++
+ 	return err;
+ }
+ 
+-static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
++static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int i, err = 0;
+ 
+-	if ((len + ofs) > mtd->size) 
++	if ((len + ofs) > mtd->size)
+ 		return -EINVAL;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		size_t size;
+ 
+-		if (ofs >= subdev->size)
+-		{
+-			size  = 0;
++		if (ofs >= subdev->size) {
++			size = 0;
+ 			ofs -= subdev->size;
++			continue;
+ 		}
++		if (ofs + len > subdev->size)
++			size = subdev->size - ofs;
+ 		else
+-		{
+-			if (ofs + len > subdev->size)
+-				size = subdev->size - ofs;
+-			else
+-				size = len;
++			size = len;
+ 
+-			err = subdev->unlock(subdev, ofs, size);
++		err = subdev->unlock(subdev, ofs, size);
+ 
+-			if(err)
+-				break;
++		if (err)
++			break;
+ 
+-			len -= size;
+-			if(len == 0)
+-				break;
++		len -= size;
++		if (len == 0)
++			break;
+ 
+-			err = -EINVAL;
+-			ofs = 0;
+-		}
++		err = -EINVAL;
++		ofs = 0;
+ 	}
++
+ 	return err;
+ }
+ 
+@@ -610,8 +600,7 @@
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int i;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		subdev->sync(subdev);
+ 	}
+@@ -622,10 +611,9 @@
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int i, rc = 0;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+-		if((rc = subdev->suspend(subdev)) < 0)
++		if ((rc = subdev->suspend(subdev)) < 0)
+ 			return rc;
+ 	}
+ 	return rc;
+@@ -636,8 +624,7 @@
+ 	struct mtd_concat *concat = CONCAT(mtd);
+ 	int i;
+ 
+-	for(i = 0; i < concat->num_subdev; i++)
+-	{
++	for (i = 0; i < concat->num_subdev; i++) {
+ 		struct mtd_info *subdev = concat->subdev[i];
+ 		subdev->resume(subdev);
+ 	}
+@@ -649,11 +636,10 @@
+  * stored to *new_dev upon success. This function does _not_
+  * register any devices: this is the caller's responsibility.
+  */
+-struct mtd_info *mtd_concat_create(
+-	struct mtd_info *subdev[],	/* subdevices to concatenate */
+-	int num_devs,				/* number of subdevices      */
+-	char *name)					/* name for the new device   */
+-{
++struct mtd_info *mtd_concat_create(struct mtd_info *subdev[],	/* subdevices to concatenate */
++				   int num_devs,	/* number of subdevices      */
++				   char *name)
++{				/* name for the new device   */
+ 	int i;
+ 	size_t size;
+ 	struct mtd_concat *concat;
+@@ -661,94 +647,103 @@
+ 	int num_erase_region;
+ 
+ 	printk(KERN_NOTICE "Concatenating MTD devices:\n");
+-	for(i = 0; i < num_devs; i++)
++	for (i = 0; i < num_devs; i++)
+ 		printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
+ 	printk(KERN_NOTICE "into device \"%s\"\n", name);
+ 
+ 	/* allocate the device structure */
+ 	size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
+-	concat = kmalloc (size, GFP_KERNEL);
+-	if(!concat)
+-	{
+-		printk ("memory allocation error while creating concatenated device \"%s\"\n",
+-				name);
+-			return NULL;
++	concat = kmalloc(size, GFP_KERNEL);
++	if (!concat) {
++		printk
++		    ("memory allocation error while creating concatenated device \"%s\"\n",
++		     name);
++		return NULL;
+ 	}
+ 	memset(concat, 0, size);
+-	concat->subdev = (struct mtd_info **)(concat + 1);
++	concat->subdev = (struct mtd_info **) (concat + 1);
+ 
+ 	/*
+ 	 * Set up the new "super" device's MTD object structure, check for
+ 	 * incompatibilites between the subdevices.
+ 	 */
+-	concat->mtd.type      = subdev[0]->type;
+-	concat->mtd.flags     = subdev[0]->flags;
+-	concat->mtd.size      = subdev[0]->size;
++	concat->mtd.type = subdev[0]->type;
++	concat->mtd.flags = subdev[0]->flags;
++	concat->mtd.size = subdev[0]->size;
+ 	concat->mtd.erasesize = subdev[0]->erasesize;
+-	concat->mtd.oobblock  = subdev[0]->oobblock;
+-	concat->mtd.oobsize   = subdev[0]->oobsize;
+-	concat->mtd.ecctype   = subdev[0]->ecctype;
+-	concat->mtd.eccsize   = subdev[0]->eccsize;
++	concat->mtd.oobblock = subdev[0]->oobblock;
++	concat->mtd.oobsize = subdev[0]->oobsize;
++	concat->mtd.ecctype = subdev[0]->ecctype;
++	concat->mtd.eccsize = subdev[0]->eccsize;
++	if (subdev[0]->read_ecc)
++		concat->mtd.read_ecc = concat_read_ecc;
++	if (subdev[0]->write_ecc)
++		concat->mtd.write_ecc = concat_write_ecc;
++	if (subdev[0]->read_oob)
++		concat->mtd.read_oob = concat_read_oob;
++	if (subdev[0]->write_oob)
++		concat->mtd.write_oob = concat_write_oob;
+ 
+-	concat->subdev[0]   = subdev[0];
++	concat->subdev[0] = subdev[0];
+ 
+-	for(i = 1; i < num_devs; i++)
+-	{
+-		if(concat->mtd.type != subdev[i]->type)
+-		{
++	for (i = 1; i < num_devs; i++) {
++		if (concat->mtd.type != subdev[i]->type) {
+ 			kfree(concat);
+-			printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
++			printk("Incompatible device type on \"%s\"\n",
++			       subdev[i]->name);
+ 			return NULL;
+ 		}
+-		if(concat->mtd.flags != subdev[i]->flags)
+-		{	/*
+-			 * Expect all flags except MTD_WRITEABLE to be equal on
+-			 * all subdevices.
++		if (concat->mtd.flags != subdev[i]->flags) {
++			/*
++			 * Expect all flags except MTD_WRITEABLE to be
++			 * equal on all subdevices.
+ 			 */
+-			if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
+-			{
++			if ((concat->mtd.flags ^ subdev[i]->
++			     flags) & ~MTD_WRITEABLE) {
+ 				kfree(concat);
+-				printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
++				printk("Incompatible device flags on \"%s\"\n",
++				       subdev[i]->name);
+ 				return NULL;
+-			}
+-			else	/* if writeable attribute differs, make super device writeable */
+-				concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
++			} else
++				/* if writeable attribute differs,
++				   make super device writeable */
++				concat->mtd.flags |=
++				    subdev[i]->flags & MTD_WRITEABLE;
+ 		}
+ 		concat->mtd.size += subdev[i]->size;
+-		if(concat->mtd.oobblock != subdev[i]->oobblock ||
+-		   concat->mtd.oobsize  != subdev[i]->oobsize  ||
+-		   concat->mtd.ecctype  != subdev[i]->ecctype  ||
+-		   concat->mtd.eccsize  != subdev[i]->eccsize)
+-		{
++		if (concat->mtd.oobblock   !=  subdev[i]->oobblock ||
++		    concat->mtd.oobsize    !=  subdev[i]->oobsize ||
++		    concat->mtd.ecctype    !=  subdev[i]->ecctype ||
++		    concat->mtd.eccsize    !=  subdev[i]->eccsize ||
++		    !concat->mtd.read_ecc  != !subdev[i]->read_ecc ||
++		    !concat->mtd.write_ecc != !subdev[i]->write_ecc ||
++		    !concat->mtd.read_oob  != !subdev[i]->read_oob ||
++		    !concat->mtd.write_oob != !subdev[i]->write_oob) {
+ 			kfree(concat);
+-			printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
++			printk("Incompatible OOB or ECC data on \"%s\"\n",
++			       subdev[i]->name);
+ 			return NULL;
+ 		}
+ 		concat->subdev[i] = subdev[i];
+-		
++
+ 	}
+ 
+-	concat->num_subdev  = num_devs;
+-	concat->mtd.name    = name;
++	concat->num_subdev = num_devs;
++	concat->mtd.name = name;
+ 
+ 	/*
+ 	 * NOTE: for now, we do not provide any readv()/writev() methods
+ 	 *       because they are messy to implement and they are not
+ 	 *       used to a great extent anyway.
+ 	 */
+-	concat->mtd.erase     = concat_erase;
+-	concat->mtd.read      = concat_read;    
+-	concat->mtd.write     = concat_write;
+-	concat->mtd.read_ecc  = concat_read_ecc;    
+-	concat->mtd.write_ecc = concat_write_ecc;
+-	concat->mtd.read_oob  = concat_read_oob;    
+-	concat->mtd.write_oob = concat_write_oob;
+-	concat->mtd.sync      = concat_sync;
+-	concat->mtd.lock      = concat_lock;
+-	concat->mtd.unlock    = concat_unlock;
+-	concat->mtd.suspend   = concat_suspend;
+-	concat->mtd.resume    = concat_resume;
+-
++	concat->mtd.erase = concat_erase;
++	concat->mtd.read = concat_read;
++	concat->mtd.write = concat_write;
++	concat->mtd.sync = concat_sync;
++	concat->mtd.lock = concat_lock;
++	concat->mtd.unlock = concat_unlock;
++	concat->mtd.suspend = concat_suspend;
++	concat->mtd.resume = concat_resume;
+ 
+ 	/*
+ 	 * Combine the erase block size info of the subdevices:
+@@ -758,44 +753,44 @@
+ 	 */
+ 	max_erasesize = curr_erasesize = subdev[0]->erasesize;
+ 	num_erase_region = 1;
+-	for(i = 0; i < num_devs; i++)
+-	{
+-		if(subdev[i]->numeraseregions == 0)
+-		{	/* current subdevice has uniform erase size */
+-			if(subdev[i]->erasesize != curr_erasesize)
+-			{	/* if it differs from the last subdevice's erase size, count it */
++	for (i = 0; i < num_devs; i++) {
++		if (subdev[i]->numeraseregions == 0) {
++			/* current subdevice has uniform erase size */
++			if (subdev[i]->erasesize != curr_erasesize) {
++				/* if it differs from the last subdevice's erase size, count it */
+ 				++num_erase_region;
+ 				curr_erasesize = subdev[i]->erasesize;
+-				if(curr_erasesize > max_erasesize)
++				if (curr_erasesize > max_erasesize)
+ 					max_erasesize = curr_erasesize;
+ 			}
+-		}
+-		else
+-		{	/* current subdevice has variable erase size */
++		} else {
++			/* current subdevice has variable erase size */
+ 			int j;
+-			for(j = 0; j < subdev[i]->numeraseregions; j++)
+-			{	/* walk the list of erase regions, count any changes */
+-				if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+-				{
++			for (j = 0; j < subdev[i]->numeraseregions; j++) {
++
++				/* walk the list of erase regions, count any changes */
++				if (subdev[i]->eraseregions[j].erasesize !=
++				    curr_erasesize) {
+ 					++num_erase_region;
+-					curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+-					if(curr_erasesize > max_erasesize)
++					curr_erasesize =
++					    subdev[i]->eraseregions[j].
++					    erasesize;
++					if (curr_erasesize > max_erasesize)
+ 						max_erasesize = curr_erasesize;
+ 				}
+ 			}
+ 		}
+ 	}
+ 
+-	if(num_erase_region == 1)
+-	{	/*
++	if (num_erase_region == 1) {
++		/*
+ 		 * All subdevices have the same uniform erase size.
+ 		 * This is easy:
+ 		 */
+ 		concat->mtd.erasesize = curr_erasesize;
+ 		concat->mtd.numeraseregions = 0;
+-	}
+-	else
+-	{	/*
++	} else {
++		/*
+ 		 * erase block size varies across the subdevices: allocate
+ 		 * space to store the data describing the variable erase regions
+ 		 */
+@@ -804,13 +799,14 @@
+ 
+ 		concat->mtd.erasesize = max_erasesize;
+ 		concat->mtd.numeraseregions = num_erase_region;
+-		concat->mtd.eraseregions = erase_region_p = kmalloc (
+-		     num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+-		if(!erase_region_p)
+-		{
++		concat->mtd.eraseregions = erase_region_p =
++		    kmalloc(num_erase_region *
++			    sizeof (struct mtd_erase_region_info), GFP_KERNEL);
++		if (!erase_region_p) {
+ 			kfree(concat);
+-			printk ("memory allocation error while creating erase region list"
+-			        " for device \"%s\"\n", name);
++			printk
++			    ("memory allocation error while creating erase region list"
++			     " for device \"%s\"\n", name);
+ 			return NULL;
+ 		}
+ 
+@@ -820,46 +816,53 @@
+ 		 */
+ 		curr_erasesize = subdev[0]->erasesize;
+ 		begin = position = 0;
+-		for(i = 0; i < num_devs; i++)
+-		{
+-			if(subdev[i]->numeraseregions == 0)
+-			{	/* current subdevice has uniform erase size */
+-				if(subdev[i]->erasesize != curr_erasesize)
+-				{	/*
++		for (i = 0; i < num_devs; i++) {
++			if (subdev[i]->numeraseregions == 0) {
++				/* current subdevice has uniform erase size */
++				if (subdev[i]->erasesize != curr_erasesize) {
++					/*
+ 					 *  fill in an mtd_erase_region_info structure for the area
+ 					 *  we have walked so far:
+ 					 */
+-					erase_region_p->offset    = begin;
+-					erase_region_p->erasesize = curr_erasesize;
+-					erase_region_p->numblocks = (position - begin) / curr_erasesize;
++					erase_region_p->offset = begin;
++					erase_region_p->erasesize =
++					    curr_erasesize;
++					erase_region_p->numblocks =
++					    (position - begin) / curr_erasesize;
+ 					begin = position;
+ 
+ 					curr_erasesize = subdev[i]->erasesize;
+ 					++erase_region_p;
+ 				}
+ 				position += subdev[i]->size;
+-			}
+-			else
+-			{	/* current subdevice has variable erase size */
++			} else {
++				/* current subdevice has variable erase size */
+ 				int j;
+-				for(j = 0; j < subdev[i]->numeraseregions; j++)
+-				{	/* walk the list of erase regions, count any changes */
+-					if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+-					{
+-						erase_region_p->offset    = begin;
+-						erase_region_p->erasesize = curr_erasesize;
+-						erase_region_p->numblocks = (position - begin) / curr_erasesize;
++				for (j = 0; j < subdev[i]->numeraseregions; j++) {
++					/* walk the list of erase regions, count any changes */
++					if (subdev[i]->eraseregions[j].
++					    erasesize != curr_erasesize) {
++						erase_region_p->offset = begin;
++						erase_region_p->erasesize =
++						    curr_erasesize;
++						erase_region_p->numblocks =
++						    (position -
++						     begin) / curr_erasesize;
+ 						begin = position;
+ 
+-						curr_erasesize = subdev[i]->eraseregions[j].erasesize;
++						curr_erasesize =
++						    subdev[i]->eraseregions[j].
++						    erasesize;
+ 						++erase_region_p;
+ 					}
+-					position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
++					position +=
++					    subdev[i]->eraseregions[j].
++					    numblocks * curr_erasesize;
+ 				}
+ 			}
+ 		}
+ 		/* Now write the final entry */
+-		erase_region_p->offset    = begin;
++		erase_region_p->offset = begin;
+ 		erase_region_p->erasesize = curr_erasesize;
+ 		erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ 	}
+@@ -874,16 +877,14 @@
+ void mtd_concat_destroy(struct mtd_info *mtd)
+ {
+ 	struct mtd_concat *concat = CONCAT(mtd);
+-	if(concat->mtd.numeraseregions)
++	if (concat->mtd.numeraseregions)
+ 		kfree(concat->mtd.eraseregions);
+ 	kfree(concat);
+ }
+ 
+-
+ EXPORT_SYMBOL(mtd_concat_create);
+ EXPORT_SYMBOL(mtd_concat_destroy);
+ 
+-
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
+ MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
+--- linux-2.6.5/drivers/mtd/maps/Makefile~heh	2004-04-03 22:36:12.000000000 -0500
++++ linux-2.6.5/drivers/mtd/maps/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -17,12 +17,14 @@
+ obj-$(CONFIG_MTD_ELAN_104NC)	+= elan-104nc.o
+ obj-$(CONFIG_MTD_EPXA10DB)	+= epxa10db-flash.o
+ obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
++obj-$(CONFIG_MTD_IQ80321)	+= iq80321.o
+ obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
+ obj-$(CONFIG_MTD_AMD76XROM)	+= amd76xrom.o
+ obj-$(CONFIG_MTD_ICH2ROM)	+= ich2rom.o
+ obj-$(CONFIG_MTD_TSUNAMI)	+= tsunami_flash.o
+ obj-$(CONFIG_MTD_LUBBOCK)	+= lubbock-flash.o
+ obj-$(CONFIG_MTD_MBX860)	+= mbx860.o
++obj-$(CONFIG_MTD_NORA)		+= nora.o
+ obj-$(CONFIG_MTD_CEIVA)		+= ceiva.o
+ obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
+ obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
+--- linux-2.6.5/drivers/mtd/maps/sa1100-flash.c~heh	2004-04-03 22:36:51.000000000 -0500
++++ linux-2.6.5/drivers/mtd/maps/sa1100-flash.c	2004-04-30 20:57:36.000000000 -0400
+@@ -14,6 +14,7 @@
+ #include <linux/init.h>
+ #include <linux/errno.h>
+ #include <linux/slab.h>
++#include <linux/device.h>
+ 
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/map.h>
+@@ -887,6 +888,7 @@
+ 	int width;
+ 	void *vbase;
+         void (*set_vpp)(struct map_info *, int);
++        char name[16];
+ 	struct map_info *map;
+ 	struct mtd_info *mtd;
+ 	struct resource *res;
+@@ -925,6 +927,8 @@
+ 		}
+ 
+ 		sa[i].map = maps + i;
++		sa[i].map->name = sa[i].name;
++		sprintf(sa[i].name, "sa1100-%d", i);
+ 
+ 		sa[i].vbase = ioremap(sa[i].base, sa[i].size);
+ 		if (!sa[i].vbase) {
+@@ -986,7 +990,7 @@
+ 			 */
+ #ifdef CONFIG_MTD_CONCAT
+ 			*rmtd = mtd_concat_create(subdev, found,
+-						  "sa1100 flash");
++						  "sa1100");
+ 			if (*rmtd == NULL)
+ 				ret = -ENXIO;
+ #else
+@@ -1044,13 +1048,9 @@
+  *  - Is the MSC setup for flash (no -> failure)
+  *  - Probe for flash
+  */
+-
+-static struct map_info sa1100_probe_map __initdata = {
+-	.name		= "SA1100-flash",
+-};
+-
+-static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
++static void sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
+ {
++	struct map_info map;
+ 	struct mtd_info *mtd;
+ 
+ 	printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
+@@ -1066,19 +1066,23 @@
+ 		return;
+ 	}
+ 
+-	sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4;
+-	sa1100_probe_map.size = SZ_1M;
+-	sa1100_probe_map.phys = phys;
+-	sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
+-	if (sa1100_probe_map.virt == 0)
++	memset(&map, 0, sizeof(map));
++
++	map.name = "Probe";
++	map.buswidth = msc & MSC_RBW ? 2 : 4;
++	map.size = SZ_1M;
++	map.phys = NO_XIP;
++	map.virt = (unsigned long)ioremap(phys, SZ_1M);
++	if (map.virt == 0)
+ 		goto fail;
+-	simple_map_init(&sa1100_probe_map);
++
++	simple_map_init(&map);
+ 
+ 	/* Shame cfi_probe blurts out kernel messages... */
+-	mtd = do_map_probe("cfi_probe", &sa1100_probe_map);
++	mtd = do_map_probe("cfi_probe", &map);
+ 	if (mtd)
+ 		map_destroy(mtd);
+-	iounmap((void *)sa1100_probe_map.virt);
++	iounmap((void *)map.virt);
+ 
+ 	if (!mtd)
+ 		goto fail;
+@@ -1090,7 +1094,7 @@
+ 	printk("failed\n");
+ }
+ 
+-static void __init sa1100_probe_flash(void)
++static void sa1100_probe_flash(void)
+ {
+ 	printk(KERN_INFO "-- SA11xx Flash probe.  Please report results.\n");
+ 	sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
+@@ -1321,10 +1325,9 @@
+ 		kfree(parsed_parts);
+ }
+ 
+-static struct mtd_info *mymtd;
+-
+-static int __init sa1100_mtd_init(void)
++static int __init sa1100_mtd_probe(struct device *dev)
+ {
++	struct mtd_info *mtd;
+ 	int ret;
+ 	int nr;
+ 
+@@ -1332,21 +1335,74 @@
+ 	if (nr < 0)
+ 		return nr;
+ 
+-	ret = sa1100_setup_mtd(info, nr, &mymtd);
+-	if (ret == 0)
+-		sa1100_locate_partitions(mymtd);
++	ret = sa1100_setup_mtd(info, nr, &mtd);
++	if (ret == 0) {
++		sa1100_locate_partitions(mtd);
++		dev_set_drvdata(dev, mtd);
++	}
+ 
+ 	return ret;
+ }
+ 
+-static void __exit sa1100_mtd_cleanup(void)
++static int __exit sa1100_mtd_remove(struct device *dev)
+ {
+-	sa1100_destroy_mtd(info, mymtd);
++	struct mtd_info *mtd = dev_get_drvdata(dev);
++	sa1100_destroy_mtd(info, mtd);
+ 	sa1100_destroy_partitions();
++	return 0;
++}
++
++static int sa1100_mtd_suspend(struct device *dev, u32 level, u32 state)
++{
++	struct mtd_info *mtd = dev_get_drvdata(dev);
++	if (level == SUSPEND_SAVE_STATE)
++		mtd->suspend(mtd);
++	return 0;
++}
++
++static int sa1100_mtd_resume(struct device *dev, u32 level)
++{
++	struct mtd_info *mtd = dev_get_drvdata(dev);
++	if (level == RESUME_RESTORE_STATE)
++		mtd->resume(mtd);
++	return 0;
++}
++
++static struct platform_device sa1100_mtd_device = {
++	.name		= "flash",
++	.id		= 0,
++};
++
++static struct device_driver sa1100_mtd_driver = {
++	.name		= "flash",
++	.bus		= &platform_bus_type,
++	.probe		= sa1100_mtd_probe,
++#ifdef MODULE
++	.remove		= sa1100_mtd_remove,
++#endif
++	.suspend	= sa1100_mtd_suspend,
++	.resume		= sa1100_mtd_resume,
++};
++
++static int __init sa1100_mtd_init(void)
++{
++	int ret = driver_register(&sa1100_mtd_driver);
++	if (ret == 0) {
++		ret = platform_device_register(&sa1100_mtd_device);
++		if (ret)
++			driver_unregister(&sa1100_mtd_driver);
++	}
++	return ret;
++}
++
++static void __exit sa1100_mtd_exit(void)
++{
++	platform_device_unregister(&sa1100_mtd_device);
++	driver_unregister(&sa1100_mtd_driver);
+ }
+ 
+ module_init(sa1100_mtd_init);
+-module_exit(sa1100_mtd_cleanup);
++module_exit(sa1100_mtd_exit);
+ 
+ MODULE_AUTHOR("Nicolas Pitre");
+ MODULE_DESCRIPTION("SA1100 CFI map driver");
+--- linux-2.6.5/drivers/mtd/maps/pcmciamtd.c~heh	2004-04-03 22:36:19.000000000 -0500
++++ linux-2.6.5/drivers/mtd/maps/pcmciamtd.c	2004-04-30 20:57:36.000000000 -0400
+@@ -25,10 +25,9 @@
+ #include <pcmcia/ds.h>
+ 
+ #include <linux/mtd/map.h>
+-#include <linux/mtd/mtd.h>
+ 
+-#ifdef CONFIG_MTD_DEBUG
+-static int debug = CONFIG_MTD_DEBUG_VERBOSE;
++#if 1 //def CONFIG_MTD_DEBUG
++static int debug = 5; //CONFIG_MTD_DEBUG_VERBOSE;
+ MODULE_PARM(debug, "i");
+ MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
+ #undef DEBUG
+@@ -88,7 +87,7 @@
+ static int setvpp;
+ 
+ /* Force card to be treated as FLASH, ROM or RAM */
+-static int mem_type;
++static int mem_type = 1;
+ 
+ MODULE_LICENSE("GPL");
+ MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+--- linux-2.6.5/drivers/mtd/maps/pci.c~heh	2004-04-03 22:36:56.000000000 -0500
++++ linux-2.6.5/drivers/mtd/maps/pci.c	2004-04-30 20:57:36.000000000 -0400
+@@ -22,6 +22,8 @@
+ #include <linux/mtd/map.h>
+ #include <linux/mtd/partitions.h>
+ 
++#include <asm/io.h>
++
+ struct map_pci_info;
+ 
+ struct mtd_pci_info {
+--- linux-2.6.5/drivers/input/Kconfig~heh	2004-04-03 22:36:18.000000000 -0500
++++ linux-2.6.5/drivers/input/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -80,7 +80,7 @@
+ 	  module will be called joydev.
+ 
+ config INPUT_TSDEV
+-	tristate "Touchscreen interface"
++	tristate "Compaq Touchscreen interface"
+ 	depends on INPUT
+ 	---help---
+ 	  Say Y here if you have an application that only can understand the
+@@ -102,6 +102,10 @@
+ 	depends on INPUT_TSDEV
+ 	default "320"
+ 
++config INPUT_TSLIBDEV
++	tristate "TSLIB Touchscreen interface"
++	depends on INPUT
++
+ config INPUT_EVDEV
+ 	tristate "Event interface"
+ 	depends on INPUT
+--- linux-2.6.5/drivers/input/serio/Kconfig~heh	2004-04-03 22:37:07.000000000 -0500
++++ linux-2.6.5/drivers/input/serio/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -80,7 +80,7 @@
+ 
+ config SERIO_RPCKBD
+ 	tristate "Acorn RiscPC keyboard controller"
+-	depends on ARCH_ACORN && SERIO
++	depends on (ARCH_ACORN || ARCH_CLPS7500) && SERIO
+ 	default y
+ 	help
+ 	  Say Y here if you have the Acorn RiscPC and want to use an AT
+@@ -89,6 +89,18 @@
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called rpckbd.
+ 
++config SERIO_CLPS7500
++	tristate "CLPS7500 PS/2 mouse port controller"
++	depends on ARCH_CLPS7500 && SERIO
++	help
++	  Say Y here if you have CLPS7500 based hardware and want to use
++	  the mouse port.
++
++	  This driver is also available as a module ( = code which can be
++	  inserted in and removed from the running kernel whenever you want).
++	  The module will be called clps7500ps2. If you want to compile it
++	  as a module, say M here and read <file:Documentation/modules.txt>.
++
+ config SERIO_AMBAKMI
+ 	tristate "AMBA KMI keyboard controller"
+ 	depends on ARCH_INTEGRATOR && SERIO
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/input/serio/sa1100ir.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,90 @@
++/*
++ *  linux/drivers/input/serio/sa1100ir.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/serio.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++
++
++
++struct sa1100_kbd {
++	struct serio	io;
++	void		*base;
++	int		irq;
++};
++
++static void sa1100ir_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct sa1100_kbd *kbd = dev_id;
++	unsigned int status;
++
++	do {
++		unsigned int flag, data;
++
++		status = readl(kbd->base + UTSR1);
++		if (!(status & UTSR1_RNE))
++			break;
++
++		flag = (status & UTSR1_FRE ? SERIO_FRAME : 0) |
++		       (status & UTSR1_PRE ? SERIO_PARITY : 0);
++
++		data = readl(kbd->base + UTDR);
++
++		serio_interrupt(&kbd->io, data, flag);
++	} while (1);
++
++	status = readl(kbd->base + UTSR0) & UTSR0_RID | UTSR0_RBB | UTSR0_REB;
++	if (status)
++		writel(status, kbd->base + UTSR0);
++}
++
++static int sa1100ir_kbd_open(struct serio *io)
++{
++	struct sa1100_kbd *kbd = io->driver;
++	int ret;
++
++	ret = request_irq(kbd->irq, sa1100ir_int, 0, kbd->io.phys, kbd);
++	if (ret)
++		return ret;
++
++	return 0;
++}
++
++static void sa1100ir_kbd_close(struct serio *io)
++{
++	struct sa1100_kbd *kbd = io->driver;
++
++	free_irq(kbd->irq, kbd);
++}
++
++static struct sa1100_kbd sa1100_kbd = {
++	.io = {
++		.type	= 0,
++		.open	= sa1100ir_kbd_open,
++		.close	= sa1100ir_kbd_close,
++		.name	= "SA11x0 IR port",
++		.phys	= "sa11x0/ir",
++		.driver	= &sa1100_kbd,
++	},
++};
++
++static int __init sa1100_kbd_init(void)
++{
++	serio_register_port(&sa1100_kbd.io);
++}
++
++static void __exit sa1100_kbd_exit(void)
++{
++	serio_unregister_port(&sa1100_kbd.io);
++}
++
++module_init(sa1100_kbd_init);
++module_exit(sa1100_kbd_exit);
+--- linux-2.6.5/drivers/input/serio/Makefile~heh	2004-04-03 22:36:16.000000000 -0500
++++ linux-2.6.5/drivers/input/serio/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -10,6 +10,7 @@
+ obj-$(CONFIG_SERIO_SERPORT)	+= serport.o
+ obj-$(CONFIG_SERIO_CT82C710)	+= ct82c710.o
+ obj-$(CONFIG_SERIO_RPCKBD)	+= rpckbd.o
++obj-$(CONFIG_SERIO_CLPS7500)	+= clps7500ps2.o
+ obj-$(CONFIG_SERIO_SA1111)	+= sa1111ps2.o
+ obj-$(CONFIG_SERIO_AMBAKMI)	+= ambakmi.o
+ obj-$(CONFIG_SERIO_Q40KBD)	+= q40kbd.o
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/input/tslibdev.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,358 @@
++/*
++ *  linux/drivers/input/tslibdev.c
++ *
++ *  Copyright (C) 2002 Russell King
++ *
++ * From tsdev.c:
++ *
++ *  Copyright (c) 2001 "Crazy" james Simmons 
++ *
++ *  Input driver to Touchscreen device driver module.
++ *
++ *  Sponsored by Transvirtual Technology
++ */
++
++/*
++ * 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
++ * 
++ * Should you need to contact me, the author, you can do so either by
++ * e-mail - mail your message to <jsimmons@transvirtual.com>.
++ */
++
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/config.h>
++#include <linux/smp_lock.h>
++#include <linux/random.h>
++#include <linux/time.h>
++#include <linux/list.h>
++#include <linux/miscdevice.h>
++
++struct ucb1x00_dev {
++	int		exist;
++	char		name[16];
++	wait_queue_head_t wait;
++	struct list_head list;
++	struct input_handle handle;
++	int		x;
++	int		y;
++	int		pressure;
++};
++
++struct ts_event {
++	u16		pressure;
++	u16		x;
++	u16		y;
++	u16		pad;
++	struct timeval	stamp;
++};
++
++#define TSDEV_BUFFER_SIZE	64
++
++struct ucb1x00_list {
++	struct list_head	list;
++	struct fasync_struct	*fasync;
++	struct ucb1x00_dev	*tsdev;
++	unsigned int		head;
++	unsigned int		tail;
++	struct ts_event		event[TSDEV_BUFFER_SIZE];
++};
++
++static struct input_handler ucb1x00_handler;
++static struct ucb1x00_dev *ucb1x00_dev;
++
++static void ucb1x00_remove(struct ucb1x00_dev *tsdev);
++
++
++static int ucb1x00_fasync(int fd, struct file *file, int on)
++{
++	struct ucb1x00_list *list = file->private_data;
++	int retval;
++
++	retval = fasync_helper(fd, file, on, &list->fasync);
++	return retval < 0 ? retval : 0;
++}
++
++static int ucb1x00_open(struct inode *inode, struct file *file)
++{
++	struct ucb1x00_list *list;
++	int empty;
++
++	if (!ucb1x00_dev || !ucb1x00_dev->exist)
++		return -ENODEV;
++
++	printk(KERN_WARNING
++		"tslibdev: process %s (%d) uses obsolete tslib device\n",
++		current->comm, current->pid);
++
++	list = kmalloc(sizeof(struct ucb1x00_list), GFP_KERNEL);
++	if (!list)
++		return -ENOMEM;
++
++	memset(list, 0, sizeof(struct ucb1x00_list));
++
++	empty = list_empty(&ucb1x00_dev->list);
++
++	list->tsdev = ucb1x00_dev;
++	list_add(&list->list, &list->tsdev->list);
++
++	file->private_data = list;
++
++	if (empty && list->tsdev->exist)
++		input_open_device(&list->tsdev->handle);
++
++	return 0;
++}
++
++static int ucb1x00_release(struct inode *inode, struct file *file)
++{
++	struct ucb1x00_list *list = file->private_data;
++
++	ucb1x00_fasync(-1, file, 0);
++
++	list_del(&list->list);
++
++	ucb1x00_remove(list->tsdev);
++
++	kfree(list);
++
++	return 0;
++}
++
++static ssize_t
++ucb1x00_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct ucb1x00_list *list = file->private_data;
++	int retval = 0;
++
++	if (list->head == list->tail) {
++		add_wait_queue(&list->tsdev->wait, &wait);
++
++		while (list->head == list->tail) {
++			set_current_state(TASK_INTERRUPTIBLE);
++
++			if (!list->tsdev->exist) {
++				retval = -ENODEV;
++				break;
++			}
++			if (file->f_flags & O_NONBLOCK) {
++				retval = -EAGAIN;
++				break;
++			}
++			if (signal_pending(current)) {
++				retval = -ERESTARTSYS;
++				break;
++			}
++			schedule();
++		}
++		set_current_state(TASK_RUNNING);
++		remove_wait_queue(&list->tsdev->wait, &wait);
++	}
++
++	if (retval)
++		return retval;
++
++	while (list->head != list->tail && count >= sizeof(struct ts_event)) {
++		if (copy_to_user(buffer, list->event + list->tail,
++				 sizeof(struct ts_event)))
++			return retval ? retval : -EFAULT;
++		list->tail = (list->tail + 1) & (TSDEV_BUFFER_SIZE - 1);
++		retval += sizeof(struct ts_event);
++		buffer += sizeof(struct ts_event);
++		count -= sizeof(struct ts_event);
++	}
++	return retval;
++}
++
++/* No kernel lock - fine */
++static unsigned int ucb1x00_poll(struct file *file, poll_table * wait)
++{
++	struct ucb1x00_list *list = file->private_data;
++
++	poll_wait(file, &list->tsdev->wait, wait);
++	if (list->head != list->tail || !list->tsdev->exist)
++		return POLLIN | POLLRDNORM;
++	return 0;
++}
++
++static int
++ucb1x00_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++	    unsigned long arg)
++{
++	return -EINVAL;
++}
++
++struct file_operations ucb1x00_fops = {
++	.owner		= THIS_MODULE,
++	.open		= ucb1x00_open,
++	.release	= ucb1x00_release,
++	.read		= ucb1x00_read,
++	.poll		= ucb1x00_poll,
++	.fasync		= ucb1x00_fasync,
++	.ioctl		= ucb1x00_ioctl,
++};
++
++/*
++ * The official UCB1x00 touchscreen is a miscdevice:
++ *   10 char        Non-serial mice, misc features
++ *                   14 = /dev/touchscreen/ucb1x00  UCB 1x00 touchscreen
++ */
++static struct miscdevice ucb1x00_ts_dev = {
++	.minor		= 14,
++	.name		= "touchscreen/ucb1x00",
++	.fops		= &ucb1x00_fops,
++	.devfs_name	= "touchscreen/ucb1x00",
++};
++
++static void ucb1x00_remove(struct ucb1x00_dev *tsdev)
++{
++	if (list_empty(&tsdev->list)) {
++		if (tsdev->exist) {
++			input_close_device(&tsdev->handle);
++			wake_up_interruptible(&tsdev->wait);
++		} else {
++			misc_deregister(&ucb1x00_ts_dev);
++			ucb1x00_dev = NULL;
++			kfree(tsdev);
++		}
++	}
++}
++
++
++static void
++ucb1x00_event(struct input_handle *handle, unsigned int type, unsigned int code,
++	    int value)
++{
++	struct ucb1x00_dev *tsdev = handle->private;
++	struct list_head *l;
++
++	/* sorry, we only handle absolute stuff */
++	if (type == EV_ABS) {
++		switch (code) {
++		case ABS_X:
++			tsdev->x = value;
++			break;
++		case ABS_Y:
++			tsdev->y = value;
++			break;
++		case ABS_PRESSURE:
++			tsdev->pressure = value;
++			break;
++		}
++		return;
++	}
++
++	if (type != EV_SYN || code != SYN_REPORT)
++		return;
++
++	list_for_each(l, &tsdev->list) {
++		struct ucb1x00_list *list = list_entry(l, struct ucb1x00_list, list);
++		list->event[list->head].pressure = tsdev->pressure;
++		if (tsdev->pressure) {
++			list->event[list->head].x = tsdev->x;
++			list->event[list->head].y = tsdev->y;
++		} else {
++			list->event[list->head].x = 0;
++			list->event[list->head].y = 0;
++		}
++		do_gettimeofday(&list->event[list->head].stamp);
++		list->head = (list->head + 1) & (TSDEV_BUFFER_SIZE - 1);
++		kill_fasync(&list->fasync, SIGIO, POLL_IN);
++	}
++	wake_up_interruptible(&tsdev->wait);
++}
++
++static struct input_handle *
++ucb1x00_connect(struct input_handler *handler, struct input_dev *dev,
++	      struct input_device_id *id)
++{
++	struct ucb1x00_dev *tsdev;
++
++	if (ucb1x00_dev)
++		return NULL;
++
++	tsdev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL);
++	if (!tsdev)
++		return NULL;
++
++	memset(tsdev, 0, sizeof(struct ucb1x00_dev));
++	init_waitqueue_head(&tsdev->wait);
++	INIT_LIST_HEAD(&tsdev->list);
++
++	ucb1x00_dev = tsdev;
++
++	strcpy(tsdev->name, ucb1x00_ts_dev.name);
++
++	tsdev->handle.dev     = dev;
++	tsdev->handle.name    = tsdev->name;
++	tsdev->handle.handler = handler;
++	tsdev->handle.private = tsdev;
++
++	misc_register(&ucb1x00_ts_dev);
++
++	tsdev->exist = 1;
++
++	return &tsdev->handle;
++}
++
++static void ucb1x00_disconnect(struct input_handle *handle)
++{
++	struct ucb1x00_dev *tsdev = handle->private;
++
++	tsdev->exist = 0;
++	ucb1x00_remove(tsdev);
++}
++
++static struct input_device_id ucb1x00_ids[] = {
++	{
++	      .flags	= INPUT_DEVICE_ID_MATCH_ABSBIT,
++	      .evbit	= { BIT(EV_ABS) },
++	      .absbit	= { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
++	},
++
++	{},/* Terminating entry */
++};
++
++MODULE_DEVICE_TABLE(input, ucb1x00_ids);
++
++static struct input_handler ucb1x00_handler = {
++	.event		= ucb1x00_event,
++	.connect	= ucb1x00_connect,
++	.disconnect	= ucb1x00_disconnect,
++	.name		= "touchscreen/ucb1x00",
++	.id_table	= ucb1x00_ids,
++};
++
++static int __init ucb1x00_init(void)
++{
++	input_register_handler(&ucb1x00_handler);
++	printk(KERN_INFO "ts: UCB1x00 touchscreen protocol output\n");
++	return 0;
++}
++
++static void __exit ucb1x00_exit(void)
++{
++	input_unregister_handler(&ucb1x00_handler);
++}
++
++module_init(ucb1x00_init);
++module_exit(ucb1x00_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("Input driver to UCB1x00 touchscreen converter");
+--- linux-2.6.5/drivers/input/Makefile~heh	2004-04-03 22:38:17.000000000 -0500
++++ linux-2.6.5/drivers/input/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -8,6 +8,7 @@
+ obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
+ obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
+ obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o
++obj-$(CONFIG_INPUT_TSLIBDEV)	+= tslibdev.o
+ obj-$(CONFIG_INPUT_TSDEV)	+= tsdev.o
+ obj-$(CONFIG_INPUT_POWER)	+= power.o
+ obj-$(CONFIG_INPUT_EVBUG)	+= evbug.o
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/char/sa1100-rtc.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,416 @@
++/*
++ *	Real Time Clock interface for Linux on Intel SA11x0/PXA2xx
++ *
++ *	Copyright (c) 2000 Nils Faerber
++ *
++ *	Based on rtc.c by Paul Gortmaker
++ *	Date/time conversion routines taken from arch/arm/kernel/time.c
++ *			by Linus Torvalds and Russel King
++ *		and the GNU C Library
++ *	( ... I love the GPL ... just take what you need! ;)
++ *
++ *	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.
++ *
++ *	1.00	2001-06-08	Nicolas Pitre <nico@cam.org>
++ *	- added periodic timer capability using OSMR1
++ *	- flag compatibility with other RTC chips
++ *	- permission checks for ioctls
++ *	- major cleanup, partial rewrite
++ *
++ *	0.03	2001-03-07	CIH <cih@coventive.com>
++ *	- Modify the bug setups RTC clock.
++ *
++ *	0.02	2001-02-27	Nils Faerber <nils@@kernelconcepts.de>
++ *	- removed mktime(), added alarm irq clear
++ *
++ *	0.01	2000-10-01	Nils Faerber <nils@@kernelconcepts.de>
++ *	- initial release
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/string.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/proc_fs.h>
++#include <linux/interrupt.h>
++#include <linux/rtc.h>
++
++#include <asm/bitops.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/rtc.h>
++
++#define TIMER_FREQ		3686400
++
++#define RTC_DEF_DIVIDER		32768 - 1
++#define RTC_DEF_TRIM		0
++
++/* Those are the bits from a classic RTC we want to mimic */
++#define RTC_IRQF		0x80	/* any of the following 3 is active */
++#define RTC_PF			0x40
++#define RTC_AF			0x20
++#define RTC_UF			0x10
++
++static unsigned long rtc_freq = 1024;
++static struct rtc_time rtc_alarm = {
++	.tm_year	= 0,
++	.tm_mon		= 0,
++	.tm_mday	= 0,
++	.tm_hour	= 0,
++	.tm_mon		= 0,
++	.tm_sec		= 0,
++};
++
++extern spinlock_t rtc_lock;
++
++static int rtc_update_alarm(struct rtc_time *alrm)
++{
++	struct rtc_time alarm_tm, now_tm;
++	unsigned long now, time;
++	int ret;
++
++	do {
++		now = RCNR;
++		rtc_time_to_tm(now, &now_tm);
++		rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
++		ret = rtc_tm_to_time(&alarm_tm, &time);
++		if (ret != 0)
++			break;
++
++		RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
++		RTAR = time;
++	} while (now != RCNR);
++
++	return ret;
++}
++
++static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned int rtsr;
++	unsigned long events = 0;
++
++	spin_lock(&rtc_lock);
++
++	rtsr = RTSR;
++	/* clear interrupt sources */
++	RTSR = 0;
++	RTSR = (RTSR_AL|RTSR_HZ) & (rtsr >> 2);
++
++	/* clear alarm interrupt if it has occurred */
++	if (rtsr & RTSR_AL)
++		rtsr &= ~RTSR_ALE;
++	RTSR = rtsr & (RTSR_ALE|RTSR_HZE);
++
++	/* update irq data & counter */
++	if (rtsr & RTSR_AL)
++		events |= (RTC_AF|RTC_IRQF);
++	if (rtsr & RTSR_HZ)
++		events |= (RTC_UF|RTC_IRQF);
++
++	rtc_update(1, events);
++
++	if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
++		rtc_update_alarm(&rtc_alarm);
++
++	spin_unlock(&rtc_lock);
++
++	return IRQ_HANDLED;
++}
++
++#if 0
++static unsigned long rtc_irq_data;
++
++static irqreturn_t timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	/*
++	 * If we match for the first time, the periodic interrupt flag won't
++	 * be set.  If it is, then we did wrap around (very unlikely but
++	 * still possible) and compute the amount of missed periods.
++	 * The match reg is updated only when the data is actually retrieved
++	 * to avoid unnecessary interrupts.
++	 */
++	OSSR = OSSR_M1;	/* clear match on timer1 */
++	if (rtc_irq_data & RTC_PF) {
++		rtc_irq_data += (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))) << 8;
++	} else {
++		rtc_update(1, RTC_PF | RTC_IRQF);
++	}
++
++	wake_up_interruptible(&rtc_wait);
++	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
++
++	return IRQ_HANDLED;
++}
++#endif
++
++static int sa1100_rtc_open(void)
++{
++	int ret;
++
++	ret = request_irq(IRQ_RTC1Hz, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL);
++	if (ret) {
++		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz);
++		goto fail_ui;
++	}
++	ret = request_irq(IRQ_RTCAlrm, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL);
++	if (ret) {
++		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm);
++		goto fail_ai;
++	}
++#if 0
++	ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", NULL);
++	if (ret) {
++		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1);
++		goto fail_pi;
++	}
++	rtc_irq_data = 0;
++#endif
++	return 0;
++
++ fail_pi:
++	free_irq(IRQ_RTCAlrm, NULL);
++ fail_ai:
++	free_irq(IRQ_RTC1Hz, NULL);
++ fail_ui:
++	return ret;
++}
++
++static void sa1100_rtc_release(void)
++{
++	spin_lock_irq (&rtc_lock);
++	RTSR = 0;
++	OIER &= ~OIER_E1;
++	OSSR = OSSR_M1;
++	spin_unlock_irq (&rtc_lock);
++
++//	free_irq(IRQ_OST1, NULL);
++	free_irq(IRQ_RTCAlrm, NULL);
++	free_irq(IRQ_RTC1Hz, NULL);
++}
++
++#if 0
++ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long data;
++	ssize_t retval;
++
++	if (count < sizeof(unsigned long))
++		return -EINVAL;
++
++	add_wait_queue(&rtc_wait, &wait);
++	set_current_state(TASK_INTERRUPTIBLE);
++	for (;;) {
++		spin_lock_irq (&rtc_lock);
++		data = rtc_irq_data;
++		if (data != 0) {
++			rtc_irq_data = 0;
++			break;
++		}
++		spin_unlock_irq (&rtc_lock);
++
++		if (file->f_flags & O_NONBLOCK) {
++			retval = -EAGAIN;
++			goto out;
++		}
++
++		if (signal_pending(current)) {
++			retval = -ERESTARTSYS;
++			goto out;
++		}
++
++		schedule();
++	}
++
++	if (data & RTC_PF) {
++		/* interpolate missed periods and set match for the next one */
++		unsigned long period = TIMER_FREQ/rtc_freq;
++		unsigned long oscr = OSCR;
++		unsigned long osmr1 = OSMR1;
++		unsigned long missed = (oscr - osmr1)/period;
++		data += missed << 8;
++		OSSR = OSSR_M1;	/* clear match on timer 1 */
++		OSMR1 = osmr1 + (missed + 1)*period;
++		/* ensure we didn't miss another match in the mean time */
++		while( (signed long)((osmr1 = OSMR1) - OSCR) <= 0 ) {
++			data += 0x100;
++			OSSR = OSSR_M1;	/* clear match on timer 1 */
++			OSMR1 = osmr1 + period;
++		}
++	}
++	spin_unlock_irq (&rtc_lock);
++
++	data -= 0x100;	/* the first IRQ wasn't actually missed */
++
++	retval = put_user(data, (unsigned long *)buf);
++	if (!retval)
++		retval = sizeof(unsigned long);
++
++out:
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&rtc_wait, &wait);
++	return retval;
++}
++#endif
++
++static int sa1100_rtc_ioctl(unsigned int cmd, unsigned long arg)
++{
++	switch (cmd) {
++	case RTC_AIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		RTSR &= ~RTSR_ALE;
++//		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_AIE_ON:
++		spin_lock_irq(&rtc_lock);
++		RTSR |= RTSR_ALE;
++//		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_UIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		RTSR &= ~RTSR_HZE;
++//		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_UIE_ON:
++		spin_lock_irq(&rtc_lock);
++		RTSR |= RTSR_HZE;
++//		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++#if 0
++	case RTC_PIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		OIER &= ~OIER_E1;
++//		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_PIE_ON:
++		if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
++			return -EACCES;
++		spin_lock_irq(&rtc_lock);
++		OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
++		OIER |= OIER_E1;
++//		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_IRQP_READ:
++		return put_user(rtc_freq, (unsigned long *)arg);
++	case RTC_IRQP_SET:
++		if (arg < 1 || arg > TIMER_FREQ)
++			        return -EINVAL;
++		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
++			        return -EACCES;
++		rtc_freq = arg;
++		return 0;
++#endif
++	}
++	return -EINVAL;
++}
++
++static void sa1100_rtc_read_time(struct rtc_time *tm)
++{
++	rtc_time_to_tm(RCNR, tm);
++}
++
++static int sa1100_rtc_set_time(struct rtc_time *tm)
++{
++	unsigned long time;
++	int ret;
++
++	ret = rtc_tm_to_time(tm, &time);
++	if (ret == 0)
++		RCNR = time;
++	return ret;
++}
++
++static void sa1100_rtc_read_alarm(struct rtc_wkalrm *alrm)
++{
++	memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
++	alrm->pending = RTSR & RTSR_AL ? 1 : 0;
++}
++
++static int sa1100_rtc_set_alarm(struct rtc_wkalrm *alrm)
++{
++	int ret;
++
++	spin_lock_irq(&rtc_lock);
++	ret = rtc_update_alarm(&alrm->time);
++	if (ret == 0) {
++		memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
++
++		if (alrm->enabled)
++			enable_irq_wake(IRQ_RTCAlrm);
++		else
++			disable_irq_wake(IRQ_RTCAlrm);
++	}
++	spin_unlock_irq(&rtc_lock);
++
++	return ret;
++}
++
++static int sa1100_rtc_proc(char *buf)
++{
++	char *p = buf;
++
++	p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR);
++	p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" );
++	p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no");
++	p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no");
++	p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq);
++
++	return p - buf;
++}
++
++static struct rtc_ops sa1100_rtc_ops = {
++	.owner		= THIS_MODULE,
++	.open		= sa1100_rtc_open,
++	.release	= sa1100_rtc_release,
++	.ioctl		= sa1100_rtc_ioctl,
++
++	.read_time	= sa1100_rtc_read_time,
++	.set_time	= sa1100_rtc_set_time,
++	.read_alarm	= sa1100_rtc_read_alarm,
++	.set_alarm	= sa1100_rtc_set_alarm,
++	.proc		= sa1100_rtc_proc,
++};
++
++static int __init rtc_init(void)
++{
++	/*
++	 * According to the manual we should be able to let RTTR be zero
++	 * and then a default diviser for a 32.768KHz clock is used.
++	 * Apparently this doesn't work, at least for my SA1110 rev 5.
++	 * If the clock divider is uninitialized then reset it to the
++	 * default value to get the 1Hz clock.
++	 */
++	if (RTTR == 0) {
++		RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
++		printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
++		/*  The current RTC value probably doesn't make sense either */
++		RCNR = 0;
++	}
++
++	register_rtc(&sa1100_rtc_ops);
++
++	return 0;
++}
++
++static void __exit rtc_exit(void)
++{
++	unregister_rtc(&sa1100_rtc_ops);
++}
++
++module_init(rtc_init);
++module_exit(rtc_exit);
++
++MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>");
++MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)");
++MODULE_LICENSE("GPL");		/* so says the header */
+--- linux-2.6.5/drivers/char/Kconfig~heh	2004-04-03 22:36:15.000000000 -0500
++++ linux-2.6.5/drivers/char/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -814,6 +814,10 @@
+ 
+ 	  If unsure, say N.
+ 
++config SA1100_RTC
++	tristate "SA1100 or PXA Real Time Clock"
++	depends on ARCH_SA1100 || ARCH_PXA
++
+ config DTLK
+ 	tristate "Double Talk PC internal speech card support"
+ 	help
+--- linux-2.6.5/drivers/char/tty_io.c~heh	2004-04-03 22:37:23.000000000 -0500
++++ linux-2.6.5/drivers/char/tty_io.c	2004-04-30 20:57:36.000000000 -0400
+@@ -1535,10 +1535,17 @@
+ 	return 0;
+ }
+ 
++/*
++ * In the case of pty's, "tty" is the master side
++ * and "real_tty" is the slave side.
++ */
+ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
+ 	struct winsize * arg)
+ {
+ 	struct winsize tmp_ws;
++	struct task_struct *p;
++	struct list_head *l;
++	struct pid *pid;
+ 
+ 	if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
+ 		return -EFAULT;
+@@ -1558,8 +1565,21 @@
+ #endif
+ 	if (tty->pgrp > 0)
+ 		kill_pg(tty->pgrp, SIGWINCH, 1);
+-	if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))
+-		kill_pg(real_tty->pgrp, SIGWINCH, 1);
++
++	/*
++	 * Send SIGWINCH to the whole session on the slave tty.
++	 * However, in the case of non-master pty's, be careful
++	 * not to send two SIGWINCH to the same procress group.
++	 */
++	if (real_tty->session > 0) {
++		read_lock(&tasklist_lock);
++		for_each_task_pid(real_tty->session, PIDTYPE_SID, p, l, pid) {
++			if (process_group(p) != tty->pgrp)
++				group_send_sig_info(SIGWINCH, (void *)1L, p);
++		}
++		read_unlock(&tasklist_lock);
++	}
++
+ 	tty->winsize = tmp_ws;
+ 	real_tty->winsize = tmp_ws;
+ 	return 0;
+--- linux-2.6.5/drivers/Makefile~heh	2004-04-03 22:37:43.000000000 -0500
++++ linux-2.6.5/drivers/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -11,6 +11,8 @@
+ # PnP must come after ACPI since it will eventually need to check if acpi
+ # was used and do nothing if so
+ obj-$(CONFIG_PNP)		+= pnp/
++obj-$(CONFIG_I2C)		+= i2c/
++obj-$(CONFIG_L3)		+= l3/
+ 
+ # char/ comes before serial/ etc so that the VT console is the boot-time
+ # default.
+@@ -41,7 +43,6 @@
+ obj-$(CONFIG_GAMEPORT)		+= input/gameport/
+ obj-$(CONFIG_SERIO)		+= input/serio/
+ obj-$(CONFIG_I2O)		+= message/
+-obj-$(CONFIG_I2C)		+= i2c/
+ obj-$(CONFIG_PHONE)		+= telephony/
+ obj-$(CONFIG_MD)		+= md/
+ obj-$(CONFIG_BT)		+= bluetooth/
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/l3/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,24 @@
++#
++# L3 bus configuration
++#
++
++menu "L3 serial bus support"
++
++config L3
++	tristate "L3 support"
++
++config L3_ALGOBIT
++	bool "L3 bit-banging interfaces"
++	depends on L3=y
++
++config L3_BIT_SA1100_GPIO
++	bool "SA11x0 GPIO adapter"
++	depends on L3_ALGOBIT && ARCH_SA1100
++
++# i2c must come before this
++config BIT_SA1100_GPIO
++	bool
++	depends on L3_BIT_SA1100_GPIO || I2C_BIT_SA1100_GPIO=y
++	default y
++
++endmenu
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/l3/l3-core.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,203 @@
++/*
++ *  linux/drivers/l3/l3-core.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ *  General structure taken from i2c-core.c by Simon G. Vogl
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  See linux/Documentation/l3 for further documentation.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/kmod.h>
++#include <linux/init.h>
++#include <linux/l3/l3.h>
++
++static DECLARE_MUTEX(adapter_lock);
++static LIST_HEAD(adapter_list);
++
++static DECLARE_MUTEX(driver_lock);
++static LIST_HEAD(driver_list);
++
++/**
++ * l3_add_adapter - register a new L3 bus adapter
++ * @adap: l3_adapter structure for the registering adapter
++ *
++ * Make the adapter available for use by clients using name adap->name.
++ * The adap->adapters list is initialised by this function.
++ *
++ * Returns 0;
++ */
++int l3_add_adapter(struct l3_adapter *adap)
++{
++	down(&adapter_lock);
++	list_add(&adap->adapters, &adapter_list);
++	up(&adapter_lock);
++	return 0;	
++}
++
++/**
++ * l3_del_adapter - unregister a L3 bus adapter
++ * @adap: l3_adapter structure to unregister
++ *
++ * Remove an adapter from the list of available L3 Bus adapters.
++ *
++ * Returns 0;
++ */
++int l3_del_adapter(struct l3_adapter *adap)
++{
++	down(&adapter_lock);
++	list_del(&adap->adapters);
++	up(&adapter_lock);
++	return 0;
++}
++
++static struct l3_adapter *__l3_get_adapter(const char *name)
++{
++	struct list_head *l;
++
++	list_for_each(l, &adapter_list) {
++		struct l3_adapter *adap = list_entry(l, struct l3_adapter, adapters);
++
++		if (strcmp(adap->name, name) == 0)
++			return adap;
++	}
++
++	return NULL;
++}
++
++/**
++ * l3_get_adapter - get a reference to an adapter
++ * @name: driver name
++ *
++ * Obtain a l3_adapter structure for the specified adapter.  If the adapter
++ * is not currently load, then load it.  The adapter will be locked in core
++ * until all references are released via l3_put_adapter.
++ */
++struct l3_adapter *l3_get_adapter(const char *name)
++{
++	struct l3_adapter *adap;
++	int try;
++
++	for (try = 0; try < 2; try ++) {
++		down(&adapter_lock);
++		adap = __l3_get_adapter(name);
++		if (adap && !try_module_get(adap->owner))
++			adap = NULL;
++		up(&adapter_lock);
++
++		if (adap)
++			break;
++
++		if (try == 0)
++			request_module(name);
++	}
++
++	return adap;
++}
++
++/**
++ * l3_put_adapter - release a reference to an adapter
++ * @adap: driver to release reference
++ *
++ * Indicate to the L3 core that you no longer require the adapter reference.
++ * The adapter module may be unloaded when there are no references to its
++ * data structure.
++ *
++ * You must not use the reference after calling this function.
++ */
++void l3_put_adapter(struct l3_adapter *adap)
++{
++	if (adap && adap->owner)
++		module_put(adap->owner);
++}
++
++/**
++ * l3_transfer - transfer information on an L3 bus
++ * @adap: adapter structure to perform transfer on
++ * @msgs: array of l3_msg structures describing transfer
++ * @num: number of l3_msg structures
++ *
++ * Transfer the specified messages to/from a device on the L3 bus.
++ *
++ * Returns number of messages successfully transferred, otherwise negative
++ * error code.
++ */
++int l3_transfer(struct l3_adapter *adap, struct l3_msg msgs[], int num)
++{
++	int ret = -ENOSYS;
++
++	if (adap->algo->xfer) {
++		down(adap->lock);
++		ret = adap->algo->xfer(adap, msgs, num);
++		up(adap->lock);
++	}
++	return ret;
++}
++
++/**
++ * l3_write - send data to a device on an L3 bus
++ * @adap: L3 bus adapter
++ * @addr: L3 bus address
++ * @buf: buffer for bytes to send
++ * @len: number of bytes to send
++ *
++ * Send len bytes pointed to by buf to device address addr on the L3 bus
++ * described by client.
++ *
++ * Returns the number of bytes transferred, or negative error code.
++ */
++int l3_write(struct l3_adapter *adap, int addr, const char *buf, int len)
++{
++	struct l3_msg msg;
++	int ret;
++
++	msg.addr = addr;
++	msg.flags = 0;
++	msg.buf = (char *)buf;
++	msg.len = len;
++
++	ret = l3_transfer(adap, &msg, 1);
++	return ret == 1 ? len : ret;
++}
++
++/**
++ * l3_read - receive data from a device on an L3 bus
++ * @adap: L3 bus adapter
++ * @addr: L3 bus address
++ * @buf: buffer for bytes to receive
++ * @len: number of bytes to receive
++ *
++ * Receive len bytes from device address addr on the L3 bus described by
++ * client to a buffer pointed to by buf.
++ *
++ * Returns the number of bytes transferred, or negative error code.
++ */
++int l3_read(struct l3_adapter *adap, int addr, char *buf, int len)
++{
++	struct l3_msg msg;
++	int ret;
++
++	msg.addr = addr;
++	msg.flags = L3_M_RD;
++	msg.buf = buf;
++	msg.len = len;
++
++	ret = l3_transfer(adap, &msg, 1);
++	return ret == 1 ? len : ret;
++}
++
++EXPORT_SYMBOL(l3_add_adapter);
++EXPORT_SYMBOL(l3_del_adapter);
++EXPORT_SYMBOL(l3_get_adapter);
++EXPORT_SYMBOL(l3_put_adapter);
++EXPORT_SYMBOL(l3_transfer);
++EXPORT_SYMBOL(l3_write);
++EXPORT_SYMBOL(l3_read);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/l3/l3-algo-bit.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,175 @@
++/*
++ * L3 bus algorithm module.
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Note that L3 buses can share the same pins as I2C buses, so we must
++ *  _not_ generate an I2C start condition.  An I2C start condition is
++ *  defined as a high-to-low transition of the data line while the clock
++ *  is high.  Therefore, we must only change the data line while the
++ *  clock is low.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/l3/l3.h>
++#include <linux/l3/algo-bit.h>
++
++#define setdat(adap,val)	adap->setdat(adap->data, val)
++#define setclk(adap,val)	adap->setclk(adap->data, val)
++#define setmode(adap,val)	adap->setmode(adap->data, val)
++#define setdatin(adap)		adap->setdir(adap->data, 1)
++#define setdatout(adap)		adap->setdir(adap->data, 0)
++#define getdat(adap)		adap->getdat(adap->data)
++
++/*
++ * Send one byte of data to the chip.  Data is latched into the chip on
++ * the rising edge of the clock.
++ */
++static void sendbyte(struct l3_algo_bit_data *adap, unsigned int byte)
++{
++	int i;
++
++	for (i = 0; i < 8; i++) {
++		setclk(adap, 0);
++		udelay(adap->data_hold);
++		setdat(adap, byte & 1);
++		udelay(adap->data_setup);
++		setclk(adap, 1);
++		udelay(adap->clock_high);
++		byte >>= 1;
++	}
++}
++
++/*
++ * Send a set of bytes to the chip.  We need to pulse the MODE line
++ * between each byte, but never at the start nor at the end of the
++ * transfer.
++ */
++static void sendbytes(struct l3_algo_bit_data *adap, const char *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++) {
++		if (i) {
++			udelay(adap->mode_hold);
++			setmode(adap, 0);
++			udelay(adap->mode);
++		}
++		setmode(adap, 1);
++		udelay(adap->mode_setup);
++		sendbyte(adap, buf[i]);
++	}
++}
++
++/*
++ * Read one byte of data from the chip.  Data is latched into the chip on
++ * the rising edge of the clock.
++ */
++static unsigned int readbyte(struct l3_algo_bit_data *adap)
++{
++	unsigned int byte = 0;
++	int i;
++
++	for (i = 0; i < 8; i++) {
++		setclk(adap, 0);
++		udelay(adap->data_hold + adap->data_setup);
++		setclk(adap, 1);
++		if (getdat(adap))
++			byte |= 1 << i;
++		udelay(adap->clock_high);
++	}
++
++	return byte;
++}
++
++/*
++ * Read a set of bytes from the chip.  We need to pulse the MODE line
++ * between each byte, but never at the start nor at the end of the
++ * transfer.
++ */
++static void readbytes(struct l3_algo_bit_data *adap, char *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++) {
++		if (i) {
++			udelay(adap->mode_hold);
++			setmode(adap, 0);
++		}
++		setmode(adap, 1);
++		udelay(adap->mode_setup);
++		buf[i] = readbyte(adap);
++	}
++}
++
++static int l3_xfer(struct l3_adapter *l3_adap, struct l3_msg msgs[], int num)
++{
++	struct l3_algo_bit_data *adap = l3_adap->algo_data;
++	int i;
++
++	/*
++	 * If we share an I2C bus, ensure that it is in STOP mode
++	 */
++	setclk(adap, 1);
++	setdat(adap, 1);
++	setmode(adap, 1);
++	setdatout(adap);
++	udelay(adap->mode);
++
++	for (i = 0; i < num; i++) {
++		struct l3_msg *pmsg = &msgs[i];
++
++		if (!(pmsg->flags & L3_M_NOADDR)) {
++			setmode(adap, 0);
++			udelay(adap->mode_setup);
++			sendbyte(adap, pmsg->addr);
++			udelay(adap->mode_hold);
++		}
++
++		if (pmsg->flags & L3_M_RD) {
++			setdatin(adap);
++			readbytes(adap, pmsg->buf, pmsg->len);
++		} else {
++			setdatout(adap);
++			sendbytes(adap, pmsg->buf, pmsg->len);
++		}
++	}
++
++	/*
++	 * Ensure that we leave the bus in I2C stop mode.
++	 */
++	setclk(adap, 1);
++	setdat(adap, 1);
++	setmode(adap, 0);
++	setdatin(adap);
++
++	return num;
++}
++
++static struct l3_algorithm l3_bit_algo = {
++	name:	"L3 bit-shift algorithm",
++	xfer:	l3_xfer,
++};
++
++int l3_bit_add_bus(struct l3_adapter *adap)
++{
++	adap->algo = &l3_bit_algo;
++	return l3_add_adapter(adap);
++}
++
++int l3_bit_del_bus(struct l3_adapter *adap)
++{
++	return l3_del_adapter(adap);
++}
++
++EXPORT_SYMBOL(l3_bit_add_bus);
++EXPORT_SYMBOL(l3_bit_del_bus);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/l3/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,11 @@
++#
++# Makefile for the L3 bus driver.
++#
++
++# Link order:
++#  (core, adapters, algorithms, drivers) then clients
++
++l3-$(CONFIG_L3_ALGOBIT)		+= l3-algo-bit.o
++l3-$(CONFIG_BIT_SA1100_GPIO)	+= l3-bit-sa1100.o
++
++obj-$(CONFIG_L3)		+= l3-core.o $(l3-y) $(l3-drv-y)
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/l3/l3-bit-sa1100.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,271 @@
++/*
++ *  linux/drivers/l3/l3-bit-sa1100.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  This is a combined I2C and L3 bus driver.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/i2c.h>
++#include <linux/i2c-algo-bit.h>
++#include <linux/l3/algo-bit.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/arch/assabet.h>
++
++#define NAME "l3-bit-sa1100-gpio"
++
++struct bit_data {
++	unsigned int	sda;
++	unsigned int	scl;
++	unsigned int	l3_mode;
++};
++
++static int getsda(void *data)
++{
++	struct bit_data *bits = data;
++
++	return GPLR & bits->sda;
++}
++
++#ifdef CONFIG_I2C_BIT_SA1100_GPIO
++static void i2c_setsda(void *data, int state)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (state)
++		GPDR &= ~bits->sda;
++	else {
++		GPCR = bits->sda;
++		GPDR |= bits->sda;
++	}
++	local_irq_restore(flags);
++}
++
++static void i2c_setscl(void *data, int state)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (state)
++		GPDR &= ~bits->scl;
++	else {
++		GPCR = bits->scl;
++		GPDR |= bits->scl;
++	}
++	local_irq_restore(flags);
++}
++
++static int i2c_getscl(void *data)
++{
++	struct bit_data *bits = data;
++
++	return GPLR & bits->scl;
++}
++
++static struct i2c_algo_bit_data i2c_bit_data = {
++	.setsda		= i2c_setsda,
++	.setscl		= i2c_setscl,
++	.getsda		= getsda,
++	.getscl		= i2c_getscl,
++	.udelay		= 10,
++	.mdelay		= 10,
++	.timeout	= 100,
++};
++
++static struct i2c_adapter i2c_adapter = {
++	.algo_data	= &i2c_bit_data,
++};
++
++#define LOCK	&i2c_adapter.bus_lock
++
++static int __init i2c_init(struct bit_data *bits)
++{
++	i2c_bit_data.data = bits;
++	return i2c_bit_add_bus(&i2c_adapter);
++}
++
++static void i2c_exit(void)
++{
++	i2c_bit_del_bus(&i2c_adapter);
++}
++
++#else
++static DECLARE_MUTEX(l3_lock);
++#define LOCK		&l3_lock
++#define i2c_init(bits)	(0)
++#define i2c_exit()	do { } while (0)
++#endif
++
++#ifdef CONFIG_L3_BIT_SA1100_GPIO
++/*
++ * iPAQs need the clock line driven hard high and low.
++ */
++static void l3_setscl(void *data, int state)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (state)
++		GPSR = bits->scl;
++	else
++		GPCR = bits->scl;
++	GPDR |= bits->scl;
++	local_irq_restore(flags);
++}
++
++static void l3_setsda(void *data, int state)
++{
++	struct bit_data *bits = data;
++
++	if (state)
++		GPSR = bits->sda;
++	else
++		GPCR = bits->sda;
++}
++
++static void l3_setdir(void *data, int in)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (in)
++		GPDR &= ~bits->sda;
++	else
++		GPDR |= bits->sda;
++	local_irq_restore(flags);
++}
++
++static void l3_setmode(void *data, int state)
++{
++	struct bit_data *bits = data;
++
++	if (state)
++		GPSR = bits->l3_mode;
++	else
++		GPCR = bits->l3_mode;
++}
++
++static struct l3_algo_bit_data l3_bit_data = {
++	.data		= NULL,
++	.setdat		= l3_setsda,
++	.setclk		= l3_setscl,
++	.setmode	= l3_setmode,
++	.setdir		= l3_setdir,
++	.getdat		= getsda,
++	.data_hold	= 1,
++	.data_setup	= 1,
++	.clock_high	= 1,
++	.mode_hold	= 1,
++	.mode_setup	= 1,
++};
++
++static struct l3_adapter l3_adapter = {
++	.owner		= THIS_MODULE,
++	.name		= NAME,
++	.algo_data	= &l3_bit_data,
++	.lock		= LOCK,
++};
++
++static int __init l3_init(struct bit_data *bits)
++{
++	l3_bit_data.data = bits;
++	return l3_bit_add_bus(&l3_adapter);
++}
++
++static void __exit l3_exit(void)
++{
++	l3_bit_del_bus(&l3_adapter);
++}
++#else
++#define l3_init(bits)	(0)
++#define l3_exit()	do { } while (0)
++#endif
++
++static struct bit_data bit_data;
++
++static int __init bus_init(void)
++{
++	struct bit_data *bit = &bit_data;
++	unsigned long flags;
++	int ret;
++
++	if (machine_is_assabet() || machine_is_pangolin()) {
++		bit->sda     = GPIO_GPIO15;
++		bit->scl     = GPIO_GPIO18;
++		bit->l3_mode = GPIO_GPIO17;
++	}
++
++	if (machine_is_h3600() || machine_is_h3100()) {
++		bit->sda     = GPIO_GPIO14;
++		bit->scl     = GPIO_GPIO16;
++		bit->l3_mode = GPIO_GPIO15;
++	}
++
++	if (machine_is_stork()) {
++		bit->sda     = GPIO_GPIO15;
++		bit->scl     = GPIO_GPIO18;
++		bit->l3_mode = GPIO_GPIO17;
++	}
++
++	if (!bit->sda)
++		return -ENODEV;
++
++	/*
++	 * Default level for L3 mode is low.
++	 * We set SCL and SDA high (i2c idle state).
++	 */
++	local_irq_save(flags);
++	GPDR &= ~(bit->scl | bit->sda);
++	GPCR = bit->l3_mode | bit->scl | bit->sda;
++	GPDR |= bit->l3_mode;
++	local_irq_restore(flags);
++
++	if (machine_is_assabet()) {
++		/*
++		 * Release reset on UCB1300, ADI7171 and UDA1341.  We
++		 * need to do this here so that we can communicate on
++		 * the I2C/L3 buses.
++		 */
++		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
++		mdelay(1);
++		ASSABET_BCR_clear(ASSABET_BCR_CODEC_RST);
++		mdelay(1);
++		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
++	}
++
++	ret = i2c_init(bit);
++	if (ret == 0 && bit->l3_mode) {
++		ret = l3_init(bit);
++		if (ret)
++			i2c_exit();
++	}
++
++	return ret;
++}
++
++static void __exit bus_exit(void)
++{
++	l3_exit();
++	i2c_exit();
++}
++
++module_init(bus_init);
++module_exit(bus_exit);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/switches.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,22 @@
++/*
++ *  linux/drivers/misc/switches.h
++ *
++ *  Copyright (C) 2001 John Dorsey
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  19 December 2001 - created.
++ */
++
++#if !defined(_SWITCHES_H)
++# define _SWITCHES_H
++
++#include <linux/switches.h>
++
++#define SWITCHES_NAME "switches"
++
++extern int  switches_event(switches_mask_t *mask);
++
++#endif  /* !defined(_SWITCHES_H) */
+--- linux-2.6.5/drivers/misc/Kconfig~heh	2004-04-03 22:36:26.000000000 -0500
++++ linux-2.6.5/drivers/misc/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -21,5 +21,62 @@
+ 
+ 	  If unsure, say N.
+ 
++menu "Multimedia Capabilities Port drivers"
++
++config MCP
++	tristate "Multimedia drivers"
++
++# Interface drivers
++config MCP_SA1100
++	tristate "Support SA1100 MCP interface"
++	depends on MCP && ARCH_SA1100
++
++# Chip drivers
++config MCP_UCB1200
++	tristate "Support for UCB1200 / UCB1300"
++	depends on MCP
++
++config MCP_UCB1200_AUDIO
++	tristate "Audio / Telephony interface support"
++	depends on MCP_UCB1200 && SOUND
++
++config MCP_UCB1200_TS
++	tristate "Touchscreen interface support"
++	depends on MCP_UCB1200 && INPUT
++
++endmenu
++
++
++menu "Console Switches"
++
++config SWITCHES
++	tristate "Console Switch Support"
++	help
++	  Say Y here to include support for simple console momentary switches.
++	  This driver implements a miscellaneous character device (named
++	  `switches' in /proc/misc) which can be read by userland programs
++	  to respond to switch press events. This mechanism is efficient for
++	  systems which may not implement a traditional heavyweight console
++	  server.
++
++	  It is also possible to say M to build this driver as a module (named
++	  `switches.o').
++
++config SWITCHES_SA1100
++	tristate "SA-1100 switches"
++	depends on SWITCHES && ARCH_SA1100
++	help
++	  Say Y here to include support for switches routed directly to
++	  interruptable signals on StrongARM SA-1100 systems.
++
++config SWITCHES_UCB1X00
++	tristate "UCB1x00 switches"
++	depends on SWITCHES && MCP_UCB1200
++	help
++	  Say Y here to include support for switches routed through a
++	  UCB1x00 modem/audio analog front-end device.
++
++endmenu
++
+ endmenu
+ 
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/ucb1x00-assabet.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,73 @@
++/*
++ *  linux/drivers/misc/ucb1x00-assabet.c
++ *
++ *  Copyright (C) 2001-2003 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  We handle the machine-specific bits of the UCB1x00 driver here.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/proc_fs.h>
++#include <linux/device.h>
++
++#include <asm/dma.h>
++
++#include "ucb1x00.h"
++
++#define UCB1X00_ATTR(name,input)\
++static ssize_t name##_show(struct class_device *dev, char *buf)	\
++{								\
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);		\
++	int val;						\
++	ucb1x00_adc_enable(ucb);				\
++	val = ucb1x00_adc_read(ucb, input, UCB_NOSYNC);		\
++	ucb1x00_adc_disable(ucb);				\
++	return sprintf(buf, "%d\n", val);			\
++}								\
++static CLASS_DEVICE_ATTR(name,0444,name##_show,NULL)
++
++UCB1X00_ATTR(vbatt, UCB_ADC_INP_AD1);
++UCB1X00_ATTR(vcharger, UCB_ADC_INP_AD0);
++UCB1X00_ATTR(batt_temp, UCB_ADC_INP_AD2);
++
++static int ucb1x00_assabet_add(struct class_device *dev)
++{
++	class_device_create_file(dev, &class_device_attr_vbatt);
++	class_device_create_file(dev, &class_device_attr_vcharger);
++	class_device_create_file(dev, &class_device_attr_batt_temp);
++	return 0;
++}
++
++static void ucb1x00_assabet_remove(struct class_device *dev)
++{
++	class_device_remove_file(dev, &class_device_attr_batt_temp);
++	class_device_remove_file(dev, &class_device_attr_vcharger);
++	class_device_remove_file(dev, &class_device_attr_vbatt);
++}
++
++static struct class_interface ucb1x00_assabet_interface = {
++	.add	= ucb1x00_assabet_add,
++	.remove	= ucb1x00_assabet_remove,
++};
++
++static int __init ucb1x00_assabet_init(void)
++{
++	return ucb1x00_register_interface(&ucb1x00_assabet_interface);
++}
++
++static void __exit ucb1x00_assabet_exit(void)
++{
++	ucb1x00_unregister_interface(&ucb1x00_assabet_interface);
++}
++
++module_init(ucb1x00_assabet_init);
++module_exit(ucb1x00_assabet_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("Assabet noddy testing only example ADC driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/mcp-pxa.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,57 @@
++/*
++ *  linux/drivers/misc/mcp-pxa.c
++ *
++ *  2002-01-10 Jeff Sutherland <jeffs@accelent.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.
++ *
++ * NOTE: This is a quick hack to gain access to the aclink codec's
++ *       touch screen facility.  Its audio is handled by a separate
++ *       (non-mcp) driver at the present time.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/ac97_codec.h>
++
++#include "mcp.h"
++
++
++extern int pxa_ac97_get(struct ac97_codec **codec);
++extern void pxa_ac97_put(void);
++
++
++struct mcp *mcp_get(void)
++{
++	struct ac97_codec *codec;
++	if (pxa_ac97_get(&codec) < 0)
++		return NULL;
++	return (struct mcp *)codec;
++}
++
++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
++{
++	struct ac97_codec *codec = (struct ac97_codec *)mcp;
++	codec->codec_write(codec, reg, val);
++}
++
++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
++{
++	struct ac97_codec *codec = (struct ac97_codec *)mcp;
++	return codec->codec_read(codec, reg);
++}
++
++void mcp_enable(struct mcp *mcp)
++{
++	/* 
++	 * Should we do something here to make sure the aclink
++	 * codec is alive???
++	 * A: not for now  --NP
++	*/
++}
++
++void mcp_disable(struct mcp *mcp)
++{
++}
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/mcp-core.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,235 @@
++/*
++ *  linux/drivers/misc/mcp-core.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ * 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.
++ *
++ *  Generic MCP (Multimedia Communications Port) layer.  All MCP locking
++ *  is solely held within this file.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/smp.h>
++#include <linux/device.h>
++
++#include <asm/dma.h>
++#include <asm/system.h>
++
++#include "mcp.h"
++
++#define to_mcp(d)		container_of(d, struct mcp, attached_device)
++#define to_mcp_driver(d)	container_of(d, struct mcp_driver, drv)
++
++static int mcp_bus_match(struct device *dev, struct device_driver *drv)
++{
++	return 1;
++}
++
++static int mcp_bus_probe(struct device *dev)
++{
++	struct mcp *mcp = to_mcp(dev);
++	struct mcp_driver *drv = to_mcp_driver(dev->driver);
++
++	return drv->probe(mcp);
++}
++
++static int mcp_bus_remove(struct device *dev)
++{
++	struct mcp *mcp = to_mcp(dev);
++	struct mcp_driver *drv = to_mcp_driver(dev->driver);
++
++	drv->remove(mcp);
++	return 0;
++}
++
++static int mcp_bus_suspend(struct device *dev, u32 state)
++{
++	struct mcp *mcp = to_mcp(dev);
++	int ret = 0;
++
++	if (dev->driver) {
++		struct mcp_driver *drv = to_mcp_driver(dev->driver);
++
++		ret = drv->suspend(mcp, state);
++	}
++	return ret;
++}
++
++static int mcp_bus_resume(struct device *dev)
++{
++	struct mcp *mcp = to_mcp(dev);
++	int ret = 0;
++
++	if (dev->driver) {
++		struct mcp_driver *drv = to_mcp_driver(dev->driver);
++
++		ret = drv->resume(mcp);
++	}
++	return ret;
++}
++
++static struct bus_type mcp_bus_type = {
++	.name		= "mcp",
++	.match		= mcp_bus_match,
++	.suspend	= mcp_bus_suspend,
++	.resume		= mcp_bus_resume,
++};
++
++/**
++ *	mcp_set_telecom_divisor - set the telecom divisor
++ *	@mcp: MCP interface structure
++ *	@div: SIB clock divisor
++ *
++ *	Set the telecom divisor on the MCP interface.  The resulting
++ *	sample rate is SIBCLOCK/div.
++ */
++void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
++{
++	spin_lock_irq(&mcp->lock);
++	mcp->set_telecom_divisor(mcp, div);
++	spin_unlock_irq(&mcp->lock);
++}
++
++/**
++ *	mcp_set_audio_divisor - set the audio divisor
++ *	@mcp: MCP interface structure
++ *	@div: SIB clock divisor
++ *
++ *	Set the audio divisor on the MCP interface.
++ */
++void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
++{
++	spin_lock_irq(&mcp->lock);
++	mcp->set_audio_divisor(mcp, div);
++	spin_unlock_irq(&mcp->lock);
++}
++
++/**
++ *	mcp_reg_write - write a device register
++ *	@mcp: MCP interface structure
++ *	@reg: 4-bit register index
++ *	@val: 16-bit data value
++ *
++ *	Write a device register.  The MCP interface must be enabled
++ *	to prevent this function hanging.
++ */
++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&mcp->lock, flags);
++	mcp->reg_write(mcp, reg, val);
++	spin_unlock_irqrestore(&mcp->lock, flags);
++}
++
++/**
++ *	mcp_reg_read - read a device register
++ *	@mcp: MCP interface structure
++ *	@reg: 4-bit register index
++ *
++ *	Read a device register and return its value.  The MCP interface
++ *	must be enabled to prevent this function hanging.
++ */
++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
++{
++	unsigned long flags;
++	unsigned int val;
++
++	spin_lock_irqsave(&mcp->lock, flags);
++	val = mcp->reg_read(mcp, reg);
++	spin_unlock_irqrestore(&mcp->lock, flags);
++
++	return val;
++}
++
++/**
++ *	mcp_enable - enable the MCP interface
++ *	@mcp: MCP interface to enable
++ *
++ *	Enable the MCP interface.  Each call to mcp_enable will need
++ *	a corresponding call to mcp_disable to disable the interface.
++ */
++void mcp_enable(struct mcp *mcp)
++{
++	spin_lock_irq(&mcp->lock);
++	if (mcp->use_count++ == 0)
++		mcp->enable(mcp);
++	spin_unlock_irq(&mcp->lock);
++}
++
++/**
++ *	mcp_disable - disable the MCP interface
++ *	@mcp: MCP interface to disable
++ *
++ *	Disable the MCP interface.  The MCP interface will only be
++ *	disabled once the number of calls to mcp_enable matches the
++ *	number of calls to mcp_disable.
++ */
++void mcp_disable(struct mcp *mcp)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&mcp->lock, flags);
++	if (--mcp->use_count == 0)
++		mcp->disable(mcp);
++	spin_unlock_irqrestore(&mcp->lock, flags);
++}
++
++int mcp_host_register(struct mcp *mcp, struct device *parent)
++{
++	mcp->attached_device.parent = parent;
++	mcp->attached_device.bus = &mcp_bus_type;
++	mcp->attached_device.dma_mask = parent->dma_mask;
++	strcpy(mcp->attached_device.bus_id, "mcp0");
++	return device_register(&mcp->attached_device);
++}
++
++void mcp_host_unregister(struct mcp *mcp)
++{
++	device_unregister_wait(&mcp->attached_device);
++}
++
++int mcp_driver_register(struct mcp_driver *mcpdrv)
++{
++	mcpdrv->drv.bus = &mcp_bus_type;
++	mcpdrv->drv.probe = mcp_bus_probe;
++	mcpdrv->drv.remove = mcp_bus_remove;
++	return driver_register(&mcpdrv->drv);
++}
++
++void mcp_driver_unregister(struct mcp_driver *mcpdrv)
++{
++	driver_unregister(&mcpdrv->drv);
++}
++
++static int __init mcp_init(void)
++{
++	return bus_register(&mcp_bus_type);
++}
++
++static void __exit mcp_exit(void)
++{
++	bus_unregister(&mcp_bus_type);
++}
++
++module_init(mcp_init);
++module_exit(mcp_exit);
++
++EXPORT_SYMBOL(mcp_set_telecom_divisor);
++EXPORT_SYMBOL(mcp_set_audio_divisor);
++EXPORT_SYMBOL(mcp_reg_write);
++EXPORT_SYMBOL(mcp_reg_read);
++EXPORT_SYMBOL(mcp_enable);
++EXPORT_SYMBOL(mcp_disable);
++EXPORT_SYMBOL(mcp_host_register);
++EXPORT_SYMBOL(mcp_host_unregister);
++EXPORT_SYMBOL(mcp_driver_register);
++EXPORT_SYMBOL(mcp_driver_unregister);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("Core multimedia communications port driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/ucb1x00-ts.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,465 @@
++/*
++ *  linux/drivers/misc/ucb1x00-ts.c
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * 21-Jan-2002 <jco@ict.es> :
++ *
++ * Added support for synchronous A/D mode. This mode is useful to
++ * avoid noise induced in the touchpanel by the LCD, provided that
++ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
++ * It is important to note that the signal connected to the ADCSYNC
++ * pin should provide pulses even when the LCD is blanked, otherwise
++ * a pen touch needed to unblank the LCD will never be read.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/sched.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/input.h>
++#include <linux/device.h>
++#include <linux/slab.h>
++
++#include <asm/dma.h>
++#include <asm/semaphore.h>
++
++#include "ucb1x00.h"
++
++
++struct ucb1x00_ts {
++	struct input_dev	idev;
++	struct ucb1x00		*ucb;
++
++	struct semaphore	irq_wait;
++	struct semaphore	sem;
++	struct completion	init_exit;
++	struct task_struct	*rtask;
++	int			use_count;
++	u16			x_res;
++	u16			y_res;
++
++	int			restart:1;
++	int			adcsync:1;
++};
++
++static int adcsync = UCB_NOSYNC;
++
++static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
++{
++	input_report_abs(&ts->idev, ABS_X, x);
++	input_report_abs(&ts->idev, ABS_Y, y);
++	input_report_abs(&ts->idev, ABS_PRESSURE, pressure);
++	input_sync(&ts->idev);
++}
++
++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
++{
++	input_report_abs(&ts->idev, ABS_PRESSURE, 0);
++	input_sync(&ts->idev);
++}
++
++/*
++ * Switch to interrupt mode.
++ */
++static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
++{
++	if (ts->ucb->id == UCB_ID_1400_BUGGY)
++		ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++				UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++				UCB_TS_CR_MODE_INT);
++	else
++		ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++				UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++				UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++				UCB_TS_CR_MODE_INT);
++}
++
++/*
++ * Switch to pressure mode, and read pressure.  We don't need to wait
++ * here, since both plates are being driven.
++ */
++static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++
++	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
++}
++
++/*
++ * Switch to X position mode and measure Y plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++	udelay(55);
++
++	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
++}
++
++/*
++ * Switch to Y position mode and measure X plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++	udelay(55);
++
++	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
++}
++
++/*
++ * Switch to X plate resistance mode.  Set MX to ground, PX to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++/*
++ * Switch to Y plate resistance mode.  Set MY to ground, PY to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++/*
++ * This is a RT kernel thread that handles the ADC accesses
++ * (mainly so we can use semaphores in the UCB1200 core code
++ * to serialise accesses to the ADC, and in the UCB1400 case where
++ * any register access may sleep).
++ */
++static int ucb1x00_thread(void *_ts)
++{
++	struct ucb1x00_ts *ts = _ts;
++	struct task_struct *tsk = current;
++	int valid;
++
++	ts->rtask = tsk;
++
++	daemonize("ktsd");
++	/* only want to receive SIGKILL */
++	allow_signal(SIGKILL);
++
++	/*
++	 * We could run as a real-time thread.  However, thus far
++	 * this doesn't seem to be necessary.
++	 */
++//	tsk->policy = SCHED_FIFO;
++//	tsk->rt_priority = 1;
++
++	complete(&ts->init_exit);
++
++	valid = 0;
++
++	for (;;) {
++		unsigned int x, y, p, val;
++
++		ts->restart = 0;
++
++		ucb1x00_adc_enable(ts->ucb);
++
++		x = ucb1x00_ts_read_xpos(ts);
++		y = ucb1x00_ts_read_ypos(ts);
++		p = ucb1x00_ts_read_pressure(ts);
++
++		/*
++		 * Switch back to interrupt mode.
++		 */
++		ucb1x00_ts_mode_int(ts);
++		ucb1x00_adc_disable(ts->ucb);
++
++		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
++		schedule_timeout(HZ / 100);
++		if (signal_pending(tsk))
++			break;
++
++		ucb1x00_enable(ts->ucb);
++		val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
++
++		if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) {
++			ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
++			ucb1x00_disable(ts->ucb);
++
++			/*
++			 * If we spat out a valid sample set last time,
++			 * spit out a "pen off" sample here.
++			 */
++			if (valid) {
++				ucb1x00_ts_event_release(ts);
++				valid = 0;
++			}
++
++			/*
++			 * Since ucb1x00_enable_irq() might sleep due
++			 * to the way the UCB1400 regs are accessed, we
++			 * can't use set_task_state() before that call,
++			 * and not changing state before enabling the
++			 * interrupt is racy.  A semaphore solves all
++			 * those issues quite nicely.
++			 */
++			down_interruptible(&ts->irq_wait);
++		} else {
++			ucb1x00_disable(ts->ucb);
++
++			/*
++			 * Filtering is policy.  Policy belongs in user
++			 * space.  We therefore leave it to user space
++			 * to do any filtering they please.
++			 */
++			if (!ts->restart) {
++				ucb1x00_ts_evt_add(ts, p, x, y);
++				valid = 1;
++			}
++
++			set_task_state(tsk, TASK_INTERRUPTIBLE);
++		}
++
++		schedule_timeout(HZ / 100);
++		if (signal_pending(tsk))
++			break;
++	}
++
++	ts->rtask = NULL;
++	complete_and_exit(&ts->init_exit, 0);
++}
++
++/*
++ * We only detect touch screen _touches_ with this interrupt
++ * handler, and even then we just schedule our task.
++ */
++static void ucb1x00_ts_irq(int idx, void *id)
++{
++	struct ucb1x00_ts *ts = id;
++	ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
++	up(&ts->irq_wait);
++}
++
++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
++{
++	input_report_abs(&ts->idev, ABS_PRESSURE, 0);
++}
++
++static int ucb1x00_ts_open(struct input_dev *idev)
++{
++	struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
++	int ret = 0;
++
++	if (down_interruptible(&ts->sem))
++		return -EINTR;
++
++	if (ts->use_count++ != 0)
++		goto out;
++
++	if (ts->rtask)
++		panic("ucb1x00: rtask running?");
++
++	sema_init(&ts->irq_wait, 0);
++	ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
++	if (ret < 0)
++		goto out;
++
++	/*
++	 * If we do this at all, we should allow the user to
++	 * measure and read the X and Y resistance at any time.
++	 */
++	ucb1x00_adc_enable(ts->ucb);
++	ts->x_res = ucb1x00_ts_read_xres(ts);
++	ts->y_res = ucb1x00_ts_read_yres(ts);
++	ucb1x00_adc_disable(ts->ucb);
++
++	init_completion(&ts->init_exit);
++	ret = kernel_thread(ucb1x00_thread, ts, CLONE_KERNEL);
++	if (ret >= 0) {
++		wait_for_completion(&ts->init_exit);
++		ret = 0;
++	} else {
++		ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++	}
++
++ out:
++	if (ret)
++		ts->use_count--;
++	up(&ts->sem);
++	return ret;
++}
++
++/*
++ * Release touchscreen resources.  Disable IRQs.
++ */
++static void ucb1x00_ts_close(struct input_dev *idev)
++{
++	struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
++
++	down(&ts->sem);
++	if (--ts->use_count == 0) {
++		if (ts->rtask) {
++			send_sig(SIGKILL, ts->rtask, 1);
++			wait_for_completion(&ts->init_exit);
++		}
++
++		ucb1x00_enable(ts->ucb);
++		ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++		ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
++		ucb1x00_disable(ts->ucb);
++	}
++	up(&ts->sem);
++}
++
++#if 0
++static int ucb1x00_ts_resume(struct device *_dev, u32 level)
++{
++	struct ucb1x00_device *dev = ucb1x00_dev(_dev);
++	struct ucb1x00_ts *ts = ucb1x00_get_drvdata(dev);
++
++	if (level == RESUME_ENABLE && ts->rtask != NULL) {
++		/*
++		 * Restart the TS thread to ensure the
++		 * TS interrupt mode is set up again
++		 * after sleep.
++		 */
++		ts->restart = 1;
++		up(&ts->irq_wait);
++	}
++	return 0;
++}
++#endif
++
++
++/*
++ * Initialisation.
++ */
++static int ucb1x00_ts_add(struct class_device *dev)
++{
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
++	struct ucb1x00_ts *ts;
++
++	ts = kmalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
++	if (!ts)
++		return -ENOMEM;
++
++	memset(ts, 0, sizeof(struct ucb1x00_ts));
++
++	ts->ucb = ucb;
++	ts->adcsync = adcsync;
++	init_MUTEX(&ts->sem);
++
++	ts->idev.name       = "Touchscreen panel";
++	ts->idev.id.product = ts->ucb->id;
++	ts->idev.open       = ucb1x00_ts_open;
++	ts->idev.close      = ucb1x00_ts_close;
++
++	__set_bit(EV_ABS, ts->idev.evbit);
++	__set_bit(ABS_X, ts->idev.absbit);
++	__set_bit(ABS_Y, ts->idev.absbit);
++	__set_bit(ABS_PRESSURE, ts->idev.absbit);
++
++	input_register_device(&ts->idev);
++
++	ucb->ts_data = ts;
++
++	return 0;
++}
++
++static void ucb1x00_ts_remove(struct class_device *dev)
++{
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
++	struct ucb1x00_ts *ts = ucb->ts_data;
++
++	input_unregister_device(&ts->idev);
++	kfree(ts);
++}
++
++static struct class_interface ucb1x00_ts_interface = {
++	.add		= ucb1x00_ts_add,
++	.remove		= ucb1x00_ts_remove,
++};
++
++static int __init ucb1x00_ts_init(void)
++{
++	return ucb1x00_register_interface(&ucb1x00_ts_interface);
++}
++
++static void __exit ucb1x00_ts_exit(void)
++{
++	ucb1x00_unregister_interface(&ucb1x00_ts_interface);
++}
++
++#ifndef MODULE
++
++/*
++ * Parse kernel command-line options.
++ *
++ * syntax : ucbts=[sync|nosync],...
++ */
++static int __init ucb1x00_ts_setup(char *str)
++{
++	char *p;
++
++	while ((p = strsep(&str, ",")) != NULL) {
++		if (strcmp(p, "sync") == 0)
++			adcsync = UCB_SYNC;
++	}
++
++	return 1;
++}
++
++__setup("ucbts=", ucb1x00_ts_setup);
++
++#else
++
++MODULE_PARM(adcsync, "i");
++MODULE_PARM_DESC(adcsync, "Enable use of ADCSYNC signal");
++
++#endif
++
++module_init(ucb1x00_ts_init);
++module_exit(ucb1x00_ts_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/ucb1x00-core.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,624 @@
++/*
++ *  linux/drivers/misc/ucb1x00-core.c
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  The UCB1x00 core driver provides basic services for handling IO,
++ *  the ADC, interrupts, and accessing registers.  It is designed
++ *  such that everything goes through this layer, thereby providing
++ *  a consistent locking methodology, as well as allowing the drivers
++ *  to be used on other non-MCP-enabled hardware platforms.
++ *
++ *  Note that all locks are private to this file.  Nothing else may
++ *  touch them.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include "ucb1x00.h"
++
++/**
++ *	ucb1x00_io_set_dir - set IO direction
++ *	@ucb: UCB1x00 structure describing chip
++ *	@in:  bitfield of IO pins to be set as inputs
++ *	@out: bitfield of IO pins to be set as outputs
++ *
++ *	Set the IO direction of the ten general purpose IO pins on
++ *	the UCB1x00 chip.  The @in bitfield has priority over the
++ *	@out bitfield, in that if you specify a pin as both input
++ *	and output, it will end up as an input.
++ *
++ *	ucb1x00_enable must have been called to enable the comms
++ *	before using this function.
++ *
++ *	This function takes a spinlock, disabling interrupts.
++ */
++void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&ucb->io_lock, flags);
++	ucb->io_dir |= out;
++	ucb->io_dir &= ~in;
++
++	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
++	spin_unlock_irqrestore(&ucb->io_lock, flags);
++}
++
++/**
++ *	ucb1x00_io_write - set or clear IO outputs
++ *	@ucb:   UCB1x00 structure describing chip
++ *	@set:   bitfield of IO pins to set to logic '1'
++ *	@clear: bitfield of IO pins to set to logic '0'
++ *
++ *	Set the IO output state of the specified IO pins.  The value
++ *	is retained if the pins are subsequently configured as inputs.
++ *	The @clear bitfield has priority over the @set bitfield -
++ *	outputs will be cleared.
++ *
++ *	ucb1x00_enable must have been called to enable the comms
++ *	before using this function.
++ *
++ *	This function takes a spinlock, disabling interrupts.
++ */
++void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&ucb->io_lock, flags);
++	ucb->io_out |= set;
++	ucb->io_out &= ~clear;
++
++	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
++	spin_unlock_irqrestore(&ucb->io_lock, flags);
++}
++
++/**
++ *	ucb1x00_io_read - read the current state of the IO pins
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Return a bitfield describing the logic state of the ten
++ *	general purpose IO pins.
++ *
++ *	ucb1x00_enable must have been called to enable the comms
++ *	before using this function.
++ *
++ *	This function does not take any semaphores or spinlocks.
++ */
++unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
++{
++	return ucb1x00_reg_read(ucb, UCB_IO_DATA);
++}
++
++/*
++ * UCB1300 data sheet says we must:
++ *  1. enable ADC	=> 5us (including reference startup time)
++ *  2. select input	=> 51*tsibclk  => 4.3us
++ *  3. start conversion	=> 102*tsibclk => 8.5us
++ * (tsibclk = 1/11981000)
++ * Period between SIB 128-bit frames = 10.7us
++ */
++
++/**
++ *	ucb1x00_adc_enable - enable the ADC converter
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Enable the ucb1x00 and ADC converter on the UCB1x00 for use.
++ *	Any code wishing to use the ADC converter must call this
++ *	function prior to using it.
++ *
++ *	This function takes the ADC semaphore to prevent two or more
++ *	concurrent uses, and therefore may sleep.  As a result, it
++ *	can only be called from process context, not interrupt
++ *	context.
++ *
++ *	You should release the ADC as soon as possible using
++ *	ucb1x00_adc_disable.
++ */
++void ucb1x00_adc_enable(struct ucb1x00 *ucb)
++{
++	down(&ucb->adc_sem);
++
++	ucb->adc_cr |= UCB_ADC_ENA;
++
++	ucb1x00_enable(ucb);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
++}
++
++/**
++ *	ucb1x00_adc_read - read the specified ADC channel
++ *	@ucb: UCB1x00 structure describing chip
++ *	@adc_channel: ADC channel mask
++ *	@sync: wait for syncronisation pulse.
++ *
++ *	Start an ADC conversion and wait for the result.  Note that
++ *	synchronised ADC conversions (via the ADCSYNC pin) must wait
++ *	until the trigger is asserted and the conversion is finished.
++ *
++ *	This function currently spins waiting for the conversion to
++ *	complete (2 frames max without sync).
++ *
++ *	If called for a synchronised ADC conversion, it may sleep
++ *	with the ADC semaphore held.
++ *	
++ *	See ucb1x00.h for definition of the UCB_ADC_DAT macro.  It
++ *	addresses a bug in the ucb1200/1300 which, of course, Philips
++ *	decided to finally fix in the ucb1400 ;-) -jws
++ */
++unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
++{
++	unsigned int val;
++
++	if (sync)
++		adc_channel |= UCB_ADC_SYNC_ENA;
++
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START);
++
++	for (;;) {
++		val = ucb1x00_reg_read(ucb, UCB_ADC_DATA);
++		if (val & UCB_ADC_DAT_VAL)
++			break;
++		/* yield to other processes */
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++
++	return UCB_ADC_DAT(val);
++}
++
++/**
++ *	ucb1x00_adc_disable - disable the ADC converter
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Disable the ADC converter and release the ADC semaphore.
++ */
++void ucb1x00_adc_disable(struct ucb1x00 *ucb)
++{
++	ucb->adc_cr &= ~UCB_ADC_ENA;
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
++	ucb1x00_disable(ucb);
++
++	up(&ucb->adc_sem);
++}
++
++/*
++ * UCB1x00 Interrupt handling.
++ *
++ * The UCB1x00 can generate interrupts when the SIBCLK is stopped.
++ * Since we need to read an internal register, we must re-enable
++ * SIBCLK to talk to the chip.  We leave the clock running until
++ * we have finished processing all interrupts from the chip.
++ *
++ * A restriction with interrupts exists when using the ucb1400, as
++ * the codec read/write routines may sleep while waiting for codec
++ * access completion and uses semaphores for access control to the
++ * AC97 bus.  A complete codec read cycle could take  anywhere from
++ * 60 to 100uSec so we *definitely* don't want to spin inside the
++ * interrupt handler waiting for codec access.  So, we handle the
++ * interrupt by scheduling a RT kernel thread to run in process
++ * context instead of interrupt context.
++ */
++
++static int ucb1x00_thread(void *_ucb)
++{
++	struct task_struct *tsk = current;
++	DECLARE_WAITQUEUE(wait, tsk);
++	struct ucb1x00 *ucb = _ucb;
++	struct ucb1x00_irq *irq;
++	unsigned int isr, i;
++
++	ucb->rtask = tsk;
++
++	daemonize();
++	reparent_to_init();
++	tsk->tty = NULL;
++	tsk->policy = SCHED_FIFO;
++	tsk->rt_priority = 1;
++	strcpy(tsk->comm, "kUCB1x00d");
++
++	/* only want to receive SIGKILL */
++	spin_lock_irq(&tsk->sigmask_lock);
++	siginitsetinv(&tsk->blocked, sigmask(SIGKILL));
++	recalc_sigpending();
++	spin_unlock_irq(&tsk->sigmask_lock);
++
++	add_wait_queue(&ucb->irq_wait, &wait);
++	set_task_state(tsk, TASK_INTERRUPTIBLE);
++	complete(&ucb->complete);
++
++	for (;;) {
++		if (signal_pending(tsk))
++			break;
++		enable_irq(ucb->irq);
++		schedule();
++
++		ucb1x00_enable(ucb);
++		isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++		for (i = 0, irq = ucb->irq_handler;
++		     i < 16 && isr; 
++		     i++, isr >>= 1, irq++)
++			if (isr & 1 && irq->fn)
++				irq->fn(i, irq->devid);
++		ucb1x00_disable(ucb);
++
++		set_task_state(tsk, TASK_INTERRUPTIBLE);
++	}
++
++	remove_wait_queue(&ucb->irq_wait, &wait);
++	ucb->rtask = NULL;
++	complete_and_exit(&ucb->complete, 0);
++}
++
++static irqreturn_t ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
++{
++	struct ucb1x00 *ucb = devid;
++	disable_irq(irqnr);
++	wake_up(&ucb->irq_wait);
++	return IRQ_HANDLED;
++}
++
++/**
++ *	ucb1x00_hook_irq - hook a UCB1x00 interrupt
++ *	@ucb:   UCB1x00 structure describing chip
++ *	@idx:   interrupt index
++ *	@fn:    function to call when interrupt is triggered
++ *	@devid: device id to pass to interrupt handler
++ *
++ *	Hook the specified interrupt.  You can only register one handler
++ *	for each interrupt source.  The interrupt source is not enabled
++ *	by this function; use ucb1x00_enable_irq instead.
++ *
++ *	Interrupt handlers will be called with other interrupts enabled.
++ *
++ *	Returns zero on success, or one of the following errors:
++ *	 -EINVAL if the interrupt index is invalid
++ *	 -EBUSY if the interrupt has already been hooked
++ */
++int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
++{
++	struct ucb1x00_irq *irq;
++	int ret = -EINVAL;
++
++	if (idx < 16) {
++		irq = ucb->irq_handler + idx;
++		ret = -EBUSY;
++
++		spin_lock_irq(&ucb->lock);
++		if (irq->fn == NULL) {
++			irq->devid = devid;
++			irq->fn = fn;
++			ret = 0;
++		}
++		spin_unlock_irq(&ucb->lock);
++	}
++	return ret;
++}
++
++/**
++ *	ucb1x00_enable_irq - enable an UCB1x00 interrupt source
++ *	@ucb: UCB1x00 structure describing chip
++ *	@idx: interrupt index
++ *	@edges: interrupt edges to enable
++ *
++ *	Enable the specified interrupt to trigger on %UCB_RISING,
++ *	%UCB_FALLING or both edges.  The interrupt should have been
++ *	hooked by ucb1x00_hook_irq.
++ */
++void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
++{
++	unsigned long flags;
++
++	if (idx < 16) {
++		spin_lock_irqsave(&ucb->lock, flags);
++
++		ucb1x00_enable(ucb);
++
++		/* This prevents spurious interrupts on the UCB1400 */
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 1 << idx);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++		if (edges & UCB_RISING) {
++			ucb->irq_ris_enbl |= 1 << idx;
++			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
++		}
++		if (edges & UCB_FALLING) {
++			ucb->irq_fal_enbl |= 1 << idx;
++			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
++		}
++		ucb1x00_disable(ucb);
++		spin_unlock_irqrestore(&ucb->lock, flags);
++	}
++}
++
++/**
++ *	ucb1x00_disable_irq - disable an UCB1x00 interrupt source
++ *	@ucb: UCB1x00 structure describing chip
++ *	@edges: interrupt edges to disable
++ *
++ *	Disable the specified interrupt triggering on the specified
++ *	(%UCB_RISING, %UCB_FALLING or both) edges.
++ */
++void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
++{
++	unsigned long flags;
++
++	if (idx < 16) {
++		spin_lock_irqsave(&ucb->lock, flags);
++
++		ucb1x00_enable(ucb);
++		if (edges & UCB_RISING) {
++			ucb->irq_ris_enbl &= ~(1 << idx);
++			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
++		}
++		if (edges & UCB_FALLING) {
++			ucb->irq_fal_enbl &= ~(1 << idx);
++			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
++		}
++		ucb1x00_disable(ucb);
++		spin_unlock_irqrestore(&ucb->lock, flags);
++	}
++}
++
++/**
++ *	ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
++ *	@ucb: UCB1x00 structure describing chip
++ *	@idx: interrupt index
++ *	@devid: device id.
++ *
++ *	Disable the interrupt source and remove the handler.  devid must
++ *	match the devid passed when hooking the interrupt.
++ *
++ *	Returns zero on success, or one of the following errors:
++ *	 -EINVAL if the interrupt index is invalid
++ *	 -ENOENT if devid does not match
++ */
++int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
++{
++	struct ucb1x00_irq *irq;
++	int ret;
++
++	if (idx >= 16)
++		goto bad;
++
++	irq = ucb->irq_handler + idx;
++	ret = -ENOENT;
++
++	spin_lock_irq(&ucb->lock);
++	if (irq->devid == devid) {
++		ucb->irq_ris_enbl &= ~(1 << idx);
++		ucb->irq_fal_enbl &= ~(1 << idx);
++
++		ucb1x00_enable(ucb);
++		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
++		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
++		ucb1x00_disable(ucb);
++
++		irq->fn = NULL;
++		irq->devid = NULL;
++		ret = 0;
++	}
++	spin_unlock_irq(&ucb->lock);
++	return ret;
++
++bad:
++	printk(KERN_ERR "Freeing bad UCB1x00 irq %d\n", idx);
++	return -EINVAL;
++}
++
++/*
++ * Try to probe our interrupt, rather than relying on lots of
++ * hard-coded machine dependencies.  For reference, the expected
++ * IRQ mappings are:
++ *
++ *  	Machine		Default IRQ
++ *	adsbitsy	IRQ_GPCIN4
++ *	cerf		IRQ_GPIO_UCB1200_IRQ
++ *	flexanet	IRQ_GPIO_GUI
++ *	freebird	IRQ_GPIO_FREEBIRD_UCB1300_IRQ
++ *	graphicsclient	ADS_EXT_IRQ(8)
++ *	graphicsmaster	ADS_EXT_IRQ(8)
++ *	lart		LART_IRQ_UCB1200
++ *	omnimeter	IRQ_GPIO23
++ *	pfs168		IRQ_GPIO_UCB1300_IRQ
++ *	simpad		IRQ_GPIO_UCB1300_IRQ
++ *	shannon		SHANNON_IRQ_GPIO_IRQ_CODEC
++ *	yopy		IRQ_GPIO_UCB1200_IRQ
++ */
++static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
++{
++	unsigned long mask;
++
++	mask = probe_irq_on();
++	if (!mask)
++		return NO_IRQ;
++
++	/*
++	 * Enable the ADC interrupt.
++	 */
++	ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
++	ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++	/*
++	 * Cause an ADC interrupt.
++	 */
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
++
++	/*
++	 * Wait for the conversion to complete.
++	 */
++	while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, 0);
++
++	/*
++	 * Disable and clear interrupt.
++	 */
++	ucb1x00_reg_write(ucb, UCB_IE_RIS, 0);
++	ucb1x00_reg_write(ucb, UCB_IE_FAL, 0);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++	/*
++	 * Read triggered interrupt.
++	 */
++	return probe_irq_off(mask);
++}
++
++static int ucb1x00_probe(struct mcp *mcp)
++{
++	struct ucb1x00 *ucb;
++	unsigned int id;
++	int ret = -ENODEV;
++
++	mcp_enable(mcp);
++	id = mcp_reg_read(mcp, UCB_ID);
++
++	if (id != UCB_ID_1200 && id != UCB_ID_1300) {
++		printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
++		goto err_disable;
++	}
++
++	ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
++	ret = -ENOMEM;
++	if (!ucb)
++		goto err_disable;
++
++	memset(ucb, 0, sizeof(struct ucb1x00));
++
++	ucb->cdev.class = &ucb1x00_class;
++	ucb->cdev.dev = &mcp->attached_device;
++	strlcpy(ucb->cdev.class_id, "ucb1x00", sizeof(ucb->cdev.class_id));
++
++	spin_lock_init(&ucb->lock);
++	spin_lock_init(&ucb->io_lock);
++	sema_init(&ucb->adc_sem, 1);
++
++	ucb->id  = id;
++	ucb->mcp = mcp;
++	ucb->irq = ucb1x00_detect_irq(ucb);
++	if (ucb->irq == NO_IRQ) {
++		printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
++		ret = -ENODEV;
++		goto err_free;
++	}
++
++	ret = request_irq(ucb->irq, ucb1x00_irq, 0, "UCB1x00", ucb);
++	if (ret) {
++		printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
++			ucb->irq, ret);
++		goto err_free;
++	}
++
++	set_irq_type(ucb->irq, IRQT_RISING);
++	mcp_set_drvdata(mcp, ucb);
++
++	ret = class_device_register(&ucb->cdev);
++	if (ret) {
++		free_irq(ucb->irq, ucb);
++ err_free:
++		kfree(ucb);
++	}
++ err_disable:
++	mcp_disable(mcp);
++	return ret;
++}
++
++static void ucb1x00_remove(struct mcp *mcp)
++{
++	struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
++
++	class_device_unregister(&ucb->cdev);
++	free_irq(ucb->irq, ucb);
++}
++
++static void ucb1x00_release(struct class_device *dev)
++{
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
++	kfree(ucb);
++}
++
++static struct class ucb1x00_class = {
++	.name		= "ucb1x00",
++	.release	= ucb1x00_release,
++};
++
++int ucb1x00_register_interface(struct class_interface *intf)
++{
++	intf->class = &ucb1x00_class;
++	return class_interface_register(intf);
++}
++
++void ucb1x00_unregister_interface(struct class_interface *intf)
++{
++	class_interface_unregister(intf);
++}
++
++static struct mcp_driver ucb1x00_driver = {
++	.drv		= {
++		.name	= "ucb1x00",
++	},
++	.probe		= ucb1x00_probe,
++	.remove		= ucb1x00_remove,
++};
++
++static int __init ucb1x00_init(void)
++{
++	int ret = class_register(&ucb1x00_class);
++	if (ret == 0) {
++		ret = mcp_driver_register(&ucb1x00_driver);
++		if (ret)
++			class_unregister(&ucb1x00_class);
++	}
++	return ret;
++}
++
++static void __exit ucb1x00_exit(void)
++{
++	mcp_driver_unregister(&ucb1x00_driver);
++	class_unregister(&ucb1x00_class);
++}
++
++module_init(ucb1x00_init);
++module_exit(ucb1x00_exit);
++
++EXPORT_SYMBOL(ucb1x00_class);
++
++EXPORT_SYMBOL(ucb1x00_io_set_dir);
++EXPORT_SYMBOL(ucb1x00_io_write);
++EXPORT_SYMBOL(ucb1x00_io_read);
++
++EXPORT_SYMBOL(ucb1x00_adc_enable);
++EXPORT_SYMBOL(ucb1x00_adc_read);
++EXPORT_SYMBOL(ucb1x00_adc_disable);
++
++EXPORT_SYMBOL(ucb1x00_hook_irq);
++EXPORT_SYMBOL(ucb1x00_free_irq);
++EXPORT_SYMBOL(ucb1x00_enable_irq);
++EXPORT_SYMBOL(ucb1x00_disable_irq);
++
++EXPORT_SYMBOL(ucb1x00_register_interface);
++EXPORT_SYMBOL(ucb1x00_unregister_interface);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 core driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/switches-ucb1x00.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,214 @@
++/*
++ *  linux/drivers/misc/switches-ucb1x00.c
++ *
++ *  Copyright (C) 2001 John Dorsey
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  19 December 2001 - created from sa1100_switches.c.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/device.h>
++
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++
++#ifdef CONFIG_SA1100_ASSABET
++#include <asm/arch/assabet.h>
++#endif
++
++#include "switches.h"
++#include "ucb1x00.h"
++
++
++static void switches_ucb1x00_handler(int irq, void *devid);
++
++
++#ifdef CONFIG_SA1100_ASSABET
++
++/* Assabet
++ * ^^^^^^^
++ * Six switches are routed to GPIO pins on the UCB1300: S3 -- S8.
++ * This code sets bits in the range [3, 8] in the mask that we
++ * return to userland. Note that we transpose signals SW7 and SW8;
++ * see assabet_switches_ucb1x00_handler().
++ */
++
++static int assabet_switches_ucb1x00_init(struct ucb1x00 *ucb)
++{
++	int i;
++
++	ucb1x00_enable(ucb);
++
++	ucb1x00_io_set_dir(ucb,
++			   UCB_IO_0 | UCB_IO_1 | UCB_IO_2 |
++			   UCB_IO_3 | UCB_IO_4 | UCB_IO_5, 0);
++
++	for (i = 0; i < 6; ++i) {
++		ucb1x00_enable_irq(ucb, i, UCB_RISING | UCB_FALLING);
++
++		if (ucb1x00_hook_irq(ucb, i,
++				     switches_ucb1x00_handler, ucb) < 0) {
++			printk(KERN_ERR "%s: unable to hook IRQ for "
++			       "UCB1300 IO_%d\n", SWITCHES_NAME, i);
++
++			/* FIXME: BUGGY ERROR HANDLING */
++			return -EBUSY;
++		}
++
++	}
++
++	ucb1x00_disable(ucb);
++
++	return 0;
++
++}
++
++static void assabet_switches_ucb1x00_shutdown(struct ucb1x00 *ucb)
++{
++	int i;
++
++	ucb1x00_enable(ucb);
++
++	for (i = 5; i >= 0; --i) {
++		ucb1x00_disable_irq(ucb, i, UCB_RISING | UCB_FALLING);
++
++		/* Only error conditions are ENOENT and EINVAL; silently
++		 * ignore:
++		 */
++		ucb1x00_free_irq(ucb, i, ucb);
++	}
++
++	ucb1x00_disable(ucb);
++}
++
++static void assabet_switches_ucb1x00_handler(struct ucb1x00 *ucb, int irq, switches_mask_t *mask)
++{
++	unsigned int last, this;
++	static unsigned int states = 0;
++
++	last = ((states & (1 << irq)) != 0);
++	this = ((ucb1x00_io_read(ucb) & (1 << irq)) != 0);
++
++	if (last == this) /* debounce */
++		return;
++
++	/* Intel StrongARM SA-1110 Development Board
++	 * Schematics Figure 5, Sheet 5 of 12
++	 *
++	 * See switches S8 and S7. Notice their
++	 * relationship to signals SW7 and SW8. Hmmm.
++	 */
++
++	switch (irq) {
++
++	case 4:
++
++		SWITCHES_SET(mask, 8, this);
++		break;
++
++	case 5:
++
++		SWITCHES_SET(mask, 7, this);
++		break;
++
++	default:
++
++		SWITCHES_SET(mask, irq + 3, this);
++
++	}
++
++	states = this ? (states | (1 << irq)) : (states & ~(1 << irq));
++
++}
++#endif  /* CONFIG_SA1100_ASSABET */
++
++
++/* switches_ucb1x00_handler()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * This routine is a generalized handler for UCB1x00 GPIO switches
++ * which calls a board-specific service routine and passes an event
++ * mask to the core event handler. This routine is appropriate for
++ * systems which use the ucb1x00 framework, and can be registered
++ * using ucb1x00_hook_irq().
++ */
++static void switches_ucb1x00_handler(int irq, void *devid)
++{
++	struct ucb1x00 *ucb = devid;
++	switches_mask_t mask;
++
++	SWITCHES_ZERO(&mask);
++
++	/* Porting note: call a board-specific UCB1x00 switch handler here.
++	 * The handler can assume that sufficient storage for `mask' has
++	 * been allocated, and that the corresponding switches_mask_t
++	 * structure has been zeroed.
++	 */
++
++#ifdef CONFIG_SA1100_ASSABET
++	if (machine_is_assabet()) {
++		assabet_switches_ucb1x00_handler(ucb, irq, &mask);
++	}
++#endif
++
++	switches_event(&mask);
++}
++
++static int switches_add(struct class_device *dev)
++{
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
++	int ret = -ENODEV;
++
++#ifdef CONFIG_SA1100_ASSABET
++	if (machine_is_assabet()) {
++		ret = assabet_switches_ucb1x00_init(ucb);
++	}
++#endif
++	/* Porting note: call a board-specific init routine here. */
++
++	return ret;
++}
++
++static void switches_remove(struct class_device *dev)
++{
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(dev);
++
++	/* Porting note: call a board-specific shutdown routine here. */
++
++#ifdef CONFIG_SA1100_ASSABET
++	if (machine_is_assabet()) {
++		assabet_switches_ucb1x00_shutdown(ucb);
++	}
++#endif
++}
++
++static struct class_interface ucb1x00_switches_interface = {
++	.add	= switches_add,
++	.remove	= switches_remove,
++};
++
++static int __init switches_ucb1x00_init(void)
++{
++	return ucb1x00_register_interface(&ucb1x00_switches_interface);
++}
++
++static void __exit switches_ucb1x00_exit(void)
++{
++	ucb1x00_unregister_interface(&ucb1x00_switches_interface);
++}
++
++module_init(switches_ucb1x00_init);
++module_exit(switches_ucb1x00_exit);
++
++MODULE_DESCRIPTION("ucb1x00 switches driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/switches-core.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,200 @@
++/*
++ *  linux/drivers/misc/switches-core.c
++ *
++ *  Copyright (C) 2000-2001 John Dorsey
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  5 October 2000 - created.
++ *
++ *  25 October 2000 - userland file interface added.
++ *
++ *  13 January 2001 - added support for Spot.
++ *
++ *  11 September 2001 - UCB1200 driver framework support added.
++ *
++ *  19 December 2001 - separated out SA-1100 and UCB1x00 code.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/kernel.h>
++#include <linux/miscdevice.h>
++#include <linux/module.h>
++#include <linux/mm.h>
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/wait.h>
++
++#include <asm/uaccess.h>
++
++#include "switches.h"
++
++
++MODULE_AUTHOR("John Dorsey");
++MODULE_DESCRIPTION("Console switch support");
++MODULE_LICENSE("GPL");
++
++
++struct switches_action {
++	struct list_head list;
++	switches_mask_t  mask;
++};
++
++
++static int switches_users = 0;
++
++static spinlock_t switches_lock = SPIN_LOCK_UNLOCKED;
++
++DECLARE_WAIT_QUEUE_HEAD(switches_wait);
++LIST_HEAD(switches_event_queue);
++
++
++static ssize_t switches_read(struct file *file, char *buffer,
++			     size_t count, loff_t *pos)
++{
++	unsigned long flags;
++	struct list_head *event;
++	struct switches_action *action;
++
++	if (count < sizeof(struct switches_mask_t))
++		return -EINVAL;
++
++	while (list_empty(&switches_event_queue)) {
++
++		if (file->f_flags & O_NDELAY)
++			return -EAGAIN;
++
++		interruptible_sleep_on(&switches_wait);
++
++		if (signal_pending(current))
++			return -ERESTARTSYS;
++
++	}
++
++	if (verify_area(VERIFY_WRITE, buffer, sizeof(struct switches_mask_t)))
++		return -EFAULT;
++
++	spin_lock_irqsave(&switches_lock, flags);
++
++	event = switches_event_queue.next;
++	action = list_entry(event, struct switches_action, list);
++	copy_to_user(buffer, &(action->mask), sizeof(struct switches_mask_t));
++	list_del(event);
++	kfree(action);
++
++	spin_unlock_irqrestore(&switches_lock, flags);
++
++	return 0;
++
++}
++
++static ssize_t switches_write(struct file *file, const char *buffer,
++			      size_t count, loff_t *ppos)
++{
++	return -EINVAL;
++}
++
++static unsigned int switches_poll(struct file *file, poll_table *wait)
++{
++
++	poll_wait(file, &switches_wait, wait);
++
++	if (!list_empty(&switches_event_queue))
++		return POLLIN | POLLRDNORM;
++
++	return 0;
++
++}
++
++static int switches_open(struct inode *inode, struct file *file)
++{
++
++	if (switches_users > 0)
++		return -EBUSY;
++
++	++switches_users;
++	return 0;
++
++}
++
++static int switches_release(struct inode *inode, struct file *file)
++{
++
++	--switches_users;
++	return 0;
++
++}
++
++static struct file_operations switches_ops = {
++	.owner		= THIS_MODULE,
++	.read		= switches_read,
++	.write		= switches_write,
++	.poll		= switches_poll,
++	.open		= switches_open,
++	.release	= switches_release,
++};
++
++static struct miscdevice switches_misc = {
++	.minor		= MISC_DYNAMIC_MINOR,
++	.name		= SWITCHES_NAME,
++	.fops		= &switches_ops,
++};
++
++int switches_event(switches_mask_t *mask)
++{
++	struct switches_action *action;
++
++	if ((switches_users > 0) && (SWITCHES_COUNT(mask) > 0)) {
++
++		if ((action = (struct switches_action *)
++		     kmalloc(sizeof(struct switches_action),
++			     GFP_KERNEL)) == NULL) {
++			printk(KERN_ERR "%s: unable to allocate action "
++			       "descriptor\n", SWITCHES_NAME);
++			return -1;
++		}
++
++		action->mask = *mask;
++
++		spin_lock(&switches_lock);
++		list_add_tail(&action->list, &switches_event_queue);
++		spin_unlock(&switches_lock);
++
++		wake_up_interruptible(&switches_wait);
++
++	}
++
++	return 0;
++
++}
++
++EXPORT_SYMBOL(switches_event);
++
++
++static int __init switches_init(void)
++{
++	if (misc_register(&switches_misc) < 0) {
++		printk(KERN_ERR "%s: unable to register misc device\n",
++		       SWITCHES_NAME);
++		return -EIO;
++	}
++
++	printk(KERN_INFO "Console switches initialized\n");
++
++	return 0;
++}
++
++static void __exit switches_exit(void)
++{
++	if (misc_deregister(&switches_misc) < 0)
++		printk(KERN_ERR "%s: unable to deregister misc device\n",
++		       SWITCHES_NAME);
++}
++
++module_init(switches_init);
++module_exit(switches_exit);
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/ucb1x00-audio.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,439 @@
++/*
++ *  linux/drivers/misc/ucb1x00-audio.c
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/list.h>
++#include <linux/device.h>
++
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++
++#include "ucb1x00.h"
++
++#include "../sound/oss/sa1100-audio.h"
++
++#define MAGIC	0x41544154
++
++struct ucb1x00_audio {
++	struct file_operations	fops;
++	struct file_operations	mops;
++	struct ucb1x00		*ucb;
++	audio_stream_t		output_stream;
++	audio_stream_t		input_stream;
++	audio_state_t		state;
++	unsigned int		rate;
++	int			dev_id;
++	int			mix_id;
++	unsigned int		daa_oh_bit;
++	unsigned int		telecom;
++	unsigned int		magic;
++	unsigned int		ctrl_a;
++	unsigned int		ctrl_b;
++
++	/* mixer info */
++	unsigned int		mod_cnt;
++	unsigned short		output_level;
++	unsigned short		input_level;
++};
++
++#define REC_MASK	(SOUND_MASK_VOLUME | SOUND_MASK_MIC)
++#define DEV_MASK	REC_MASK
++
++static int
++ucb1x00_mixer_ioctl(struct inode *ino, struct file *filp, uint cmd, ulong arg)
++{
++	struct ucb1x00_audio *ucba;
++	unsigned int val, gain;
++	int ret = 0;
++
++	ucba = list_entry(filp->f_op, struct ucb1x00_audio, mops);
++
++	if (_IOC_TYPE(cmd) != 'M')
++		return -EINVAL;
++
++	if (cmd == SOUND_MIXER_INFO) {
++		struct mixer_info mi;
++
++		strncpy(mi.id, "UCB1x00", sizeof(mi.id));
++		strncpy(mi.name, "Philips UCB1x00", sizeof(mi.name));
++		mi.modify_counter = ucba->mod_cnt;
++		return copy_to_user((void *)arg, &mi, sizeof(mi)) ? -EFAULT : 0;
++	}
++
++	if (_IOC_DIR(cmd) & _IOC_WRITE) {
++		unsigned int left, right;
++
++		ret = get_user(val, (unsigned int *)arg);
++		if (ret)
++			goto out;
++
++		left  = val & 255;
++		right = val >> 8;
++
++		if (left > 100)
++			left = 100;
++		if (right > 100)
++			right = 100;
++
++		gain = (left + right) / 2;
++
++		ret = -EINVAL;
++		if (!ucba->telecom) {
++			switch(_IOC_NR(cmd)) {
++			case SOUND_MIXER_VOLUME:
++				ucba->output_level = gain | gain << 8;
++				ucba->mod_cnt++;
++				ucba->ctrl_b = (ucba->ctrl_b & 0xff00) |
++					       ((gain * 31) / 100);
++				ucb1x00_reg_write(ucba->ucb, UCB_AC_B,
++						  ucba->ctrl_b);
++				ret = 0;
++				break;
++
++			case SOUND_MIXER_MIC:
++				ucba->input_level = gain | gain << 8;
++				ucba->mod_cnt++;
++				ucba->ctrl_a = (ucba->ctrl_a & 0x7f) |
++					       (((gain * 31) / 100) << 7);
++				ucb1x00_reg_write(ucba->ucb, UCB_AC_A,
++						  ucba->ctrl_a);
++				ret = 0;
++				break;
++			}
++		}
++	}
++
++	if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
++		switch (_IOC_NR(cmd)) {
++		case SOUND_MIXER_VOLUME:
++			val = ucba->output_level;
++			break;
++
++		case SOUND_MIXER_MIC:
++			val = ucba->input_level;
++			break;
++
++		case SOUND_MIXER_RECSRC:
++		case SOUND_MIXER_RECMASK:
++			val = ucba->telecom ? 0 : REC_MASK;
++			break;
++
++		case SOUND_MIXER_DEVMASK:
++			val = ucba->telecom ? 0 : DEV_MASK;
++			break;
++
++		case SOUND_MIXER_CAPS:
++		case SOUND_MIXER_STEREODEVS:
++			val = 0;
++			break;
++
++		default:
++			val = 0;
++			ret = -EINVAL;
++			break;
++		}
++
++		if (ret == 0)
++			ret = put_user(val, (int *)arg);
++	}
++ out:
++	return ret;
++}
++
++static int ucb1x00_audio_setrate(struct ucb1x00_audio *ucba, int rate)
++{
++	unsigned int div_rate = ucb1x00_clkrate(ucba->ucb) / 32;
++	unsigned int div;
++
++	div = (div_rate + (rate / 2)) / rate;
++	if (div < 6)
++		div = 6;
++	if (div > 127)
++		div = 127;
++
++	ucba->ctrl_a = (ucba->ctrl_a & ~0x7f) | div;
++
++	if (ucba->telecom) {
++		ucb1x00_reg_write(ucba->ucb, UCB_TC_B, 0);
++		ucb1x00_set_telecom_divisor(ucba->ucb, div * 32);
++		ucb1x00_reg_write(ucba->ucb, UCB_TC_A, ucba->ctrl_a);
++		ucb1x00_reg_write(ucba->ucb, UCB_TC_B, ucba->ctrl_b);
++	} else {
++		ucb1x00_reg_write(ucba->ucb, UCB_AC_B, 0);
++		ucb1x00_set_audio_divisor(ucba->ucb, div * 32);
++		ucb1x00_reg_write(ucba->ucb, UCB_AC_A, ucba->ctrl_a);
++		ucb1x00_reg_write(ucba->ucb, UCB_AC_B, ucba->ctrl_b);
++	}
++
++	ucba->rate = div_rate / div;
++
++	return ucba->rate;
++}
++
++static int ucb1x00_audio_getrate(struct ucb1x00_audio *ucba)
++{
++	return ucba->rate;
++}
++
++static void ucb1x00_audio_startup(void *data)
++{
++	struct ucb1x00_audio *ucba = data;
++
++	ucb1x00_enable(ucba->ucb);
++	ucb1x00_audio_setrate(ucba, ucba->rate);
++
++	ucb1x00_reg_write(ucba->ucb, UCB_MODE, UCB_MODE_DYN_VFLAG_ENA);
++
++	/*
++	 * Take off-hook
++	 */
++	if (ucba->daa_oh_bit)
++		ucb1x00_io_write(ucba->ucb, 0, ucba->daa_oh_bit);
++}
++
++static void ucb1x00_audio_shutdown(void *data)
++{
++	struct ucb1x00_audio *ucba = data;
++
++	/*
++	 * Place on-hook
++	 */
++	if (ucba->daa_oh_bit)
++		ucb1x00_io_write(ucba->ucb, ucba->daa_oh_bit, 0);
++
++	ucb1x00_reg_write(ucba->ucb, ucba->telecom ? UCB_TC_B : UCB_AC_B, 0);
++	ucb1x00_disable(ucba->ucb);
++}
++
++static int
++ucb1x00_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++	struct ucb1x00_audio *ucba;
++	int val, ret = 0;
++
++	ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
++
++	/*
++	 * Make sure we have our magic number
++	 */
++	if (ucba->magic != MAGIC)
++		return -ENODEV;
++
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *)arg);
++		if (ret)
++			return ret;
++		if (val != 0)
++			return -EINVAL;
++		val = 0;
++		break;
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		val = 1;
++		break;
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (int *)arg);
++		if (ret)
++			return ret;
++		val = ucb1x00_audio_setrate(ucba, val);
++		break;
++
++	case SOUND_PCM_READ_RATE:
++		val = ucb1x00_audio_getrate(ucba);
++		break;
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		val = AFMT_S16_LE;
++		break;
++
++	default:
++		return ucb1x00_mixer_ioctl(inode, file, cmd, arg);
++	}
++
++	return put_user(val, (int *)arg);
++}
++
++static int ucb1x00_audio_open(struct inode *inode, struct file *file)
++{
++	struct ucb1x00_audio *ucba;
++
++	ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
++
++	return sa1100_audio_attach(inode, file, &ucba->state);
++}
++
++static struct ucb1x00_audio *ucb1x00_audio_alloc(struct ucb1x00 *ucb)
++{
++	struct ucb1x00_audio *ucba;
++
++	ucba = kmalloc(sizeof(*ucba), GFP_KERNEL);
++	if (ucba) {
++		memset(ucba, 0, sizeof(*ucba));
++
++		ucba->magic = MAGIC;
++		ucba->ucb = ucb;
++		ucba->fops.owner = THIS_MODULE;
++		ucba->fops.open  = ucb1x00_audio_open;
++		ucba->mops.owner = THIS_MODULE;
++		ucba->mops.ioctl = ucb1x00_mixer_ioctl;
++		ucba->state.output_stream = &ucba->output_stream;
++		ucba->state.input_stream = &ucba->input_stream;
++		ucba->state.data = ucba;
++		ucba->state.hw_init = ucb1x00_audio_startup;
++		ucba->state.hw_shutdown = ucb1x00_audio_shutdown;
++		ucba->state.client_ioctl = ucb1x00_audio_ioctl;
++
++		/* There is a bug in the StrongARM causes corrupt MCP data to be sent to
++		 * the codec when the FIFOs are empty and writes are made to the OS timer
++		 * match register 0. To avoid this we must make sure that data is always
++		 * sent to the codec.
++		 */
++		ucba->state.need_tx_for_rx = 1;
++
++		init_MUTEX(&ucba->state.sem);
++		ucba->rate = 8000;
++	}
++	return ucba;
++}
++
++static struct ucb1x00_audio *ucb1x00_audio_add_one(struct ucb1x00 *ucb, int telecom)
++{
++	struct ucb1x00_audio *a;
++
++	a = ucb1x00_audio_alloc(ucb);
++	if (a) {
++		a->telecom = telecom;
++
++		a->input_stream.dev = ucb->cdev.dev;
++		a->output_stream.dev = ucb->cdev.dev;
++		a->ctrl_a = 0;
++
++		if (a->telecom) {
++			a->input_stream.dma_dev = ucb->mcp->dma_telco_rd;
++			a->input_stream.id = "UCB1x00 telco in";
++			a->output_stream.dma_dev = ucb->mcp->dma_telco_wr;
++			a->output_stream.id = "UCB1x00 telco out";
++			a->ctrl_b = UCB_TC_B_IN_ENA|UCB_TC_B_OUT_ENA;
++#if 0
++			a->daa_oh_bit = UCB_IO_8;
++
++			ucb1x00_enable(ucb);
++			ucb1x00_io_write(ucb, a->daa_oh_bit, 0);
++			ucb1x00_io_set_dir(ucb, UCB_IO_7 | UCB_IO_6, a->daa_oh_bit);
++			ucb1x00_disable(ucb);
++#endif
++		} else {
++			a->input_stream.dma_dev  = ucb->mcp->dma_audio_rd;
++			a->input_stream.id = "UCB1x00 audio in";
++			a->output_stream.dma_dev = ucb->mcp->dma_audio_wr;
++			a->output_stream.id = "UCB1x00 audio out";
++			a->ctrl_b = UCB_AC_B_IN_ENA|UCB_AC_B_OUT_ENA;
++		}
++
++		a->dev_id = register_sound_dsp(&a->fops, -1);
++		a->mix_id = register_sound_mixer(&a->mops, -1);
++
++		printk("Sound: UCB1x00 %s: dsp id %d mixer id %d\n",
++			a->telecom ? "telecom" : "audio",
++			a->dev_id, a->mix_id);
++	}
++
++	return a;
++}
++
++static void ucb1x00_audio_remove_one(struct ucb1x00_audio *a)
++{
++	unregister_sound_dsp(a->dev_id);
++	unregister_sound_mixer(a->mix_id);
++	kfree(a);
++}
++
++static int ucb1x00_audio_add(struct class_device *cdev)
++{
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(cdev);
++
++	if (ucb->cdev.dev == NULL || ucb->cdev.dev->dma_mask == NULL)
++		return -ENXIO;
++
++	ucb->audio_data = ucb1x00_audio_add_one(ucb, 0);
++	ucb->telecom_data = ucb1x00_audio_add_one(ucb, 1);
++
++	return 0;
++}
++
++static void ucb1x00_audio_remove(struct class_device *cdev)
++{
++	struct ucb1x00 *ucb = classdev_to_ucb1x00(cdev);
++
++	ucb1x00_audio_remove_one(ucb->audio_data);
++	ucb1x00_audio_remove_one(ucb->telecom_data);
++}
++
++#if 0 //def CONFIG_PM
++static int ucb1x00_audio_suspend(struct ucb1x00 *ucb, u32 state)
++{
++	struct ucb1x00_audio *a;
++
++	a = ucb->audio_data;
++	sa1100_audio_suspend(&a->state, state);
++	a = ucb->telecom_data;
++	sa1100_audio_suspend(&a->state, state);
++
++	return 0;
++}
++
++static int ucb1x00_audio_resume(struct ucb1x00 *ucb)
++{
++	struct ucb1x00_audio *a;
++
++	a = ucb->audio_data;
++	sa1100_audio_resume(&a->state);
++	a = ucb->telecom_data;
++	sa1100_audio_resume(&a->state);
++
++	return 0;
++}
++#else
++#define ucb1x00_audio_suspend	NULL
++#define ucb1x00_audio_resume	NULL
++#endif
++
++static struct class_interface ucb1x00_audio_interface = {
++	.add		= ucb1x00_audio_add,
++	.remove		= ucb1x00_audio_remove,
++};
++
++static int __init ucb1x00_audio_init(void)
++{
++	return ucb1x00_register_interface(&ucb1x00_audio_interface);
++}
++
++static void __exit ucb1x00_audio_exit(void)
++{
++	ucb1x00_unregister_interface(&ucb1x00_audio_interface);
++}
++
++module_init(ucb1x00_audio_init);
++module_exit(ucb1x00_audio_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 telecom/audio driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/mcp-sa1100.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,275 @@
++/*
++ *  linux/drivers/misc/mcp-sa1100.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ * 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.
++ *
++ *  SA1100 MCP (Multimedia Communications Port) driver.
++ *
++ *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/device.h>
++
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/system.h>
++
++#include <asm/arch/assabet.h>
++
++#include "mcp.h"
++
++static void
++mcp_sa1100_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
++{
++	unsigned int mccr0;
++
++	divisor /= 32;
++
++	mccr0 = Ser4MCCR0 & ~0x00007f00;
++	mccr0 |= divisor << 8;
++	Ser4MCCR0 = mccr0;
++}
++
++static void
++mcp_sa1100_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
++{
++	unsigned int mccr0;
++
++	divisor /= 32;
++
++	mccr0 = Ser4MCCR0 & ~0x0000007f;
++	mccr0 |= divisor;
++	Ser4MCCR0 = mccr0;
++}
++
++/*
++ * Write data to the device.  The bit should be set after 3 subframe
++ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
++ * We really should try doing something more productive while we
++ * wait.
++ */
++static void
++mcp_sa1100_write(struct mcp *mcp, unsigned int reg, unsigned int val)
++{
++	int ret = -ETIME;
++	int i;
++
++	Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
++
++	for (i = 0; i < 2; i++) {
++		udelay(mcp->rw_timeout);
++		if (Ser4MCSR & MCSR_CWC) {
++			ret = 0;
++			break;
++		}
++	}
++
++	if (ret < 0)
++		printk(KERN_WARNING "mcp: write timed out\n");
++}
++
++/*
++ * Read data from the device.  The bit should be set after 3 subframe
++ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
++ * We really should try doing something more productive while we
++ * wait.
++ */
++static unsigned int
++mcp_sa1100_read(struct mcp *mcp, unsigned int reg)
++{
++	int ret = -ETIME;
++	int i;
++
++	Ser4MCDR2 = reg << 17 | MCDR2_Rd;
++
++	for (i = 0; i < 2; i++) {
++		udelay(mcp->rw_timeout);
++		if (Ser4MCSR & MCSR_CRC) {
++			ret = Ser4MCDR2 & 0xffff;
++			break;
++		}
++	}
++
++	if (ret < 0)
++		printk(KERN_WARNING "mcp: read timed out\n");
++
++	return ret;
++}
++
++static void mcp_sa1100_enable(struct mcp *mcp)
++{
++	Ser4MCSR = -1;
++	Ser4MCCR0 |= MCCR0_MCE;
++}
++
++static void mcp_sa1100_disable(struct mcp *mcp)
++{
++	Ser4MCCR0 &= ~MCCR0_MCE;
++}
++
++/*
++ * Our methods.
++ */
++static struct mcp mcp_sa1100 = {
++	.owner			= THIS_MODULE,
++	.lock			= SPIN_LOCK_UNLOCKED,
++	.sclk_rate		= 11981000,
++	.dma_audio_rd		= DMA_Ser4MCP0Rd,
++	.dma_audio_wr		= DMA_Ser4MCP0Wr,
++	.dma_telco_rd		= DMA_Ser4MCP1Rd,
++	.dma_telco_wr		= DMA_Ser4MCP1Wr,
++	.set_telecom_divisor	= mcp_sa1100_set_telecom_divisor,
++	.set_audio_divisor	= mcp_sa1100_set_audio_divisor,
++	.reg_write		= mcp_sa1100_write,
++	.reg_read		= mcp_sa1100_read,
++	.enable			= mcp_sa1100_enable,
++	.disable		= mcp_sa1100_disable,
++};
++
++static int mcp_sa1100_probe(struct device *dev)
++{
++	struct platform_device *pdev = to_platform_device(dev);
++	struct mcp *mcp = &mcp_sa1100;
++	int ret;
++
++	if (!machine_is_adsbitsy()       && !machine_is_assabet()        &&
++	    !machine_is_cerf()           && !machine_is_flexanet()       &&
++	    !machine_is_freebird()       && !machine_is_graphicsclient() &&
++	    !machine_is_graphicsmaster() && !machine_is_lart()           &&
++	    !machine_is_omnimeter()      && !machine_is_pfs168()         &&
++	    !machine_is_shannon()        && !machine_is_simpad()         &&
++	    !machine_is_yopy())
++		return -ENODEV;
++
++	if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
++		return -EBUSY;
++
++	mcp->me = dev;
++	dev_set_drvdata(dev, mcp);
++
++	if (machine_is_assabet()) {
++		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
++	}
++
++	/*
++	 * Setup the PPC unit correctly.
++	 */
++	PPDR &= ~PPC_RXD4;
++	PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
++	PSDR |= PPC_RXD4;
++	PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
++	PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
++
++	Ser4MCSR = -1;
++	Ser4MCCR1 = 0;
++	Ser4MCCR0 = 0x00007f7f | MCCR0_ADM;
++
++	/*
++	 * Calculate the read/write timeout (us) from the bit clock
++	 * rate.  This is the period for 3 64-bit frames.  Always
++	 * round this time up.
++	 */
++	mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
++			  mcp->sclk_rate;
++
++	ret = mcp_host_register(mcp, &pdev->dev);
++	if (ret != 0) {
++		release_mem_region(0x80060000, 0x60);
++		dev_set_drvdata(dev, NULL);
++	}
++
++	return ret;
++}
++
++static int mcp_sa1100_remove(struct device *dev)
++{
++	struct mcp *mcp = dev_get_drvdata(dev);
++
++	dev_set_drvdata(dev, NULL);
++
++	mcp_host_unregister(mcp);
++	release_mem_region(0x80060000, 0x60);
++
++	return 0;
++}
++
++struct mcp_sa1100_state {
++	u32	mccr0;
++	u32	mccr1;
++};
++
++static int mcp_sa1100_suspend(struct device *dev, u32 state, u32 level)
++{
++	struct mcp_sa1100_state *s = (struct mcp_sa1100_state *)dev->saved_state;
++
++	if (!s) {
++		s = kmalloc(sizeof(struct mcp_sa1100_state), GFP_KERNEL);
++		dev->saved_state = (unsigned char *)s;
++	}
++
++	if (s) {
++		s->mccr0 = Ser4MCCR0;
++		s->mccr1 = Ser4MCCR1;
++	}
++
++	if (level == SUSPEND_DISABLE)
++		Ser4MCCR0 &= ~MCCR0_MCE;
++	return 0;
++}
++
++static int mcp_sa1100_resume(struct device *dev, u32 level)
++{
++	struct mcp_sa1100_state *s = (struct mcp_sa1100_state *)dev->saved_state;
++
++	if (s && level == RESUME_RESTORE_STATE) {
++		Ser4MCCR1 = s->mccr1;
++		Ser4MCCR0 = s->mccr0;
++
++		dev->saved_state = NULL;
++		kfree(s);
++	}
++	return 0;
++}
++
++/*
++ * The driver for the SA11x0 MCP port.
++ */
++static struct device_driver mcp_sa1100_driver = {
++	.name		= "sa11x0-mcp",
++	.bus		= &platform_bus_type,
++	.probe		= mcp_sa1100_probe,
++	.remove		= mcp_sa1100_remove,
++	.suspend	= mcp_sa1100_suspend,
++	.resume		= mcp_sa1100_resume,
++};
++
++/*
++ * This needs re-working
++ */
++static int __init mcp_sa1100_init(void)
++{
++	return driver_register(&mcp_sa1100_driver);
++}
++
++static void __exit mcp_sa1100_exit(void)
++{
++	driver_unregister(&mcp_sa1100_driver);
++}
++
++module_init(mcp_sa1100_init);
++module_exit(mcp_sa1100_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/mcp.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,58 @@
++/*
++ *  linux/drivers/misc/mcp.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ */
++#ifndef MCP_H
++#define MCP_H
++
++struct mcp {
++	struct module	*owner;
++	struct device	*me;
++	spinlock_t	lock;
++	int		use_count;
++	unsigned int	sclk_rate;
++	unsigned int	rw_timeout;
++	dma_device_t	dma_audio_rd;
++	dma_device_t	dma_audio_wr;
++	dma_device_t	dma_telco_rd;
++	dma_device_t	dma_telco_wr;
++	void		(*set_telecom_divisor)(struct mcp *, unsigned int);
++	void		(*set_audio_divisor)(struct mcp *, unsigned int);
++	void		(*reg_write)(struct mcp *, unsigned int, unsigned int);
++	unsigned int	(*reg_read)(struct mcp *, unsigned int);
++	void		(*enable)(struct mcp *);
++	void		(*disable)(struct mcp *);
++	struct device	attached_device;
++};
++
++void mcp_set_telecom_divisor(struct mcp *, unsigned int);
++void mcp_set_audio_divisor(struct mcp *, unsigned int);
++void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
++unsigned int mcp_reg_read(struct mcp *, unsigned int);
++void mcp_enable(struct mcp *);
++void mcp_disable(struct mcp *);
++#define mcp_get_sclk_rate(mcp)	((mcp)->sclk_rate)
++
++int mcp_host_register(struct mcp *, struct device *);
++void mcp_host_unregister(struct mcp *);
++
++struct mcp_driver {
++	struct device_driver drv;
++	int (*probe)(struct mcp *);
++	void (*remove)(struct mcp *);
++	int (*suspend)(struct mcp *, u32);
++	int (*resume)(struct mcp *);
++};
++
++int mcp_driver_register(struct mcp_driver *);
++void mcp_driver_unregister(struct mcp_driver *);
++
++#define mcp_get_drvdata(mcp)	dev_get_drvdata(&(mcp)->attached_device)
++#define mcp_set_drvdata(mcp,d)	dev_set_drvdata(&(mcp)->attached_device, d)
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/ucb1x00-input.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,233 @@
++/*
++ *  linux/drivers/misc/ucb1x00.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ */
++#ifndef UCB1200_H
++#define UCB1200_H
++
++#define UCB_IO_DATA	0x00
++#define UCB_IO_DIR	0x01
++
++#define UCB_IO_0		(1 << 0)
++#define UCB_IO_1		(1 << 1)
++#define UCB_IO_2		(1 << 2)
++#define UCB_IO_3		(1 << 3)
++#define UCB_IO_4		(1 << 4)
++#define UCB_IO_5		(1 << 5)
++#define UCB_IO_6		(1 << 6)
++#define UCB_IO_7		(1 << 7)
++#define UCB_IO_8		(1 << 8)
++#define UCB_IO_9		(1 << 9)
++
++#define UCB_IE_RIS	0x02
++#define UCB_IE_FAL	0x03
++#define UCB_IE_STATUS	0x04
++#define UCB_IE_CLEAR	0x04
++#define UCB_IE_ADC		(1 << 11)
++#define UCB_IE_TSPX		(1 << 12)
++#define UCB_IE_TSMX		(1 << 13)
++#define UCB_IE_TCLIP		(1 << 14)
++#define UCB_IE_ACLIP		(1 << 15)
++
++#define UCB_IRQ_TSPX		12
++
++#define UCB_TC_A	0x05
++#define UCB_TC_A_LOOP		(1 << 7)	/* UCB1200 */
++#define UCB_TC_A_AMPL		(1 << 7)	/* UCB1300 */
++
++#define UCB_TC_B	0x06
++#define UCB_TC_B_VOICE_ENA	(1 << 3)
++#define UCB_TC_B_CLIP		(1 << 4)
++#define UCB_TC_B_ATT		(1 << 6)
++#define UCB_TC_B_SIDE_ENA	(1 << 11)
++#define UCB_TC_B_MUTE		(1 << 13)
++#define UCB_TC_B_IN_ENA		(1 << 14)
++#define UCB_TC_B_OUT_ENA	(1 << 15)
++
++#define UCB_AC_A	0x07
++#define UCB_AC_B	0x08
++#define UCB_AC_B_LOOP		(1 << 8)
++#define UCB_AC_B_MUTE		(1 << 13)
++#define UCB_AC_B_IN_ENA		(1 << 14)
++#define UCB_AC_B_OUT_ENA	(1 << 15)
++
++#define UCB_TS_CR	0x09
++#define UCB_TS_CR_TSMX_POW	(1 << 0)
++#define UCB_TS_CR_TSPX_POW	(1 << 1)
++#define UCB_TS_CR_TSMY_POW	(1 << 2)
++#define UCB_TS_CR_TSPY_POW	(1 << 3)
++#define UCB_TS_CR_TSMX_GND	(1 << 4)
++#define UCB_TS_CR_TSPX_GND	(1 << 5)
++#define UCB_TS_CR_TSMY_GND	(1 << 6)
++#define UCB_TS_CR_TSPY_GND	(1 << 7)
++#define UCB_TS_CR_MODE_INT	(0 << 8)
++#define UCB_TS_CR_MODE_PRES	(1 << 8)
++#define UCB_TS_CR_MODE_POS	(2 << 8)
++#define UCB_TS_CR_BIAS_ENA	(1 << 11)
++#define UCB_TS_CR_TSPX_LOW	(1 << 12)
++#define UCB_TS_CR_TSMX_LOW	(1 << 13)
++
++#define UCB_ADC_CR	0x0a
++#define UCB_ADC_SYNC_ENA	(1 << 0)
++#define UCB_ADC_VREFBYP_CON	(1 << 1)
++#define UCB_ADC_INP_TSPX	(0 << 2)
++#define UCB_ADC_INP_TSMX	(1 << 2)
++#define UCB_ADC_INP_TSPY	(2 << 2)
++#define UCB_ADC_INP_TSMY	(3 << 2)
++#define UCB_ADC_INP_AD0		(4 << 2)
++#define UCB_ADC_INP_AD1		(5 << 2)
++#define UCB_ADC_INP_AD2		(6 << 2)
++#define UCB_ADC_INP_AD3		(7 << 2)
++#define UCB_ADC_EXT_REF		(1 << 5)
++#define UCB_ADC_START		(1 << 7)
++#define UCB_ADC_ENA		(1 << 15)
++
++#define UCB_ADC_DATA	0x0b
++#define UCB_ADC_DAT_VAL		(1 << 15)
++#define UCB_ADC_DAT(x)		(((x) & 0x7fe0) >> 5)
++
++#define UCB_ID		0x0c
++#define UCB_ID_1200		0x1004
++#define UCB_ID_1300		0x1005
++#define UCB_ID_1400		0x4304
++#define UCB_ID_1400_BUGGY	0x4303	/* fake ID */
++
++#define UCB_MODE	0x0d
++#define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
++#define UCB_MODE_AUD_OFF_CAN	(1 << 13)
++
++#include "mcp.h"
++
++struct ucb1x00;
++
++struct ucb1x00_irq {
++	void *devid;
++	void (*fn)(int, void *);
++};
++
++struct ucb1x00 {
++	spinlock_t		lock;
++	struct mcp		*mcp;
++	unsigned int		irq;
++	struct semaphore	adc_sem;
++	spinlock_t		io_lock;
++	u16			id;
++	u16			io_dir;
++	u16			io_out;
++	u16			adc_cr;
++	u16			irq_fal_enbl;
++	u16			irq_ris_enbl;
++	struct ucb1x00_irq	irq_handler[16];
++};
++
++/**
++ *	ucb1x00_clkrate - return the UCB1x00 SIB clock rate
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Return the SIB clock rate in Hz.
++ */
++static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
++{
++	return mcp_get_sclk_rate(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_enable - enable the UCB1x00 SIB clock
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Enable the SIB clock.  This can be called multiple times.
++ */
++static inline void ucb1x00_enable(struct ucb1x00 *ucb)
++{
++	mcp_enable(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_disable - disable the UCB1x00 SIB clock
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Disable the SIB clock.  The SIB clock will only be disabled
++ *	when the number of ucb1x00_enable calls match the number of
++ *	ucb1x00_disable calls.
++ */
++static inline void ucb1x00_disable(struct ucb1x00 *ucb)
++{
++	mcp_disable(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_reg_write - write a UCB1x00 register
++ *	@ucb: UCB1x00 structure describing chip
++ *	@reg: UCB1x00 4-bit register index to write
++ *	@val: UCB1x00 16-bit value to write
++ *
++ *	Write the UCB1x00 register @reg with value @val.  The SIB
++ *	clock must be running for this function to return.
++ */
++static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
++{
++	mcp_reg_write(ucb->mcp, reg, val);
++}
++
++/**
++ *	ucb1x00_reg_read - read a UCB1x00 register
++ *	@ucb: UCB1x00 structure describing chip
++ *	@reg: UCB1x00 4-bit register index to write
++ *
++ *	Read the UCB1x00 register @reg and return its value.  The SIB
++ *	clock must be running for this function to return.
++ */
++static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
++{
++	return mcp_reg_read(ucb->mcp, reg);
++}
++/**
++ *	ucb1x00_set_audio_divisor - 
++ *	@ucb: UCB1x00 structure describing chip
++ *	@div: SIB clock divisor
++ */
++static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++	mcp_set_audio_divisor(ucb->mcp, div);
++}
++
++/**
++ *	ucb1x00_set_telecom_divisor -
++ *	@ucb: UCB1x00 structure describing chip
++ *	@div: SIB clock divisor
++ */
++static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++	mcp_set_telecom_divisor(ucb->mcp, div);
++}
++
++struct ucb1x00 *ucb1x00_get(void);
++
++void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
++void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
++unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
++
++#define UCB_NOSYNC	(0)
++#define UCB_SYNC	(1)
++
++unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
++void ucb1x00_adc_enable(struct ucb1x00 *ucb);
++void ucb1x00_adc_disable(struct ucb1x00 *ucb);
++
++/*
++ * Which edges of the IRQ do you want to control today?
++ */
++#define UCB_RISING	(1 << 0)
++#define UCB_FALLING	(1 << 1)
++
++int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
++void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/ucb1x00.h	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,271 @@
++/*
++ *  linux/drivers/misc/ucb1x00.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ */
++#ifndef UCB1200_H
++#define UCB1200_H
++
++#ifdef CONFIG_ARCH_PXA
++
++/* ucb1400 aclink register mappings: */
++
++#define UCB_IO_DATA	0x5a
++#define UCB_IO_DIR	0x5c
++#define UCB_IE_RIS	0x5e
++#define UCB_IE_FAL	0x60
++#define UCB_IE_STATUS	0x62
++#define UCB_IE_CLEAR	0x62
++#define UCB_TS_CR	0x64
++#define UCB_ADC_CR	0x66
++#define UCB_ADC_DATA	0x68
++#define UCB_ID		0x7e /* 7c is mfr id, 7e part id (from aclink spec) */
++
++#define UCB_ADC_DAT(x)		((x) & 0x3ff)
++
++#else
++
++/* ucb1x00 SIB register mappings: */
++
++#define UCB_IO_DATA	0x00
++#define UCB_IO_DIR	0x01
++#define UCB_IE_RIS	0x02
++#define UCB_IE_FAL	0x03
++#define UCB_IE_STATUS	0x04
++#define UCB_IE_CLEAR	0x04
++#define UCB_TC_A	0x05
++#define UCB_TC_B	0x06
++#define UCB_AC_A	0x07
++#define UCB_AC_B	0x08
++#define UCB_TS_CR	0x09
++#define UCB_ADC_CR	0x0a
++#define UCB_ADC_DATA	0x0b
++#define UCB_ID		0x0c
++#define UCB_MODE	0x0d
++
++#define UCB_ADC_DAT(x)		(((x) & 0x7fe0) >> 5)
++
++#endif
++
++
++#define UCB_IO_0		(1 << 0)
++#define UCB_IO_1		(1 << 1)
++#define UCB_IO_2		(1 << 2)
++#define UCB_IO_3		(1 << 3)
++#define UCB_IO_4		(1 << 4)
++#define UCB_IO_5		(1 << 5)
++#define UCB_IO_6		(1 << 6)
++#define UCB_IO_7		(1 << 7)
++#define UCB_IO_8		(1 << 8)
++#define UCB_IO_9		(1 << 9)
++
++#define UCB_IE_ADC		(1 << 11)
++#define UCB_IE_TSPX		(1 << 12)
++#define UCB_IE_TSMX		(1 << 13)
++#define UCB_IE_TCLIP		(1 << 14)
++#define UCB_IE_ACLIP		(1 << 15)
++
++#define UCB_IRQ_TSPX		12
++
++#define UCB_TC_A_LOOP		(1 << 7)	/* UCB1200 */
++#define UCB_TC_A_AMPL		(1 << 7)	/* UCB1300 */
++
++#define UCB_TC_B_VOICE_ENA	(1 << 3)
++#define UCB_TC_B_CLIP		(1 << 4)
++#define UCB_TC_B_ATT		(1 << 6)
++#define UCB_TC_B_SIDE_ENA	(1 << 11)
++#define UCB_TC_B_MUTE		(1 << 13)
++#define UCB_TC_B_IN_ENA		(1 << 14)
++#define UCB_TC_B_OUT_ENA	(1 << 15)
++
++#define UCB_AC_B_LOOP		(1 << 8)
++#define UCB_AC_B_MUTE		(1 << 13)
++#define UCB_AC_B_IN_ENA		(1 << 14)
++#define UCB_AC_B_OUT_ENA	(1 << 15)
++
++#define UCB_TS_CR_TSMX_POW	(1 << 0)
++#define UCB_TS_CR_TSPX_POW	(1 << 1)
++#define UCB_TS_CR_TSMY_POW	(1 << 2)
++#define UCB_TS_CR_TSPY_POW	(1 << 3)
++#define UCB_TS_CR_TSMX_GND	(1 << 4)
++#define UCB_TS_CR_TSPX_GND	(1 << 5)
++#define UCB_TS_CR_TSMY_GND	(1 << 6)
++#define UCB_TS_CR_TSPY_GND	(1 << 7)
++#define UCB_TS_CR_MODE_INT	(0 << 8)
++#define UCB_TS_CR_MODE_PRES	(1 << 8)
++#define UCB_TS_CR_MODE_POS	(2 << 8)
++#define UCB_TS_CR_BIAS_ENA	(1 << 11)
++#define UCB_TS_CR_TSPX_LOW	(1 << 12)
++#define UCB_TS_CR_TSMX_LOW	(1 << 13)
++
++#define UCB_ADC_SYNC_ENA	(1 << 0)
++#define UCB_ADC_VREFBYP_CON	(1 << 1)
++#define UCB_ADC_INP_TSPX	(0 << 2)
++#define UCB_ADC_INP_TSMX	(1 << 2)
++#define UCB_ADC_INP_TSPY	(2 << 2)
++#define UCB_ADC_INP_TSMY	(3 << 2)
++#define UCB_ADC_INP_AD0		(4 << 2)
++#define UCB_ADC_INP_AD1		(5 << 2)
++#define UCB_ADC_INP_AD2		(6 << 2)
++#define UCB_ADC_INP_AD3		(7 << 2)
++#define UCB_ADC_EXT_REF		(1 << 5)
++#define UCB_ADC_START		(1 << 7)
++#define UCB_ADC_ENA		(1 << 15)
++
++#define UCB_ADC_DAT_VAL		(1 << 15)
++
++#define UCB_ID_1200		0x1004
++#define UCB_ID_1300		0x1005
++#define UCB_ID_1400		0x4304
++#define UCB_ID_1400_BUGGY	0x4303	/* fake ID */
++
++#define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
++#define UCB_MODE_AUD_OFF_CAN	(1 << 13)
++
++#include <linux/completion.h>
++#include "mcp.h"
++
++struct ucb1x00_irq {
++	void *devid;
++	void (*fn)(int, void *);
++};
++
++extern struct class ucb1x00_class;
++
++struct ucb1x00 {
++	spinlock_t		lock;
++	struct mcp		*mcp;
++	unsigned int		irq;
++	struct semaphore	adc_sem;
++	spinlock_t		io_lock;
++	wait_queue_head_t	irq_wait;
++	struct completion	complete;
++	struct task_struct	*rtask;
++	u16			id;
++	u16			io_dir;
++	u16			io_out;
++	u16			adc_cr;
++	u16			irq_fal_enbl;
++	u16			irq_ris_enbl;
++	struct ucb1x00_irq	irq_handler[16];
++	struct class_device	cdev;
++	void			*audio_data;
++	void			*telecom_data;
++	void			*ts_data;
++};
++
++#define classdev_to_ucb1x00(cd)	container_of(cd, struct ucb1x00, cdev)
++
++int ucb1x00_register_interface(struct class_interface *intf);
++void ucb1x00_unregister_interface(struct class_interface *intf);
++
++/**
++ *	ucb1x00_clkrate - return the UCB1x00 SIB clock rate
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Return the SIB clock rate in Hz.
++ */
++static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
++{
++	return mcp_get_sclk_rate(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_enable - enable the UCB1x00 SIB clock
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Enable the SIB clock.  This can be called multiple times.
++ */
++static inline void ucb1x00_enable(struct ucb1x00 *ucb)
++{
++	mcp_enable(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_disable - disable the UCB1x00 SIB clock
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Disable the SIB clock.  The SIB clock will only be disabled
++ *	when the number of ucb1x00_enable calls match the number of
++ *	ucb1x00_disable calls.
++ */
++static inline void ucb1x00_disable(struct ucb1x00 *ucb)
++{
++	mcp_disable(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_reg_write - write a UCB1x00 register
++ *	@ucb: UCB1x00 structure describing chip
++ *	@reg: UCB1x00 4-bit register index to write
++ *	@val: UCB1x00 16-bit value to write
++ *
++ *	Write the UCB1x00 register @reg with value @val.  The SIB
++ *	clock must be running for this function to return.
++ */
++static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
++{
++	mcp_reg_write(ucb->mcp, reg, val);
++}
++
++/**
++ *	ucb1x00_reg_read - read a UCB1x00 register
++ *	@ucb: UCB1x00 structure describing chip
++ *	@reg: UCB1x00 4-bit register index to write
++ *
++ *	Read the UCB1x00 register @reg and return its value.  The SIB
++ *	clock must be running for this function to return.
++ */
++static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
++{
++	return mcp_reg_read(ucb->mcp, reg);
++}
++/**
++ *	ucb1x00_set_audio_divisor - 
++ *	@ucb: UCB1x00 structure describing chip
++ *	@div: SIB clock divisor
++ */
++static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++	mcp_set_audio_divisor(ucb->mcp, div);
++}
++
++/**
++ *	ucb1x00_set_telecom_divisor -
++ *	@ucb: UCB1x00 structure describing chip
++ *	@div: SIB clock divisor
++ */
++static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++	mcp_set_telecom_divisor(ucb->mcp, div);
++}
++
++#define ucb1x00_get()	NULL
++
++void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
++void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
++unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
++
++#define UCB_NOSYNC	(0)
++#define UCB_SYNC	(1)
++
++unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
++void ucb1x00_adc_enable(struct ucb1x00 *ucb);
++void ucb1x00_adc_disable(struct ucb1x00 *ucb);
++
++/*
++ * Which edges of the IRQ do you want to control today?
++ */
++#define UCB_RISING	(1 << 0)
++#define UCB_FALLING	(1 << 1)
++
++int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
++void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
++
++#endif
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/misc/switches-sa1100.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,323 @@
++/*
++ *  linux/drivers/misc/switches-sa1100.c
++ *
++ *  Copyright (C) 2001 John Dorsey
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  19 December 2001 - created from sa1100_switches.c.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/irq.h>
++
++#include <asm/arch/assabet.h>
++#include <asm/arch/neponset.h>
++#include <asm/arch/badge4.h>
++
++#include "switches.h"
++
++
++static irqreturn_t switches_sa1100_handler(int irq, void *dev_id,
++					   struct pt_regs *regs);
++
++
++#ifdef CONFIG_SA1100_ASSABET
++
++/* Assabet
++ * ^^^^^^^
++ * We have two general-purpose switches, S1 and S2, available via GPIO
++ * on Assabet. This code sets bits in the range [1, 2] in the mask that
++ * we return to userland.
++ */
++
++static int assabet_switches_sa1100_init(void)
++{
++
++	if (machine_has_neponset())
++		NCR_0 |= NCR_GP01_OFF;
++
++	if (request_irq(IRQ_GPIO0, switches_sa1100_handler, SA_INTERRUPT,
++			SWITCHES_NAME, NULL) < 0) {
++		printk(KERN_ERR "%s: unable to register IRQ for GPIO 0\n",
++		       SWITCHES_NAME);
++		return -EIO;
++	}
++
++	if (request_irq(IRQ_GPIO1, switches_sa1100_handler, SA_INTERRUPT,
++			SWITCHES_NAME, NULL) < 0) {
++		printk(KERN_ERR "%s: unable to register IRQ for GPIO 1\n",
++		       SWITCHES_NAME);
++		free_irq(IRQ_GPIO0, NULL);
++		return -EIO;
++	}
++
++	set_irq_type(IRQ_GPIO0, IRQT_BOTHEDGE);
++	set_irq_type(IRQ_GPIO1, IRQT_BOTHEDGE);
++
++	return 0;
++
++}
++
++static void assabet_switches_sa1100_shutdown(void)
++{
++
++	free_irq(IRQ_GPIO1, NULL);
++	free_irq(IRQ_GPIO0, NULL);
++
++}
++
++static irqreturn_t assabet_switches_sa1100_handler(int irq, switches_mask_t *mask)
++{
++	unsigned int s, last, this;
++	static unsigned int states = 0;
++
++	switch (irq) {
++
++	case IRQ_GPIO0:	s = 0; break;
++
++	case IRQ_GPIO1:	s = 1; break;
++
++	default:	return IRQ_NONE;
++
++	}
++
++	last = ((states & (1 << s)) != 0);
++	this = ((GPLR & GPIO_GPIO(s)) != 0);
++
++	if (last == this) /* debounce */
++		return IRQ_HANDLED;
++
++	SWITCHES_SET(mask, s + 1, this);
++
++	states = this ? (states | (1 << s)) : (states & ~(1 << s));
++
++	return IRQ_HANDLED;
++}
++#endif  /* CONFIG_SA1100_ASSABET */
++
++#ifdef CONFIG_SA1100_BADGE4
++
++/* BadgePAD 4
++ * ^^^^^^^^^^
++ *
++ * Here we use test point J6 (BADGE4_GPIO_TESTPT_J6 aka GPIO 23) as a
++ * general purpose switch input.   We map this to switch #0.
++ */
++
++#define BADGE4_SW0_GPIO GPIO_GPIO23	/* aka BADGE4_GPIO_TESTPT_J6  */
++#define BADGE4_SW0_IRQ  IRQ_GPIO23
++
++static int badge4_switches_sa1100_init(void)
++{
++	if (request_irq(BADGE4_SW0_IRQ, switches_sa1100_handler, SA_INTERRUPT,
++			SWITCHES_NAME, NULL) < 0) {
++		printk(KERN_ERR "%s: unable to register IRQ for SW0\n",
++		       SWITCHES_NAME);
++		return -EIO;
++	}
++
++	set_irq_type(BADGE4_SW0_IRQ, IRQT_BOTHEDGE);
++
++	return 0;
++}
++
++static void badge4_switches_sa1100_shutdown(void)
++{
++	free_irq(BADGE4_SW0_IRQ, NULL);
++}
++
++static irqreturn_t badge4_switches_sa1100_handler(int irq, switches_mask_t *mask)
++{
++	unsigned int swno, last, this, gpio;
++	static unsigned int states = 0;
++
++	switch (irq) {
++	case BADGE4_SW0_IRQ:
++		swno = 0;
++		gpio = BADGE4_SW0_GPIO;
++		break;
++	default:
++		return IRQ_NONE;
++	}
++
++	last = ((states & gpio) != 0);
++	this = ((GPLR & gpio) != 0);
++
++	if (last == this) /* debounce */
++		return IRQ_HANDLED;
++
++	SWITCHES_SET(mask, swno, this);
++
++	states = this ? (states | gpio) : (states & ~gpio);
++
++	return IRQ_HANDLED;
++}
++#endif /* CONFIG_SA1100_BADGE4 */
++
++
++#ifdef CONFIG_SA1100_SPOT
++
++/* Spot
++ * ^^^^
++ * Spot (R2, R3) has a single general-purpose switch (S1), which is
++ * also the power-on switch. We set bit [1] in the mask we return to
++ * userland.
++ */
++
++static int spot_switches_sa1100_init(void)
++{
++
++	set_GPIO_IRQ_edge(GPIO_SW1, GPIO_BOTH_EDGES);
++
++	if (request_irq(IRQ_GPIO_SW1, switches_sa1100_handler, SA_INTERRUPT,
++			SWITCHES_NAME, NULL) < 0) {
++		printk(KERN_ERR "%s: unable to register IRQ for SW1\n",
++		       SWITCHES_NAME);
++		return -EIO;
++	}
++
++	return 0;
++
++}
++
++static void spot_switches_sa1100_shutdown(void)
++{
++
++	free_irq(IRQ_GPIO_SW1, NULL);
++
++}
++
++static irqreturn_t spot_switches_sa1100_handler(int irq, switches_mask_t *mask)
++{
++	unsigned int s, last, this;
++	static unsigned int states = 0;
++
++	switch (irq) {
++
++	case IRQ_GPIO_SW1:	s = 0; break;
++
++	default:		return IRQ_NONE;
++
++	}
++
++	last = ((states & (1 << s)) != 0);
++	this = ((GPLR & GPIO_GPIO(s)) != 0);
++
++	if (last == this) /* debounce */
++		return IRQ_HANDLED;
++
++	SWITCHES_SET(mask, s + 1, this);
++
++	states = this ? (states | (1 << s)) : (states & ~(1 << s));
++
++	return IRQ_HANDLED;
++
++}
++#endif  /* CONFIG_SA1100_SPOT */
++
++
++/* switches_sa1100_handler()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^
++ * This routine is a generalized handler for SA-1100 switches
++ * which manages action descriptors and calls a board-specific
++ * service routine. This routine is appropriate for GPIO switches
++ * or other primary interrupt sources, and can be registered as a
++ * first-class IRQ handler using request_irq().
++ */
++static irqreturn_t switches_sa1100_handler(int irq, void *dev_id,
++					   struct pt_regs *regs)
++{
++	switches_mask_t mask;
++	irqreturn_t ret = IRQ_NONE;
++
++	SWITCHES_ZERO(&mask);
++
++	/* Porting note: call a board-specific switch interrupt handler
++	 * here. The handler can assume that sufficient storage for
++	 * `mask' has been allocated, and that the corresponding
++	 * switches_mask_t structure has been zeroed.
++	 */
++
++	if (machine_is_assabet()) {
++#ifdef CONFIG_SA1100_ASSABET
++		ret = assabet_switches_sa1100_handler(irq, &mask);
++#endif
++	} else if (machine_is_badge4()) {
++#ifdef CONFIG_SA1100_BADGE4
++		ret = badge4_switches_sa1100_handler(irq, &mask);
++#endif
++	} else if (machine_is_spot()) {
++#ifdef CONFIG_SA1100_SPOT
++		ret = spot_switches_sa1100_handler(irq, &mask);
++#endif
++	}
++
++	switches_event(&mask);
++
++	return ret;
++}
++
++int __init switches_sa1100_init(void)
++{
++
++	/* Porting note: call a board-specific init routine here. */
++
++	if (machine_is_assabet()) {
++#ifdef CONFIG_SA1100_ASSABET
++		if (assabet_switches_sa1100_init() < 0)
++			return -EIO;
++#endif
++	} else if (machine_is_badge4()) {
++#ifdef CONFIG_SA1100_BADGE4
++		if (badge4_switches_sa1100_init() < 0)
++			return -EIO;
++#endif
++	} else if (machine_is_spot()) {
++#ifdef CONFIG_SA1100_SPOT
++		if (spot_switches_sa1100_init() < 0)
++			return -EIO;
++#endif
++	}
++
++	return 0;
++
++}
++
++void __exit switches_sa1100_exit(void)
++{
++
++	/* Porting note: call a board-specific shutdown routine here. */
++
++	if (machine_is_assabet()) {
++#ifdef CONFIG_SA1100_ASSABET
++		assabet_switches_sa1100_shutdown();
++#endif
++	} else if (machine_is_badge4()) {
++#ifdef CONFIG_SA1100_BADGE4
++		badge4_switches_sa1100_shutdown();
++#endif
++	} else if (machine_is_spot()) {
++#ifdef CONFIG_SA1100_SPOT
++		spot_switches_sa1100_shutdown();
++#endif
++	}
++
++}
++
++module_init(switches_sa1100_init);
++module_exit(switches_sa1100_exit);
++
++MODULE_DESCRIPTION("SA-1100 switches driver");
++MODULE_LICENSE("GPL");
+--- linux-2.6.5/drivers/misc/Makefile~heh	2004-04-03 22:38:17.000000000 -0500
++++ linux-2.6.5/drivers/misc/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -4,3 +4,21 @@
+ obj- := misc.o	# Dummy rule to force built-in.o to be made
+ 
+ obj-$(CONFIG_IBM_ASM)	+= ibmasm/
++
++obj-$(CONFIG_MCP)		+= mcp-core.o
++obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
++obj-$(CONFIG_MCP_UCB1200_AUDIO)	+= ucb1x00-audio.o
++obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-ts.o
++
++ifeq ($(CONFIG_SA1100_ASSABET),y)
++obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-assabet.o
++endif
++
++obj-$(CONFIG_SWITCHES)		+= switches-core.o
++obj-$(CONFIG_SWITCHES_SA1100)	+= switches-sa1100.o
++obj-$(CONFIG_SWITCHES_UCB1X00)	+= switches-ucb1x00.o
++
++obj-$(CONFIG_MCP_SA1100)	+= mcp-sa1100.o
++
++obj-$(CONFIG_UCB1400_TS)	+= mcp-pxa.o ucb1x00-core.o ucb1x00-ts.o
++
+--- linux-2.6.5/drivers/i2c/busses/Kconfig~heh	2004-04-03 22:38:10.000000000 -0500
++++ linux-2.6.5/drivers/i2c/busses/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -70,6 +70,16 @@
+ 	  This support is also available as a module.  If so, the module
+ 	  will be called i2c-hydra.
+ 
++config I2C_BIT_SA1100_GPIO
++	bool "SA1100 I2C GPIO adapter"
++	depends on ARCH_SA1100 && I2C_ALGOBIT
++	help
++	  This supports I2C on the SA11x0 processor GPIO pins.  This
++	  shares support with the L3 driver.
++
++	  This support is also available as a module.  If so, the module
++	  will be called l3-bit-sa1100.
++
+ config I2C_I801
+ 	tristate "Intel 801"
+ 	depends on I2C && PCI && EXPERIMENTAL
+@@ -241,6 +251,18 @@
+ 	  This support is also available as a module.  If so, the module 
+ 	  will be called i2c-prosavage.
+ 
++config I2C_PXA2XX
++	tristate "PXA I2C Interface"
++	depends on I2C && ARCH_PXA
++	select I2C_ALGOPXA
++	help
++	  This supports the use of the PXA I2C interface found on the Intel 
++	  PXA 25x and PXA 26x systems. Say Y if you have one of these. 
++
++          This support is also available as a module. If you want to compile
++          it as a module, say M here and read Documentation/modules.txt.
++          The module will be called i2c-adap-pxa.
++
+ config I2C_RPXLITE
+ 	tristate "Embedded Planet RPX Lite/Classic support"
+ 	depends on (RPXLITE || RPXCLASSIC) && I2C
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/i2c/busses/pxa2xx_i2c.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,388 @@
++/*
++ *  i2c_adap_pxa.c
++ *
++ *  I2C adapter for the PXA I2C bus access.
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Apr 2002: Initial version [CS]
++ *    Jun 2002: Properly seperated algo/adap [FB]
++ *    Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
++ *    Jan 2003: added limited signal handling [Kai-Uwe Bloem]
++ *    Jun 2003: updated for 2.5 [Dustin McIntire]
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-id.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/irqs.h>              /* for IRQ_I2C */
++
++#include <linux/i2c-pxa.h>
++
++/*
++ * Set this to zero to remove all debug statements via dead code elimination.
++ */
++//#define DEBUG       1
++
++#if DEBUG
++static unsigned int i2c_debug = DEBUG;
++#else
++#define i2c_debug	0
++#endif
++
++static int irq = 0;
++static volatile int i2c_pending = 0;             /* interrupt pending when 1 */
++static volatile int bus_error = 0;
++static volatile int tx_finished = 0;
++static volatile int rx_finished = 0;
++
++static wait_queue_head_t i2c_wait;
++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte);
++
++/* place a byte in the transmit register */
++static void i2c_pxa_write_byte(u8 value)
++{
++	IDBR = value;
++}
++
++/* read byte in the receive register */
++static u8 i2c_pxa_read_byte(void)
++{
++	return (u8) (0xff & IDBR);
++}
++
++static void i2c_pxa_start(void)
++{
++	unsigned long icr = ICR;
++	icr |= ICR_START;
++	icr &= ~(ICR_STOP | ICR_ALDIE | ICR_ACKNAK);
++	ICR = icr;
++
++	bus_error=0;            /* clear any bus_error from previous txfers */
++	tx_finished=0;          /* clear rx and tx interrupts from previous txfers */
++	rx_finished=0;
++	i2c_pending = 0;
++}
++
++static void i2c_pxa_repeat_start(void)
++{
++	unsigned long icr = ICR;
++	icr |= ICR_START;
++	icr &= ~(ICR_STOP | ICR_ALDIE);
++	ICR = icr;
++
++	bus_error=0;            /* clear any bus_error from previous txfers */
++	tx_finished=0;          /* clear rx and tx interrupts from previous txfers */
++	rx_finished=0;
++	i2c_pending = 0;
++}
++
++static void i2c_pxa_stop(void)
++{
++	unsigned long icr = ICR;
++	icr |= ICR_STOP;
++	icr &= ~(ICR_START);
++	ICR = icr;
++}
++
++static void i2c_pxa_midbyte(void)
++{
++	unsigned long icr = ICR;
++	icr &= ~(ICR_START | ICR_STOP);
++	ICR = icr;
++}
++
++static void i2c_pxa_abort(void)
++{
++	unsigned long timeout = jiffies + HZ/4;
++
++#ifdef PXA_ABORT_MA
++	while ((long)(timeout - jiffies) > 0 && (ICR & ICR_TB)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++
++	ICR |= ICR_MA;
++	udelay(100);
++#else
++	while ((long)(timeout - jiffies) > 0 && (IBMR & 0x1) == 0) {
++		i2c_pxa_transfer( 1, I2C_RECEIVE, 1);
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++#endif
++	ICR &= ~(ICR_MA | ICR_START | ICR_STOP);
++}
++
++static int i2c_pxa_wait_bus_not_busy( void)
++{
++	int timeout = DEF_TIMEOUT;
++
++	while (timeout-- && (ISR & ISR_IBB)) {
++		udelay(100); /* wait for 100 us */
++	}
++
++	return (timeout<=0);
++}
++
++spinlock_t i2c_pxa_irqlock = SPIN_LOCK_UNLOCKED;
++
++static void i2c_pxa_wait_for_ite(void){
++	unsigned long flags;
++	if (irq > 0) {
++	    spin_lock_irqsave(&i2c_pxa_irqlock, flags);
++		if (i2c_pending == 0) {
++			interruptible_sleep_on_timeout(&i2c_wait, I2C_SLEEP_TIMEOUT );
++		}
++		i2c_pending = 0;
++		spin_unlock_irqrestore(&i2c_pxa_irqlock, flags);
++	} else {
++		udelay(100);
++	}
++}
++
++static int i2c_pxa_wait_for_int( int wait_type)
++{
++	int timeout = DEF_TIMEOUT;
++#ifdef DEBUG
++	if (bus_error)
++		printk(KERN_INFO"i2c_pxa_wait_for_int: Bus error on enter\n");
++	if (rx_finished)
++		printk(KERN_INFO"i2c_pxa_wait_for_int: Receive interrupt on enter\n");
++	if (tx_finished)
++		printk(KERN_INFO"i2c_pxa_wait_for_int: Transmit interrupt on enter\n");
++#endif
++
++	if (wait_type == I2C_RECEIVE){         /* wait on receive */
++
++		do {
++			i2c_pxa_wait_for_ite();
++		} while (!(rx_finished) && timeout-- && !signal_pending(current));
++
++#ifdef DEBUG
++		if (timeout<0){
++			if (tx_finished)
++				printk("Error: i2c-algo-pxa.o: received a tx"
++						" interrupt while waiting on a rx in wait_for_int");
++		}
++#endif
++	} else {                  /* wait on transmit */
++
++		do {
++			i2c_pxa_wait_for_ite();
++		} while (!(tx_finished) && timeout-- && !signal_pending(current));
++
++#ifdef DEBUG
++		if (timeout<0){
++			if (rx_finished)
++				printk("Error: i2c-algo-pxa.o: received a rx"
++					" interrupt while waiting on a tx in wait_for_int");
++		}
++#endif
++	}
++
++	udelay(ACK_DELAY);      /* this is needed for the bus error */
++
++	tx_finished=0;
++	rx_finished=0;
++
++	if (bus_error){
++		bus_error=0;
++		if( i2c_debug > 2)printk("wait_for_int: error - no ack.\n");
++		return BUS_ERROR;
++	}
++
++	if (signal_pending(current)) {
++		return (-ERESTARTSYS);
++	} else if (timeout < 0) {
++		if( i2c_debug > 2)printk("wait_for_int: timeout.\n");
++		return(-EIO);
++	} else
++		return(0);
++}
++
++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte)
++{
++	if( lastbyte)
++	{
++		if( receive==I2C_RECEIVE) ICR |= ICR_ACKNAK;
++		i2c_pxa_stop();
++	}
++	else if( midbyte)
++	{
++		i2c_pxa_midbyte();
++	}
++	ICR |= ICR_TB;
++}
++
++static void i2c_pxa_reset( void)
++{
++#ifdef DEBUG
++	printk("Resetting I2C Controller Unit\n");
++#endif
++
++	/* abort any transfer currently under way */
++	i2c_pxa_abort();
++
++	/* reset according to 9.8 */
++	ICR = ICR_UR;
++	ISR = I2C_ISR_INIT;
++	ICR &= ~ICR_UR;
++
++	/* set the global I2C clock on */
++	CKEN |= CKEN14_I2C;
++
++	/* set our slave address */
++	ISAR = I2C_PXA_SLAVE_ADDR;
++
++	/* set control register values */
++	ICR = I2C_ICR_INIT;
++
++	/* clear any leftover states from prior transmissions */
++	i2c_pending = rx_finished = tx_finished = bus_error = 0;
++
++	/* enable unit */
++	ICR |= ICR_IUE;
++	udelay(100);
++}
++
++static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
++{
++    unsigned long flags;
++	int status, wakeup = 0;
++	status = (ISR);
++
++	if (status & ISR_BED){
++		(ISR) |= ISR_BED;
++		bus_error=ISR_BED;
++		wakeup = 1;
++	}
++	if (status & ISR_ITE){
++		(ISR) |= ISR_ITE;
++		tx_finished=ISR_ITE;
++		wakeup = 1;
++	}
++	if (status & ISR_IRF){
++		(ISR) |= ISR_IRF;
++		rx_finished=ISR_IRF;
++		wakeup = 1;
++	}
++	if (wakeup) {
++	    spin_lock_irqsave(&i2c_pxa_irqlock, flags);
++		i2c_pending = 1;
++		spin_unlock_irqrestore(&i2c_pxa_irqlock, flags);
++		wake_up_interruptible(&i2c_wait);
++	}
++	return IRQ_HANDLED;
++}
++
++static int i2c_pxa_resource_init( void)
++{
++	init_waitqueue_head(&i2c_wait);
++
++	if (request_irq(IRQ_I2C, &i2c_pxa_handler, SA_INTERRUPT, "I2C", 0) < 0) {
++		irq = 0;
++		if(i2c_debug)
++			printk(KERN_INFO "I2C: Failed to register I2C irq %i\n", IRQ_I2C);
++		return -ENODEV;
++	}
++	return 0;
++}
++
++static void i2c_pxa_resource_release( void)
++{
++	if( irq > 0)
++	{
++		disable_irq(irq);
++		free_irq(irq,0);
++		irq=0;
++	}
++}
++
++static int i2c_pxa_client_register(struct i2c_client *client)
++{
++	return 0;
++}
++
++static int i2c_pxa_client_unregister(struct i2c_client *client)
++{
++	return 0;
++}
++
++static struct i2c_algo_pxa_data i2c_pxa_data = {
++	write_byte:		i2c_pxa_write_byte,
++	read_byte:		i2c_pxa_read_byte,
++
++	start:			i2c_pxa_start,
++	repeat_start:		i2c_pxa_repeat_start,
++	stop:			i2c_pxa_stop,
++	abort:			i2c_pxa_abort,
++
++	wait_bus_not_busy:	i2c_pxa_wait_bus_not_busy,
++	wait_for_interrupt:	i2c_pxa_wait_for_int,
++	transfer:		i2c_pxa_transfer,
++	reset:			i2c_pxa_reset,
++
++	udelay:			10,
++	timeout:		DEF_TIMEOUT,
++};
++
++static struct i2c_adapter i2c_pxa_ops = {
++	.owner      = THIS_MODULE,
++    .id         = I2C_ALGO_PXA,
++    .algo_data  = &i2c_pxa_data,
++    .dev        = {
++        .name   = "PXA I2C Adapter",
++    },
++	.client_register   = i2c_pxa_client_register,
++	.client_unregister = i2c_pxa_client_unregister,
++	.retries           = 2,
++};
++
++extern int i2c_pxa_add_bus(struct i2c_adapter *);
++extern int i2c_pxa_del_bus(struct i2c_adapter *);
++
++static int __init i2c_adap_pxa_init(void)
++{
++	if( i2c_pxa_resource_init() == 0) {
++
++		if (i2c_pxa_add_bus(&i2c_pxa_ops) < 0) {
++			i2c_pxa_resource_release();
++			printk(KERN_INFO "I2C: Failed to add bus\n");
++			return -ENODEV;
++		}
++	} else {
++		return -ENODEV;
++	}
++
++	printk(KERN_INFO "I2C: Successfully added bus\n");
++
++	return 0;
++}
++
++static void i2c_adap_pxa_exit(void)
++{
++	i2c_pxa_del_bus( &i2c_pxa_ops);
++	i2c_pxa_resource_release();
++
++	printk(KERN_INFO "I2C: Successfully removed bus\n");
++}
++
++module_init(i2c_adap_pxa_init);
++module_exit(i2c_adap_pxa_exit);
+--- linux-2.6.5/drivers/i2c/busses/Makefile~heh	2004-04-03 22:36:17.000000000 -0500
++++ linux-2.6.5/drivers/i2c/busses/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -21,6 +21,7 @@
+ obj-$(CONFIG_I2C_PARPORT_LIGHT)	+= i2c-parport-light.o
+ obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
+ obj-$(CONFIG_I2C_PROSAVAGE)	+= i2c-prosavage.o
++obj-$(CONFIG_I2C_PXA)		+= pxa2xx_i2c.o
+ obj-$(CONFIG_I2C_RPXLITE)	+= i2c-rpx.o
+ obj-$(CONFIG_I2C_SAVAGE4)	+= i2c-savage4.o
+ obj-$(CONFIG_I2C_SIS5595)	+= i2c-sis5595.o
+--- linux-2.6.5/drivers/i2c/algos/Kconfig~heh	2004-04-03 22:37:59.000000000 -0500
++++ linux-2.6.5/drivers/i2c/algos/Kconfig	2004-04-30 20:57:36.000000000 -0400
+@@ -38,6 +38,18 @@
+ 	  This support is also available as a module.  If so, the module 
+ 	  will be called i2c-algo-ite.
+ 
++config I2C_ALGOPXA
++	tristate "PXA I2C Algorithm"
++	depends on ARCH_PXA && I2C
++	help
++	  This supports the use of the PXA I2C interface found on the Intel
++	  PXA 25x and PXA 26x systems. Say Y if you have one of these. 
++	  You should also say Y for the PXA I2C peripheral driver support below.
++
++	  This support is also available as a module. If you want to compile
++	  it as a module, say M here and read Documentation/modules.txt.
++	  The module will be called i2c-algo-pxa.
++
+ config I2C_ALGO8XX
+ 	tristate "MPC8xx CPM I2C interface"
+ 	depends on 8xx && I2C
+--- /dev/null	2003-09-23 18:19:32.000000000 -0400
++++ linux-2.6.5/drivers/i2c/algos/i2c-algo-pxa.c	2004-04-30 20:57:36.000000000 -0400
+@@ -0,0 +1,384 @@
++/*
++ *  i2c-algo-pxa.c
++ *
++ *  I2C algorithm for the PXA I2C bus access.
++ *  Byte driven algorithm similar to pcf.
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Apr 2002: Initial version [CS]
++ *    Jun 2002: Properly seperated algo/adap [FB]
++ *    Jan 2003: added limited signal handling [Kai-Uwe Bloem]
++ *    Jan 2003: allow SMBUS_QUICK as valid msg [FB]
++ *    Jun 2003: updated for 2.5 [Dustin McIntire]
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/i2c.h>          /* struct i2c_msg and others */
++#include <linux/i2c-id.h>
++
++#include <linux/i2c-pxa.h>
++
++/*
++ * Set this to zero to remove all the debug statements via dead code elimination.
++ */
++//#define DEBUG		1
++
++#if DEBUG
++static unsigned int i2c_debug = DEBUG;
++#else
++#define i2c_debug	0
++#endif
++
++static int pxa_scan = 1;
++
++static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num)
++{
++	int i;
++	if (num < 1 || num > MAX_MESSAGES){
++		if( i2c_debug)
++			printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n",
++				MAX_MESSAGES, num);
++		return -EINVAL;
++	}
++
++	/* check consistency of our messages */
++	for (i=0;i<num;i++){
++		if (&msgs[i]==NULL){
++			if( i2c_debug) printk(KERN_INFO "Msgs is NULL\n");
++			return -EINVAL;
++		} else {
++			if (msgs[i].buf == NULL){
++				if( i2c_debug)printk(KERN_INFO "Length is less than zero");
++				return -EINVAL;
++			}
++		}
++	}
++
++	return 1;
++}
++
++static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf,
++			int count, int last)
++{
++
++	int i, timeout=0;
++	struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++
++	/* increment number of bytes to read by one -- read dummy byte */
++	for (i = 0; i <= count; i++) {
++		if (i!=0){
++			/* set ACK to NAK for last received byte ICR[ACKNAK] = 1
++			   only if not a repeated start */
++
++			if ((i == count) && last) {
++				adap->transfer( last, I2C_RECEIVE, 0);
++			}else{
++				adap->transfer( 0, I2C_RECEIVE, 1);
++			}
++
++			timeout = adap->wait_for_interrupt(I2C_RECEIVE);
++
++#ifdef DEBUG
++			if (timeout==BUS_ERROR){
++				printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n");
++				adap->reset();
++				return I2C_RETRY;
++			} else
++#endif
++			if (timeout == -ERESTARTSYS) {
++				adap->abort();
++				return timeout;
++			} else
++			if (timeout){
++#ifdef DEBUG
++				printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n");
++#endif
++				adap->reset();
++				return I2C_RETRY;
++			}
++
++		}
++
++		if (i) {
++			buf[i - 1] = adap->read_byte();
++		} else {
++			adap->read_byte(); /* dummy read */
++		}
++	}
++	return (i - 1);
++}
++
++static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
++                         int count, int last)
++{
++
++	struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++	int wrcount, timeout;
++
++	for (wrcount=0; wrcount<count; ++wrcount) {
++
++		adap->write_byte(buf[wrcount]);
++		if ((wrcount==(count-1)) && last) {
++			adap->transfer( last, I2C_TRANSMIT, 0);
++		}else{
++			adap->transfer( 0, I2C_TRANSMIT, 1);
++		}
++
++		timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
++
++#ifdef DEBUG
++		if (timeout==BUS_ERROR) {
++			printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n");
++			adap->reset();
++			return I2C_RETRY;
++		} else
++#endif
++		if (timeout == -ERESTARTSYS) {
++			adap->abort();
++			return timeout;
++		} else
++		if (timeout) {
++#ifdef DEBUG
++			printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n");
++#endif
++			adap->reset();
++			return I2C_RETRY;
++		}
++	}
++	return (wrcount);
++}
++
++
++static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg)
++{
++	u16 flags = msg->flags;
++	u8 addr;
++	addr = (u8) ( (0x7f & msg->addr) << 1 );
++	if (flags & I2C_M_RD )
++		addr |= 1;
++	if (flags & I2C_M_REV_DIR_ADDR )
++		addr ^= 1;
++	adap->write_byte(addr);
++	return 0;
++}
++
++static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++{
++	struct i2c_algo_pxa_data * adap;
++	struct i2c_msg *pmsg=NULL;
++	int i;
++	int ret=0, timeout;
++
++	adap = i2c_adap->algo_data;
++
++	timeout = adap->wait_bus_not_busy();
++
++	if (timeout) {
++		return I2C_RETRY;
++	}
++
++	for (i = 0;ret >= 0 && i < num; i++) {
++		int last = i + 1 == num;
++		pmsg = &msgs[i];
++
++		ret = i2c_pxa_set_ctrl_byte(adap,pmsg);
++
++		/* Send START */
++		if (i == 0) {
++			adap->start();
++		}else{
++			adap->repeat_start();
++		}
++
++		adap->transfer(0, I2C_TRANSMIT, 0);
++
++		/* Wait for ITE (transmit empty) */
++		timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
++
++#ifdef DEBUG
++		/* Check for ACK (bus error) */
++		if (timeout==BUS_ERROR){
++			printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing reset\n");
++			adap->reset();
++			return I2C_RETRY;
++		} else
++#endif
++		if (timeout == -ERESTARTSYS) {
++			adap->abort();
++			return timeout;
++		} else
++		if (timeout) {
++#ifdef DEBUG
++			printk(KERN_INFO "i2c_pxa_do_xfer: timeout -> forcing reset\n");
++#endif
++			adap->reset();
++			return I2C_RETRY;
++		}
++/* FIXME: handle arbitration... */
++#if 0
++		/* Check for bus arbitration loss */
++		if (adap->arbitration_loss()){
++			printk("Arbitration loss detected \n");
++			adap->reset();
++			return I2C_RETRY;
++		}
++#endif
++
++		/* Read */
++		if (pmsg->flags & I2C_M_RD) {
++			/* read bytes into buffer*/
++			ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last);
++#if DEBUG > 2
++			if (ret != pmsg->len) {
++				printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.\n",
++					ret, pmsg->len);
++			} else {
++				printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.\n",ret);
++			}
++#endif
++		} else { /* Write */
++			ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last);
++#if DEBUG > 2
++			if (ret != pmsg->len) {
++				printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.\n",
++					ret, pmsg->len);
++			} else {
++				printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.\n",ret);
++			}
++#endif
++		}
++	}
++
++	if (ret<0){
++		return ret;
++	}else{
++		return i;
++	}
++}
++
++static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++{
++	int retval = i2c_pxa_valid_messages( msgs, num);
++	if( retval > 0)
++	{
++		int i;
++		for (i=i2c_adap->retries; i>=0; i--){
++			int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num);
++			if (retval!=I2C_RETRY){
++				return retval;
++			}
++			if( i2c_debug)printk(KERN_INFO"Retrying transmission \n");
++			udelay(100);
++		}
++		if( i2c_debug)printk(KERN_INFO"Retried %i times\n",i2c_adap->retries);
++		return -EREMOTEIO;
++
++	}
++	return retval;
++}
++
++static u32 i2c_pxa_functionality(struct i2c_adapter * adapter)
++{
++    /* Emulate the SMBUS functions */
++	return I2C_FUNC_SMBUS_EMUL;
++}
++
++struct i2c_algorithm i2c_pxa_algorithm  = {
++	name:                   "PXA I2C Algorithm",
++	id:                     I2C_ALGO_PXA,
++	master_xfer:            i2c_pxa_xfer,
++	smbus_xfer:             NULL,
++	slave_send:             NULL,
++	slave_recv:             NULL,
++	algo_control:           NULL,
++    functionality:          i2c_pxa_functionality,
++};
++
++/*
++ * registering functions to load algorithms at runtime
++ */
++int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap)
++{
++	struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++
++	printk(KERN_INFO"I2C: Adding %s.\n", i2c_adap->dev.name);
++
++	i2c_adap->algo = &i2c_pxa_algorithm;
++
++	MOD_INC_USE_COUNT;
++
++	/* register new adapter to i2c module... */
++	i2c_add_adapter(i2c_adap);
++
++	adap->reset();
++
++	/* scan bus */
++	if (pxa_scan) {
++		int i;
++		printk(KERN_INFO "I2C: Scanning bus ");
++		for (i = 0x02; i < 0xff; i+=2) {
++			if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue;
++
++			if (adap->wait_bus_not_busy()) {
++				printk(KERN_INFO "I2C: scanning bus %s - TIMEOUT.\n",
++						i2c_adap->dev.name);
++				return -EIO;
++			}
++			adap->write_byte(i);
++			adap->start();
++			adap->transfer(0, I2C_TRANSMIT, 0);
++
++			if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) {
++				printk("(%02x)",i>>1);
++				adap->abort();
++			} else {
++//				printk(".");
++				adap->stop();
++			}
++			udelay(adap->udelay);
++		}
++		printk("\n");
++	}
++	return 0;
++}
++
++int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap)
++{
++	int res;
++	if ((res = i2c_del_adapter(i2c_adap)) < 0)
++		return res;
++
++	MOD_DEC_USE_COUNT;
++
++	printk(KERN_INFO "I2C: Removing %s.\n", i2c_adap->dev.name);
++
++	return 0;
++}
++
++static int __init i2c_algo_pxa_init (void)
++{
++	printk(KERN_INFO "I2C: PXA algorithm module loaded.\n");
++	return 0;
++}
++
++EXPORT_SYMBOL(i2c_pxa_add_bus);
++EXPORT_SYMBOL(i2c_pxa_del_bus);
++
++MODULE_PARM(pxa_scan, "i");
++MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus");
++
++MODULE_AUTHOR("Intrinsyc Software Inc.");
++MODULE_LICENSE("GPL");
++
++module_init(i2c_algo_pxa_init);
+--- linux-2.6.5/drivers/i2c/algos/Makefile~heh	2004-04-03 22:37:37.000000000 -0500
++++ linux-2.6.5/drivers/i2c/algos/Makefile	2004-04-30 20:57:36.000000000 -0400
+@@ -4,6 +4,7 @@
+ 
+ obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
+ obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
++obj-$(CONFIG_I2C_ALGOPXA)	+= i2c-algo-pxa.o
+ obj-$(CONFIG_I2C_ALGOITE)	+= i2c-algo-ite.o
+ 
+ ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
+--- linux-2.6.5/Makefile~heh	2004-04-03 22:37:36.000000000 -0500
++++ linux-2.6.5/Makefile	2004-04-30 20:57:58.000000000 -0400
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+ SUBLEVEL = 5
+-EXTRAVERSION =
++EXTRAVERSION = -gnalm1
+ NAME=Zonked Quokka
+ 
+ # *DOCUMENTATION*
diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa
index e69de29bb2..9446168fdb 100644
--- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa
+++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqpxa
@@ -0,0 +1,1575 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MINIMAL_OOPS is not set
+
+#
+# Linux As Bootldr support
+#
+# CONFIG_LAB is not set
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_CONSUS is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_JORNADA56X is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_REGISTERS is not set
+
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_PXA_CERF is not set
+CONFIG_ARCH_H3900=y
+CONFIG_ARCH_H1900=y
+CONFIG_ARCH_H5400=y
+# CONFIG_ARCH_H2200 is not set
+CONFIG_ARCH_AXIM=y
+CONFIG_PXA_USB=m
+CONFIG_PXA_USB_NETLINK=m
+CONFIG_PXA_USB_CHAR=m
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+CONFIG_CPU_32v5=y
+CONFIG_CPU_XSCALE=y
+CONFIG_XSCALE_PXA250=y
+# CONFIG_XSCALE_80200_OLD is not set
+# CONFIG_CPU_32v3 is not set
+# CONFIG_CPU_32v4 is not set
+# CONFIG_SA1100_IPAQ is not set
+CONFIG_PXA_IPAQ=y
+CONFIG_IPAQ_HANDHELD=y
+
+#
+# Compaq iPAQ Handheld
+#
+CONFIG_IPAQ_HAL=m
+# CONFIG_H3600_MICRO is not set
+CONFIG_IPAQ_HAS_ROSELLA=y
+CONFIG_H3600_ASIC=m
+CONFIG_H3900_ASIC_DEBUG=m
+CONFIG_H5400_ASIC=m
+CONFIG_H1900_ASIC=m
+CONFIG_H1900_TS=m
+CONFIG_H3600_HARDWARE=y
+CONFIG_IPAQ_SLEEVE=m
+CONFIG_SLEEVE_DEBUG=y
+CONFIG_SLEEVE_DEBUG_VERBOSE=0
+# CONFIG_SLEEVE_IRQ_DEMUX is not set
+
+#
+# Dell Axim X5
+#
+CONFIG_AXIM_HAL=m
+
+#
+# Processor Features
+#
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+# CONFIG_PCMCIA_SA1100 is not set
+CONFIG_PCMCIA_PXA=m
+# CONFIG_MERCURY_BACKPAQ is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=m
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_DEBUG_VERBOSE=0
+CONFIG_MMC_SAMSUNG_ASIC=m
+# CONFIG_MMC_S3C2410 is not set
+CONFIG_MMC_H5400=m
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_XIP_KERNEL is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+CONFIG_APM=m
+# CONFIG_HWTIMER is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_IDP is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_LUBBOCK is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_AUTCPU12 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_H720X is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_NVRD=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_DM=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_IPV6_TUNNEL=m
+CONFIG_IPV6_MOBILITY=m
+CONFIG_IPV6_MOBILITY_MN=m
+# CONFIG_IPV6_MOBILITY_HA is not set
+CONFIG_IPV6_MOBILITY_DEBUG=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC=m
+
+#
+# IPSec options (FreeS/WAN)
+#
+CONFIG_IPSEC_IPIP=y
+CONFIG_IPSEC_AH=y
+CONFIG_IPSEC_AUTH_HMAC_MD5=y
+CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+CONFIG_IPSEC_ESP=y
+CONFIG_IPSEC_ENC_3DES=y
+CONFIG_IPSEC_IPCOMP=y
+CONFIG_IPSEC_DEBUG=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+# CONFIG_SPECTRUM24T is not set
+
+#
+# Wireless Pcmcia cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_WVLAN_CS is not set
+# CONFIG_MWVLAN_CS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+CONFIG_NET_WIRELESS=y
+CONFIG_ATMELWLAN=y
+CONFIG_ATMELWLAN_USB_503A_RFMD=m
+CONFIG_ATMELWLAN_PCMCIA_502A=m
+CONFIG_ATMELWLAN_PCMCIA_3COM=m
+CONFIG_ATMELWLAN_PCMCIA_502AD=m
+CONFIG_ATMELWLAN_PCMCIA_502AE=m
+CONFIG_ATMELWLAN_PCMCIA_504=m
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_PXA_FIR=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_SCSI_PCMCIA=y
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_DETECT_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_S3C2410 is not set
+# CONFIG_SERIAL_S3C2410_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL_SIR_PXA is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+CONFIG_NEWTONKBD=m
+# CONFIG_SA1100_PROFILER is not set
+
+#
+# Compaq iPAQ H3600 support
+#
+CONFIG_TOUCHSCREEN_H3600=m
+# CONFIG_H3600_BACKPAQ_FPGA is not set
+# CONFIG_H3600_BACKPAQ_ACCEL is not set
+# CONFIG_H3600_BACKPAQ_GASGAUGE is not set
+# CONFIG_H3600_BACKPAQ_SRAM is not set
+# CONFIG_H3600_BACKPAQ_AUDIO is not set
+# CONFIG_H3600_STOWAWAY is not set
+# CONFIG_H3800_MICROKBD is not set
+# CONFIG_SA1100_LIRC is not set
+CONFIG_H5400_BUZZER=m
+CONFIG_H5400_FSI=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_PXA_ALGO=m
+CONFIG_I2C_PXA_ADAP=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+# CONFIG_I2C_DS1307 is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_S3C2410 is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_L3_BACKPAQ is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=m
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=m
+CONFIG_INPUT_SERPORT=m
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+CONFIG_PXA_WATCHDOG=m
+# CONFIG_OMAHA_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_PXA_RTC=m
+CONFIG_PXA_RTC_HACK=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+CONFIG_PCMCIA_MOBILISCAN_CS=m
+# CONFIG_AXIM_TS is not set
+CONFIG_AXIM_KEY=m
+# CONFIG_AXIM_KEY_FIX is not set
+
+#
+# Multimedia devices
+#
+CONFIG_MEDIA=m
+CONFIG_VIDEO_DEV=m
+CONFIG_V4L2_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_USB=m
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+# CONFIG_VIDEO_CYBERPRO is not set
+# CONFIG_VIDEO_H3600_BACKPAQ is not set
+# CONFIG_VIDEO_HAWKEYE is not set
+
+#
+# Video for Linux 2 (V4L2)
+#
+CONFIG_VIDEO_WINNOV_CS=m
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DRIVERFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_S3C2410 is not set
+# CONFIG_FB_SA1100 is not set
+# CONFIG_FB_EPSON1356 is not set
+# CONFIG_FB_MQ200 is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_8BPP is not set
+CONFIG_FB_PXA_16BPP=y
+CONFIG_FB_MQ1100=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_NO_LOGO is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_H3900_UDA1380=m
+CONFIG_SOUND_H5400=m
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_VIDC is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+CONFIG_SOUND_PXA_AC97=m
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_MCP_UCB1400_TS is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=m
+# CONFIG_USB_OHCI_SA1111 is not set
+CONFIG_USB_OHCI_H5400=m
+# CONFIG_USB_OHCI_S3C2410 is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+CONFIG_USB_CDCETHER=m
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_BRLVGER is not set
+
+#
+# Linux As Bootldr Modules
+#
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+# CONFIG_YMODEM is not set
+# CONFIG_LAB_DUMMY is not set
+# CONFIG_LAB_CRC is not set
+# CONFIG_LAB_YMODEM is not set
+# CONFIG_LAB_MTD is not set
+# CONFIG_LAB_COPY is not set
+# CONFIG_LAB_COPY_YMODEM is not set
+# CONFIG_LAB_COPY_FLASH is not set
+# CONFIG_LAB_COPY_FS is not set
+# CONFIG_LAB_COPY_WRAPPER is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
+# CONFIG_BLUEZ_HCIBFUSB is not set
+CONFIG_BLUEZ_HCIDTL1=m
+CONFIG_BLUEZ_HCIBT3C=m
+CONFIG_BLUEZ_HCIBLUECARD=m
+CONFIG_BLUEZ_HCIBTUART=m
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa
index e69de29bb2..681818f9ab 100644
--- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa
+++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.13/defconfig-ipaqpxa
@@ -0,0 +1,1577 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MINIMAL_OOPS is not set
+
+#
+# Linux As Bootldr support
+#
+# CONFIG_LAB is not set
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_CONSUS is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_JORNADA56X is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_REGISTERS is not set
+
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_PXA_CERF is not set
+CONFIG_ARCH_H3900=y
+CONFIG_ARCH_H1900=y
+CONFIG_ARCH_H5400=y
+# CONFIG_ARCH_H2200 is not set
+CONFIG_ARCH_AXIM=y
+CONFIG_PXA_USB=m
+CONFIG_PXA_USB_NETLINK=m
+CONFIG_PXA_USB_CHAR=m
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+CONFIG_CPU_32v5=y
+CONFIG_CPU_XSCALE=y
+CONFIG_XSCALE_PXA250=y
+# CONFIG_XSCALE_80200_OLD is not set
+# CONFIG_CPU_32v3 is not set
+# CONFIG_CPU_32v4 is not set
+# CONFIG_SA1100_IPAQ is not set
+CONFIG_PXA_IPAQ=y
+CONFIG_IPAQ_HANDHELD=y
+
+#
+# Compaq iPAQ Handheld
+#
+CONFIG_IPAQ_HAL=m
+# CONFIG_H3600_MICRO is not set
+CONFIG_IPAQ_HAS_ROSELLA=y
+CONFIG_IPAQ_HAS_ASIC3=y
+CONFIG_H3600_ASIC=m
+CONFIG_H3900_ASIC_DEBUG=m
+CONFIG_H5400_ASIC=m
+CONFIG_H1900_ASIC=m
+CONFIG_H1900_TS=m
+CONFIG_H3600_HARDWARE=y
+CONFIG_IPAQ_SLEEVE=m
+CONFIG_SLEEVE_DEBUG=y
+CONFIG_SLEEVE_DEBUG_VERBOSE=0
+# CONFIG_SLEEVE_IRQ_DEMUX is not set
+
+#
+# Dell Axim X5
+#
+CONFIG_AXIM_HAL=m
+
+#
+# Processor Features
+#
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+# CONFIG_PCMCIA_SA1100 is not set
+CONFIG_PCMCIA_PXA=m
+# CONFIG_MERCURY_BACKPAQ is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=m
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_DEBUG_VERBOSE=0
+CONFIG_MMC_SAMSUNG_ASIC=m
+# CONFIG_MMC_S3C2410 is not set
+CONFIG_MMC_H5400=m
+CONFIG_MMC_ASIC3=m
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_XIP_KERNEL is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+CONFIG_APM=m
+# CONFIG_HWTIMER is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_IDP is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_LUBBOCK is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_AUTCPU12 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_H720X is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_NVRD=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_DM=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_IPV6_TUNNEL=m
+CONFIG_IPV6_MOBILITY=m
+CONFIG_IPV6_MOBILITY_MN=m
+# CONFIG_IPV6_MOBILITY_HA is not set
+CONFIG_IPV6_MOBILITY_DEBUG=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC=m
+
+#
+# IPSec options (FreeS/WAN)
+#
+CONFIG_IPSEC_IPIP=y
+CONFIG_IPSEC_AH=y
+CONFIG_IPSEC_AUTH_HMAC_MD5=y
+CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+CONFIG_IPSEC_ESP=y
+CONFIG_IPSEC_ENC_3DES=y
+CONFIG_IPSEC_IPCOMP=y
+CONFIG_IPSEC_DEBUG=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+# CONFIG_SPECTRUM24T is not set
+
+#
+# Wireless Pcmcia cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_WVLAN_CS is not set
+# CONFIG_MWVLAN_CS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+CONFIG_NET_WIRELESS=y
+CONFIG_ATMELWLAN=y
+CONFIG_ATMELWLAN_USB_503A_RFMD=m
+CONFIG_ATMELWLAN_PCMCIA_502A=m
+CONFIG_ATMELWLAN_PCMCIA_3COM=m
+CONFIG_ATMELWLAN_PCMCIA_502AD=m
+CONFIG_ATMELWLAN_PCMCIA_502AE=m
+CONFIG_ATMELWLAN_PCMCIA_504=m
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_PXA_FIR=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_SCSI_PCMCIA=y
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_DETECT_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_S3C2410 is not set
+# CONFIG_SERIAL_S3C2410_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL_SIR_PXA is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+CONFIG_NEWTONKBD=m
+# CONFIG_SA1100_PROFILER is not set
+
+#
+# Compaq iPAQ H3600 support
+#
+CONFIG_TOUCHSCREEN_H3600=m
+# CONFIG_H3600_BACKPAQ_FPGA is not set
+# CONFIG_H3600_BACKPAQ_ACCEL is not set
+# CONFIG_H3600_BACKPAQ_GASGAUGE is not set
+# CONFIG_H3600_BACKPAQ_SRAM is not set
+# CONFIG_H3600_BACKPAQ_AUDIO is not set
+# CONFIG_H3600_STOWAWAY is not set
+# CONFIG_H3800_MICROKBD is not set
+# CONFIG_SA1100_LIRC is not set
+CONFIG_H5400_BUZZER=m
+CONFIG_H5400_FSI=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_PXA_ALGO=m
+CONFIG_I2C_PXA_ADAP=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+# CONFIG_I2C_DS1307 is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_S3C2410 is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_L3_BACKPAQ is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=m
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=m
+CONFIG_INPUT_SERPORT=m
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+CONFIG_PXA_WATCHDOG=m
+# CONFIG_OMAHA_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_PXA_RTC=m
+CONFIG_PXA_RTC_HACK=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+CONFIG_PCMCIA_MOBILISCAN_CS=m
+# CONFIG_AXIM_TS is not set
+CONFIG_AXIM_KEY=m
+# CONFIG_AXIM_KEY_FIX is not set
+
+#
+# Multimedia devices
+#
+CONFIG_MEDIA=m
+CONFIG_VIDEO_DEV=m
+CONFIG_V4L2_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_USB=m
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+# CONFIG_VIDEO_CYBERPRO is not set
+# CONFIG_VIDEO_H3600_BACKPAQ is not set
+# CONFIG_VIDEO_HAWKEYE is not set
+
+#
+# Video for Linux 2 (V4L2)
+#
+CONFIG_VIDEO_WINNOV_CS=m
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DRIVERFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_S3C2410 is not set
+# CONFIG_FB_SA1100 is not set
+# CONFIG_FB_EPSON1356 is not set
+# CONFIG_FB_MQ200 is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_8BPP is not set
+CONFIG_FB_PXA_16BPP=y
+CONFIG_FB_MQ1100=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_NO_LOGO is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_H3900_UDA1380=m
+CONFIG_SOUND_H5400=m
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_VIDC is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+CONFIG_SOUND_PXA_AC97=m
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_MCP_UCB1400_TS is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=m
+# CONFIG_USB_OHCI_SA1111 is not set
+CONFIG_USB_OHCI_H5400=m
+# CONFIG_USB_OHCI_S3C2410 is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+CONFIG_USB_CDCETHER=m
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_BRLVGER is not set
+
+#
+# Linux As Bootldr Modules
+#
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+# CONFIG_YMODEM is not set
+# CONFIG_LAB_DUMMY is not set
+# CONFIG_LAB_CRC is not set
+# CONFIG_LAB_YMODEM is not set
+# CONFIG_LAB_MTD is not set
+# CONFIG_LAB_COPY is not set
+# CONFIG_LAB_COPY_YMODEM is not set
+# CONFIG_LAB_COPY_FLASH is not set
+# CONFIG_LAB_COPY_FS is not set
+# CONFIG_LAB_COPY_WRAPPER is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
+# CONFIG_BLUEZ_HCIBFUSB is not set
+CONFIG_BLUEZ_HCIDTL1=m
+CONFIG_BLUEZ_HCIBT3C=m
+CONFIG_BLUEZ_HCIBLUECARD=m
+CONFIG_BLUEZ_HCIBTUART=m
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa
index e69de29bb2..fc9682743a 100644
--- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa
+++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh36.14/defconfig-ipaqpxa
@@ -0,0 +1,1578 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MINIMAL_OOPS is not set
+
+#
+# Linux As Bootldr support
+#
+# CONFIG_LAB is not set
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_CONSUS is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_JORNADA56X is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_REGISTERS is not set
+
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_PXA_CERF is not set
+CONFIG_ARCH_H3900=y
+CONFIG_ARCH_H1900=y
+CONFIG_ARCH_H5400=y
+# CONFIG_ARCH_H2200 is not set
+CONFIG_ARCH_AXIM=y
+CONFIG_PXA_USB=m
+CONFIG_PXA_USB_NETLINK=m
+CONFIG_PXA_USB_CHAR=m
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+CONFIG_CPU_32v5=y
+CONFIG_CPU_XSCALE=y
+CONFIG_XSCALE_PXA250=y
+# CONFIG_XSCALE_80200_OLD is not set
+# CONFIG_CPU_32v3 is not set
+# CONFIG_CPU_32v4 is not set
+# CONFIG_SA1100_IPAQ is not set
+CONFIG_PXA_IPAQ=y
+CONFIG_IPAQ_HANDHELD=y
+
+#
+# Compaq iPAQ Handheld
+#
+CONFIG_IPAQ_HAL=m
+# CONFIG_H3600_MICRO is not set
+CONFIG_IPAQ_HAS_ROSELLA=y
+CONFIG_IPAQ_HAS_ASIC3=y
+CONFIG_H3600_ASIC=m
+CONFIG_H3900_ASIC_DEBUG=m
+CONFIG_H5400_ASIC=m
+CONFIG_H1900_ASIC=m
+CONFIG_H1900_TS=m
+CONFIG_H3600_HARDWARE=y
+CONFIG_IPAQ_SLEEVE=m
+CONFIG_SLEEVE_DEBUG=y
+CONFIG_SLEEVE_DEBUG_VERBOSE=0
+# CONFIG_SLEEVE_IRQ_DEMUX is not set
+
+#
+# Dell Axim X5
+#
+CONFIG_AXIM_HAL=m
+
+#
+# Processor Features
+#
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+# CONFIG_PCMCIA_SA1100 is not set
+CONFIG_PCMCIA_PXA=m
+# CONFIG_MERCURY_BACKPAQ is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=m
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_DEBUG_VERBOSE=0
+CONFIG_MMC_SAMSUNG_ASIC=m
+# CONFIG_MMC_S3C2410 is not set
+CONFIG_MMC_H5400=m
+CONFIG_MMC_ASIC3=m
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_XIP_KERNEL is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+CONFIG_APM=m
+# CONFIG_HWTIMER is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_IDP is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_LUBBOCK is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_AUTCPU12 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_H720X is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_NVRD=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_DM=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_IPV6_TUNNEL=m
+CONFIG_IPV6_MOBILITY=m
+CONFIG_IPV6_MOBILITY_MN=m
+# CONFIG_IPV6_MOBILITY_HA is not set
+CONFIG_IPV6_MOBILITY_DEBUG=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC=m
+
+#
+# IPSec options (FreeS/WAN)
+#
+CONFIG_KLIPS_AUTH_HMAC_MD5=y
+CONFIG_KLIPS_AUTH_HMAC_SHA1=y
+CONFIG_KLIPS_ENC_3DES=y
+
+#
+#  ESP always enabled with tunnel mode
+#
+CONFIG_KLIPS_IPCOMP=y
+CONFIG_KLIPS_DEBUG=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+# CONFIG_SPECTRUM24T is not set
+
+#
+# Wireless Pcmcia cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_WVLAN_CS is not set
+# CONFIG_MWVLAN_CS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+CONFIG_NET_WIRELESS=y
+CONFIG_ATMELWLAN=y
+CONFIG_ATMELWLAN_USB_503A_RFMD=m
+CONFIG_ATMELWLAN_PCMCIA_502A=m
+CONFIG_ATMELWLAN_PCMCIA_3COM=m
+CONFIG_ATMELWLAN_PCMCIA_502AD=m
+CONFIG_ATMELWLAN_PCMCIA_502AE=m
+CONFIG_ATMELWLAN_PCMCIA_504=m
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_PXA_FIR=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_SCSI_PCMCIA=y
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_DETECT_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_S3C2410 is not set
+# CONFIG_SERIAL_S3C2410_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL_SIR_PXA is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+CONFIG_NEWTONKBD=m
+# CONFIG_SA1100_PROFILER is not set
+
+#
+# Compaq iPAQ H3600 support
+#
+CONFIG_TOUCHSCREEN_H3600=m
+# CONFIG_H3600_BACKPAQ_FPGA is not set
+# CONFIG_H3600_BACKPAQ_ACCEL is not set
+# CONFIG_H3600_BACKPAQ_GASGAUGE is not set
+# CONFIG_H3600_BACKPAQ_SRAM is not set
+# CONFIG_H3600_BACKPAQ_AUDIO is not set
+# CONFIG_H3600_STOWAWAY is not set
+# CONFIG_H3800_MICROKBD is not set
+# CONFIG_SA1100_LIRC is not set
+CONFIG_H5400_BUZZER=m
+CONFIG_H5400_FSI=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_PXA_ALGO=m
+CONFIG_I2C_PXA_ADAP=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+# CONFIG_I2C_DS1307 is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_S3C2410 is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_L3_BACKPAQ is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=m
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=m
+CONFIG_INPUT_SERPORT=m
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+CONFIG_PXA_WATCHDOG=m
+# CONFIG_OMAHA_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_PXA_RTC=m
+CONFIG_PXA_RTC_HACK=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+CONFIG_PCMCIA_MOBILISCAN_CS=m
+# CONFIG_AXIM_TS is not set
+CONFIG_AXIM_KEY=m
+# CONFIG_AXIM_KEY_FIX is not set
+
+#
+# Multimedia devices
+#
+CONFIG_MEDIA=m
+CONFIG_VIDEO_DEV=m
+CONFIG_V4L2_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_USB=m
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+# CONFIG_VIDEO_CYBERPRO is not set
+# CONFIG_VIDEO_H3600_BACKPAQ is not set
+# CONFIG_VIDEO_HAWKEYE is not set
+
+#
+# Video for Linux 2 (V4L2)
+#
+CONFIG_VIDEO_WINNOV_CS=m
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DRIVERFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_S3C2410 is not set
+# CONFIG_FB_SA1100 is not set
+# CONFIG_FB_EPSON1356 is not set
+# CONFIG_FB_MQ200 is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_8BPP is not set
+CONFIG_FB_PXA_16BPP=y
+CONFIG_FB_MQ1100=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_NO_LOGO is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_H3900_UDA1380=m
+CONFIG_SOUND_H5400=m
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_VIDC is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+CONFIG_SOUND_PXA_AC97=m
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_MCP_UCB1400_TS is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=m
+# CONFIG_USB_OHCI_SA1111 is not set
+CONFIG_USB_OHCI_H5400=m
+# CONFIG_USB_OHCI_S3C2410 is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+CONFIG_USB_CDCETHER=m
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_BRLVGER is not set
+
+#
+# Linux As Bootldr Modules
+#
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+# CONFIG_YMODEM is not set
+# CONFIG_LAB_DUMMY is not set
+# CONFIG_LAB_CRC is not set
+# CONFIG_LAB_YMODEM is not set
+# CONFIG_LAB_MTD is not set
+# CONFIG_LAB_COPY is not set
+# CONFIG_LAB_COPY_YMODEM is not set
+# CONFIG_LAB_COPY_FLASH is not set
+# CONFIG_LAB_COPY_FS is not set
+# CONFIG_LAB_COPY_WRAPPER is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
+# CONFIG_BLUEZ_HCIBFUSB is not set
+CONFIG_BLUEZ_HCIDTL1=m
+CONFIG_BLUEZ_HCIBT3C=m
+CONFIG_BLUEZ_HCIBLUECARD=m
+CONFIG_BLUEZ_HCIBTUART=m
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa
index e69de29bb2..ee30cf0a42 100644
--- a/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa
+++ b/linux/handhelds-pxa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqpxa
@@ -0,0 +1,1578 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MINIMAL_OOPS is not set
+
+#
+# Linux As Bootldr support
+#
+# CONFIG_LAB is not set
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_CONSUS is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_JORNADA56X is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_REGISTERS is not set
+
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_PXA_CERF is not set
+CONFIG_ARCH_H3900=y
+CONFIG_ARCH_H1900=y
+CONFIG_ARCH_H5400=y
+# CONFIG_ARCH_H2200 is not set
+CONFIG_ARCH_AXIM=y
+CONFIG_PXA_USB=m
+CONFIG_PXA_USB_NETLINK=m
+CONFIG_PXA_USB_CHAR=m
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+CONFIG_CPU_32v5=y
+CONFIG_CPU_XSCALE=y
+CONFIG_XSCALE_PXA250=y
+# CONFIG_XSCALE_80200_OLD is not set
+# CONFIG_CPU_32v3 is not set
+# CONFIG_CPU_32v4 is not set
+# CONFIG_SA1100_IPAQ is not set
+CONFIG_PXA_IPAQ=y
+CONFIG_IPAQ_HANDHELD=y
+
+#
+# Compaq iPAQ Handheld
+#
+CONFIG_IPAQ_HAL=m
+# CONFIG_H3600_MICRO is not set
+CONFIG_IPAQ_HAS_ROSELLA=y
+CONFIG_IPAQ_HAS_ASIC3=y
+CONFIG_H3600_ASIC=m
+CONFIG_H3900_ASIC_DEBUG=m
+CONFIG_H5400_ASIC=m
+CONFIG_H1900_ASIC=m
+CONFIG_H1900_TS=m
+CONFIG_H3600_HARDWARE=y
+CONFIG_IPAQ_SLEEVE=m
+CONFIG_SLEEVE_DEBUG=y
+CONFIG_SLEEVE_DEBUG_VERBOSE=0
+# CONFIG_SLEEVE_IRQ_DEMUX is not set
+
+#
+# Dell Axim X5
+#
+CONFIG_AXIM_HAL=m
+
+#
+# Processor Features
+#
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+# CONFIG_PCMCIA_SA1100 is not set
+CONFIG_PCMCIA_PXA=m
+# CONFIG_MERCURY_BACKPAQ is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=m
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_DEBUG_VERBOSE=0
+CONFIG_MMC_SAMSUNG_ASIC=m
+# CONFIG_MMC_S3C2410 is not set
+CONFIG_MMC_H5400=m
+CONFIG_MMC_ASIC3=m
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_XIP_KERNEL is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+CONFIG_APM=m
+# CONFIG_HWTIMER is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_PC_CML1=m
+# CONFIG_PARPORT_SERIAL is not set
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+CONFIG_PARPORT_PC_PCMCIA=m
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_IDP is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_OTHER is not set
+# CONFIG_PARPORT_1284 is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_LUBBOCK is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_AUTCPU12 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_H720X is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_NVRD=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_DM=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MOBILITY=m
+CONFIG_IPV6_MOBILITY_MN=m
+# CONFIG_IPV6_MOBILITY_HA is not set
+CONFIG_IPV6_MOBILITY_DEBUG=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC=m
+
+#
+# IPSec options (FreeS/WAN)
+#
+CONFIG_KLIPS_AUTH_HMAC_MD5=y
+CONFIG_KLIPS_AUTH_HMAC_SHA1=y
+CONFIG_KLIPS_ENC_3DES=y
+
+#
+#  ESP always enabled with tunnel mode
+#
+CONFIG_KLIPS_IPCOMP=y
+CONFIG_KLIPS_DEBUG=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+# CONFIG_SPECTRUM24T is not set
+
+#
+# Wireless Pcmcia cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_WVLAN_CS is not set
+# CONFIG_MWVLAN_CS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+CONFIG_NET_WIRELESS=y
+CONFIG_ATMELWLAN=y
+CONFIG_ATMELWLAN_USB_503A_RFMD=m
+CONFIG_ATMELWLAN_PCMCIA_502A=m
+CONFIG_ATMELWLAN_PCMCIA_3COM=m
+CONFIG_ATMELWLAN_PCMCIA_502AD=m
+CONFIG_ATMELWLAN_PCMCIA_502AE=m
+CONFIG_ATMELWLAN_PCMCIA_504=m
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_PXA_FIR=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_SCSI_PCMCIA=y
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_EXTENDED=y
+# CONFIG_SERIAL_MANY_PORTS is not set
+# CONFIG_SERIAL_SHARE_IRQ is not set
+# CONFIG_SERIAL_DETECT_IRQ is not set
+# CONFIG_SERIAL_MULTIPORT is not set
+# CONFIG_HUB6 is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_S3C2410 is not set
+# CONFIG_SERIAL_S3C2410_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL_SIR_PXA is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+CONFIG_NEWTONKBD=m
+# CONFIG_SA1100_PROFILER is not set
+
+#
+# Compaq iPAQ H3600 support
+#
+CONFIG_TOUCHSCREEN_H3600=m
+# CONFIG_H3600_BACKPAQ_FPGA is not set
+# CONFIG_H3600_BACKPAQ_ACCEL is not set
+# CONFIG_H3600_BACKPAQ_GASGAUGE is not set
+# CONFIG_H3600_BACKPAQ_SRAM is not set
+# CONFIG_H3600_BACKPAQ_AUDIO is not set
+# CONFIG_H3600_STOWAWAY is not set
+# CONFIG_H3800_MICROKBD is not set
+# CONFIG_SA1100_LIRC is not set
+CONFIG_H5400_BUZZER=m
+CONFIG_H5400_FSI=m
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_PXA_ALGO=m
+CONFIG_I2C_PXA_ADAP=m
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_PROC=m
+# CONFIG_I2C_DS1307 is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_S3C2410 is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_L3_BACKPAQ is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=m
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=m
+CONFIG_INPUT_SERPORT=m
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+CONFIG_PXA_WATCHDOG=m
+# CONFIG_OMAHA_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_PXA_RTC=m
+CONFIG_PXA_RTC_HACK=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+CONFIG_PCMCIA_MOBILISCAN_CS=m
+# CONFIG_AXIM_TS is not set
+CONFIG_AXIM_KEY=m
+# CONFIG_AXIM_KEY_FIX is not set
+
+#
+# Multimedia devices
+#
+CONFIG_MEDIA=m
+CONFIG_VIDEO_DEV=m
+CONFIG_V4L2_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_BWQCAM is not set
+# CONFIG_VIDEO_CQCAM is not set
+CONFIG_VIDEO_CPIA=m
+CONFIG_VIDEO_CPIA_USB=m
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+# CONFIG_VIDEO_CYBERPRO is not set
+# CONFIG_VIDEO_H3600_BACKPAQ is not set
+# CONFIG_VIDEO_HAWKEYE is not set
+
+#
+# Video for Linux 2 (V4L2)
+#
+CONFIG_VIDEO_WINNOV_CS=m
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DRIVERFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_S3C2410 is not set
+# CONFIG_FB_SA1100 is not set
+# CONFIG_FB_EPSON1356 is not set
+# CONFIG_FB_MQ200 is not set
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_8BPP is not set
+CONFIG_FB_PXA_16BPP=y
+CONFIG_FB_MQ1100=y
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_NO_LOGO is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_H3900_UDA1380=m
+CONFIG_SOUND_H5400=m
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_VIDC is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+CONFIG_SOUND_PXA_AC97=m
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_MCP_UCB1400_TS is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_LONG_TIMEOUT is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=m
+# CONFIG_USB_OHCI_SA1111 is not set
+CONFIG_USB_OHCI_H5400=m
+# CONFIG_USB_OHCI_S3C2410 is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_AUDIO=m
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+CONFIG_USB_CDCETHER=m
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_BRLVGER is not set
+
+#
+# Linux As Bootldr Modules
+#
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+# CONFIG_YMODEM is not set
+# CONFIG_LAB_DUMMY is not set
+# CONFIG_LAB_CRC is not set
+# CONFIG_LAB_YMODEM is not set
+# CONFIG_LAB_MTD is not set
+# CONFIG_LAB_COPY is not set
+# CONFIG_LAB_COPY_YMODEM is not set
+# CONFIG_LAB_COPY_FLASH is not set
+# CONFIG_LAB_COPY_FS is not set
+# CONFIG_LAB_COPY_WRAPPER is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
+# CONFIG_BLUEZ_HCIBFUSB is not set
+CONFIG_BLUEZ_HCIDTL1=m
+CONFIG_BLUEZ_HCIBT3C=m
+CONFIG_BLUEZ_HCIBLUECARD=m
+CONFIG_BLUEZ_HCIBTUART=m
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6 b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6
index e69de29bb2..0a7d4a6694 100644
--- a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6
+++ b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6
@@ -0,0 +1,1304 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_STANDALONE=y
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=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_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+CONFIG_IKCONFIG=y
+# CONFIG_MINIMAL_OOPS is not set
+CONFIG_IKCONFIG_PROC=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_H1900 is not set
+CONFIG_ARCH_H2200=y
+CONFIG_H2200_PCMCIA=m
+CONFIG_H2200_LCD=m
+# CONFIG_H2200_BATTERY is not set
+CONFIG_H2200_TS=m
+CONFIG_ARCH_H3900=y
+CONFIG_MACH_H4000=y
+CONFIG_ARCH_H5400=y
+CONFIG_ARCH_AXIMX5=y
+# CONFIG_AXIMX5_MISC is not set
+# CONFIG_AXIMX5_LCD is not set
+# CONFIG_AXIMX5_PCMCIA is not set
+# CONFIG_AXIMX5_BUTTONS is not set
+# CONFIG_ARCH_AXIMX3 is not set
+CONFIG_MACH_E740=y
+CONFIG_MACH_E750=y
+CONFIG_MACH_E800=y
+CONFIG_ARCH_ESERIES=y
+# CONFIG_ARCH_ROVERP5P is not set
+
+#
+# S3C2410 Implementations
+#
+
+#
+# Linux As Bootloader
+#
+# CONFIG_LAB is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_XSCALE_PXA250=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_FASTCALL is not set
+CONFIG_ARM_THUMB=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Compaq/iPAQ Options
+#
+CONFIG_PXA_IPAQ=y
+
+#
+# XScale-based iPAQ
+#
+CONFIG_IPAQ_HANDHELD=y
+CONFIG_IPAQ_SLEEVE=m
+CONFIG_IPAQ_ASIC2=m
+CONFIG_IPAQ_ASIC2_TOUCHSCREEN=m
+CONFIG_IPAQ_ASIC3=m
+CONFIG_IPAQ_H3900_LCD=m
+CONFIG_IPAQ_H4000_LCD=m
+CONFIG_IPAQ_SAMCOP=m
+CONFIG_IPAQ_SAMCOP_ADC=m
+CONFIG_IPAQ_SAMCOP_TOUCHSCREEN=m
+CONFIG_IPAQ_SHAMCOP=m
+CONFIG_IPAQ_SHAMCOP_ADC=m
+CONFIG_IPAQ_SHAMCOP_TOUCHSCREEN=m
+CONFIG_IPAQ_SHAMCOP_NAND=m
+CONFIG_IPAQ_H5400_LCD=m
+CONFIG_IPAQ_H5400_WIFI=m
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_CPU_FREQ is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PXA2XX=m
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+# CONFIG_FW_LOADER is not set
+CONFIG_SOC_DEVICE=m
+# CONFIG_DOCKING_HOTPLUG is not set
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=m
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_H1900 is not set
+CONFIG_MTD_NAND_IDS=m
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_PHYSDEV is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+# CONFIG_IP_NF_TARGET_CLASSIFY is not set
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IP_NF_RAW is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+# 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_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+CONFIG_IRPORT_SIR=m
+
+#
+# Old Serial dongle support
+#
+# CONFIG_DONGLE_OLD is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+CONFIG_BT=m
+# CONFIG_BT_L2CAP is not set
+# CONFIG_BT_SCO is not set
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
+# CONFIG_SMC91X is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+CONFIG_PCMCIA_RAYCS=m
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_HERMES=m
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_NET_WIRELESS=y
+# CONFIG_HOSTAP is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_REPORT_LUNS=y
+# 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
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN 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=m
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_TSLIBDEV=m
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_KEYBOARD_NEWTON=m
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_INPUT_MISC 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_DZ is not set
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_PXA_JTAG is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPXA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PXA is not set
+# CONFIG_SCx200_ACB is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# L3 serial bus support
+#
+CONFIG_L3=m
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+CONFIG_VIDEO_CPIA=m
+# CONFIG_VIDEO_CPIA_USB is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=m
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_NAND=y
+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=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_MODES=y
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_DEVICE=y
+# CONFIG_FB_VSFB is not set
+CONFIG_FB_MQ1100=m
+CONFIG_FB_PXA=m
+# CONFIG_FB_PXA_8BPP is not set
+CONFIG_FB_PXA_16BPP=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=m
+CONFIG_PCI_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+
+#
+# Console Switches
+#
+CONFIG_SWITCHES=m
+
+#
+# SoC drivers
+#
+CONFIG_SOC_MQ11XX=m
+# CONFIG_BATTERY_MONITOR is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+# CONFIG_USB_SL811HS_ALT is not set
+
+#
+# USB Device Class drivers
+#
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID 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_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_W9968CF is not set
+
+#
+# USB Network adaptors
+#
+# 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
+
+#
+# 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_TIGL 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_TEST is not set
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+
+#
+# USB Device Controller drivers
+#
+CONFIG_USB_GADGET_PXA2XX=m
+CONFIG_USB_PXA2XX=y
+CONFIG_USB_PXA2XX_SMALL=y
+CONFIG_USB_GADGET_MQ11XX=m
+CONFIG_USB_MQ11XX=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+
+#
+# USB Gadget Drivers
+#
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_G_CHAR is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_LL_PXA_JTAG is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=m
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0 b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0
index e69de29bb2..8d03220347 100644
--- a/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0
+++ b/linux/handhelds-pxa-2.6/defconfig-ipaq-pxa-2.6_2.6.8.1-hh0
@@ -0,0 +1,1382 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=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_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+CONFIG_IKCONFIG=y
+# CONFIG_MINIMAL_OOPS is not set
+CONFIG_IKCONFIG_PROC=y
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# Intel PXA2xx Implementations
+#
+CONFIG_PXA25x=y
+# CONFIG_PXA27x is not set
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+CONFIG_ARCH_ESERIES=y
+CONFIG_MACH_E740=y
+CONFIG_MACH_E750=y
+CONFIG_MACH_E800=y
+CONFIG_ESERIES_TMIO=y
+CONFIG_OHCI_TMIO=y
+CONFIG_MTD_NAND_TMIO=y
+CONFIG_ESERIES_UDC=y
+# CONFIG_E740_PCMCIA is not set
+# CONFIG_E750_PCMCIA is not set
+# CONFIG_E800_PCMCIA is not set
+CONFIG_MACH_A620=y
+CONFIG_A620_LCD=m
+CONFIG_A620_BUTTONS=m
+CONFIG_ARCH_H1900=y
+CONFIG_ARCH_H2200=y
+CONFIG_H2200_PCMCIA=m
+CONFIG_H2200_LCD=m
+# CONFIG_H2200_BATTERY is not set
+CONFIG_H2200_TS=m
+CONFIG_H2200_AUDIO=m
+CONFIG_ARCH_H3900=y
+CONFIG_MACH_H4000=y
+CONFIG_ARCH_H5400=y
+# CONFIG_ARCH_AXIMX5 is not set
+# CONFIG_ARCH_AXIMX3 is not set
+CONFIG_ARCH_ROVERP1=y
+CONFIG_ARCH_ROVERP5P=y
+CONFIG_ROVERP5P_LCD=m
+CONFIG_ROVERP5P_PCMCIA=m
+
+#
+# Linux As Bootloader
+#
+# CONFIG_LAB is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_XSCALE_PXA250=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_FASTCALL is not set
+CONFIG_ARM_THUMB=y
+CONFIG_XSCALE_PMU=y
+
+#
+# Compaq/iPAQ Options
+#
+CONFIG_PXA_IPAQ=y
+
+#
+# XScale-based iPAQ
+#
+CONFIG_IPAQ_HANDHELD=y
+# CONFIG_IPAQ_SLEEVE is not set
+CONFIG_IPAQ_ASIC2=m
+CONFIG_IPAQ_ASIC2_TOUCHSCREEN=m
+CONFIG_IPAQ_ASIC3=m
+# CONFIG_IPAQ_H1900_LCD is not set
+# CONFIG_IPAQ_H3900_LCD is not set
+CONFIG_IPAQ_H4000_LCD=m
+CONFIG_IPAQ_SAMCOP=m
+CONFIG_IPAQ_SAMCOP_ADC=m
+CONFIG_IPAQ_SAMCOP_TOUCHSCREEN=m
+CONFIG_IPAQ_SHAMCOP=m
+CONFIG_IPAQ_SHAMCOP_ADC=m
+CONFIG_IPAQ_SHAMCOP_TOUCHSCREEN=m
+CONFIG_IPAQ_SHAMCOP_NAND=m
+CONFIG_IPAQ_H5400_LCD=m
+CONFIG_IPAQ_H5400_WIFI=m
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_CPU_FREQ is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PXA2XX=m
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+CONFIG_SOC_DEVICE=m
+# CONFIG_DOCKING_HOTPLUG is not set
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+# CONFIG_PREEMPT is not set
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=m
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_H1900 is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+# CONFIG_IP_NF_MATCH_IPRANGE is not set
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+# CONFIG_IP_NF_MATCH_PHYSDEV is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+# CONFIG_IP_NF_TARGET_SAME is not set
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+# CONFIG_IP_NF_TARGET_CLASSIFY is not set
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_REALM is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_IP6_NF_RAW is not set
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+# 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_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+CONFIG_IRPORT_SIR=m
+
+#
+# Old Serial dongle support
+#
+# CONFIG_DONGLE_OLD is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+CONFIG_BT=m
+# CONFIG_BT_L2CAP is not set
+# CONFIG_BT_SCO is not set
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+CONFIG_PCMCIA_WAVELAN=m
+CONFIG_PCMCIA_NETWAVE=m
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+CONFIG_PCMCIA_RAYCS=m
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_HERMES=m
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_NET_WIRELESS=y
+# CONFIG_HOSTAP is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI=m
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# 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
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN 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=m
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_TSLIBDEV=m
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_KEYBOARD_NEWTON=m
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_INPUT_MISC 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_DZ is not set
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_ALGOPXA=m
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+CONFIG_I2C_PXA=m
+# CONFIG_SCx200_ACB is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_I2C_DEBUG_CORE=y
+CONFIG_I2C_DEBUG_ALGO=y
+CONFIG_I2C_DEBUG_BUS=y
+CONFIG_I2C_DEBUG_CHIP=y
+
+#
+# L3 serial bus support
+#
+CONFIG_L3=m
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+CONFIG_VIDEO_CPIA=m
+# CONFIG_VIDEO_CPIA_USB is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=m
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=m
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_NAND=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V4 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_MODES=y
+CONFIG_LCD_CLASS_DEVICE=m
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_DEVICE=y
+# CONFIG_FB_VSFB is not set
+CONFIG_FB_MQ1100=m
+CONFIG_FB_PXA=m
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_PXA_8BPP is not set
+CONFIG_FB_PXA_16BPP=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=m
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_VERBOSE_PRINTK=y
+CONFIG_SND_DEBUG=y
+CONFIG_SND_DEBUG_MEMORY=y
+CONFIG_SND_DEBUG_DETECT=y
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+CONFIG_SND_PXA2XX_UDA1380=m
+# CONFIG_SND_H5XXX_AK4535 is not set
+# CONFIG_SND_PXA_AC97 is not set
+
+#
+# ALSA USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# PCMCIA devices
+#
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+# CONFIG_SOUND_UDA1341 is not set
+
+#
+# Misc devices
+#
+
+#
+# SoC drivers
+#
+CONFIG_SOC_MQ11XX=m
+# CONFIG_BATTERY_MONITOR is not set
+
+#
+# USB support
+#
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+# CONFIG_USB_SL811HS_ALT is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+
+#
+# USB Bluetooth TTY can only be used with disabled Bluetooth subsystem
+#
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID 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_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+
+#
+# USB Network adaptors
+#
+# 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
+
+#
+# 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_TIGL 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_PHIDGETSERVO is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_GADGET_PXA2XX=y
+CONFIG_USB_PXA2XX=m
+# CONFIG_USB_PXA2XX_SMALL is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+# CONFIG_USB_GADGET_MQ11XX is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=m
+CONFIG_USB_ETH=m
+# CONFIG_USB_ETH_RNDIS is not set
+# CONFIG_USB_GADGETFS is not set
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_G_CHAR is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_LL_PXA_JTAG is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=m
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa
index e69de29bb2..f144aa6c17 100644
--- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa
+++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/defconfig-ipaqsa
@@ -0,0 +1,1505 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MINIMAL_OOPS is not set
+
+#
+# Linux As Bootldr support
+#
+# CONFIG_LAB is not set
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+CONFIG_SA1100_H3100=y
+CONFIG_SA1100_H3600=y
+CONFIG_SA1100_H3800=y
+# CONFIG_SA1100_CONSUS is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_JORNADA56X is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+CONFIG_SA1100_USB=m
+CONFIG_SA1100_USB_NETLINK=m
+CONFIG_SA1100_USB_CHAR=m
+CONFIG_REGISTERS=m
+
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_PXA_CERF is not set
+# CONFIG_ARCH_H3900 is not set
+# CONFIG_ARCH_H1900 is not set
+# CONFIG_ARCH_H5400 is not set
+# CONFIG_ARCH_H2200 is not set
+# CONFIG_ARCH_AXIM is not set
+# CONFIG_PXA_USB is not set
+# CONFIG_PXA_USB_NETLINK is not set
+# CONFIG_PXA_USB_CHAR is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+CONFIG_SA1100_IPAQ=y
+# CONFIG_PXA_IPAQ is not set
+CONFIG_IPAQ_HANDHELD=y
+
+#
+# Compaq iPAQ Handheld
+#
+CONFIG_IPAQ_HAL=m
+CONFIG_H3600_MICRO=m
+CONFIG_IPAQ_HAS_ROSELLA=y
+CONFIG_H3600_ASIC=m
+CONFIG_H3900_ASIC_DEBUG=y
+# CONFIG_H5400_ASIC is not set
+# CONFIG_H1900_ASIC is not set
+# CONFIG_H1900_TS is not set
+CONFIG_H3600_HARDWARE=y
+CONFIG_IPAQ_SLEEVE=m
+CONFIG_SLEEVE_DEBUG=y
+CONFIG_SLEEVE_DEBUG_VERBOSE=0
+# CONFIG_SLEEVE_IRQ_DEMUX is not set
+
+#
+# Processor Features
+#
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+CONFIG_PCMCIA_SA1100=m
+# CONFIG_PCMCIA_PXA is not set
+CONFIG_MERCURY_BACKPAQ=m
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=m
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_DEBUG_VERBOSE=0
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+CONFIG_APM=m
+CONFIG_HWTIMER=m
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_LUBBOCK is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_AUTCPU12 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_H720X is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_NVRD=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_DM=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_IPV6_TUNNEL=m
+CONFIG_IPV6_MOBILITY=m
+CONFIG_IPV6_MOBILITY_MN=m
+# CONFIG_IPV6_MOBILITY_HA is not set
+CONFIG_IPV6_MOBILITY_DEBUG=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC=m
+
+#
+# IPSec options (FreeS/WAN)
+#
+CONFIG_IPSEC_IPIP=y
+CONFIG_IPSEC_AH=y
+CONFIG_IPSEC_AUTH_HMAC_MD5=y
+CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+CONFIG_IPSEC_ESP=y
+CONFIG_IPSEC_ENC_3DES=y
+CONFIG_IPSEC_IPCOMP=y
+CONFIG_IPSEC_DEBUG=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_HERMES is not set
+# CONFIG_SPECTRUM24T is not set
+
+#
+# Wireless Pcmcia cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_WVLAN_CS is not set
+# CONFIG_MWVLAN_CS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+CONFIG_NET_WIRELESS=y
+CONFIG_ATMELWLAN=y
+# CONFIG_ATMELWLAN_USB_503A_RFMD is not set
+CONFIG_ATMELWLAN_PCMCIA_502A=m
+CONFIG_ATMELWLAN_PCMCIA_3COM=m
+CONFIG_ATMELWLAN_PCMCIA_502AD=m
+CONFIG_ATMELWLAN_PCMCIA_502AE=m
+CONFIG_ATMELWLAN_PCMCIA_504=m
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_SA1100_FIR=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_SCSI_PCMCIA=y
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=m
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_S3C2410 is not set
+# CONFIG_SERIAL_S3C2410_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=115200
+CONFIG_SERIAL_H3800_ASIC=m
+# CONFIG_SERIAL_SIR_PXA is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+CONFIG_NEWTONKBD=m
+CONFIG_SA1100_PROFILER=m
+
+#
+# Compaq iPAQ H3600 support
+#
+CONFIG_TOUCHSCREEN_H3600=m
+CONFIG_H3600_BACKPAQ_FPGA=m
+CONFIG_H3600_BACKPAQ_ACCEL=m
+CONFIG_H3600_BACKPAQ_GASGAUGE=m
+CONFIG_H3600_BACKPAQ_SRAM=m
+CONFIG_H3600_BACKPAQ_AUDIO=m
+CONFIG_H3600_STOWAWAY=m
+CONFIG_H3800_MICROKBD=m
+CONFIG_SA1100_LIRC=m
+# CONFIG_H5400_BUZZER is not set
+# CONFIG_H5400_FSI is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+CONFIG_L3=y
+CONFIG_L3_ALGOBIT=y
+CONFIG_L3_BIT_SA1100_GPIO=y
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_S3C2410 is not set
+# CONFIG_L3_SA1111 is not set
+CONFIG_L3_BACKPAQ=m
+CONFIG_BIT_SA1100_GPIO=y
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=m
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=m
+CONFIG_INPUT_SERPORT=m
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=m
+# CONFIG_PXA_WATCHDOG is not set
+# CONFIG_OMAHA_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=m
+# CONFIG_PXA_RTC_HACK is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+# CONFIG_PCMCIA_MOBILISCAN_CS is not set
+# CONFIG_AXIM_KEY_FIX is not set
+
+#
+# Multimedia devices
+#
+CONFIG_MEDIA=m
+CONFIG_VIDEO_DEV=m
+CONFIG_V4L2_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+# CONFIG_VIDEO_CYBERPRO is not set
+CONFIG_VIDEO_H3600_BACKPAQ=m
+# CONFIG_VIDEO_HAWKEYE is not set
+
+#
+# Video for Linux 2 (V4L2)
+#
+CONFIG_VIDEO_WINNOV_CS=m
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DRIVERFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_S3C2410 is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_EPSON1356 is not set
+# CONFIG_FB_MQ200 is not set
+# CONFIG_FB_PXA is not set
+# CONFIG_FB_MQ1100 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+CONFIG_FBCON_CFB4=y
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_NO_LOGO is not set
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_SA1100=m
+CONFIG_SOUND_UDA1341=m
+# CONFIG_SOUND_SA1100_MONO is not set
+# CONFIG_SOUND_ASSABET_UDA1341 is not set
+CONFIG_SOUND_H3600_UDA1341=m
+# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
+# CONFIG_SOUND_SA1111_UDA1341 is not set
+# CONFIG_SOUND_SA1100SSP is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_VIDC is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+# CONFIG_SOUND_PXA_AC97 is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_MCP_UCB1400_TS is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
+# USB support
+#
+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_LONG_TIMEOUT is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+# CONFIG_USB_OHCI_H5400 is not set
+# CONFIG_USB_OHCI_S3C2410 is not set
+CONFIG_USB_SL811HS=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+CONFIG_USB_CDCETHER=m
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_BRLVGER is not set
+
+#
+# Linux As Bootldr Modules
+#
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+# CONFIG_YMODEM is not set
+# CONFIG_LAB_DUMMY is not set
+# CONFIG_LAB_CRC is not set
+# CONFIG_LAB_YMODEM is not set
+# CONFIG_LAB_MTD is not set
+# CONFIG_LAB_COPY is not set
+# CONFIG_LAB_COPY_YMODEM is not set
+# CONFIG_LAB_COPY_FLASH is not set
+# CONFIG_LAB_COPY_FS is not set
+# CONFIG_LAB_COPY_WRAPPER is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
+# CONFIG_BLUEZ_HCIBFUSB is not set
+CONFIG_BLUEZ_HCIDTL1=m
+CONFIG_BLUEZ_HCIBT3C=m
+CONFIG_BLUEZ_HCIBLUECARD=m
+CONFIG_BLUEZ_HCIBTUART=m
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch
index e69de29bb2..79ba036323 100644
--- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch
+++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/disable-pcmcia-probe.patch
@@ -0,0 +1,17 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe	2003-05-13 11:18:23.000000000 +0200
++++ linux/drivers/pcmcia/Config.in	2004-05-27 13:59:50.000000000 +0200
+@@ -15,9 +15,6 @@
+ tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+ if [ "$CONFIG_PCMCIA" != "n" ]; then
+    # yes, I really mean the following...
+-   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then
+-      define_bool CONFIG_PCMCIA_PROBE y
+-   fi
+    if [ "$CONFIG_PCI" != "n" ]; then
+       bool '  CardBus support' CONFIG_CARDBUS
+    fi
diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch
index e69de29bb2..4e2efc035b 100644
--- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch
+++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/ipsec.patch
@@ -0,0 +1,1446 @@
+--- linux/net/Makefile	3 Dec 2003 19:15:16 -0000	1.25
++++ linux/net/Makefile	20 Feb 2003 15:50:38 -0000	1.24
+@@ -19,6 +19,7 @@
+ subdir-$(CONFIG_NETFILTER)	+= ipv4/netfilter
+ subdir-$(CONFIG_UNIX)		+= unix
+ subdir-$(CONFIG_IPV6)		+= ipv6
++subdir-$(CONFIG_IPSEC)		+= ipsec
+ 
+ ifneq ($(CONFIG_IPV6),n)
+ ifneq ($(CONFIG_IPV6),)
+--- /dev/null	2004-02-02 20:32:13.000000000 +0000
++++ linux/include/zlib/zlib.h	2004-07-05 23:56:59.000000000 +0100
+@@ -0,0 +1,893 @@
++/* zlib.h -- interface of the 'zlib' general purpose compression library
++  version 1.1.4, March 11th, 2002
++
++  Copyright (C) 1995-2002 Jean-loup Gailly and Mark Adler
++
++  This software is provided 'as-is', without any express or implied
++  warranty.  In no event will the authors be held liable for any damages
++  arising from the use of this software.
++
++  Permission is granted to anyone to use this software for any purpose,
++  including commercial applications, and to alter it and redistribute it
++  freely, subject to the following restrictions:
++
++  1. The origin of this software must not be misrepresented; you must not
++     claim that you wrote the original software. If you use this software
++     in a product, an acknowledgment in the product documentation would be
++     appreciated but is not required.
++  2. Altered source versions must be plainly marked as such, and must not be
++     misrepresented as being the original software.
++  3. This notice may not be removed or altered from any source distribution.
++
++  Jean-loup Gailly        Mark Adler
++  jloup@gzip.org          madler@alumni.caltech.edu
++
++
++  The data format used by the zlib library is described by RFCs (Request for
++  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
++  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
++*/
++
++#ifndef _ZLIB_H
++#define _ZLIB_H
++
++#include "zconf.h"
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#define ZLIB_VERSION "1.1.4"
++
++/* 
++     The 'zlib' compression library provides in-memory compression and
++  decompression functions, including integrity checks of the uncompressed
++  data.  This version of the library supports only one compression method
++  (deflation) but other algorithms will be added later and will have the same
++  stream interface.
++
++     Compression can be done in a single step if the buffers are large
++  enough (for example if an input file is mmap'ed), or can be done by
++  repeated calls of the compression function.  In the latter case, the
++  application must provide more input and/or consume the output
++  (providing more output space) before each call.
++
++     The library also supports reading and writing files in gzip (.gz) format
++  with an interface similar to that of stdio.
++
++     The library does not install any signal handler. The decoder checks
++  the consistency of the compressed data, so the library should never
++  crash even in case of corrupted input.
++*/
++
++typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
++typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
++
++struct internal_state;
++
++typedef struct z_stream_s {
++    Bytef    *next_in;  /* next input byte */
++    uInt     avail_in;  /* number of bytes available at next_in */
++    uLong    total_in;  /* total nb of input bytes read so far */
++
++    Bytef    *next_out; /* next output byte should be put there */
++    uInt     avail_out; /* remaining free space at next_out */
++    uLong    total_out; /* total nb of bytes output so far */
++
++    const char     *msg;      /* last error message, NULL if no error */
++    struct internal_state FAR *state; /* not visible by applications */
++
++    alloc_func zalloc;  /* used to allocate the internal state */
++    free_func  zfree;   /* used to free the internal state */
++    voidpf     opaque;  /* private data object passed to zalloc and zfree */
++
++    int     data_type;  /* best guess about the data type: ascii or binary */
++    uLong   adler;      /* adler32 value of the uncompressed data */
++    uLong   reserved;   /* reserved for future use */
++} z_stream;
++
++typedef z_stream FAR *z_streamp;
++
++/*
++   The application must update next_in and avail_in when avail_in has
++   dropped to zero. It must update next_out and avail_out when avail_out
++   has dropped to zero. The application must initialize zalloc, zfree and
++   opaque before calling the init function. All other fields are set by the
++   compression library and must not be updated by the application.
++
++   The opaque value provided by the application will be passed as the first
++   parameter for calls of zalloc and zfree. This can be useful for custom
++   memory management. The compression library attaches no meaning to the
++   opaque value.
++
++   zalloc must return Z_NULL if there is not enough memory for the object.
++   If zlib is used in a multi-threaded application, zalloc and zfree must be
++   thread safe.
++
++   On 16-bit systems, the functions zalloc and zfree must be able to allocate
++   exactly 65536 bytes, but will not be required to allocate more than this
++   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
++   pointers returned by zalloc for objects of exactly 65536 bytes *must*
++   have their offset normalized to zero. The default allocation function
++   provided by this library ensures this (see zutil.c). To reduce memory
++   requirements and avoid any allocation of 64K objects, at the expense of
++   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
++
++   The fields total_in and total_out can be used for statistics or
++   progress reports. After compression, total_in holds the total size of
++   the uncompressed data and may be saved for use in the decompressor
++   (particularly if the decompressor wants to decompress everything in
++   a single step).
++*/
++
++                        /* constants */
++
++#define Z_NO_FLUSH      0
++#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
++#define Z_SYNC_FLUSH    2
++#define Z_FULL_FLUSH    3
++#define Z_FINISH        4
++/* Allowed flush values; see deflate() below for details */
++
++#define Z_OK            0
++#define Z_STREAM_END    1
++#define Z_NEED_DICT     2
++#define Z_ERRNO        (-1)
++#define Z_STREAM_ERROR (-2)
++#define Z_DATA_ERROR   (-3)
++#define Z_MEM_ERROR    (-4)
++#define Z_BUF_ERROR    (-5)
++#define Z_VERSION_ERROR (-6)
++/* Return codes for the compression/decompression functions. Negative
++ * values are errors, positive values are used for special but normal events.
++ */
++
++#define Z_NO_COMPRESSION         0
++#define Z_BEST_SPEED             1
++#define Z_BEST_COMPRESSION       9
++#define Z_DEFAULT_COMPRESSION  (-1)
++/* compression levels */
++
++#define Z_FILTERED            1
++#define Z_HUFFMAN_ONLY        2
++#define Z_DEFAULT_STRATEGY    0
++/* compression strategy; see deflateInit2() below for details */
++
++#define Z_BINARY   0
++#define Z_ASCII    1
++#define Z_UNKNOWN  2
++/* Possible values of the data_type field */
++
++#define Z_DEFLATED   8
++/* The deflate compression method (the only one supported in this version) */
++
++#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
++
++#define zlib_version zlibVersion()
++/* for compatibility with versions < 1.0.2 */
++
++                        /* basic functions */
++
++ZEXTERN const char * ZEXPORT zlibVersion OF((void));
++/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
++   If the first character differs, the library code actually used is
++   not compatible with the zlib.h header file used by the application.
++   This check is automatically made by deflateInit and inflateInit.
++ */
++
++/* 
++ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
++
++     Initializes the internal stream state for compression. The fields
++   zalloc, zfree and opaque must be initialized before by the caller.
++   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
++   use default allocation functions.
++
++     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
++   1 gives best speed, 9 gives best compression, 0 gives no compression at
++   all (the input data is simply copied a block at a time).
++   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
++   compression (currently equivalent to level 6).
++
++     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
++   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
++   with the version assumed by the caller (ZLIB_VERSION).
++   msg is set to null if there is no error message.  deflateInit does not
++   perform any compression: this will be done by deflate().
++*/
++
++
++ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
++/*
++    deflate compresses as much data as possible, and stops when the input
++  buffer becomes empty or the output buffer becomes full. It may introduce some
++  output latency (reading input without producing any output) except when
++  forced to flush.
++
++    The detailed semantics are as follows. deflate performs one or both of the
++  following actions:
++
++  - Compress more input starting at next_in and update next_in and avail_in
++    accordingly. If not all input can be processed (because there is not
++    enough room in the output buffer), next_in and avail_in are updated and
++    processing will resume at this point for the next call of deflate().
++
++  - Provide more output starting at next_out and update next_out and avail_out
++    accordingly. This action is forced if the parameter flush is non zero.
++    Forcing flush frequently degrades the compression ratio, so this parameter
++    should be set only when necessary (in interactive applications).
++    Some output may be provided even if flush is not set.
++
++  Before the call of deflate(), the application should ensure that at least
++  one of the actions is possible, by providing more input and/or consuming
++  more output, and updating avail_in or avail_out accordingly; avail_out
++  should never be zero before the call. The application can consume the
++  compressed output when it wants, for example when the output buffer is full
++  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
++  and with zero avail_out, it must be called again after making room in the
++  output buffer because there might be more output pending.
++
++    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
++  flushed to the output buffer and the output is aligned on a byte boundary, so
++  that the decompressor can get all input data available so far. (In particular
++  avail_in is zero after the call if enough output space has been provided
++  before the call.)  Flushing may degrade compression for some compression
++  algorithms and so it should be used only when necessary.
++
++    If flush is set to Z_FULL_FLUSH, all output is flushed as with
++  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
++  restart from this point if previous compressed data has been damaged or if
++  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
++  the compression.
++
++    If deflate returns with avail_out == 0, this function must be called again
++  with the same value of the flush parameter and more output space (updated
++  avail_out), until the flush is complete (deflate returns with non-zero
++  avail_out).
++
++    If the parameter flush is set to Z_FINISH, pending input is processed,
++  pending output is flushed and deflate returns with Z_STREAM_END if there
++  was enough output space; if deflate returns with Z_OK, this function must be
++  called again with Z_FINISH and more output space (updated avail_out) but no
++  more input data, until it returns with Z_STREAM_END or an error. After
++  deflate has returned Z_STREAM_END, the only possible operations on the
++  stream are deflateReset or deflateEnd.
++  
++    Z_FINISH can be used immediately after deflateInit if all the compression
++  is to be done in a single step. In this case, avail_out must be at least
++  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
++  Z_STREAM_END, then it must be called again as described above.
++
++    deflate() sets strm->adler to the adler32 checksum of all input read
++  so far (that is, total_in bytes).
++
++    deflate() may update data_type if it can make a good guess about
++  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
++  binary. This field is only for information purposes and does not affect
++  the compression algorithm in any manner.
++
++    deflate() returns Z_OK if some progress has been made (more input
++  processed or more output produced), Z_STREAM_END if all input has been
++  consumed and all output has been produced (only when flush is set to
++  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
++  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
++  (for example avail_in or avail_out was zero).
++*/
++
++
++ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
++/*
++     All dynamically allocated data structures for this stream are freed.
++   This function discards any unprocessed input and does not flush any
++   pending output.
++
++     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
++   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
++   prematurely (some input or output was discarded). In the error case,
++   msg may be set but then points to a static string (which must not be
++   deallocated).
++*/
++
++
++/* 
++ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
++
++     Initializes the internal stream state for decompression. The fields
++   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
++   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
++   value depends on the compression method), inflateInit determines the
++   compression method from the zlib header and allocates all data structures
++   accordingly; otherwise the allocation will be deferred to the first call of
++   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
++   use default allocation functions.
++
++     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
++   version assumed by the caller.  msg is set to null if there is no error
++   message. inflateInit does not perform any decompression apart from reading
++   the zlib header if present: this will be done by inflate().  (So next_in and
++   avail_in may be modified, but next_out and avail_out are unchanged.)
++*/
++
++
++ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
++/*
++    inflate decompresses as much data as possible, and stops when the input
++  buffer becomes empty or the output buffer becomes full. It may some
++  introduce some output latency (reading input without producing any output)
++  except when forced to flush.
++
++  The detailed semantics are as follows. inflate performs one or both of the
++  following actions:
++
++  - Decompress more input starting at next_in and update next_in and avail_in
++    accordingly. If not all input can be processed (because there is not
++    enough room in the output buffer), next_in is updated and processing
++    will resume at this point for the next call of inflate().
++
++  - Provide more output starting at next_out and update next_out and avail_out
++    accordingly.  inflate() provides as much output as possible, until there
++    is no more input data or no more space in the output buffer (see below
++    about the flush parameter).
++
++  Before the call of inflate(), the application should ensure that at least
++  one of the actions is possible, by providing more input and/or consuming
++  more output, and updating the next_* and avail_* values accordingly.
++  The application can consume the uncompressed output when it wants, for
++  example when the output buffer is full (avail_out == 0), or after each
++  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
++  must be called again after making room in the output buffer because there
++  might be more output pending.
++
++    If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much
++  output as possible to the output buffer. The flushing behavior of inflate is
++  not specified for values of the flush parameter other than Z_SYNC_FLUSH
++  and Z_FINISH, but the current implementation actually flushes as much output
++  as possible anyway.
++
++    inflate() should normally be called until it returns Z_STREAM_END or an
++  error. However if all decompression is to be performed in a single step
++  (a single call of inflate), the parameter flush should be set to
++  Z_FINISH. In this case all pending input is processed and all pending
++  output is flushed; avail_out must be large enough to hold all the
++  uncompressed data. (The size of the uncompressed data may have been saved
++  by the compressor for this purpose.) The next operation on this stream must
++  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
++  is never required, but can be used to inform inflate that a faster routine
++  may be used for the single inflate() call.
++
++     If a preset dictionary is needed at this point (see inflateSetDictionary
++  below), inflate sets strm-adler to the adler32 checksum of the
++  dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise 
++  it sets strm->adler to the adler32 checksum of all output produced
++  so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or
++  an error code as described below. At the end of the stream, inflate()
++  checks that its computed adler32 checksum is equal to that saved by the
++  compressor and returns Z_STREAM_END only if the checksum is correct.
++
++    inflate() returns Z_OK if some progress has been made (more input processed
++  or more output produced), Z_STREAM_END if the end of the compressed data has
++  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
++  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
++  corrupted (input stream not conforming to the zlib format or incorrect
++  adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent
++  (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not
++  enough memory, Z_BUF_ERROR if no progress is possible or if there was not
++  enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR
++  case, the application may then call inflateSync to look for a good
++  compression block.
++*/
++
++
++ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
++/*
++     All dynamically allocated data structures for this stream are freed.
++   This function discards any unprocessed input and does not flush any
++   pending output.
++
++     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
++   was inconsistent. In the error case, msg may be set but then points to a
++   static string (which must not be deallocated).
++*/
++
++                        /* Advanced functions */
++
++/*
++    The following functions are needed only in some special applications.
++*/
++
++/*   
++ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
++                                     int  level,
++                                     int  method,
++                                     int  windowBits,
++                                     int  memLevel,
++                                     int  strategy));
++
++     This is another version of deflateInit with more compression options. The
++   fields next_in, zalloc, zfree and opaque must be initialized before by
++   the caller.
++
++     The method parameter is the compression method. It must be Z_DEFLATED in
++   this version of the library.
++
++     The windowBits parameter is the base two logarithm of the window size
++   (the size of the history buffer).  It should be in the range 8..15 for this
++   version of the library. Larger values of this parameter result in better
++   compression at the expense of memory usage. The default value is 15 if
++   deflateInit is used instead.
++
++     The memLevel parameter specifies how much memory should be allocated
++   for the internal compression state. memLevel=1 uses minimum memory but
++   is slow and reduces compression ratio; memLevel=9 uses maximum memory
++   for optimal speed. The default value is 8. See zconf.h for total memory
++   usage as a function of windowBits and memLevel.
++
++     The strategy parameter is used to tune the compression algorithm. Use the
++   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
++   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
++   string match).  Filtered data consists mostly of small values with a
++   somewhat random distribution. In this case, the compression algorithm is
++   tuned to compress them better. The effect of Z_FILTERED is to force more
++   Huffman coding and less string matching; it is somewhat intermediate
++   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
++   the compression ratio but not the correctness of the compressed output even
++   if it is not set appropriately.
++
++      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
++   method). msg is set to null if there is no error message.  deflateInit2 does
++   not perform any compression: this will be done by deflate().
++*/
++                            
++ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
++                                             const Bytef *dictionary,
++                                             uInt  dictLength));
++/*
++     Initializes the compression dictionary from the given byte sequence
++   without producing any compressed output. This function must be called
++   immediately after deflateInit, deflateInit2 or deflateReset, before any
++   call of deflate. The compressor and decompressor must use exactly the same
++   dictionary (see inflateSetDictionary).
++
++     The dictionary should consist of strings (byte sequences) that are likely
++   to be encountered later in the data to be compressed, with the most commonly
++   used strings preferably put towards the end of the dictionary. Using a
++   dictionary is most useful when the data to be compressed is short and can be
++   predicted with good accuracy; the data can then be compressed better than
++   with the default empty dictionary.
++
++     Depending on the size of the compression data structures selected by
++   deflateInit or deflateInit2, a part of the dictionary may in effect be
++   discarded, for example if the dictionary is larger than the window size in
++   deflate or deflate2. Thus the strings most likely to be useful should be
++   put at the end of the dictionary, not at the front.
++
++     Upon return of this function, strm->adler is set to the Adler32 value
++   of the dictionary; the decompressor may later use this value to determine
++   which dictionary has been used by the compressor. (The Adler32 value
++   applies to the whole dictionary even if only a subset of the dictionary is
++   actually used by the compressor.)
++
++     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
++   parameter is invalid (such as NULL dictionary) or the stream state is
++   inconsistent (for example if deflate has already been called for this stream
++   or if the compression method is bsort). deflateSetDictionary does not
++   perform any compression: this will be done by deflate().
++*/
++
++ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
++                                    z_streamp source));
++/*
++     Sets the destination stream as a complete copy of the source stream.
++
++     This function can be useful when several compression strategies will be
++   tried, for example when there are several ways of pre-processing the input
++   data with a filter. The streams that will be discarded should then be freed
++   by calling deflateEnd.  Note that deflateCopy duplicates the internal
++   compression state which can be quite large, so this strategy is slow and
++   can consume lots of memory.
++
++     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
++   (such as zalloc being NULL). msg is left unchanged in both source and
++   destination.
++*/
++
++ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
++/*
++     This function is equivalent to deflateEnd followed by deflateInit,
++   but does not free and reallocate all the internal compression state.
++   The stream will keep the same compression level and any other attributes
++   that may have been set by deflateInit2.
++
++      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++   stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
++				      int level,
++				      int strategy));
++/*
++     Dynamically update the compression level and compression strategy.  The
++   interpretation of level and strategy is as in deflateInit2.  This can be
++   used to switch between compression and straight copy of the input data, or
++   to switch to a different kind of input data requiring a different
++   strategy. If the compression level is changed, the input available so far
++   is compressed with the old level (and may be flushed); the new level will
++   take effect only at the next call of deflate().
++
++     Before the call of deflateParams, the stream state must be set as for
++   a call of deflate(), since the currently available input may have to
++   be compressed and flushed. In particular, strm->avail_out must be non-zero.
++
++     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
++   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
++   if strm->avail_out was zero.
++*/
++
++/*   
++ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
++                                     int  windowBits));
++
++     This is another version of inflateInit with an extra parameter. The
++   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
++   before by the caller.
++
++     The windowBits parameter is the base two logarithm of the maximum window
++   size (the size of the history buffer).  It should be in the range 8..15 for
++   this version of the library. The default value is 15 if inflateInit is used
++   instead. If a compressed stream with a larger window size is given as
++   input, inflate() will return with the error code Z_DATA_ERROR instead of
++   trying to allocate a larger window.
++
++      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative
++   memLevel). msg is set to null if there is no error message.  inflateInit2
++   does not perform any decompression apart from reading the zlib header if
++   present: this will be done by inflate(). (So next_in and avail_in may be
++   modified, but next_out and avail_out are unchanged.)
++*/
++
++ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
++                                             const Bytef *dictionary,
++                                             uInt  dictLength));
++/*
++     Initializes the decompression dictionary from the given uncompressed byte
++   sequence. This function must be called immediately after a call of inflate
++   if this call returned Z_NEED_DICT. The dictionary chosen by the compressor
++   can be determined from the Adler32 value returned by this call of
++   inflate. The compressor and decompressor must use exactly the same
++   dictionary (see deflateSetDictionary).
++
++     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
++   parameter is invalid (such as NULL dictionary) or the stream state is
++   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
++   expected one (incorrect Adler32 value). inflateSetDictionary does not
++   perform any decompression: this will be done by subsequent calls of
++   inflate().
++*/
++
++ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
++/* 
++    Skips invalid compressed data until a full flush point (see above the
++  description of deflate with Z_FULL_FLUSH) can be found, or until all
++  available input is skipped. No output is provided.
++
++    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
++  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
++  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
++  case, the application may save the current current value of total_in which
++  indicates where valid compressed data was found. In the error case, the
++  application may repeatedly call inflateSync, providing more input each time,
++  until success or end of the input data.
++*/
++
++ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
++/*
++     This function is equivalent to inflateEnd followed by inflateInit,
++   but does not free and reallocate all the internal decompression state.
++   The stream will keep attributes that may have been set by inflateInit2.
++
++      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
++   stream state was inconsistent (such as zalloc or state being NULL).
++*/
++
++
++                        /* utility functions */
++
++/*
++     The following utility functions are implemented on top of the
++   basic stream-oriented functions. To simplify the interface, some
++   default options are assumed (compression level and memory usage,
++   standard memory allocation functions). The source code of these
++   utility functions can easily be modified if you need special options.
++*/
++
++ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
++                                 const Bytef *source, uLong sourceLen));
++/*
++     Compresses the source buffer into the destination buffer.  sourceLen is
++   the byte length of the source buffer. Upon entry, destLen is the total
++   size of the destination buffer, which must be at least 0.1% larger than
++   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
++   compressed buffer.
++     This function can be used to compress a whole file at once if the
++   input file is mmap'ed.
++     compress returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_BUF_ERROR if there was not enough room in the output
++   buffer.
++*/
++
++ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
++                                  const Bytef *source, uLong sourceLen,
++                                  int level));
++/*
++     Compresses the source buffer into the destination buffer. The level
++   parameter has the same meaning as in deflateInit.  sourceLen is the byte
++   length of the source buffer. Upon entry, destLen is the total size of the
++   destination buffer, which must be at least 0.1% larger than sourceLen plus
++   12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
++
++     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
++   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
++   Z_STREAM_ERROR if the level parameter is invalid.
++*/
++
++ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
++                                   const Bytef *source, uLong sourceLen));
++/*
++     Decompresses the source buffer into the destination buffer.  sourceLen is
++   the byte length of the source buffer. Upon entry, destLen is the total
++   size of the destination buffer, which must be large enough to hold the
++   entire uncompressed data. (The size of the uncompressed data must have
++   been saved previously by the compressor and transmitted to the decompressor
++   by some mechanism outside the scope of this compression library.)
++   Upon exit, destLen is the actual size of the compressed buffer.
++     This function can be used to decompress a whole file at once if the
++   input file is mmap'ed.
++
++     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
++   enough memory, Z_BUF_ERROR if there was not enough room in the output
++   buffer, or Z_DATA_ERROR if the input data was corrupted.
++*/
++
++
++typedef voidp gzFile;
++
++ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
++/*
++     Opens a gzip (.gz) file for reading or writing. The mode parameter
++   is as in fopen ("rb" or "wb") but can also include a compression level
++   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
++   Huffman only compression as in "wb1h". (See the description
++   of deflateInit2 for more information about the strategy parameter.)
++
++     gzopen can be used to read a file which is not in gzip format; in this
++   case gzread will directly read from the file without decompression.
++
++     gzopen returns NULL if the file could not be opened or if there was
++   insufficient memory to allocate the (de)compression state; errno
++   can be checked to distinguish the two cases (if errno is zero, the
++   zlib error is Z_MEM_ERROR).  */
++
++ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
++/*
++     gzdopen() associates a gzFile with the file descriptor fd.  File
++   descriptors are obtained from calls like open, dup, creat, pipe or
++   fileno (in the file has been previously opened with fopen).
++   The mode parameter is as in gzopen.
++     The next call of gzclose on the returned gzFile will also close the
++   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
++   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
++     gzdopen returns NULL if there was insufficient memory to allocate
++   the (de)compression state.
++*/
++
++ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
++/*
++     Dynamically update the compression level or strategy. See the description
++   of deflateInit2 for the meaning of these parameters.
++     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
++   opened for writing.
++*/
++
++ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
++/*
++     Reads the given number of uncompressed bytes from the compressed file.
++   If the input file was not in gzip format, gzread copies the given number
++   of bytes into the buffer.
++     gzread returns the number of uncompressed bytes actually read (0 for
++   end of file, -1 for error). */
++
++ZEXTERN int ZEXPORT    gzwrite OF((gzFile file, 
++				   const voidp buf, unsigned len));
++/*
++     Writes the given number of uncompressed bytes into the compressed file.
++   gzwrite returns the number of uncompressed bytes actually written
++   (0 in case of error).
++*/
++
++ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
++/*
++     Converts, formats, and writes the args to the compressed file under
++   control of the format string, as in fprintf. gzprintf returns the number of
++   uncompressed bytes actually written (0 in case of error).
++*/
++
++ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
++/*
++      Writes the given null-terminated string to the compressed file, excluding
++   the terminating null character.
++      gzputs returns the number of characters written, or -1 in case of error.
++*/
++
++ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
++/*
++      Reads bytes from the compressed file until len-1 characters are read, or
++   a newline character is read and transferred to buf, or an end-of-file
++   condition is encountered.  The string is then terminated with a null
++   character.
++      gzgets returns buf, or Z_NULL in case of error.
++*/
++
++ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
++/*
++      Writes c, converted to an unsigned char, into the compressed file.
++   gzputc returns the value that was written, or -1 in case of error.
++*/
++
++ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
++/*
++      Reads one byte from the compressed file. gzgetc returns this byte
++   or -1 in case of end of file or error.
++*/
++
++ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
++/*
++     Flushes all pending output into the compressed file. The parameter
++   flush is as in the deflate() function. The return value is the zlib
++   error number (see function gzerror below). gzflush returns Z_OK if
++   the flush parameter is Z_FINISH and all output could be flushed.
++     gzflush should be called only when strictly necessary because it can
++   degrade compression.
++*/
++
++ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
++				      z_off_t offset, int whence));
++/* 
++      Sets the starting position for the next gzread or gzwrite on the
++   given compressed file. The offset represents a number of bytes in the
++   uncompressed data stream. The whence parameter is defined as in lseek(2);
++   the value SEEK_END is not supported.
++     If the file is opened for reading, this function is emulated but can be
++   extremely slow. If the file is opened for writing, only forward seeks are
++   supported; gzseek then compresses a sequence of zeroes up to the new
++   starting position.
++
++      gzseek returns the resulting offset location as measured in bytes from
++   the beginning of the uncompressed stream, or -1 in case of error, in
++   particular if the file is opened for writing and the new starting position
++   would be before the current position.
++*/
++
++ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
++/*
++     Rewinds the given file. This function is supported only for reading.
++
++   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
++*/
++
++ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
++/*
++     Returns the starting position for the next gzread or gzwrite on the
++   given compressed file. This position represents a number of bytes in the
++   uncompressed data stream.
++
++   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
++*/
++
++ZEXTERN int ZEXPORT gzeof OF((gzFile file));
++/*
++     Returns 1 when EOF has previously been detected reading the given
++   input stream, otherwise zero.
++*/
++
++ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
++/*
++     Flushes all pending output if necessary, closes the compressed file
++   and deallocates all the (de)compression state. The return value is the zlib
++   error number (see function gzerror below).
++*/
++
++ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
++/*
++     Returns the error message for the last error which occurred on the
++   given compressed file. errnum is set to zlib error number. If an
++   error occurred in the file system and not in the compression library,
++   errnum is set to Z_ERRNO and the application may consult errno
++   to get the exact error code.
++*/
++
++                        /* checksum functions */
++
++/*
++     These functions are not related to compression but are exported
++   anyway because they might be useful in applications using the
++   compression library.
++*/
++
++ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
++
++/*
++     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
++   return the updated checksum. If buf is NULL, this function returns
++   the required initial value for the checksum.
++   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
++   much faster. Usage example:
++
++     uLong adler = adler32(0L, Z_NULL, 0);
++
++     while (read_buffer(buffer, length) != EOF) {
++       adler = adler32(adler, buffer, length);
++     }
++     if (adler != original_adler) error();
++*/
++
++ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
++/*
++     Update a running crc with the bytes buf[0..len-1] and return the updated
++   crc. If buf is NULL, this function returns the required initial value
++   for the crc. Pre- and post-conditioning (one's complement) is performed
++   within this function so it shouldn't be done by the application.
++   Usage example:
++
++     uLong crc = crc32(0L, Z_NULL, 0);
++
++     while (read_buffer(buffer, length) != EOF) {
++       crc = crc32(crc, buffer, length);
++     }
++     if (crc != original_crc) error();
++*/
++
++
++                        /* various hacks, don't look :) */
++
++/* deflateInit and inflateInit are macros to allow checking the zlib version
++ * and the compiler's view of z_stream:
++ */
++ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
++                                     const char *version, int stream_size));
++ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
++                                     const char *version, int stream_size));
++ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
++                                      int windowBits, int memLevel,
++                                      int strategy, const char *version,
++                                      int stream_size));
++ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
++                                      const char *version, int stream_size));
++#define deflateInit(strm, level) \
++        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
++#define inflateInit(strm) \
++        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
++#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
++        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
++                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
++#define inflateInit2(strm, windowBits) \
++        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
++
++
++#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
++    struct internal_state {int dummy;}; /* hack for buggy compilers */
++#endif
++
++ZEXTERN const char   * ZEXPORT zError           OF((int err));
++ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
++ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _ZLIB_H */
+--- /dev/null	2004-02-02 20:32:13.000000000 +0000
++++ linux/include/zlib/zutil.h	2004-07-05 23:59:30.000000000 +0100
+@@ -0,0 +1,225 @@
++/* zutil.h -- internal interface and configuration of the compression library
++ * Copyright (C) 1995-2002 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h
++ */
++
++/* WARNING: this file should *not* be used by applications. It is
++   part of the implementation of the compression library and is
++   subject to change. Applications should only use zlib.h.
++ */
++
++/* @(#) $Id$ */
++
++#ifndef _Z_UTIL_H
++#define _Z_UTIL_H
++
++#include "zlib.h"
++
++#include <linux/string.h>
++#define HAVE_MEMCPY
++
++#if 0 // #ifdef STDC
++#  include <stddef.h>
++#  include <string.h>
++#  include <stdlib.h>
++#endif
++#ifndef __KERNEL__
++#ifdef NO_ERRNO_H
++    extern int errno;
++#else
++#   include <errno.h>
++#endif
++#endif
++
++#ifndef local
++#  define local static
++#endif
++/* compile with -Dlocal if your debugger can't find static symbols */
++
++typedef unsigned char  uch;
++typedef uch FAR uchf;
++typedef unsigned short ush;
++typedef ush FAR ushf;
++typedef unsigned long  ulg;
++
++extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
++/* (size given to avoid silly warnings with Visual C++) */
++
++#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
++
++#define ERR_RETURN(strm,err) \
++  return (strm->msg = ERR_MSG(err), (err))
++/* To be used only when the state is known to be valid */
++
++        /* common constants */
++
++#ifndef DEF_WBITS
++#  define DEF_WBITS MAX_WBITS
++#endif
++/* default windowBits for decompression. MAX_WBITS is for compression only */
++
++#if MAX_MEM_LEVEL >= 8
++#  define DEF_MEM_LEVEL 8
++#else
++#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
++#endif
++/* default memLevel */
++
++#define STORED_BLOCK 0
++#define STATIC_TREES 1
++#define DYN_TREES    2
++/* The three kinds of block type */
++
++#define MIN_MATCH  3
++#define MAX_MATCH  258
++/* The minimum and maximum match lengths */
++
++#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
++
++        /* target dependencies */
++
++#ifdef MSDOS
++#  define OS_CODE  0x00
++#  if defined(__TURBOC__) || defined(__BORLANDC__)
++#    if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
++       /* Allow compilation with ANSI keywords only enabled */
++       void _Cdecl farfree( void *block );
++       void *_Cdecl farmalloc( unsigned long nbytes );
++#    else
++#     include <alloc.h>
++#    endif
++#  else /* MSC or DJGPP */
++#    include <malloc.h>
++#  endif
++#endif
++
++#ifdef OS2
++#  define OS_CODE  0x06
++#endif
++
++#ifdef WIN32 /* Window 95 & Windows NT */
++#  define OS_CODE  0x0b
++#endif
++
++#if defined(VAXC) || defined(VMS)
++#  define OS_CODE  0x02
++#  define F_OPEN(name, mode) \
++     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
++#endif
++
++#ifdef AMIGA
++#  define OS_CODE  0x01
++#endif
++
++#if defined(ATARI) || defined(atarist)
++#  define OS_CODE  0x05
++#endif
++
++#if defined(MACOS) || defined(TARGET_OS_MAC)
++#  define OS_CODE  0x07
++#  if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
++#    include <unix.h> /* for fdopen */
++#  else
++#    ifndef fdopen
++#      define fdopen(fd,mode) NULL /* No fdopen() */
++#    endif
++#  endif
++#endif
++
++#ifdef __50SERIES /* Prime/PRIMOS */
++#  define OS_CODE  0x0F
++#endif
++
++#ifdef TOPS20
++#  define OS_CODE  0x0a
++#endif
++
++#if defined(_BEOS_) || defined(RISCOS)
++#  define fdopen(fd,mode) NULL /* No fdopen() */
++#endif
++
++#if (defined(_MSC_VER) && (_MSC_VER > 600))
++#  define fdopen(fd,type)  _fdopen(fd,type)
++#endif
++
++
++        /* Common defaults */
++
++#ifndef OS_CODE
++#  define OS_CODE  0x03  /* assume Unix */
++#endif
++
++#ifndef F_OPEN
++#  define F_OPEN(name, mode) fopen((name), (mode))
++#endif
++
++         /* functions */
++
++#ifdef HAVE_STRERROR
++   extern char *strerror OF((int));
++#  define zstrerror(errnum) strerror(errnum)
++#else
++#  define zstrerror(errnum) ""
++#endif
++
++#if defined(pyr)
++#  define NO_MEMCPY
++#endif
++#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
++ /* Use our own functions for small and medium model with MSC <= 5.0.
++  * You may have to use the same strategy for Borland C (untested).
++  * The __SC__ check is for Symantec.
++  */
++#  define NO_MEMCPY
++#endif
++#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
++#  define HAVE_MEMCPY
++#endif
++#ifdef HAVE_MEMCPY
++#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
++#    define zmemcpy _fmemcpy
++#    define zmemcmp _fmemcmp
++#    define zmemzero(dest, len) _fmemset(dest, 0, len)
++#  else
++#    define zmemcpy memcpy
++#    define zmemcmp memcmp
++#    define zmemzero(dest, len) memset(dest, 0, len)
++#  endif
++#else
++   extern void zmemcpy  OF((Bytef* dest, const Bytef* source, uInt len));
++   extern int  zmemcmp  OF((const Bytef* s1, const Bytef* s2, uInt len));
++   extern void zmemzero OF((Bytef* dest, uInt len));
++#endif
++
++/* Diagnostic functions */
++#ifdef DEBUG
++#  include <stdio.h>
++   extern int z_verbose;
++   extern void z_error    OF((char *m));
++#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
++#  define Trace(x) {if (z_verbose>=0) fprintf x ;}
++#  define Tracev(x) {if (z_verbose>0) fprintf x ;}
++#  define Tracevv(x) {if (z_verbose>1) fprintf x ;}
++#  define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
++#  define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
++#else
++#  define Assert(cond,msg)
++#  define Trace(x)
++#  define Tracev(x)
++#  define Tracevv(x)
++#  define Tracec(c,x)
++#  define Tracecv(c,x)
++#endif
++
++
++typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf,
++				       uInt len));
++voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
++void   zcfree  OF((voidpf opaque, voidpf ptr));
++
++#define ZALLOC(strm, items, size) \
++           (*((strm)->zalloc))((strm)->opaque, (items), (size))
++#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
++#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
++
++#endif /* _Z_UTIL_H */
+--- /dev/null	2004-02-02 20:32:13.000000000 +0000
++++ linux/include/zconf.h	2004-07-04 15:38:31.000000000 +0100
+@@ -0,0 +1,309 @@
++/* zconf.h -- configuration of the zlib compression library
++ * Copyright (C) 1995-2002 Jean-loup Gailly.
++ * For conditions of distribution and use, see copyright notice in zlib.h 
++ */
++
++/* @(#) $Id$ */
++
++#ifndef _ZCONF_H
++#define _ZCONF_H
++
++/*
++ * If you *really* need a unique prefix for all types and library functions,
++ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
++ */
++#ifdef IPCOMP_PREFIX
++#  define deflateInit_	ipcomp_deflateInit_
++#  define deflate	ipcomp_deflate
++#  define deflateEnd	ipcomp_deflateEnd
++#  define inflateInit_ 	ipcomp_inflateInit_
++#  define inflate	ipcomp_inflate
++#  define inflateEnd	ipcomp_inflateEnd
++#  define deflateInit2_	ipcomp_deflateInit2_
++#  define deflateSetDictionary ipcomp_deflateSetDictionary
++#  define deflateCopy	ipcomp_deflateCopy
++#  define deflateReset	ipcomp_deflateReset
++#  define deflateParams	ipcomp_deflateParams
++#  define inflateInit2_	ipcomp_inflateInit2_
++#  define inflateSetDictionary ipcomp_inflateSetDictionary
++#  define inflateSync	ipcomp_inflateSync
++#  define inflateSyncPoint ipcomp_inflateSyncPoint
++#  define inflateReset	ipcomp_inflateReset
++#  define compress	ipcomp_compress
++#  define compress2	ipcomp_compress2
++#  define uncompress	ipcomp_uncompress
++#  define adler32	ipcomp_adler32
++#  define crc32		ipcomp_crc32
++#  define get_crc_table ipcomp_get_crc_table
++/* SSS: these also need to be prefixed to avoid clash with ppp_deflate and ext2compression */
++#  define inflate_blocks ipcomp_deflate_blocks
++#  define inflate_blocks_free ipcomp_deflate_blocks_free
++#  define inflate_blocks_new ipcomp_inflate_blocks_new
++#  define inflate_blocks_reset ipcomp_inflate_blocks_reset
++#  define inflate_blocks_sync_point ipcomp_inflate_blocks_sync_point
++#  define inflate_set_dictionary ipcomp_inflate_set_dictionary
++#  define inflate_codes ipcomp_inflate_codes
++#  define inflate_codes_free ipcomp_inflate_codes_free
++#  define inflate_codes_new ipcomp_inflate_codes_new
++#  define inflate_fast ipcomp_inflate_fast
++#  define inflate_trees_bits ipcomp_inflate_trees_bits
++#  define inflate_trees_dynamic ipcomp_inflate_trees_dynamic
++#  define inflate_trees_fixed ipcomp_inflate_trees_fixed
++#  define inflate_flush ipcomp_inflate_flush
++#  define inflate_mask ipcomp_inflate_mask
++#  define _dist_code _ipcomp_dist_code
++#  define _length_code _ipcomp_length_code
++#  define _tr_align _ipcomp_tr_align
++#  define _tr_flush_block _ipcomp_tr_flush_block
++#  define _tr_init _ipcomp_tr_init
++#  define _tr_stored_block _ipcomp_tr_stored_block
++#  define _tr_tally _ipcomp_tr_tally
++#  define zError ipcomp_zError
++#  define z_errmsg ipcomp_z_errmsg
++#  define zlibVersion ipcomp_zlibVersion
++#  define match_init ipcomp_match_init
++#  define longest_match ipcomp_longest_match
++#endif
++
++#ifdef Z_PREFIX
++#  define Byte		z_Byte
++#  define uInt		z_uInt
++#  define uLong		z_uLong
++#  define Bytef	        z_Bytef
++#  define charf		z_charf
++#  define intf		z_intf
++#  define uIntf		z_uIntf
++#  define uLongf	z_uLongf
++#  define voidpf	z_voidpf
++#  define voidp		z_voidp
++#endif
++
++#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
++#  define WIN32
++#endif
++#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
++#  ifndef __32BIT__
++#    define __32BIT__
++#  endif
++#endif
++#if defined(__MSDOS__) && !defined(MSDOS)
++#  define MSDOS
++#endif
++
++/*
++ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
++ * than 64k bytes at a time (needed on systems with 16-bit int).
++ */
++#if defined(MSDOS) && !defined(__32BIT__)
++#  define MAXSEG_64K
++#endif
++#ifdef MSDOS
++#  define UNALIGNED_OK
++#endif
++
++#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
++#  define STDC
++#endif
++#if defined(__STDC__) || defined(__cplusplus) || defined(__OS2__)
++#  ifndef STDC
++#    define STDC
++#  endif
++#endif
++
++#ifndef STDC
++#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
++#    define const
++#  endif
++#endif
++
++/* Some Mac compilers merge all .h files incorrectly: */
++#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
++#  define NO_DUMMY_DECL
++#endif
++
++/* Old Borland C incorrectly complains about missing returns: */
++#if defined(__BORLANDC__) && (__BORLANDC__ < 0x500)
++#  define NEED_DUMMY_RETURN
++#endif
++
++
++/* Maximum value for memLevel in deflateInit2 */
++#ifndef MAX_MEM_LEVEL
++#  ifdef MAXSEG_64K
++#    define MAX_MEM_LEVEL 8
++#  else
++#    define MAX_MEM_LEVEL 9
++#  endif
++#endif
++
++/* Maximum value for windowBits in deflateInit2 and inflateInit2.
++ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
++ * created by gzip. (Files created by minigzip can still be extracted by
++ * gzip.)
++ */
++#ifndef MAX_WBITS
++#  define MAX_WBITS   15 /* 32K LZ77 window */
++#endif
++
++/* The memory requirements for deflate are (in bytes):
++            (1 << (windowBits+2)) +  (1 << (memLevel+9))
++ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
++ plus a few kilobytes for small objects. For example, if you want to reduce
++ the default memory requirements from 256K to 128K, compile with
++     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
++ Of course this will generally degrade compression (there's no free lunch).
++
++   The memory requirements for inflate are (in bytes) 1 << windowBits
++ that is, 32K for windowBits=15 (default value) plus a few kilobytes
++ for small objects.
++*/
++
++                        /* Type declarations */
++
++#ifndef OF /* function prototypes */
++#  ifdef STDC
++#    define OF(args)  args
++#  else
++#    define OF(args)  ()
++#  endif
++#endif
++
++/* The following definitions for FAR are needed only for MSDOS mixed
++ * model programming (small or medium model with some far allocations).
++ * This was tested only with MSC; for other MSDOS compilers you may have
++ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
++ * just define FAR to be empty.
++ */
++#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
++   /* MSC small or medium model */
++#  define SMALL_MEDIUM
++#  ifdef _MSC_VER
++#    define FAR _far
++#  else
++#    define FAR far
++#  endif
++#endif
++#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
++#  ifndef __32BIT__
++#    define SMALL_MEDIUM
++#    define FAR _far
++#  endif
++#endif
++
++/* Compile with -DZLIB_DLL for Windows DLL support */
++#if defined(ZLIB_DLL)
++#  if defined(_WINDOWS) || defined(WINDOWS)
++#    ifdef FAR
++#      undef FAR
++#    endif
++#    include <windows.h>
++#    define ZEXPORT  WINAPI
++#    ifdef WIN32
++#      define ZEXPORTVA  WINAPIV
++#    else
++#      define ZEXPORTVA  FAR _cdecl _export
++#    endif
++#  endif
++#  if defined (__BORLANDC__)
++#    if (__BORLANDC__ >= 0x0500) && defined (WIN32)
++#      include <windows.h>
++#      define ZEXPORT __declspec(dllexport) WINAPI
++#      define ZEXPORTRVA __declspec(dllexport) WINAPIV
++#    else
++#      if defined (_Windows) && defined (__DLL__)
++#        define ZEXPORT _export
++#        define ZEXPORTVA _export
++#      endif
++#    endif
++#  endif
++#endif
++
++#if defined (__BEOS__)
++#  if defined (ZLIB_DLL)
++#    define ZEXTERN extern __declspec(dllexport)
++#  else
++#    define ZEXTERN extern __declspec(dllimport)
++#  endif
++#endif
++
++#ifndef ZEXPORT
++#  define ZEXPORT
++#endif
++#ifndef ZEXPORTVA
++#  define ZEXPORTVA
++#endif
++#ifndef ZEXTERN
++#  define ZEXTERN extern
++#endif
++
++#ifndef FAR
++#   define FAR
++#endif
++
++#if !defined(MACOS) && !defined(TARGET_OS_MAC)
++typedef unsigned char  Byte;  /* 8 bits */
++#endif
++typedef unsigned int   uInt;  /* 16 bits or more */
++typedef unsigned long  uLong; /* 32 bits or more */
++
++#ifdef SMALL_MEDIUM
++   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
++#  define Bytef Byte FAR
++#else
++   typedef Byte  FAR Bytef;
++#endif
++typedef char  FAR charf;
++typedef int   FAR intf;
++typedef uInt  FAR uIntf;
++typedef uLong FAR uLongf;
++
++#ifdef STDC
++   typedef void FAR *voidpf;
++   typedef void     *voidp;
++#else
++   typedef Byte FAR *voidpf;
++   typedef Byte     *voidp;
++#endif
++
++#ifdef HAVE_UNISTD_H
++#  include <sys/types.h> /* for off_t */
++#  include <unistd.h>    /* for SEEK_* and off_t */
++#  define z_off_t  off_t
++#endif
++#ifndef SEEK_SET
++#  define SEEK_SET        0       /* Seek from beginning of file.  */
++#  define SEEK_CUR        1       /* Seek from current position.  */
++#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
++#endif
++#ifndef z_off_t
++#  define  z_off_t long
++#endif
++
++/* MVS linker does not support external names larger than 8 bytes */
++#if defined(__MVS__)
++#   pragma map(deflateInit_,"DEIN")
++#   pragma map(deflateInit2_,"DEIN2")
++#   pragma map(deflateEnd,"DEEND")
++#   pragma map(inflateInit_,"ININ")
++#   pragma map(inflateInit2_,"ININ2")
++#   pragma map(inflateEnd,"INEND")
++#   pragma map(inflateSync,"INSY")
++#   pragma map(inflateSetDictionary,"INSEDI")
++#   pragma map(inflate_blocks,"INBL")
++#   pragma map(inflate_blocks_new,"INBLNE")
++#   pragma map(inflate_blocks_free,"INBLFR")
++#   pragma map(inflate_blocks_reset,"INBLRE")
++#   pragma map(inflate_codes_free,"INCOFR")
++#   pragma map(inflate_codes,"INCO")
++#   pragma map(inflate_fast,"INFA")
++#   pragma map(inflate_flush,"INFLU")
++#   pragma map(inflate_mask,"INMA")
++#   pragma map(inflate_set_dictionary,"INSEDI2")
++#   pragma map(ipcomp_inflate_copyright,"INCOPY")
++#   pragma map(inflate_trees_bits,"INTRBI")
++#   pragma map(inflate_trees_dynamic,"INTRDY")
++#   pragma map(inflate_trees_fixed,"INTRFI")
++#   pragma map(inflate_trees_free,"INTRFR")
++#endif
++
++#endif /* _ZCONF_H */
diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch
index e69de29bb2..4daeaa11be 100644
--- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch
+++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh36.12/mkdep.patch
@@ -0,0 +1,16 @@
+
+#
+# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/Makefile~mkdep	2003-12-19 09:36:51.000000000 -0800
++++ linux/Makefile	2003-12-19 09:57:44.000000000 -0800
+@@ -458,7 +458,7 @@
+ 
+ dep-files: scripts/mkdep archdep include/linux/version.h
+ 	scripts/mkdep -- init/*.c > .depend
+-	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
++	$(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)
+ 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
+ ifdef CONFIG_MODVERSIONS
+ 	$(MAKE) update-modverfile
diff --git a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa
index e69de29bb2..c440fd3d59 100644
--- a/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa
+++ b/linux/handhelds-sa-2.4.19-rmk6-pxa1-hh37.1/defconfig-ipaqsa
@@ -0,0 +1,1508 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200DK is not set
+# CONFIG_MINIMAL_OOPS is not set
+
+#
+# Linux As Bootldr support
+#
+# CONFIG_LAB is not set
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+
+#
+# Archimedes/A5000 Implementations (select only ONE)
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+CONFIG_SA1100_H3100=y
+CONFIG_SA1100_H3600=y
+CONFIG_SA1100_H3800=y
+# CONFIG_SA1100_CONSUS is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_JORNADA56X is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+CONFIG_SA1100_USB=m
+CONFIG_SA1100_USB_NETLINK=m
+CONFIG_SA1100_USB_CHAR=m
+CONFIG_REGISTERS=m
+
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_PXA_CERF is not set
+# CONFIG_ARCH_H3900 is not set
+# CONFIG_ARCH_H1900 is not set
+# CONFIG_ARCH_H5400 is not set
+# CONFIG_ARCH_H2200 is not set
+# CONFIG_ARCH_AXIM is not set
+# CONFIG_PXA_USB is not set
+# CONFIG_PXA_USB_NETLINK is not set
+# CONFIG_PXA_USB_CHAR is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+CONFIG_SA1100_IPAQ=y
+# CONFIG_PXA_IPAQ is not set
+CONFIG_IPAQ_HANDHELD=y
+
+#
+# Compaq iPAQ Handheld
+#
+CONFIG_IPAQ_HAL=m
+CONFIG_H3600_MICRO=m
+CONFIG_IPAQ_HAS_ROSELLA=y
+# CONFIG_IPAQ_HAS_ASIC3 is not set
+CONFIG_H3600_ASIC=m
+CONFIG_H3900_ASIC_DEBUG=y
+# CONFIG_H5400_ASIC is not set
+# CONFIG_H1900_ASIC is not set
+# CONFIG_H1900_TS is not set
+CONFIG_H3600_HARDWARE=y
+CONFIG_IPAQ_SLEEVE=m
+CONFIG_SLEEVE_DEBUG=y
+CONFIG_SLEEVE_DEBUG_VERBOSE=0
+# CONFIG_SLEEVE_IRQ_DEMUX is not set
+
+#
+# Processor Features
+#
+CONFIG_DISCONTIGMEM=y
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_CPU_FREQ=y
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+# CONFIG_PCMCIA_CLPS6700 is not set
+CONFIG_PCMCIA_SA1100=m
+# CONFIG_PCMCIA_PXA is not set
+CONFIG_MERCURY_BACKPAQ=m
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=m
+CONFIG_MMC_DEBUG=y
+CONFIG_MMC_DEBUG_VERBOSE=0
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_PM=y
+CONFIG_APM=m
+CONFIG_HWTIMER=m
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="keepinitrd"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_CFI_B1 is not set
+CONFIG_MTD_CFI_B2=y
+CONFIG_MTD_CFI_B4=y
+# CONFIG_MTD_CFI_B8 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_IPAQ=y
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_LUBBOCK is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_AUTCPU12 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_H720X is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+CONFIG_MTD_MTDRAM=m
+CONFIG_MTDRAM_TOTAL_SIZE=4096
+CONFIG_MTDRAM_ERASE_SIZE=128
+CONFIG_MTD_BLKMTD=m
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_NVRD=m
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_BLK_DEV_LVM=m
+CONFIG_BLK_DEV_DM=m
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+# CONFIG_IP_NF_AMANDA is not set
+# CONFIG_IP_NF_TFTP is not set
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+# CONFIG_IP_NF_MATCH_PKTTYPE is not set
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+# CONFIG_IP_NF_MATCH_RECENT is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_DSCP is not set
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+# CONFIG_IP_NF_MATCH_HELPER is not set
+CONFIG_IP_NF_MATCH_STATE=m
+# CONFIG_IP_NF_MATCH_CONNTRACK is not set
+# CONFIG_IP_NF_MATCH_UNCLEAN is not set
+# CONFIG_IP_NF_MATCH_OWNER is not set
+CONFIG_IP_NF_FILTER=m
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_MIRROR is not set
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+# CONFIG_IP_NF_NAT_SNMP_BASIC is not set
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_DSCP is not set
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+# CONFIG_IP_NF_ARPTABLES is not set
+CONFIG_IP_NF_COMPAT_IPCHAINS=m
+CONFIG_IP_NF_NAT_NEEDED=y
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MOBILITY=m
+CONFIG_IPV6_MOBILITY_MN=m
+# CONFIG_IPV6_MOBILITY_HA is not set
+CONFIG_IPV6_MOBILITY_DEBUG=y
+
+#
+#   IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+# CONFIG_IP6_NF_MATCH_RT is not set
+# CONFIG_IP6_NF_MATCH_OPTS is not set
+# CONFIG_IP6_NF_MATCH_FRAG is not set
+# CONFIG_IP6_NF_MATCH_HL is not set
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+# CONFIG_IP6_NF_MATCH_OWNER is not set
+CONFIG_IP6_NF_MATCH_MARK=m
+# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set
+# CONFIG_IP6_NF_MATCH_AHESP is not set
+# CONFIG_IP6_NF_MATCH_LENGTH is not set
+# CONFIG_IP6_NF_MATCH_EUI64 is not set
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+
+#
+#  
+#
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_IPSEC=m
+
+#
+# IPSec options (FreeS/WAN)
+#
+CONFIG_KLIPS_AUTH_HMAC_MD5=y
+CONFIG_KLIPS_AUTH_HMAC_SHA1=y
+CONFIG_KLIPS_ENC_3DES=y
+
+#
+#  ESP always enabled with tunnel mode
+#
+CONFIG_KLIPS_IPCOMP=y
+CONFIG_KLIPS_DEBUG=y
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_SPECTRUM24T is not set
+
+#
+# Wireless Pcmcia cards support
+#
+# CONFIG_PCMCIA_HERMES is not set
+# CONFIG_AIRO_CS is not set
+# CONFIG_WVLAN_CS is not set
+# CONFIG_MWVLAN_CS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_HOSTAP_CS is not set
+CONFIG_NET_WIRELESS=y
+CONFIG_ATMELWLAN=y
+# CONFIG_ATMELWLAN_USB_503A_RFMD is not set
+CONFIG_ATMELWLAN_PCMCIA_502A=m
+CONFIG_ATMELWLAN_PCMCIA_3COM=m
+CONFIG_ATMELWLAN_PCMCIA_502AD=m
+CONFIG_ATMELWLAN_PCMCIA_502AE=m
+CONFIG_ATMELWLAN_PCMCIA_504=m
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_PCMCIA_NETWAVE=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRNET=m
+CONFIG_IRCOMM=m
+CONFIG_IRDA_ULTRA=y
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+CONFIG_SA1100_FIR=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
+# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
+# CONFIG_BLK_DEV_IDEDISK_IBM is not set
+# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
+# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
+# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
+# CONFIG_BLK_DEV_IDEDISK_WD is not set
+# CONFIG_BLK_DEV_COMMERIAL is not set
+# CONFIG_BLK_DEV_TIVO is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_SCSI_PCMCIA=y
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=m
+CONFIG_INPUT_KEYBDEV=m
+CONFIG_INPUT_MOUSEDEV=m
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_UINPUT=m
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_SERIAL=m
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_S3C2410 is not set
+# CONFIG_SERIAL_S3C2410_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=115200
+CONFIG_SERIAL_H3800_ASIC=m
+# CONFIG_SERIAL_SIR_PXA is not set
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=32
+CONFIG_NEWTONKBD=m
+CONFIG_SA1100_PROFILER=m
+
+#
+# Compaq iPAQ H3600 support
+#
+CONFIG_TOUCHSCREEN_H3600=m
+CONFIG_H3600_BACKPAQ_FPGA=m
+CONFIG_H3600_BACKPAQ_ACCEL=m
+CONFIG_H3600_BACKPAQ_GASGAUGE=m
+CONFIG_H3600_BACKPAQ_SRAM=m
+CONFIG_H3600_BACKPAQ_AUDIO=m
+CONFIG_H3600_STOWAWAY=m
+CONFIG_H3800_MICROKBD=m
+CONFIG_SA1100_LIRC=m
+# CONFIG_H5400_BUZZER is not set
+# CONFIG_H5400_FSI is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+CONFIG_L3=y
+CONFIG_L3_ALGOBIT=y
+CONFIG_L3_BIT_SA1100_GPIO=y
+
+#
+# Other L3 adapters
+#
+# CONFIG_L3_S3C2410 is not set
+# CONFIG_L3_SA1111 is not set
+CONFIG_L3_BACKPAQ=m
+CONFIG_BIT_SA1100_GPIO=y
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=m
+# CONFIG_PSMOUSE is not set
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+CONFIG_INPUT_SERIO=m
+CONFIG_INPUT_SERPORT=m
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=m
+# CONFIG_PXA_WATCHDOG is not set
+# CONFIG_OMAHA_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=m
+# CONFIG_PXA_RTC_HACK is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+CONFIG_PCMCIA_SERIAL_CS=m
+# CONFIG_PCMCIA_MOBILISCAN_CS is not set
+# CONFIG_AXIM_KEY_FIX is not set
+
+#
+# Multimedia devices
+#
+CONFIG_MEDIA=m
+CONFIG_VIDEO_DEV=m
+CONFIG_V4L2_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+# CONFIG_VIDEO_CYBERPRO is not set
+CONFIG_VIDEO_H3600_BACKPAQ=m
+# CONFIG_VIDEO_HAWKEYE is not set
+
+#
+# Video for Linux 2 (V4L2)
+#
+CONFIG_VIDEO_WINNOV_CS=m
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+# CONFIG_RADIO_MIROPCM20_RDS is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DRIVERFS_FS is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_ROOT_NFS is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Console drivers
+#
+CONFIG_PC_KEYMAP=y
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_S3C2410 is not set
+CONFIG_FB_SA1100=y
+# CONFIG_FB_EPSON1356 is not set
+# CONFIG_FB_MQ200 is not set
+# CONFIG_FB_PXA is not set
+# CONFIG_FB_MQ1100 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+CONFIG_FBCON_CFB4=y
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_NO_LOGO is not set
+CONFIG_FBCON_FONTWIDTH8_ONLY=y
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_SA1100=m
+CONFIG_SOUND_UDA1341=m
+# CONFIG_SOUND_SA1100_MONO is not set
+# CONFIG_SOUND_ASSABET_UDA1341 is not set
+CONFIG_SOUND_H3600_UDA1341=m
+# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
+# CONFIG_SOUND_SA1111_UDA1341 is not set
+# CONFIG_SOUND_SA1100SSP is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_VIDC is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+# CONFIG_SOUND_PXA_AC97 is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+# CONFIG_MCP_UCB1400_TS is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
+# USB support
+#
+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_LONG_TIMEOUT is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+# CONFIG_USB_OHCI_H5400 is not set
+# CONFIG_USB_OHCI_S3C2410 is not set
+CONFIG_USB_SL811HS=m
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# USB Human Interface Devices (HID)
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_WACOM is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+
+#
+# USB Multimedia devices
+#
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# USB Network adaptors
+#
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+CONFIG_USB_CDCETHER=m
+# CONFIG_USB_USBNET is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_BRLVGER is not set
+
+#
+# Linux As Bootldr Modules
+#
+# CONFIG_BIG_KERNEL is not set
+# CONFIG_USE_DATE_CODE is not set
+# CONFIG_YMODEM is not set
+# CONFIG_LAB_DUMMY is not set
+# CONFIG_LAB_CRC is not set
+# CONFIG_LAB_YMODEM is not set
+# CONFIG_LAB_MTD is not set
+# CONFIG_LAB_COPY is not set
+# CONFIG_LAB_COPY_YMODEM is not set
+# CONFIG_LAB_COPY_FLASH is not set
+# CONFIG_LAB_COPY_FS is not set
+# CONFIG_LAB_COPY_WRAPPER is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BLUEZ_HCIUSB is not set
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+# CONFIG_BLUEZ_HCIUART_BCSP_TXCRC is not set
+# CONFIG_BLUEZ_HCIBFUSB is not set
+CONFIG_BLUEZ_HCIDTL1=m
+CONFIG_BLUEZ_HCIBT3C=m
+CONFIG_BLUEZ_HCIBLUECARD=m
+CONFIG_BLUEZ_HCIBTUART=m
+# CONFIG_BLUEZ_HCIVHCI is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/handhelds-sa-2.6/defconfig-jornada56x b/linux/handhelds-sa-2.6/defconfig-jornada56x
index e69de29bb2..ebc9a88f2c 100644
--- a/linux/handhelds-sa-2.6/defconfig-jornada56x
+++ b/linux/handhelds-sa-2.6/defconfig-jornada56x
@@ -0,0 +1,877 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=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_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+# CONFIG_MINIMAL_OOPS is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
+CONFIG_SA1100_JORNADA56X=y
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_STORK is not set
+# CONFIG_SA1100_SSP is not set
+CONFIG_SA1100_USB=y
+CONFIG_SA1100_USB_NETLINK=y
+# CONFIG_SA1100_USB_CHAR is not set
+
+#
+# Linux As Bootloader
+#
+# CONFIG_LAB is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_SA1100=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_FASTCALL is not set
+
+#
+# Compaq/iPAQ Options
+#
+
+#
+# General setup
+#
+CONFIG_DISCONTIGMEM=y
+CONFIG_ISA=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+# CONFIG_CPU_FREQ is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=y
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_SOC_DEVICE is not set
+# CONFIG_DOCKING_HOTPLUG is not set
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+CONFIG_APM=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE=""
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=3
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_RAM is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM 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_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+# CONFIG_BT_L2CAP is not set
+# CONFIG_BT_SCO is not set
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUART is not set
+CONFIG_BT_HCIDTL1=m
+CONFIG_BT_HCIBT3C=m
+CONFIG_BT_HCIBLUECARD=m
+CONFIG_BT_HCIBTUART=m
+# CONFIG_BT_HCIVHCI is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+CONFIG_ARLAN=m
+CONFIG_WAVELAN=m
+CONFIG_PCMCIA_WAVELAN=m
+# CONFIG_PCMCIA_NETWAVE is not set
+
+#
+# Wireless 802.11 Frequency Hopping cards support
+#
+# CONFIG_PCMCIA_RAYCS is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_HERMES=m
+# CONFIG_ATMEL is not set
+
+#
+# Wireless 802.11b Pcmcia/Cardbus cards support
+#
+CONFIG_PCMCIA_HERMES=m
+CONFIG_AIRO_CS=m
+# CONFIG_PCMCIA_WL3501 is not set
+CONFIG_NET_WIRELESS=y
+# CONFIG_HOSTAP is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_PCMCIA_AXNET is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=m
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=m
+# CONFIG_IDEDISK_MULTI_MODE is not set
+CONFIG_BLK_DEV_IDECS=m
+CONFIG_BLK_DEV_IDECD=m
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_IDE_TASKFILE_IO is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+# CONFIG_INPUT_TSLIBDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+# CONFIG_SERIO is not set
+# CONFIG_SERIO_I8042 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=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_INPUT_MISC 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_DZ is not set
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+CONFIG_SA1100_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+CONFIG_DEVFS_DEBUG=y
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN 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=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+# CONFIG_EXPORTFS is not set
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT 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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_MODES=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_FB_SA1100=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_MINI_4x6=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# SoC drivers
+#
+# CONFIG_BATTERY_MONITOR is not set
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_KERNEL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/linux-bast-2.4.25-vrs1-bast1/defconfig b/linux/linux-bast-2.4.25-vrs1-bast1/defconfig
index e69de29bb2..1dc6f19154 100644
--- a/linux/linux-bast-2.4.25-vrs1-bast1/defconfig
+++ b/linux/linux-bast-2.4.25-vrs1-bast1/defconfig
@@ -0,0 +1,1115 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+CONFIG_ARCH_BAST=y
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSAGC is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_ADSBITSYPLUS is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_H3600_SLEEVE is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_SA1100_SSP is not set
+
+#
+# AT91RM9200 Implementations
+#
+# CONFIG_ARCH_AT91RM9200DK is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_GUIDEA07 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_PLD is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_S3C2410X=y
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1020E is not set
+# CONFIG_CPU_ARM1022 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_DISCONTIGMEM is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+CONFIG_ISA=y
+# CONFIG_ISA_DMA is not set
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_PM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="root=/dev/hda1 ro"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=y
+# CONFIG_PARPORT_PC_FIFO is not set
+CONFIG_PARPORT_PC_SUPERIO=y
+# CONFIG_PARPORT_PC_PCMCIA is not set
+# CONFIG_PARPORT_ARC is not set
+# CONFIG_PARPORT_IDP is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_IP22 is not set
+CONFIG_PARPORT_OTHER=y
+CONFIG_PARPORT_1284=y
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_REDBOOT_PARTS=y
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_AFS_PARTS=y
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+CONFIG_NFTL=y
+CONFIG_NFTL_RW=y
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_RAM=y
+CONFIG_MTD_ROM=y
+CONFIG_MTD_ABSENT=y
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_EPXA is not set
+# CONFIG_MTD_BAST is not set
+# CONFIG_MTD_AUTCPU12 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+CONFIG_MTD_NAND_IDS=y
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=y
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_ARM_CIRRUS is not set
+CONFIG_NE2K_BAST=y
+CONFIG_DM9000_BAST=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_ISA=y
+# CONFIG_E2100 is not set
+# CONFIG_EWRK3 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_LP486E is not set
+# CONFIG_ETH16I is not set
+# CONFIG_NE2000 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+CONFIG_IRDA=y
+CONFIG_IRLAN=y
+# CONFIG_IRNET is not set
+CONFIG_IRCOMM=y
+CONFIG_IRDA_ULTRA=y
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+# CONFIG_IRTTY_SIR is not set
+# CONFIG_IRPORT_SIR is not set
+# CONFIG_DONGLE is not set
+# CONFIG_USB_IRDA is not set
+CONFIG_NSC_FIR=y
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_TOSHIBA_OLD is not set
+# CONFIG_TOSHIBA_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VLSI_FIR is not set
+# CONFIG_VIA_IRCC_FIR is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=y
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_IDEDISK_STROKE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDE_BAST=y
+# CONFIG_IDE_CHIPSETS is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_DMA_NONPCI is not set
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_KEYBDEV=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=y
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_MX1TS is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_DUMMY_KEYB=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_ANAKIN is not set
+# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+# CONFIG_SERIAL_UART00 is not set
+# CONFIG_SERIAL_UART00_CONSOLE is not set
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+# CONFIG_SERIAL_OMAHA is not set
+# CONFIG_SERIAL_OMAHA_CONSOLE is not set
+# CONFIG_SERIAL_AT91 is not set
+# CONFIG_SERIAL_AT91_CONSOLE is not set
+CONFIG_SERIAL_S3C2410X=y
+CONFIG_SERIAL_S3C2410X_CONSOLE=y
+# CONFIG_SERIAL_8250 is not set
+# CONFIG_SERIAL_8250_CONSOLE is not set
+# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+# CONFIG_SERIAL_8250_SHARE_IRQ is not set
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_MULTIPORT is not set
+# CONFIG_SERIAL_8250_HUB6 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_PRINTER=y
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=y
+# CONFIG_TIPAR is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+CONFIG_I2C_PHILIPSPAR=y
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_VELLEMAN is not set
+# CONFIG_SCx200_I2C is not set
+# CONFIG_I2C_GUIDE is not set
+CONFIG_I2C_S3C2410BIT=y
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_PROC=y
+# CONFIG_I2C_DS1307 is not set
+
+#
+# L3 serial bus support
+#
+# CONFIG_L3 is not set
+# CONFIG_L3_ALGOBIT is not set
+# CONFIG_L3_BIT_SA1100_GPIO is not set
+# CONFIG_L3_SA1111 is not set
+# CONFIG_BIT_SA1100_GPIO is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_INPUT_NS558 is not set
+# CONFIG_INPUT_LIGHTNING is not set
+# CONFIG_INPUT_PCIGAME is not set
+# CONFIG_INPUT_CS461X is not set
+# CONFIG_INPUT_EMU10K1 is not set
+# CONFIG_INPUT_SERIO is not set
+# CONFIG_INPUT_SERPORT is not set
+# CONFIG_INPUT_ANALOG is not set
+# CONFIG_INPUT_A3D is not set
+# CONFIG_INPUT_ADI is not set
+# CONFIG_INPUT_COBRA is not set
+# CONFIG_INPUT_GF2K is not set
+# CONFIG_INPUT_GRIP is not set
+# CONFIG_INPUT_INTERACT is not set
+# CONFIG_INPUT_TMDC is not set
+# CONFIG_INPUT_SIDEWINDER is not set
+# CONFIG_INPUT_IFORCE_USB is not set
+# CONFIG_INPUT_IFORCE_232 is not set
+# CONFIG_INPUT_WARRIOR is not set
+# CONFIG_INPUT_MAGELLAN is not set
+# CONFIG_INPUT_SPACEORB is not set
+# CONFIG_INPUT_SPACEBALL is not set
+# CONFIG_INPUT_STINGER is not set
+# CONFIG_INPUT_DB9 is not set
+# CONFIG_INPUT_GAMECON is not set
+# CONFIG_INPUT_TURBOGRAFX is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+# CONFIG_ACQUIRE_WDT is not set
+# CONFIG_ADVANTECH_WDT is not set
+# CONFIG_ALIM1535_WDT is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_SC520_WDT is not set
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_21285_WATCHDOG is not set
+# CONFIG_977_WATCHDOG is not set
+# CONFIG_SA1100_WATCHDOG is not set
+# CONFIG_EPXA_WATCHDOG is not set
+# CONFIG_OMAHA_WATCHDOG is not set
+CONFIG_S3C2410_WATCHDOG=y
+# CONFIG_AT91_WATCHDOG is not set
+# CONFIG_EUROTECH_WDT is not set
+# CONFIG_IB700_WDT is not set
+# CONFIG_WAFER_WDT is not set
+# CONFIG_I810_TCO is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_60XX_WDT is not set
+# CONFIG_SC1200_WDT is not set
+# CONFIG_SCx200_WDT is not set
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_W83877F_WDT is not set
+# CONFIG_WDT is not set
+# CONFIG_WDTPCI is not set
+# CONFIG_MACHZ_WDT is not set
+# CONFIG_AMD7XX_TCO is not set
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_BAST_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS_FS=y
+CONFIG_JFFS_FS_VERBOSE=0
+CONFIG_JFFS_PROC_FS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_CRAMFS=y
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=y
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_ZISOFS_FS=y
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Console drivers
+#
+# CONFIG_VGA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_ACORN is not set
+# CONFIG_FB_ANAKIN is not set
+# CONFIG_FB_CLPS711X is not set
+# CONFIG_FB_SA1100 is not set
+CONFIG_FB_S3C2410=y
+# CONFIG_FB_DBMX1 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+CONFIG_FBCON_CFB4=y
+CONFIG_FBCON_CFB8=y
+# CONFIG_FBCON_CFB16 is not set
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+CONFIG_FONT_ACORN_8x8=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_S3C2410=y
+CONFIG_SOUND_S3C2410_TLV320AIC23=y
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_VIDC is not set
+# CONFIG_SOUND_WAVEARTIST is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+# CONFIG_SOUND_WM97XX is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+# CONFIG_MCP_SA1100 is not set
+# CONFIG_MCP_UCB1200 is not set
+# CONFIG_MCP_UCB1200_AUDIO is not set
+# CONFIG_MCP_UCB1200_TS is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+# CONFIG_USB_OHCI is not set
+# CONFIG_USB_OHCI_SA1111 is not set
+CONFIG_USB_OHCI_S3C2410=y
+# CONFIG_USB_SL811HS_ALT is not set
+# CONFIG_USB_SL811HS is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_STORAGE is not set
+# 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_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=y
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+CONFIG_USB_HIDDEV=y
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_CDCETHER is not set
+CONFIG_USB_USBNET=y
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_DEBUG is not set
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=y
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SLAB=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_WAITQ=y
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+CONFIG_DEBUG_S3C2410X_UART0=y
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch b/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch
index e69de29bb2..57218a7d1a 100644
--- a/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch
+++ b/linux/linux-bast-2.4.25-vrs1-bast1/mkdep.patch
@@ -0,0 +1,16 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.25/Makefile~mkdep	2004-03-31 17:15:12.000000000 +0200
++++ linux-2.4.25/Makefile	2004-03-31 17:18:50.000000000 +0200
+@@ -502,7 +502,7 @@
+ ifdef CONFIG_MODVERSIONS
+ 	$(MAKE) update-modverfile
+ endif
+-	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
++	$(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)	
+ 	scripts/mkdep -- init/*.c > .depend
+ 
+ ifdef CONFIG_MODVERSIONS
diff --git a/linux/linux-mtx-1-2.4.24/defconfig-mtx-1 b/linux/linux-mtx-1-2.4.24/defconfig-mtx-1
index e69de29bb2..84ab6de3a8 100644
--- a/linux/linux-mtx-1-2.4.24/defconfig-mtx-1
+++ b/linux/linux-mtx-1-2.4.24/defconfig-mtx-1
@@ -0,0 +1,1265 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_HYDROGEN3 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_XXS1500 is not set
+CONFIG_MIPS_MTX1=y
+# CONFIG_COGENT_CSB250 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_CASIO_E55 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_IBM_WORKPAD is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TANBAC_TB0226 is not set
+# CONFIG_TANBAC_TB0229 is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_VICTOR_MPC30X is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_SOC_AU1X00=y
+CONFIG_SOC_AU1500=y
+CONFIG_NEW_TIME_C=y
+CONFIG_PCI=y
+CONFIG_NEW_PCI=y
+CONFIG_PCI_AUTO=y
+# CONFIG_NONCOHERENT_IO is not set
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+CONFIG_64BIT_PHYS_ADDR=y
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_NET=y
+CONFIG_PCI_NAMES=y
+# CONFIG_ISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_MIPS32_O32 is not set
+# CONFIG_MIPS32_N32 is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_AMDSTD_RETRY=y
+CONFIG_MTD_CFI_AMDSTD_RETRY_MAX=5
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_DB1X00 is not set
+CONFIG_MTD_MTX1=y
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_LASAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_NETLINK_DEV=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_PHYSDEV=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+
+#
+#   IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IPV6_SCTP__=m
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_IPF=m
+CONFIG_BRIDGE_EBT_ARPF=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_VLANF=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_MARKF=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+CONFIG_IPSEC=m
+CONFIG_IPSEC_IPIP=y
+CONFIG_IPSEC_AH=y
+CONFIG_IPSEC_AUTH_HMAC_MD5=y
+CONFIG_IPSEC_AUTH_HMAC_SHA1=y
+CONFIG_IPSEC_ESP=y
+CONFIG_IPSEC_ENC_3DES=y
+CONFIG_IPSEC_IPCOMP=y
+# CONFIG_IPSEC_DEBUG is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_MEGARAID2 is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MIPS_AU1X00_ENET=y
+# CONFIG_BCM5222_DUAL_PHY is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+# CONFIG_PPP_FILTER is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+CONFIG_AIRONET4500=m
+CONFIG_AIRONET4500_NONCS=m
+# CONFIG_AIRONET4500_PNP is not set
+CONFIG_AIRONET4500_PCI=y
+# CONFIG_AIRONET4500_ISA is not set
+# CONFIG_AIRONET4500_I365 is not set
+CONFIG_AIRONET4500_PROC=m
+CONFIG_AIRO=m
+# CONFIG_HERMES is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+# CONFIG_SERIAL_TX3912 is not set
+# CONFIG_SERIAL_TX3912_CONSOLE is not set
+# CONFIG_SERIAL_TXX9 is not set
+# CONFIG_SERIAL_TXX9_CONSOLE is not set
+CONFIG_AU1X00_UART=y
+CONFIG_AU1X00_SERIAL_CONSOLE=y
+# CONFIG_AU1X00_USB_TTY is not set
+# CONFIG_AU1X00_USB_RAW is not set
+# CONFIG_TXX927_SERIAL is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_MIPS_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+CONFIG_AU1X00_GPIO=m
+# CONFIG_TS_AU1X00_ADS7846 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_JFFS2_FS_NAND is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_ZISOFS_FS=m
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-15"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+# CONFIG_VIDEO_PROC_FS is not set
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_AU1X00 is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_KAHLUA is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+# CONFIG_SOUND_WM97XX is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+CONFIG_USB_NON_PCI_OHCI=y
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_MIDI is not set
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+# 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_HP8200e is not set
+CONFIG_USB_STORAGE_SDDR09=y
+# CONFIG_USB_STORAGE_SDDR55 is not set
+CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDINPUT is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+CONFIG_USB_DC2XX=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_SCANNER=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+# CONFIG_USB_W9968CF is not set
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_DABUSB=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_CATC=m
+CONFIG_USB_AX8817X=m
+CONFIG_USB_CDCETHER=m
+CONFIG_USB_USBNET=m
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_TIGL=m
+CONFIG_USB_BRLVGER=m
+CONFIG_USB_LCD=m
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# USB clients (devices, not hosts)
+#
+CONFIG_USBD=m
+CONFIG_USBD_HIGH_SPEED=y
+# CONFIG_USBD_NO_SERIAL_NUMBER is not set
+CONFIG_USBD_SERIAL_NUMBER_STR=""
+CONFIG_USBD_MAXPOWER=0
+CONFIG_USBD_PROCFS=y
+CONFIG_USBD_PROCFSM=m
+
+#
+# Network Function
+#
+CONFIG_USBD_NETWORK=m
+CONFIG_USBD_NETWORK_VENDORID=2001
+CONFIG_USBD_NETWORK_PRODUCTID=1a00
+CONFIG_USBD_NETWORK_BCDDEVICE=0100
+CONFIG_USBD_NETWORK_MANUFACTURER="Belcarra"
+CONFIG_USBD_NETWORK_PRODUCT_NAME="Belcarra BLAN Device"
+CONFIG_USBD_NETWORK_BLAN=y
+CONFIG_USBD_NETWORK_BLAN_DESC="BLAN Net Cfg"
+CONFIG_USBD_NETWORK_BLAN_INTF="Comm/Data Intf"
+CONFIG_USBD_NETWORK_BLAN_CRC=y
+CONFIG_USBD_NETWORK_BLAN_PADBEFORE=y
+CONFIG_USBD_NETWORK_BLAN_PADAFTER=y
+CONFIG_USBD_NETWORK_BLAN_PADBYTES=8
+CONFIG_USBD_NETWORK_BLAN_FERMAT=y
+CONFIG_USBD_NETWORK_BLAN_DO_NOT_SETTIME=y
+# CONFIG_USBD_NETWORK_BLAN_HOSTNAME is not set
+CONFIG_USBD_NETWORK_BLAN_NONBRIDGED=y
+# CONFIG_USBD_NETWORK_SAFE is not set
+CONFIG_USBD_NETWORK_CDC=y
+CONFIG_USBD_NETWORK_CDC_DESC="SAFE Net Cfg"
+CONFIG_USBD_NETWORK_CDC_COMM_INTF="Comm Intf"
+CONFIG_USBD_NETWORK_CDC_NODATA_INTF="Data (Disabled) Intf"
+CONFIG_USBD_NETWORK_CDC_DATA_INTF="Dat Intf"
+# CONFIG_USBD_NETWORK_BASIC is not set
+# CONFIG_USBD_NETWORK_BASIC2 is not set
+CONFIG_USBD_NETWORK_START_SINGLE=y
+CONFIG_USBD_NETWORK_EP0TEST=y
+
+#
+# CDC ACM Function
+#
+CONFIG_USBD_ACM=m
+CONFIG_USBD_ACM_VENDORID=12b9
+CONFIG_USBD_ACM_PRODUCTID=f002
+CONFIG_USBD_ACM_BCDDEVICE=0100
+CONFIG_USBD_ACM_MANUFACTURER="Belcarra"
+CONFIG_USBD_ACM_PRODUCT_NAME="Belcarra ACM Device"
+CONFIG_USBD_ACM_DESC="Acm Cfg"
+CONFIG_USBD_ACM_COMM_INTF="Comm Intf"
+CONFIG_USBD_ACM_DATA_INTF="Data Intf"
+CONFIG_USBD_ACM_TRACE=y
+
+#
+# Random Mouse Function
+#
+CONFIG_USBD_MOUSE=m
+CONFIG_USBD_MOUSE_VENDORID=12b9
+CONFIG_USBD_MOUSE_PRODUCTID=f003
+CONFIG_USBD_MOUSE_BCDDEVICE=0100
+CONFIG_USBD_MOUSE_MANUFACTURER="Belcarra"
+CONFIG_USBD_MOUSE_DESC="Acm Cfg"
+CONFIG_USBD_MOUSE_COMM_INTF="Comm Intf"
+CONFIG_USBD_MOUSE_BH=y
+
+#
+# AMD AU1X000 Bus Interface
+#
+CONFIG_USBD_AU1X00_BUS=m
+CONFIG_USBD_AU1X00_SCLOCK=400
+CONFIG_AU1000_USB_DEVICE=y
+CONFIG_AU1X00_USB_DEVICE=y
+CONFIG_USBD_BI_REGISTER_TRACE=y
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BLUEZ_HCIUSB=m
+CONFIG_BLUEZ_HCIUSB_SCO=y
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
+CONFIG_BLUEZ_HCIBFUSB=m
+# CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
+# CONFIG_BLUEZ_HCIBLUECARD is not set
+# CONFIG_BLUEZ_HCIBTUART is not set
+CONFIG_BLUEZ_HCIVHCI=m
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_KGDB is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+CONFIG_LOG_BUF_SHIFT=0
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC32=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_FW_LOADER=m
diff --git a/linux/linux-mtx-1-2.4.27/defconfig-mtx-1 b/linux/linux-mtx-1-2.4.27/defconfig-mtx-1
index e69de29bb2..03e8dc6dbd 100644
--- a/linux/linux-mtx-1-2.4.27/defconfig-mtx-1
+++ b/linux/linux-mtx-1-2.4.27/defconfig-mtx-1
@@ -0,0 +1,1183 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_HYDROGEN3 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_XXS1500 is not set
+CONFIG_MIPS_MTX1=y
+# CONFIG_COGENT_CSB250 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_CASIO_E55 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_IBM_WORKPAD is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_PMC_BIG_SUR is not set
+# CONFIG_PMC_STRETCH is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TANBAC_TB0226 is not set
+# CONFIG_TANBAC_TB0229 is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_VICTOR_MPC30X is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_SOC_AU1X00=y
+CONFIG_SOC_AU1500=y
+CONFIG_NONCOHERENT_IO=y
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+CONFIG_64BIT_PHYS_ADDR=y
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_NET=y
+CONFIG_PCI=y
+CONFIG_PCI_NEW=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_NAMES=y
+# CONFIG_ISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+# CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE is not set
+# CONFIG_HOTPLUG_PCI_PCIE is not set
+# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_MIPS32_O32 is not set
+# CONFIG_MIPS32_N32 is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_OOM_KILLER is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PB1000 is not set
+# CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
+# CONFIG_MTD_BOSPORUS is not set
+# CONFIG_MTD_XXS1500 is not set
+CONFIG_MTD_MTX1=y
+# CONFIG_MTD_DB1X00 is not set
+# CONFIG_MTD_PB1550 is not set
+# CONFIG_MTD_HYDROGEN3 is not set
+# CONFIG_MTD_MIRAGE is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_LASAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_CISS_MONITOR_THREAD is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+CONFIG_SYN_COOKIES=y
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+
+#
+#   IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+
+#
+#   IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_MEGARAID2 is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_SATA_SVW is not set
+# CONFIG_SCSI_SATA_PROMISE is not set
+# CONFIG_SCSI_SATA_SX4 is not set
+# CONFIG_SCSI_SATA_SIL is not set
+# CONFIG_SCSI_SATA_SIS is not set
+# CONFIG_SCSI_SATA_VIA is not set
+# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_BOOT is not set
+# CONFIG_FUSION_ISENSE is not set
+# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION_LAN is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MIPS_AU1X00_ENET=y
+# CONFIG_BCM5222_DUAL_PHY is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+# CONFIG_SERIAL_TX3912 is not set
+# CONFIG_SERIAL_TX3912_CONSOLE is not set
+# CONFIG_SERIAL_TXX9 is not set
+# CONFIG_SERIAL_TXX9_CONSOLE is not set
+CONFIG_AU1X00_UART=y
+CONFIG_AU1X00_SERIAL_CONSOLE=y
+CONFIG_AU1X00_USB_TTY=m
+CONFIG_AU1X00_USB_RAW=m
+CONFIG_AU1X00_USB_DEVICE=y
+# CONFIG_TXX927_SERIAL is not set
+# CONFIG_MIPS_HYDROGEN3_BUTTONS is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200 is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+
+#
+# Direct Rendering Manager (XFree86 DRI support)
+#
+# CONFIG_DRM is not set
+CONFIG_AU1X00_GPIO=m
+# CONFIG_TS_AU1X00_ADS7846 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+CONFIG_UDF_FS=m
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_SMB_UNIX=y
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_ZISOFS_FS=m
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-15"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+# CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_PMS is not set
+CONFIG_VIDEO_CPIA=m
+# CONFIG_VIDEO_CPIA_PP is not set
+CONFIG_VIDEO_CPIA_USB=m
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_AU1X00 is not set
+# CONFIG_SOUND_AU1550_PSC is not set
+# CONFIG_SOUND_AU1550_I2S is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+CONFIG_SOUND_OSS=m
+# CONFIG_SOUND_TRACEINIT is not set
+# CONFIG_SOUND_DMAP is not set
+# CONFIG_SOUND_AD1816 is not set
+# CONFIG_SOUND_AD1889 is not set
+# CONFIG_SOUND_SGALAXY is not set
+# CONFIG_SOUND_ADLIB is not set
+# CONFIG_SOUND_ACI_MIXER is not set
+# CONFIG_SOUND_CS4232 is not set
+# CONFIG_SOUND_SSCAPE is not set
+# CONFIG_SOUND_GUS is not set
+# CONFIG_SOUND_VMIDI is not set
+# CONFIG_SOUND_TRIX is not set
+# CONFIG_SOUND_MSS is not set
+# CONFIG_SOUND_MPU401 is not set
+# CONFIG_SOUND_NM256 is not set
+# CONFIG_SOUND_MAD16 is not set
+# CONFIG_SOUND_PAS is not set
+# CONFIG_PAS_JOYSTICK is not set
+# CONFIG_SOUND_PSS is not set
+# CONFIG_SOUND_SB is not set
+# CONFIG_SOUND_AWE32_SYNTH is not set
+# CONFIG_SOUND_KAHLUA is not set
+# CONFIG_SOUND_WAVEFRONT is not set
+# CONFIG_SOUND_MAUI is not set
+# CONFIG_SOUND_YM3812 is not set
+# CONFIG_SOUND_OPL3SA1 is not set
+# CONFIG_SOUND_OPL3SA2 is not set
+# CONFIG_SOUND_YMFPCI is not set
+# CONFIG_SOUND_YMFPCI_LEGACY is not set
+# CONFIG_SOUND_UART6850 is not set
+# CONFIG_SOUND_AEDSP16 is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+# CONFIG_SOUND_WM97XX is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+CONFIG_USB_NON_PCI_OHCI=y
+CONFIG_USB_AUDIO=m
+CONFIG_USB_EMI26=m
+CONFIG_USB_MIDI=m
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+# CONFIG_USB_STORAGE_ISD200 is not set
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_HP8200e=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDINPUT is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+CONFIG_USB_DC2XX=m
+CONFIG_USB_MDC800=m
+CONFIG_USB_SCANNER=m
+CONFIG_USB_MICROTEK=m
+CONFIG_USB_HPUSBSCSI=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+# CONFIG_USB_W9968CF is not set
+CONFIG_USB_VICAM=m
+CONFIG_USB_DSBR=m
+CONFIG_USB_DABUSB=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_CATC=m
+CONFIG_USB_CDCETHER=m
+CONFIG_USB_USBNET=m
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
+CONFIG_USB_SERIAL_GENERIC=y
+CONFIG_USB_SERIAL_BELKIN=m
+CONFIG_USB_SERIAL_WHITEHEAT=m
+CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
+CONFIG_USB_SERIAL_EMPEG=m
+CONFIG_USB_SERIAL_FTDI_SIO=m
+CONFIG_USB_SERIAL_VISOR=m
+CONFIG_USB_SERIAL_IPAQ=m
+CONFIG_USB_SERIAL_IR=m
+CONFIG_USB_SERIAL_EDGEPORT=m
+CONFIG_USB_SERIAL_EDGEPORT_TI=m
+CONFIG_USB_SERIAL_KEYSPAN_PDA=m
+CONFIG_USB_SERIAL_KEYSPAN=m
+CONFIG_USB_SERIAL_KEYSPAN_USA28=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XA=y
+CONFIG_USB_SERIAL_KEYSPAN_USA28XB=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19=y
+CONFIG_USB_SERIAL_KEYSPAN_USA18X=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QW=y
+CONFIG_USB_SERIAL_KEYSPAN_USA19QI=y
+CONFIG_USB_SERIAL_KEYSPAN_MPR=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49W=y
+CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
+CONFIG_USB_SERIAL_MCT_U232=m
+CONFIG_USB_SERIAL_KLSI=m
+CONFIG_USB_SERIAL_KOBIL_SCT=m
+CONFIG_USB_SERIAL_PL2303=m
+CONFIG_USB_SERIAL_CYBERJACK=m
+CONFIG_USB_SERIAL_XIRCOM=m
+CONFIG_USB_SERIAL_OMNINET=m
+CONFIG_USB_RIO500=m
+CONFIG_USB_AUERSWALD=m
+CONFIG_USB_TIGL=m
+CONFIG_USB_BRLVGER=m
+CONFIG_USB_LCD=m
+
+#
+# Support for USB gadgets
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Bluetooth support
+#
+CONFIG_BLUEZ=m
+CONFIG_BLUEZ_L2CAP=m
+CONFIG_BLUEZ_SCO=m
+CONFIG_BLUEZ_RFCOMM=m
+CONFIG_BLUEZ_RFCOMM_TTY=y
+CONFIG_BLUEZ_BNEP=m
+CONFIG_BLUEZ_BNEP_MC_FILTER=y
+CONFIG_BLUEZ_BNEP_PROTO_FILTER=y
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BLUEZ_HCIUSB=m
+CONFIG_BLUEZ_HCIUSB_SCO=y
+CONFIG_BLUEZ_HCIUART=m
+CONFIG_BLUEZ_HCIUART_H4=y
+CONFIG_BLUEZ_HCIUART_BCSP=y
+CONFIG_BLUEZ_HCIUART_BCSP_TXCRC=y
+CONFIG_BLUEZ_HCIBFUSB=m
+# CONFIG_BLUEZ_HCIDTL1 is not set
+# CONFIG_BLUEZ_HCIBT3C is not set
+# CONFIG_BLUEZ_HCIBLUECARD is not set
+# CONFIG_BLUEZ_HCIBTUART is not set
+CONFIG_BLUEZ_HCIVHCI=m
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_KGDB is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+CONFIG_LOG_BUF_SHIFT=0
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Library routines
+#
+CONFIG_CRC32=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_FW_LOADER=m
diff --git a/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff b/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff
index e69de29bb2..9a13c2a403 100644
--- a/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff
+++ b/linux/linux-mtx-1-2.4.27/mtx-1-board-reset.diff
@@ -0,0 +1,15 @@
+--- linux/arch/mips/au1000/mtx-1/board_setup.c.orig	2004-10-13 19:05:15.340583632 +0200
++++ linux/arch/mips/au1000/mtx-1/board_setup.c	2004-10-13 19:01:03.402883984 +0200
+@@ -48,6 +48,12 @@
+ 
+ extern struct rtc_ops no_rtc_ops;
+ 
++void board_reset (void)
++{
++	/* Hit BCSR.SYSTEM_CONTROL[SW_RST] */
++	au_writel(0x00000000, 0xAE00001C);
++}
++
+ void __init board_setup(void)
+ {
+ 	rtc_ops = &no_rtc_ops;
diff --git a/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch b/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch
index e69de29bb2..dca79a3000 100644
--- a/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch
+++ b/linux/linux-mtx-1-2.4.27/zimage-flash-bin.patch
@@ -0,0 +1,11 @@
+diff -Nurb oe/tmp/work/linux-mtx-1-2.4.27-r0/linux/arch/mips/zboot/pb1xxx/Makefile linux.m/arch/mips/zboot/pb1xxx/Makefile
+--- oe/tmp/work/linux-mtx-1-2.4.27-r0/linux/arch/mips/zboot/pb1xxx/Makefile	2004-10-13 21:08:49.840408328 +0200
++++ linux.m/arch/mips/zboot/pb1xxx/Makefile	2004-10-13 21:08:29.736464592 +0200
+@@ -131,5 +131,7 @@
+ zImage.flash: zImage
+ 	$(OBJCOPY) -O srec --adjust-vma 0x3ed00000 \
+ 		../images/zImage.$(BNAME) ../images/$(BNAME).flash.srec
++	$(OBJCOPY) -O binary --adjust-vma 0x3ed00000 \
++		../images/zImage.$(BNAME) ../images/$(BNAME).flash.bin
+ 
+ include $(TOPDIR)/Rules.make
diff --git a/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig b/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig
index e69de29bb2..8b4d7f27ce 100644
--- a/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig
+++ b/linux/linux-omap-2.6-2.6.9-omap1/omap1610h2/defconfig
@@ -0,0 +1,840 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.9-rc4-omap1
+# Thu Oct 14 16:30:44 2004
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_IOMAP=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
+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_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SHMEM=y
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+CONFIG_ARCH_OMAP=y
+# CONFIG_ARCH_VERSATILE_PB is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+
+#
+# TI OMAP Implementations
+#
+
+#
+# OMAP Core Type
+#
+# CONFIG_ARCH_OMAP730 is not set
+# CONFIG_ARCH_OMAP1510 is not set
+CONFIG_ARCH_OMAP16XX=y
+CONFIG_ARCH_OMAP_OTG=y
+
+#
+# OMAP Board Type
+#
+# CONFIG_MACH_OMAP_INNOVATOR is not set
+CONFIG_MACH_OMAP_H2=y
+# CONFIG_MACH_OMAP_H3 is not set
+# CONFIG_MACH_OMAP_H4 is not set
+# CONFIG_MACH_OMAP_OSK is not set
+# CONFIG_MACH_OMAP_GENERIC is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_BOOT_TAG is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+CONFIG_OMAP_ARM_192MHZ=y
+# CONFIG_OMAP_ARM_168MHZ is not set
+# CONFIG_OMAP_ARM_120MHZ is not set
+# CONFIG_OMAP_ARM_60MHZ is not set
+# CONFIG_OMAP_ARM_30MHZ is not set
+# CONFIG_OMAP_DSP is not set
+
+#
+# h720x Implementations
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x10C08000
+CONFIG_ZBOOT_ROM_BSS=0x10200000
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_PM is not set
+CONFIG_PREEMPT=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 initrd=0x10A00000,8M root=/dev/ram0 rw ip=dhcp devfs=mount"
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER 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_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_SMC91X=y
+# CONFIG_SMC9194 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PPP=y
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_ASYNC is not set
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_PPP_DEFLATE is not set
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+CONFIG_SLIP=y
+CONFIG_SLIP_COMPRESSED=y
+# CONFIG_SLIP_SMART is not set
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_RAW is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_OMAP=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC 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=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_8250_OMAP=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_OMAP16XX_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_OMAP_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_PCA_ISA is not set
+CONFIG_I2C_OMAP=y
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+CONFIG_ISP1301_OMAP=m
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_TLV320AIC23 is not set
+CONFIG_GPIOEXPANDER_OMAP=y
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=y
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_OVCAMCHIP is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_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_SYSFS=y
+CONFIG_DEVFS_FS=y
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# 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_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_EXPORTFS is not set
+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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_OMAP=y
+CONFIG_FB_OMAP_INTERNAL_LCDC=y
+# CONFIG_FB_OMAP_EXTERNAL_LCDC is not set
+# CONFIG_FB_OMAP_DMA_TUNE is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=y
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_SONICVIBES is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+# CONFIG_SOUND_AD1980 is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+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 is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811HS is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_BLUETOOTH_TTY is not set
+# CONFIG_USB_MIDI is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_STORAGE is not set
+
+#
+# USB Human Interface Devices (HID)
+#
+# CONFIG_USB_HID 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_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+
+#
+# USB Network adaptors
+#
+# 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
+
+#
+# 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_TIGL 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_PHIDGETSERVO is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Synchronous Serial Interfaces (SSI)
+#
+CONFIG_OMAP_UWIRE=y
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_POINTER=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_SCHEDSTATS=y
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch b/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch
index e69de29bb2..f5823a9943 100644
--- a/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch
+++ b/linux/linux-omap-2.6-2.6.9-omap1/schedstats-arm.patch
@@ -0,0 +1,26 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.6.9-rc4/arch/arm/Kconfig.debug~schedstats-arm
++++ linux-2.6.9-rc4/arch/arm/Kconfig.debug
+@@ -57,6 +57,18 @@
+ 	  time and disk space needed for compilation of the kernel. If in
+ 	  doubt say N.
+ 
++config SCHEDSTATS
++	bool "Collect scheduler statistics"
++	depends on DEBUG_KERNEL && PROC_FS
++	help
++	  If you say Y here, additional code will be inserted into the
++	  scheduler and related routines to collect statistics about
++	  scheduler behavior and provide them in /proc/schedstat.  These
++	  stats may be useful for both tuning and debugging the scheduler
++	  If you aren't debugging the scheduler or trying to tune a specific
++	  application, you can say N to avoid the very slight overhead
++	  this adds.
++
+ # These options are only for real kernel hackers who want to get their hands dirty.
+ config DEBUG_LL
+ 	bool "Kernel low-level debugging functions"
diff --git a/linux/linux-sun4cdm-2.4.26/defconfig b/linux/linux-sun4cdm-2.4.26/defconfig
index e69de29bb2..8704f6307e 100644
--- a/linux/linux-sun4cdm-2.4.26/defconfig
+++ b/linux/linux-sun4cdm-2.4.26/defconfig
@@ -0,0 +1,473 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_UID16=y
+CONFIG_HIGHMEM=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SMP is not set
+CONFIG_SPARC32=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_MCA is not set
+# CONFIG_PCMCIA is not set
+CONFIG_SBUS=y
+CONFIG_SBUSCHAR=y
+CONFIG_BUSMOUSE=y
+CONFIG_SUN_MOUSE=y
+CONFIG_SERIAL=y
+CONFIG_SUN_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SUN_KEYBOARD=y
+CONFIG_SUN_CONSOLE=y
+CONFIG_SUN_AUXIO=y
+CONFIG_SUN_IO=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_SUN_PM=y
+# CONFIG_SUN4 is not set
+CONFIG_PCI=y
+# CONFIG_PCI_NAMES is not set
+CONFIG_SUN_OPENPROMFS=m
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_SUNOS_EMUL=y
+# CONFIG_OOM_KILLER is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+# CONFIG_PRINTER is not set
+
+#
+# Console drivers
+#
+# CONFIG_PROM_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_INTEL is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+CONFIG_FB_SBUS=y
+# CONFIG_FB_CGSIX is not set
+CONFIG_FB_BWTWO=y
+CONFIG_FB_CGTHREE=y
+# CONFIG_FB_TCX is not set
+# CONFIG_FB_CGFOURTEEN is not set
+# CONFIG_FB_P9100 is not set
+# CONFIG_FB_LEO is not set
+# CONFIG_FB_PCI is not set
+# CONFIG_FB_IT8181 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_MFB=y
+CONFIG_FBCON_CFB8=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FONT_SUN8x16=y
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FBCON_FONTS is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Misc Linux/SPARC drivers
+#
+CONFIG_SUN_OPENPROMIO=m
+CONFIG_SUN_MOSTEK_RTC=m
+# CONFIG_SUN_BPP is not set
+# CONFIG_SUN_VIDEOPIX is not set
+# CONFIG_SUN_AURORA is not set
+# CONFIG_TADPOLE_TS102_UCTRL is not set
+# CONFIG_SUN_JSFLASH is not set
+CONFIG_APM_RTC_IS_GMT=y
+CONFIG_RTC=y
+
+#
+# Linux/SPARC audio subsystem (EXPERIMENTAL)
+#
+# CONFIG_SPARCAUDIO is not set
+# CONFIG_SPARCAUDIO_AMD7930 is not set
+# CONFIG_SPARCAUDIO_DBRI is not set
+# CONFIG_SPARCAUDIO_CS4231 is not set
+# CONFIG_SPARCAUDIO_DUMMY is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_IPV6=y
+# CONFIG_KHTTPD is not set
+
+#
+#    SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+CONFIG_SCTP_DBG_OBJCNT=y
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_SCSI_SUNESP=y
+CONFIG_SCSI_QLOGICPTI=m
+
+#
+# Fibre Channel support
+#
+# CONFIG_FC4 is not set
+# CONFIG_FC4_SOC is not set
+# CONFIG_FC4_SOCAL is not set
+# CONFIG_SCSI_PLUTO is not set
+# CONFIG_SCSI_FCAL is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+CONFIG_TUN=m
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+CONFIG_SUNLANCE=y
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNBMAC=m
+CONFIG_SUNQE=m
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_VORTEX is not set
+
+#
+# Unix98 PTY support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_TMPFS is not set
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=m
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_RT=y
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SUN_PARTITION=y
+# CONFIG_SMB_NLS is not set
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Watchdog
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_IOVIRT is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_LOG_BUF_SHIFT=14
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig b/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig
index e69de29bb2..49b84791ae 100644
--- a/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig
+++ b/linux/linux-sun4cdm-2.6.8.1/sun4c_defconfig
@@ -0,0 +1,689 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_HIGHMEM=y
+CONFIG_GENERIC_ISA_DMA=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_HOTPLUG is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_EMBEDDED is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# General setup
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_SPARC32=y
+CONFIG_SBUS=y
+CONFIG_SBUSCHAR=y
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SUN_AUXIO=y
+CONFIG_SUN_IO=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_SUN_PM=y
+# CONFIG_SUN4 is not set
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+CONFIG_SUN_OPENPROMFS=m
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_MISC=m
+CONFIG_SUNOS_EMUL=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+CONFIG_FB_BW2=y
+CONFIG_FB_CG3=y
+CONFIG_FB_CG6=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON_OLD is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+CONFIG_FB_SBUS=y
+# CONFIG_FB_TCX is not set
+# CONFIG_FB_CG14 is not set
+# CONFIG_FB_P9100 is not set
+# CONFIG_FB_LEO is not set
+# CONFIG_FB_PCI is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_MDA_CONSOLE is not set
+# CONFIG_PROM_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FONTS is not set
+CONFIG_FONT_SUN8x16=y
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SUNCORE=y
+CONFIG_SERIAL_SUNZILOG=y
+CONFIG_SERIAL_SUNZILOG_CONSOLE=y
+CONFIG_SERIAL_SUNSU=y
+CONFIG_SERIAL_SUNSU_CONSOLE=y
+# CONFIG_SERIAL_SUNSAB is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+
+#
+# Misc Linux/SPARC drivers
+#
+CONFIG_SUN_OPENPROMIO=m
+CONFIG_SUN_MOSTEK_RTC=m
+# CONFIG_SUN_BPP is not set
+# CONFIG_SUN_VIDEOPIX is not set
+# CONFIG_TADPOLE_TS102_UCTRL is not set
+# CONFIG_SUN_JSFLASH is not set
+CONFIG_APM_RTC_IS_GMT=y
+CONFIG_RTC=m
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# 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_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# SCSI device support
+#
+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=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+
+#
+# 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=m
+# CONFIG_SCSI_FC_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# 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_SCSI_MEGARAID is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS 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_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+CONFIG_SCSI_QLOGICPTI=m
+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_QLA6322 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
+CONFIG_SCSI_SUNESP=y
+
+#
+# Fibre Channel support
+#
+# CONFIG_FC4 is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_NETLINK_DEV=y
+CONFIG_UNIX=y
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_NETFILTER is not set
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+CONFIG_SCTP_DBG_OBJCNT=y
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# 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_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+CONFIG_SUNLANCE=y
+CONFIG_HAPPYMEAL=m
+CONFIG_SUNBMAC=m
+CONFIG_SUNQE=m
+# CONFIG_SUNGEM 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_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# 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
+
+#
+# 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
+
+#
+# Unix98 PTY support
+#
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_JOYDEV=m
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=m
+CONFIG_INPUT_EVBUG=m
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=m
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PCIPS2 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=m
+CONFIG_KEYBOARD_SUNKBD=m
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=m
+CONFIG_MOUSE_SERIAL=m
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_RT=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=m
+# CONFIG_QUOTA is not set
+CONFIG_QUOTACTL=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS 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_DEVFS_FS is not set
+CONFIG_DEVPTS_FS_XATTR=y
+# CONFIG_DEVPTS_FS_SECURITY is not set
+# CONFIG_TMPFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# 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_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_EXPORTFS is not set
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_POSIX is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SUN_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_KHAZAD is not set
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/linux-xxs1500-2.4.21/Makefile b/linux/linux-xxs1500-2.4.21/Makefile
index e69de29bb2..7ef3faa145 100644
--- a/linux/linux-xxs1500-2.4.21/Makefile
+++ b/linux/linux-xxs1500-2.4.21/Makefile
@@ -0,0 +1,756 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License.  See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994, 1995, 1996 by Ralf Baechle
+# DECStation modifications by Paul M. Antoine, 1996
+# Copyright (C) 2002, 2003  Maciej W. Rozycki
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+#
+
+#
+# Select the object file format to substitute into the linker script.
+#
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+tool-prefix	= mipsel-linux-
+ld-emul		= elf32ltsmip
+else
+tool-prefix	= mips-linux-
+ld-emul		= elf32btsmip
+endif
+
+ifdef CONFIG_CROSSCOMPILE
+CROSS_COMPILE	= $(tool-prefix)
+endif
+
+check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+
+#
+#
+# GCC uses -G 0 -mabicalls -fpic as default.  We don't want PIC in the kernel
+# code since it only slows down the whole thing.  At some point we might make
+# use of global pointer optimizations but their use of $28 conflicts with
+# the current pointer optimization.
+#
+# The DECStation requires an ECOFF kernel for remote booting, other MIPS
+# machines may also.  Since BFD is incredibly buggy with respect to
+# crossformat linking we rely on the elf2ecoff tool for format conversion.
+#
+GCCFLAGS	:= -I $(TOPDIR)/include/asm/gcc
+GCCFLAGS	+= -G 0 -mno-abicalls -fno-pic -pipe
+GCCFLAGS	+= $(call check_gcc, -finline-limit=100000,)
+LINKFLAGS	+= -G 0 -static # -N
+MODFLAGS	+= -mlong-calls
+
+ifdef CONFIG_DEBUG_INFO
+GCCFLAGS	+= -g
+ifdef CONFIG_SB1XXX_CORELIS
+GCCFLAGS	+= -mno-sched-prolog -fno-omit-frame-pointer
+endif
+endif
+
+#
+# Use: $(call set_gccflags,<cpu0>,<isa0>,<cpu1>,<isa1>,<isa2>)
+#
+# <cpu0>,<isa0> -- preferred CPU and ISA designations (may require
+#                  recent tools)
+# <cpu1>,<isa1> -- fallback CPU and ISA designations (have to work
+#                  with up to the oldest supported tools)
+# <isa2>        -- an ISA designation used as an ABI selector for
+#                  gcc versions that do not support "-mabi=32"
+#                  (depending on the CPU type, either "mips1" or
+#                  "mips2")
+#
+set_gccflags = $(shell \
+while :; do \
+	cpu=$(1); isa=-$(2); \
+	for gcc_opt in -march= -mcpu=; do \
+		$(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
+			-xc /dev/null > /dev/null 2>&1 && \
+			break 2; \
+	done; \
+	cpu=$(3); isa=-$(4); \
+	for gcc_opt in -march= -mcpu=; do \
+		$(CC) $$gcc_opt$$cpu $$isa -S -o /dev/null \
+			-xc /dev/null > /dev/null 2>&1 && \
+			break 2; \
+	done; \
+	break; \
+done; \
+gcc_abi=-mabi=32; gcc_cpu=$$cpu; \
+if $(CC) $$gcc_abi -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then \
+	gcc_isa=$$isa; \
+else \
+	gcc_abi=; gcc_isa=-$(5); \
+fi; \
+gas_abi=-Wa,-32; gas_cpu=$$cpu; gas_isa=-Wa,$$isa; \
+while :; do \
+	for gas_opt in -Wa,-march= -Wa,-mcpu=; do \
+		$(CC) $$gas_abi $$gas_opt$$cpu $$gas_isa -Wa,-Z -c \
+			-o /dev/null -xassembler /dev/null > /dev/null 2>&1 && \
+			break 2; \
+	done; \
+	gas_abi=; gas_opt=; gas_cpu=; gas_isa=; \
+	break; \
+done; \
+echo $$gcc_abi $$gcc_opt$$gcc_cpu $$gcc_isa $$gas_abi $$gas_opt$$gas_cpu $$gas_isa)
+
+#
+# CPU-dependent compiler/assembler options for optimization.
+#
+ifdef CONFIG_CPU_R3000
+GCCFLAGS	+= $(call set_gccflags,r3000,mips1,r3000,mips1,mips1)
+endif
+ifdef CONFIG_CPU_TX39XX
+GCCFLAGS	+= $(call set_gccflags,r3900,mips1,r3000,mips1,mips1)
+endif
+ifdef CONFIG_CPU_R6000
+GCCFLAGS	+= $(call set_gccflags,r6000,mips2,r6000,mips2,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_R4300
+GCCFLAGS	+= $(call set_gccflags,r4300,mips3,r4300,mips3,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_VR41XX
+GCCFLAGS	+= $(call set_gccflags,r4100,mips3,r4600,mips3,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_R4X00
+GCCFLAGS	+= $(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_TX49XX
+GCCFLAGS	+= $(call set_gccflags,r4600,mips3,r4600,mips3,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_MIPS32
+GCCFLAGS	+= $(call set_gccflags,mips32,mips32,r4600,mips3,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_MIPS64
+GCCFLAGS	+= $(call set_gccflags,mips64,mips64,r4600,mips3,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_R5000
+GCCFLAGS	+= $(call set_gccflags,r5000,mips4,r5000,mips4,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_R5432
+GCCFLAGS	+= $(call set_gccflags,r5400,mips4,r5000,mips4,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_NEVADA
+GCCFLAGS	+= $(call set_gccflags,rm5200,mips4,r5000,mips4,mips2) \
+		   -Wa,--trap
+#GCCFLAGS	+= $(call check_gcc,-mmad,)
+endif
+ifdef CONFIG_CPU_RM7000
+GCCFLAGS	+= $(call set_gccflags,rm7000,mips4,r5000,mips4,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_RM9000
+GCCFLAGS	+= $(call set_gccflags,rm9000,mips4,r5000,mips4,mips2) \
+		   -Wa,--trap
+endif
+ifdef CONFIG_CPU_SB1
+GCCFLAGS	+= $(call set_gccflags,sb1,mips64,r5000,mips4,mips2) \
+		   -Wa,--trap
+ifdef CONFIG_SB1_PASS_1_WORKAROUNDS
+MODFLAGS	+= -msb1-pass1-workarounds
+endif
+endif
+
+AFLAGS		+= $(GCCFLAGS)
+CFLAGS		+= $(GCCFLAGS)
+LDFLAGS		+= -m $(ld-emul)
+
+
+#
+# We unconditionally build the math emulator
+#
+CORE_FILES	+= arch/mips/math-emu/fpu_emulator.o
+SUBDIRS		+= arch/mips/math-emu
+
+#
+# ramdisk/initrd support
+# You need a compressed ramdisk image, named ramdisk.gz in
+# arch/mips/ramdisk
+#
+ifdef CONFIG_EMBEDDED_RAMDISK
+CORE_FILES	+= arch/mips/ramdisk/ramdisk.o
+SUBDIRS		+= arch/mips/ramdisk
+endif
+
+
+#
+# Board-dependent options and extra files
+#
+
+#
+# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
+#
+ifdef CONFIG_MIPS_JAZZ
+CORE_FILES	+= arch/mips/jazz/jazz.o
+SUBDIRS		+= arch/mips/jazz arch/mips/arc
+LIBS		+= arch/mips/arc/arclib.a
+LOADADDR	:= 0x80080000
+endif
+
+#
+# Au1000 (Alchemy Semi PB1000) eval board
+#
+ifdef CONFIG_MIPS_PB1000
+LIBS		+= arch/mips/au1000/pb1000/pb1000.o \
+		   arch/mips/au1000/common/au1000.o
+SUBDIRS		+= arch/mips/au1000/pb1000 arch/mips/au1000/common
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Au1100 (Alchemy Semi PB1100) eval board
+#
+ifdef CONFIG_MIPS_PB1100
+LIBS          += arch/mips/au1000/pb1100/pb1100.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/pb1100 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+#
+# Au1500 (Alchemy Semi PB1500) eval board
+#
+ifdef CONFIG_MIPS_PB1500
+LIBS		+= arch/mips/au1000/pb1500/pb1500.o \
+		   arch/mips/au1000/common/au1000.o
+SUBDIRS		+= arch/mips/au1000/pb1500 arch/mips/au1000/common
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Au1x00 (AMD/Alchemy) eval boards
+#
+ifdef CONFIG_MIPS_DB1000
+LIBS          += arch/mips/au1000/db1x00/db1x00.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/db1x00 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_DB1500
+LIBS          += arch/mips/au1000/db1x00/db1x00.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/db1x00 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_DB1100
+LIBS          += arch/mips/au1000/db1x00/db1x00.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/db1x00 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_HYDROGEN3
+LIBS          += arch/mips/au1000/hydrogen3/hydrogen3.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/hydrogen3 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_BOSPORUS
+LIBS          += arch/mips/au1000/db1x00/db1x00.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/db1x00 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_MIRAGE
+LIBS          += arch/mips/au1000/db1x00/db1x00.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/db1x00 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_XXS1500
+LIBS          += arch/mips/au1000/xxs1500/xxs1500.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/xxs1500 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_MTX1
+LIBS          += arch/mips/au1000/mtx-1/mtx-1.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/mtx-1 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+ifdef CONFIG_MIPS_PB1550
+LIBS          += arch/mips/au1000/pb1550/pb1550.o \
+                 arch/mips/au1000/common/au1000.o
+SUBDIRS       += arch/mips/au1000/pb1550 arch/mips/au1000/common
+LOADADDR      += 0x80100000
+endif
+
+
+#
+# Cogent CSB250
+#
+ifdef CONFIG_COGENT_CSB250
+LIBS		+= arch/mips/au1000/csb250/csb250.o \
+		   arch/mips/au1000/common/au1000.o
+SUBDIRS		+= arch/mips/au1000/csb250 arch/mips/au1000/common
+LOADADDR	:= 0x80100000
+endif
+
+ifdef CONFIG_PCI
+CORE_FILES    += arch/mips/pci/pci-core.o
+SUBDIRS       += arch/mips/pci
+endif
+
+#
+# Algorithmics P4032
+#
+ifdef CONFIG_ALGOR_P4032
+CORE_FILES	+= arch/mips/algor/algor.o
+SUBDIRS		+= arch/mips/algor
+LOADADDR	:= 0x80000000
+endif
+
+#
+# Baget/MIPS
+#
+ifdef CONFIG_BAGET_MIPS
+SUBDIRS		+= arch/mips/baget arch/mips/baget/prom
+LIBS		+= arch/mips/baget/baget.a arch/mips/baget/prom/bagetlib.a
+LOADADDR	:= 0x80001000
+endif
+
+#
+# Cobalt Server
+#
+ifdef CONFIG_MIPS_COBALT
+SUBDIRS		+= arch/mips/cobalt
+CORE_FILES	+= arch/mips/cobalt/cobalt.o
+LOADADDR	:= 0x80080000
+endif
+
+#
+# DECstation family
+#
+ifdef CONFIG_DECSTATION
+CORE_FILES	+= arch/mips/dec/dec.o
+SUBDIRS		+= arch/mips/dec arch/mips/dec/prom
+LIBS		+= arch/mips/dec/prom/rexlib.a
+LOADADDR	:= 0x80040000
+endif
+
+#
+# Galileo EV64120 Board
+#
+ifdef CONFIG_MIPS_EV64120
+LIBS		+= arch/mips/gt64120/common/gt64120.o \
+		   arch/mips/gt64120/ev64120/ev64120.o
+SUBDIRS		+= arch/mips/gt64120/common arch/mips/gt64120/ev64120
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Galileo EV96100 Board
+#
+ifdef CONFIG_MIPS_EV96100
+LIBS		+= arch/mips/galileo-boards/ev96100/ev96100.o
+SUBDIRS		+= arch/mips/galileo-boards/ev96100
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Globespan IVR eval board with QED 5231 CPU
+#
+ifdef CONFIG_MIPS_IVR
+LIBS		+= arch/mips/ite-boards/ivr/ivr.o \
+		   arch/mips/ite-boards/generic/it8172.o
+SUBDIRS		+= arch/mips/ite-boards/generic arch/mips/ite-boards/ivr
+LOADADDR	:= 0x80100000
+endif
+
+#
+# HP LaserJet
+#
+ifdef CONFIG_HP_LASERJET
+SUBDIRS		+= arch/mips/hp-lj
+LIBS		+= arch/mips/hp-lj/hp-lj.o
+LOADADDR	:= 0x80030000
+endif
+
+#
+# ITE 8172 eval board with QED 5231 CPU
+#
+ifdef CONFIG_MIPS_ITE8172
+LIBS		+= arch/mips/ite-boards/qed-4n-s01b/ite.o \
+		   arch/mips/ite-boards/generic/it8172.o
+SUBDIRS		+= arch/mips/ite-boards/generic arch/mips/ite-boards/qed-4n-s01b
+LOADADDR	:= 0x80100000
+endif
+
+#
+# MIPS Atlas board
+#
+ifdef CONFIG_MIPS_ATLAS
+LIBS		+= arch/mips/mips-boards/atlas/atlas.o \
+		   arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS		+= arch/mips/mips-boards/generic arch/mips/mips-boards/atlas
+LOADADDR	:= 0x80100000
+endif
+
+#
+# MIPS Malta board
+#
+ifdef CONFIG_MIPS_MALTA
+LIBS		+= arch/mips/mips-boards/malta/malta.o \
+		   arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS		+= arch/mips/mips-boards/malta arch/mips/mips-boards/generic
+LOADADDR	:= 0x80100000
+endif
+
+#
+# MIPS SEAD board
+#
+ifdef CONFIG_MIPS_SEAD
+LIBS		+= arch/mips/mips-boards/sead/sead.o \
+		   arch/mips/mips-boards/generic/mipsboards.o
+SUBDIRS		+= arch/mips/mips-boards/generic arch/mips/mips-boards/sead
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Momentum Ocelot board
+#
+ifdef CONFIG_MOMENCO_OCELOT
+# The Ocelot setup.o must be linked early - it does the ioremap() for the
+# mips_io_port_base.
+CORE_FILES	+= arch/mips/gt64120/common/gt64120.o \
+		   arch/mips/gt64120/momenco_ocelot/momenco_ocelot.o
+SUBDIRS		+= arch/mips/gt64120/common arch/mips/gt64120/momenco_ocelot
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Momentum Ocelot-G board
+#
+ifdef CONFIG_MOMENCO_OCELOT_G
+# The Ocelot-G setup.o must be linked early - it does the ioremap() for the
+# mips_io_port_base.
+CORE_FILES	+= arch/mips/momentum/ocelot_g/ocelot_g.o
+SUBDIRS		+= arch/mips/momentum/ocelot_g
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Momentum Ocelot-C and -CS boards
+#
+ifdef CONFIG_MOMENCO_OCELOT_C
+# The Ocelot-C[S] setup.o must be linked early - it does the ioremap() for the
+# mips_io_port_base.
+CORE_FILES	+= arch/mips/momentum/ocelot_c/ocelot_c.o
+SUBDIRS		+= arch/mips/momentum/ocelot_c
+LOADADDR	:= 0x80100000
+endif
+
+ifdef CONFIG_MOMENCO_JAGUAR_ATX
+LIBS		+= arch/mips/momentum/jaguar_atx/jaguar_atx.o
+SUBDIRS		+= arch/mips/momentum/jaguar_atx
+ifdef CONFIG_JAGUAR_DMALOW
+LOADADDR	:= 0x88000000
+else
+LOADADDR	:= 0x80100000
+endif
+endif
+
+#
+# NEC DDB Vrc-5074
+#
+ifdef CONFIG_DDB5074
+SUBDIRS		+= arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5074
+LIBS		+= arch/mips/ddb5xxx/common/ddb5xxx.o arch/mips/ddb5xxx/ddb5074/ddb5074.o
+LOADADDR	:= 0x80080000
+endif
+
+#
+# NEC DDB Vrc-5476
+#
+ifdef CONFIG_DDB5476
+SUBDIRS		+= arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5476
+LIBS		+= arch/mips/ddb5xxx/common/ddb5xxx.o \
+		   arch/mips/ddb5xxx/ddb5476/ddb5476.o
+LOADADDR	:= 0x80080000
+endif
+
+#
+# NEC DDB Vrc-5477
+#
+ifdef CONFIG_DDB5477
+SUBDIRS		+= arch/mips/ddb5xxx/common arch/mips/ddb5xxx/ddb5477
+LIBS		+= arch/mips/ddb5xxx/common/ddb5xxx.o \
+		   arch/mips/ddb5xxx/ddb5477/ddb5477.o
+LOADADDR	:= 0x80100000
+endif
+
+ifdef CONFIG_LASAT
+LIBS          += arch/mips/lasat/lasatkern.o
+SUBDIRS       += arch/mips/lasat
+LOADADDR      += 0x80000000
+endif
+#
+# NEC Osprey (vr4181) board
+#
+ifdef CONFIG_NEC_OSPREY
+SUBDIRS		+= arch/mips/vr4181/common arch/mips/vr4181/osprey
+LIBS		+= arch/mips/vr4181/common/vr4181.o \
+		   arch/mips/vr4181/osprey/osprey.o
+LOADADDR	:= 0x80002000
+endif
+
+#
+# NEC Eagle/Hawk (VR4122/VR4131) board
+#
+ifdef CONFIG_NEC_EAGLE
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/nec-eagle
+CORE_FILES	+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/nec-eagle/eagle.o
+LOADADDR	:= 0x80000000
+endif
+
+#
+# ZAO Networks Capcella (VR4131)
+#
+ifdef CONFIG_ZAO_CAPCELLA
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/zao-capcella
+CORE_FILES	+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/zao-capcella/capcella.o
+LOADADDR	:= 0x80000000
+endif
+
+#
+# Victor MP-C303/304 (VR4122)
+#
+ifdef CONFIG_VICTOR_MPC30X
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/victor-mpc30x
+CORE_FILES	+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/victor-mpc30x/mpc30x.o
+LOADADDR	:= 0x80001000
+endif
+
+#
+# IBM WorkPad z50 (VR4121)
+#
+ifdef CONFIG_IBM_WORKPAD
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/ibm-workpad
+CORE_FILES	+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/ibm-workpad/workpad.o
+LOADADDR	+= 0x80004000
+endif
+
+#
+# CASIO CASSIPEIA E-55/65 (VR4111)
+#
+ifdef CONFIG_CASIO_E55
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/casio-e55
+CORE_FILES	+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/casio-e55/e55.o
+LOADADDR	+= 0x80004000
+endif
+
+#
+# TANBAC TB0226 Mbase (VR4131)
+#
+ifdef CONFIG_TANBAC_TB0226
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/tanbac-tb0226
+CORE_FILES	+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/tanbac-tb0226/tb0226.o
+LOADADDR	:= 0x80000000
+endif
+
+#
+# TANBAC TB0229 (VR4131DIMM)
+#
+ifdef CONFIG_TANBAC_TB0229
+SUBDIRS		+= arch/mips/vr41xx/common \
+		   arch/mips/vr41xx/tanbac-tb0229
+CORE_FILES	+= arch/mips/vr41xx/common/vr41xx.o \
+		   arch/mips/vr41xx/tanbac-tb0229/tb0229.o
+LOADADDR	:= 0x80000000
+endif
+
+#
+# Philips Nino
+#
+ifdef CONFIG_NINO
+CORE_FILES	+= arch/mips/philips/nino/nino.o
+SUBDIRS		+= arch/mips/philips/nino
+LOADADDR	:= 0x80000000
+endif
+
+#
+# SGI IP22 (Indy/Indigo2)
+#
+ifdef CONFIG_SGI_IP22
+CORE_FILES	+= arch/mips/sgi-ip22/ip22-kern.o
+LIBS		+= arch/mips/arc/arclib.a
+SUBDIRS		+= arch/mips/sgi-ip22 arch/mips/arc
+#
+# Set LOADADDR to >= 0x88069000 if you want to leave space for symmon,
+# 0x88002000 for production kernels.  Note that the value must be
+# 8kb aligned or the handling of the current variable will break.
+#
+LOADADDR	:= 0x88002000
+endif
+
+#
+# Sibyte SB1250 SOC and Broadcom (SiByte) BCM112x SOCs
+#
+ifneq ($(CONFIG_SIBYTE_SB1250)$(CONFIG_SIBYTE_BCM112X),)
+# This is a LIB so that it links at the end, and initcalls are later
+# the sequence; but it is built as an object so that modules don't get
+# removed (as happens, even if they have __initcall/module_init)
+LIBS		+= arch/mips/sibyte/sb1250/sb1250.o
+SUBDIRS		+= arch/mips/sibyte/sb1250
+LOADADDR	:= 0x80100000
+endif
+
+#
+# Sibyte boards:
+#
+# BCM91250A (SWARM),
+# BCM91250E (Sentosa),
+# BCM91120C (CRhine),
+# BCM91120x (Carmel),
+# BCM91125C (CRhone),
+# BCM91125E (Rhone).
+#
+ifdef CONFIG_SIBYTE_BOARD
+LIBS		+= arch/mips/sibyte/swarm/sbswarm.a
+SUBDIRS		+= arch/mips/sibyte/swarm
+endif
+
+#
+# Sibyte CFE firmware
+#
+ifdef CONFIG_SIBYTE_CFE
+LIBS		+= arch/mips/sibyte/cfe/cfe.a
+SUBDIRS		+= arch/mips/sibyte/cfe
+endif
+
+#
+# SNI RM200 PCI
+#
+ifdef CONFIG_SNI_RM200_PCI
+CORE_FILES	+= arch/mips/sni/sni.o
+SUBDIRS		+= arch/mips/sni arch/mips/arc
+LIBS		+= arch/mips/arc/arclib.a
+LOADADDR	:= 0x80080000
+endif
+
+#
+# Toshiba JMR-TX3927 board
+#
+ifdef CONFIG_TOSHIBA_JMR3927
+CORE_FILES	+= arch/mips/jmr3927/rbhma3100/jmr3927.o \
+		   arch/mips/jmr3927/common/tx3927.o
+SUBDIRS		+= arch/mips/jmr3927/rbhma3100 arch/mips/jmr3927/common
+LOADADDR	:= 0x80050000
+endif
+
+#
+# Toshiba RBTX4927 board or
+# Toshiba RBTX4937 board
+#
+ifdef CONFIG_TOSHIBA_RBTX4927
+MIPS           = arch/mips
+CEC            = tx4927
+COMMON         = $(MIPS)/$(CEC)/common
+BOARD          = $(MIPS)/$(CEC)/toshiba_rbtx4927
+LIBS          += $(BOARD)/toshiba_rbtx4927.o $(COMMON)/tx4927.o
+SUBDIRS       += $(BOARD)                    $(COMMON)
+LOADADDR      += 0x80020000
+endif
+
+#
+# Choosing incompatible machines durings configuration will result in
+# error messages during linking.  Select a default linkscript if
+# none has been choosen above.
+#
+vmlinux: arch/$(ARCH)/ld.script
+
+arch/$(ARCH)/ld.script: arch/$(ARCH)/ld.script.in arch/$(ARCH)/Makefile
+	sed -e 's/@@LOADADDR@@/$(LOADADDR)/' <$< >$@
+LINKFLAGS	+= -T arch/$(ARCH)/ld.script
+
+HEAD := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
+
+SUBDIRS := $(addprefix arch/mips/, tools) $(SUBDIRS) $(addprefix arch/mips/, kernel mm lib)
+CORE_FILES := arch/mips/kernel/kernel.o arch/mips/mm/mm.o $(CORE_FILES)
+LIBS := arch/mips/lib/lib.a $(LIBS)
+
+ifdef CONFIG_BAGET_MIPS
+
+BAGETBOOT = $(MAKE) -C arch/$(ARCH)/baget
+
+balo: vmlinux
+	$(BAGETBOOT) balo
+
+endif
+
+ifdef CONFIG_MIPS_EV64120
+gboot: vmlinux
+	$(MAKE) -C arch/$(ARCH)/galileo-boards/ev64120/compressed
+endif
+
+ifdef CONFIG_LASAT
+rom.bin rom.sw: vmlinux
+	$(MAKE) -C arch/$(ARCH)/lasat/image $@
+endif
+
+MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
+MAKEZBOOT = $(MAKE) -C arch/$(ARCH)/zboot
+BOOT_TARGETS = zImage zImage.initrd zImage.flash zImage.flash.bin
+
+vmlinux.ecoff: vmlinux
+	@$(MAKEBOOT) $@
+
+ $(BOOT_TARGETS): vmlinux
+	@$(MAKEZBOOT) $@
+
+vmlinux.srec: vmlinux
+	@$(MAKEBOOT) $@
+
+archclean:
+	@$(MAKEBOOT) clean
+	@$(MAKEZBOOT) clean
+	rm -f arch/$(ARCH)/ld.script
+	$(MAKE) -C arch/$(ARCH)/tools clean
+	$(MAKE) -C arch/mips/baget clean
+	$(MAKE) -C arch/mips/lasat clean
+
+archmrproper:
+	@$(MAKEBOOT) mrproper
+	$(RM) $(TOPDIR)/include/asm-$(ARCH)/offset.h
+	$(MAKE) -C arch/$(ARCH)/tools mrproper
+
+archdep:
+	if [ ! -f $(TOPDIR)/include/asm-$(ARCH)/offset.h ]; then \
+		touch $(TOPDIR)/include/asm-$(ARCH)/offset.h; \
+	fi;
+	@$(MAKEBOOT) dep
diff --git a/linux/linux-xxs1500-2.4.21/defconfig-xxs1500 b/linux/linux-xxs1500-2.4.21/defconfig-xxs1500
index e69de29bb2..0fc84863ca 100644
--- a/linux/linux-xxs1500-2.4.21/defconfig-xxs1500
+++ b/linux/linux-xxs1500-2.4.21/defconfig-xxs1500
@@ -0,0 +1,1199 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_MIPS=y
+CONFIG_MIPS32=y
+# CONFIG_MIPS64 is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# Machine selection
+#
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+CONFIG_MIPS_XXS1500=y
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_BAGET_MIPS is not set
+# CONFIG_CASIO_E55 is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+# CONFIG_MIPS_EV96100 is not set
+# CONFIG_MIPS_IVR is not set
+# CONFIG_HP_LASERJET is not set
+# CONFIG_IBM_WORKPAD is not set
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ITE8172 is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_DDB5074 is not set
+# CONFIG_DDB5476 is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_NEC_OSPREY is not set
+# CONFIG_NEC_EAGLE is not set
+# CONFIG_OLIVETTI_M700 is not set
+# CONFIG_NINO is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SIBYTE_SB1xxx_SOC is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TANBAC_TB0226 is not set
+# CONFIG_TANBAC_TB0229 is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_VICTOR_MPC30X is not set
+# CONFIG_ZAO_CAPCELLA is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+CONFIG_SOC_AU1X00=y
+CONFIG_SOC_AU1500=y
+CONFIG_PCI=y
+CONFIG_NEW_PCI=y
+CONFIG_PCI_AUTO=y
+CONFIG_NONCOHERENT_IO=y
+CONFIG_PC_KEYB=y
+# CONFIG_MIPS_AU1000 is not set
+
+#
+# CPU selection
+#
+CONFIG_CPU_MIPS32=y
+# CONFIG_CPU_MIPS64 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+# CONFIG_CPU_R4X00 is not set
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_CPU_HAS_PREFETCH=y
+# CONFIG_VTAG_ICACHE is not set
+CONFIG_64BIT_PHYS_ADDR=y
+# CONFIG_CPU_ADVANCED is not set
+CONFIG_CPU_HAS_LLSC=y
+# CONFIG_CPU_HAS_LLDSCD is not set
+# CONFIG_CPU_HAS_WB is not set
+CONFIG_CPU_HAS_SYNC=y
+
+#
+# General setup
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_NET=y
+CONFIG_PCI_NAMES=y
+# CONFIG_ISA is not set
+# CONFIG_EISA is not set
+# CONFIG_TC is not set
+# CONFIG_MCA is not set
+# CONFIG_SBUS is not set
+CONFIG_HOTPLUG=y
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=m
+# CONFIG_CARDBUS is not set
+# CONFIG_TCIC is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+CONFIG_PCMCIA_AU1X00=m
+# CONFIG_PCMCIA_PB1X00 is not set
+# CONFIG_PCMCIA_DB1X00 is not set
+CONFIG_PCMCIA_XXS1500=y
+# CONFIG_PCMCIA_VRC4173 is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ is not set
+# CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM is not set
+# CONFIG_HOTPLUG_PCI_ACPI is not set
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+# CONFIG_BINFMT_AOUT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_MIPS32_COMPAT is not set
+# CONFIG_MIPS32_O32 is not set
+# CONFIG_MIPS32_N32 is not set
+# CONFIG_BINFMT_ELF32 is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PB1000 is not set
+# CONFIG_MTD_PB1500 is not set
+# CONFIG_MTD_PB1100 is not set
+# CONFIG_MTD_BOSPORUS is not set
+CONFIG_MTD_XXS1500=y
+# CONFIG_MTD_MTX1 is not set
+# CONFIG_MTD_DB1X00 is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_OCELOT is not set
+# CONFIG_MTD_LASAT is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_PC_PCMCIA is not set
+# CONFIG_PARPORT_AMIGA is not set
+# CONFIG_PARPORT_MFC3 is not set
+# CONFIG_PARPORT_ATARI is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_SUNBPP is not set
+# CONFIG_PARPORT_IP22 is not set
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_FWMARK=y
+CONFIG_IP_ROUTE_NAT=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_TOS=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_LARGE_TABLES=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_INET_ECN=y
+CONFIG_SYN_COOKIES=y
+
+#
+#   IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_LIMIT=m
+CONFIG_IP_NF_MATCH_MAC=m
+CONFIG_IP_NF_MATCH_PKTTYPE=m
+CONFIG_IP_NF_MATCH_MARK=m
+CONFIG_IP_NF_MATCH_MULTIPORT=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_DSCP=m
+CONFIG_IP_NF_MATCH_AH_ESP=m
+CONFIG_IP_NF_MATCH_LENGTH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_TCPMSS=m
+CONFIG_IP_NF_MATCH_HELPER=m
+CONFIG_IP_NF_MATCH_STATE=m
+CONFIG_IP_NF_MATCH_CONNTRACK=m
+CONFIG_IP_NF_MATCH_UNCLEAN=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_MIRROR=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_NAT_AMANDA=m
+# CONFIG_IP_NF_NAT_LOCAL is not set
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_DSCP=m
+CONFIG_IP_NF_TARGET_MARK=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+CONFIG_IPV6=m
+
+#
+#   IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_LIMIT=m
+CONFIG_IP6_NF_MATCH_MAC=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_MULTIPORT=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_MARK=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AHESP=m
+CONFIG_IP6_NF_MATCH_LENGTH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_MARK=m
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+CONFIG_BRIDGE=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_POLICE=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+# CONFIG_PHONE_IXJ is not set
+# CONFIG_PHONE_IXJ_PCMCIA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+CONFIG_IDE=m
+
+#
+# IDE, ATA and ATAPI Block devices
+#
+CONFIG_BLK_DEV_IDE=m
+# CONFIG_BLK_DEV_HD_IDE is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_BLK_DEV_IDEDISK=m
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_IDEDISK_STROKE is not set
+CONFIG_BLK_DEV_IDECS=m
+# 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
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
+# CONFIG_BLK_DEV_ISAPNP is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+CONFIG_BLK_DEV_OFFBOARD=y
+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
+CONFIG_IDEDMA_PCI_AUTO=y
+# CONFIG_IDEDMA_ONLYDISK is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_PCI_WIP is not set
+# CONFIG_BLK_DEV_ADMA100 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_WDC_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_AMD74XX_OVERRIDE is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_HPT34X_AUTODMA is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_PDC202XX_BURST is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SIS5513 is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_CHIPSETS is not set
+CONFIG_IDEDMA_AUTO=y
+# CONFIG_IDEDMA_IVB is not set
+# CONFIG_DMA_NONPCI is not set
+CONFIG_BLK_DEV_IDE_MODES=y
+# CONFIG_BLK_DEV_ATARAID is not set
+# CONFIG_BLK_DEV_ATARAID_PDC is not set
+# CONFIG_BLK_DEV_ATARAID_HPT is not set
+# CONFIG_BLK_DEV_ATARAID_SII is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=m
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_SCSI_DEBUG_QUEUES is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+CONFIG_SCSI_PCMCIA=y
+CONFIG_PCMCIA_AHA152X=m
+CONFIG_PCMCIA_FDOMAIN=m
+CONFIG_PCMCIA_NINJA_SCSI=m
+# CONFIG_PCMCIA_QLOGIC is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MIPS_AU1X00_ENET=y
+CONFIG_BCM5222_DUAL_PHY=y
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPPOE=m
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_STRIP is not set
+# CONFIG_WAVELAN is not set
+# CONFIG_ARLAN is not set
+# CONFIG_AIRONET4500 is not set
+# CONFIG_AIRONET4500_NONCS is not set
+# CONFIG_AIRONET4500_PROC is not set
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+# CONFIG_PLX_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_PCMCIA_HERMES is not set
+CONFIG_AIRO_CS=m
+CONFIG_NET_WIRELESS=y
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+CONFIG_SHAPER=m
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# PCMCIA network device support
+#
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_AXNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+# CONFIG_ARCNET_COM20020_CS is not set
+# CONFIG_PCMCIA_IBMTR is not set
+CONFIG_NET_PCMCIA_RADIO=y
+# CONFIG_PCMCIA_RAYCS is not set
+# CONFIG_PCMCIA_NETWAVE is not set
+# CONFIG_PCMCIA_WAVELAN is not set
+# CONFIG_AIRONET4500_CS is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_DIGI is not set
+# CONFIG_ESPSERIAL is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+# CONFIG_SERIAL_TX3912 is not set
+# CONFIG_SERIAL_TX3912_CONSOLE is not set
+# CONFIG_SERIAL_TXX9 is not set
+# CONFIG_SERIAL_TXX9_CONSOLE is not set
+CONFIG_AU1X00_UART=y
+CONFIG_AU1X00_SERIAL_CONSOLE=y
+# CONFIG_AU1X00_USB_TTY is not set
+# CONFIG_AU1X00_USB_RAW is not set
+# CONFIG_TXX927_SERIAL is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_PRINTER is not set
+# CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_PHILIPSPAR is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_VELLEMAN is not set
+# CONFIG_SCx200_I2C is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_CHARDEV=m
+# CONFIG_I2C_PROC is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_PCMCIA_SERIAL_CS is not set
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_AU1X00_GPIO is not set
+# CONFIG_TS_AU1X00_ADS7846 is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=m
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=m
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=m
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=2
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=m
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_TCP is not set
+CONFIG_SUNRPC=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+CONFIG_ZISOFS_FS=m
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+CONFIG_VIDEO_PROC_FS=y
+# CONFIG_I2C_PARPORT is not set
+CONFIG_VIDEO_BT848=m
+# CONFIG_VIDEO_PMS is not set
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_W9966=m
+CONFIG_VIDEO_CPIA=m
+# CONFIG_VIDEO_CPIA_PP is not set
+CONFIG_VIDEO_CPIA_USB=m
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+# CONFIG_VIDEO_STRADIS is not set
+# CONFIG_VIDEO_ZORAN is not set
+# CONFIG_VIDEO_ZORAN_BUZ is not set
+# CONFIG_VIDEO_ZORAN_DC10 is not set
+# CONFIG_VIDEO_ZORAN_LML33 is not set
+# CONFIG_VIDEO_ZR36120 is not set
+# CONFIG_VIDEO_MEYE is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_MIROPCM20 is not set
+
+#
+# Console drivers
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_MDA_CONSOLE is not set
+
+#
+# Frame-buffer support
+#
+CONFIG_FB=y
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_CLGEN is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_INTEL is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_E1356 is not set
+CONFIG_FB_MB86290=y
+CONFIG_FB_LYNX3DM=y
+# CONFIG_FB_VIRTUAL is not set
+CONFIG_FBCON_ADVANCED=y
+# CONFIG_FBCON_MFB is not set
+# CONFIG_FBCON_CFB2 is not set
+# CONFIG_FBCON_CFB4 is not set
+# CONFIG_FBCON_CFB8 is not set
+CONFIG_FBCON_CFB16=y
+# CONFIG_FBCON_CFB24 is not set
+# CONFIG_FBCON_CFB32 is not set
+# CONFIG_FBCON_AFB is not set
+# CONFIG_FBCON_ILBM is not set
+# CONFIG_FBCON_IPLAN2P2 is not set
+# CONFIG_FBCON_IPLAN2P4 is not set
+# CONFIG_FBCON_IPLAN2P8 is not set
+# CONFIG_FBCON_MAC is not set
+# CONFIG_FBCON_VGA_PLANES is not set
+# CONFIG_FBCON_VGA is not set
+# CONFIG_FBCON_HGA is not set
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+CONFIG_FBCON_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+# CONFIG_SOUND_ALI5455 is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_CMPCI is not set
+# CONFIG_SOUND_EMU10K1 is not set
+# CONFIG_MIDI_EMU10K1 is not set
+# CONFIG_SOUND_FUSION is not set
+# CONFIG_SOUND_CS4281 is not set
+# CONFIG_SOUND_ES1370 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ESSSOLO1 is not set
+# CONFIG_SOUND_MAESTRO is not set
+# CONFIG_SOUND_MAESTRO3 is not set
+# CONFIG_SOUND_FORTE is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_RME96XX is not set
+# CONFIG_SOUND_SONICVIBES is not set
+CONFIG_SOUND_AU1X00=y
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+# CONFIG_MIDI_VIA82CXXX is not set
+# CONFIG_SOUND_OSS is not set
+# CONFIG_SOUND_TVMIXER is not set
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_UHCI is not set
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+CONFIG_USB_NON_PCI_OHCI=y
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_DEBUG=y
+# 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_HP8200e is not set
+CONFIG_USB_STORAGE_SDDR09=y
+# CONFIG_USB_STORAGE_SDDR55 is not set
+CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+CONFIG_USB_HID=m
+# CONFIG_USB_HIDINPUT is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+CONFIG_USB_OV511=m
+CONFIG_USB_PWC=m
+CONFIG_USB_SE401=m
+CONFIG_USB_STV680=m
+CONFIG_USB_VICAM=m
+# CONFIG_USB_DSBR is not set
+CONFIG_USB_DABUSB=m
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_CATC=m
+CONFIG_USB_CDCETHER=m
+CONFIG_USB_USBNET=m
+CONFIG_USB_USS720=m
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_DEBUG is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+CONFIG_USB_LCD=m
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_CROSSCOMPILE=y
+# CONFIG_RUNTIME_DEBUG is not set
+# CONFIG_KGDB is not set
+# CONFIG_GDB_CONSOLE is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_MIPS_UNCACHED is not set
+
+#
+# Library routines
+#
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff b/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff
index e69de29bb2..da17a12f38 100644
--- a/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff
+++ b/linux/linux-xxs1500-2.4.21/zboot-Makefile-flags.diff
@@ -0,0 +1,11 @@
+--- arch/mips/zboot/Makefile.o	2004-10-09 19:44:27.380145288 +0200
++++ arch/mips/zboot/Makefile	2004-10-09 19:46:17.643382728 +0200
+@@ -27,7 +27,7 @@
+ 
+ CFLAGS	:= $(CPPFLAGS) -O2 -D__BOOTER__ \
+ 	-fomit-frame-pointer -fno-strict-aliasing -fno-common \
+-	-G 0 -mno-abicalls -fno-pic -mcpu=r4600 -mips2 \
++	-G 0 -mno-abicalls -fno-pic -mabi=32 -march=mips32 -mips32 \
+ 		-I$(TOPDIR)/arch/$(ARCH)/zboot/include \
+ 		-I$(TOPDIR)/include/asm
+ AFLAGS	+= -D__BOOTER__
diff --git a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch
index e69de29bb2..f8343f89e1 100644
--- a/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch
+++ b/linux/montavista-sa-2.4.17-mvl21/apm-hh-merge.patch
@@ -0,0 +1,561 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c~apm-hh-merge
++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/apm.c
+@@ -86,6 +86,8 @@
+ 	int		magic;
+ 	struct apm_user *	next;
+ 	int		suser: 1;
++	int             writer : 1;
++	int             reader : 1;
+ 	int		suspend_wait: 1;
+ 	int		suspend_result;
+ 	int		suspends_pending;
+@@ -105,7 +107,7 @@
+ /*
+  * Local variables
+  */
+-//static int			suspends_pending;
++static int			suspends_pending;
+ //static int			standbys_pending;
+ //static int			ignore_normal_resume;
+ 
+@@ -123,8 +125,6 @@
+ #else
+ static int			power_off = 1;
+ #endif
+-static int			exit_kapmd;
+-static int			kapmd_running;
+ 
+ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
+ static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+@@ -192,6 +192,41 @@
+ 	return as->events[as->event_tail];
+ }
+ 
++static void queue_event(apm_event_t event, struct apm_user *sender)
++{
++	struct apm_user *	as;
++	if (user_list == NULL)
++		return;
++	for (as = user_list; as != NULL; as = as->next) {
++		if ((as == sender) || (!as->reader))
++			continue;
++		as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
++		if (as->event_head == as->event_tail) {
++			static int notified;
++
++			if (notified++ == 0)
++				printk(KERN_ERR "apm: an event queue overflowed\n");
++			as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
++		}
++		as->events[as->event_head] = event;
++		if ((!as->suser) || (!as->writer))
++			continue;
++		switch (event) {
++		case APM_SYS_SUSPEND:
++		case APM_USER_SUSPEND:
++			as->suspends_pending++;
++			suspends_pending++;
++			break;
++
++		case APM_SYS_STANDBY:
++		case APM_USER_STANDBY:
++			as->standbys_pending++;
++			break;
++		}
++	}
++	wake_up_interruptible(&apm_waitqueue);
++}
++
+ static int check_apm_user(struct apm_user *as, const char *func)
+ {
+ 	if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
+@@ -270,7 +305,6 @@
+ 	return 0;
+ }
+ 
+-extern int pm_do_suspend(void);
+ 
+ static int do_ioctl(struct inode * inode, struct file *filp,
+ 		    u_int cmd, u_long arg)
+@@ -284,7 +318,17 @@
+ 		return -EPERM;
+ 	switch (cmd) {
+         case APM_IOC_SUSPEND:
+-		pm_do_suspend();
++		if (as->suspends_read > 0) {
++			as->suspends_read--;
++			as->suspends_pending--;
++			suspends_pending--;
++		} else {
++			queue_event(APM_USER_SUSPEND, as);
++		}
++
++		if (suspends_pending <= 0)
++			wake_up(&apm_suspend_waitqueue);
++
+ 		break;
+ 	default:
+ 		return -EINVAL;
+@@ -301,6 +345,20 @@
+ 		return 0;
+ 	filp->private_data = NULL;
+ 	lock_kernel();
++	if (user_list == as)
++		user_list = as->next;
++	else {
++		struct apm_user *	as1;
++
++		for (as1 = user_list;
++		     (as1 != NULL) && (as1->next != as);
++		     as1 = as1->next)
++			;
++		if (as1 == NULL)
++			printk(KERN_ERR "apm: filp not in user list\n");
++		else
++			as1->next = as->next;
++	}
+ 	unlock_kernel();
+ 	kfree(as);
+ 	return 0;
+@@ -328,6 +386,8 @@
+ 	 * privileged operation -- cevans
+ 	 */
+ 	as->suser = capable(CAP_SYS_ADMIN);
++	as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
++	as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
+ 	as->next = user_list;
+ 	user_list = as;
+ 	filp->private_data = as;
+@@ -411,33 +471,7 @@
+ 	return p - buf;
+ }
+ 
+-#ifndef MODULE
+-static int __init apm_setup(char *str)
+-{
+-	int	invert;
+-
+-	while ((str != NULL) && (*str != '\0')) {
+-		if (strncmp(str, "off", 3) == 0)
+-			apm_disabled = 1;
+-		if (strncmp(str, "on", 2) == 0)
+-			apm_disabled = 0;
+-		invert = (strncmp(str, "no-", 3) == 0);
+-		if (invert)
+-			str += 3;
+-		if (strncmp(str, "debug", 5) == 0)
+-			debug = !invert;
+-		if ((strncmp(str, "power-off", 9) == 0) ||
+-		    (strncmp(str, "power_off", 9) == 0))
+-			power_off = !invert;
+-		str = strchr(str, ',');
+-		if (str != NULL)
+-			str += strspn(str, ", \t");
+-	}
+-	return 1;
+-}
+ 
+-__setup("apm=", apm_setup);
+-#endif
+ 
+ static struct file_operations apm_bios_fops = {
+ 	owner:		THIS_MODULE,
+@@ -449,13 +483,55 @@
+ };
+ 
+ static struct miscdevice apm_device = {
+-	APM_MINOR_DEV,
+-	"apm_bios",
+-	&apm_bios_fops
++	minor : APM_MINOR_DEV,
++	name  : "apm_bios",
++	fops  : &apm_bios_fops
+ };
+ 
+ #define APM_INIT_ERROR_RETURN	return -1
+ 
++static pid_t apmd_pid;
++static DECLARE_COMPLETION(apmd_exited);
++
++static int apm(void *unused)
++{
++	unsigned short	bx;
++	unsigned short	cx;
++	unsigned short	dx;
++	int		error;
++	char *		power_stat;
++	char *		bat_stat;
++	DECLARE_WAITQUEUE(wait, current);
++	struct apm_user au, *as;
++
++	lock_kernel();
++
++	daemonize();
++
++	strcpy(current->comm, "kapmd");
++
++	as = &au;
++	as->magic = APM_BIOS_MAGIC;
++	as->event_tail = as->event_head = 0;
++	as->suspends_pending = as->standbys_pending = 0;
++	as->suspends_read = as->standbys_read = 0;
++	as->suser = 1;
++	as->writer = 1;
++	as->reader = 0;
++
++	while (!signal_pending (current)) {
++		interruptible_sleep_on(&apm_suspend_waitqueue);
++
++		pm_suggest_suspend();
++
++		queue_event(APM_NORMAL_RESUME, as);
++	}
++
++	unlock_kernel();
++
++	complete_and_exit(&apmd_exited, 0);
++}
++
+ /*
+  * Just start the APM thread. We do NOT want to do APM BIOS
+  * calls from anything but the APM thread, if for no other reason
+@@ -494,18 +570,19 @@
+ 
+ 	misc_register(&apm_device);
+ 
++	apmd_pid = kernel_thread(apm, NULL, 0);
++
+ 	return 0;
+ }
+ 
+ static void __exit apm_exit(void)
+ {
+ 	misc_deregister(&apm_device);
+-	remove_proc_entry("apm", NULL);
++	remove_proc_entry("apm", NULL);	
++	kill_proc (apmd_pid, SIGTERM, 1);
++	wait_for_completion(&apmd_exited);
+ 	if (power_off)
+ 		pm_power_off = NULL;
+-	exit_kapmd = 1;
+-	while (kapmd_running)
+-		schedule();
+ 	pm_active = 0;
+ }
+ 
+@@ -514,6 +591,7 @@
+ 
+ MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell");
+ MODULE_DESCRIPTION("A minimal emulation of APM");
++MODULE_LICENSE("GPL");
+ MODULE_PARM(debug, "i");
+ MODULE_PARM_DESC(debug, "Enable debug mode");
+ MODULE_PARM(power_off, "i");
+--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c~apm-hh-merge
++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/pm.c
+@@ -53,6 +53,10 @@
+ #include <asm/arch/assabet.h>
+ #endif
+ 
++#define __KERNEL_SYSCALLS__
++#include <linux/unistd.h>
++
++
+ /*
+  * ARGH!  Stupid ACPI people.  They should define this in linux/sysctl.h,
+  * NOT linux/acpi.h.
+@@ -64,123 +68,6 @@
+ #define CTL_ACPI 9999
+ #define ACPI_S1_SLP_TYP 19
+ 
+-#ifndef CONFIG_SA1100_BEAGLE
+-
+-extern void sa1100_cpu_suspend(void);
+-extern void sa1100_cpu_resume(void);
+-
+-extern unsigned long *sleep_save;	/* virtual address */
+-extern unsigned long  sleep_save_p;	/* physical address */
+-
+-#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
+-#define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
+-
+-int sa1110_suspend(void)
+-{
+-	int retval;
+-
+-	/* set up pointer to sleep parameters */
+-	sleep_save = kmalloc (SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC);
+-	if (!sleep_save)
+-		return -ENOMEM;
+-	sleep_save_p = virt_to_phys(sleep_save);
+-
+-	retval = pm_send_all(PM_SUSPEND, (void *)2);
+-	if (retval) {
+-		kfree(sleep_save);
+-		return retval;
+-	}
+-
+-	cli();
+-
+-	/* preserve current time */
+-	RCNR = xtime.tv_sec;
+-
+-	/* save vital registers */
+-	SAVE(OSCR);
+-	SAVE(OSMR0);
+-	SAVE(OSMR1);
+-	SAVE(OSMR2);
+-	SAVE(OSMR3);
+-	SAVE(OIER);
+-
+-	SAVE(GPDR);
+-	SAVE(GRER);
+-	SAVE(GFER);
+-	SAVE(GAFR);
+-
+-	SAVE(PPDR);
+-	SAVE(PPSR);
+-	SAVE(PPAR);
+-	SAVE(PSDR);
+-
+-	SAVE(Ser1SDCR0);
+-
+-	SAVE(ICMR);
+-
+-	/* ... maybe a global variable initialized by arch code to set this? */
+-	GRER = PWER;
+-	GFER = 0;
+-	GEDR = GEDR;
+-
+-	/* Clear previous reset status */
+-	RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
+-
+-	/* set resume return address */
+-	PSPR = virt_to_phys(sa1100_cpu_resume);
+-
+-	/* go zzz */
+-	sa1100_cpu_suspend();
+-
+-	/* ensure not to come back here if it wasn't intended */
+-	PSPR = 0;
+-
+-	DPRINTK("*** made it back from resume\n");
+-
+-	/* restore registers */
+-	RESTORE(GPDR);
+-	RESTORE(GRER);
+-	RESTORE(GFER);
+-	RESTORE(GAFR);
+-
+-	/* clear any edge detect bit */
+-	GEDR = GEDR;
+-
+-	RESTORE(PPDR);
+-	RESTORE(PPSR);
+-	RESTORE(PPAR);
+-	RESTORE(PSDR);
+-
+-	RESTORE(Ser1SDCR0);
+-
+-	PSSR = PSSR_PH;
+-
+-	RESTORE(OSMR0);
+-	RESTORE(OSMR1);
+-	RESTORE(OSMR2);
+-	RESTORE(OSMR3);
+-	RESTORE(OSCR);
+-	RESTORE(OIER);
+-
+-	ICLR = 0;
+-	ICCR = 1;
+-	RESTORE(ICMR);
+-
+-	/* restore current time */
+-	xtime.tv_sec = RCNR;
+-
+-	sti();
+-
+-	kfree (sleep_save);
+-
+-#ifdef CONFIG_CPU_FREQ
+-	cpufreq_restore();
+-#endif
+-
+-	return pm_send_all(PM_RESUME, (void *)0);
+-}
+-
+-#else //CONFIG_SA1100_BEAGLE
+ 
+ typedef struct _tag_SLEEP_SAVED_DATA {
+ 	uint wakeup_addr;
+@@ -363,9 +250,6 @@
+ 	" );
+ }
+ 
+-extern void h3600_control_egpio( enum ipaq_egpio_type x, int setp );
+-extern unsigned long h3600_read_egpio( void );
+-
+ static int GPDR_saved;
+ static int GPLR_saved;
+ static int GRER_saved;
+@@ -742,21 +626,37 @@
+ 	Ser3UTSR1 = 0xff;
+ }
+ 
+-#endif //CONFIG_SA1100_BEAGLE
+-
++/*
++ * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend.
++ *
++ * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend.
++ * If it returns a true value, then pm_suspend is not called. 
++ * Use this to hook in apmd, for now.
++ *
++ * -not exported just so that the code compiles
++ */
++int (*pm_suggest_suspend_hook)(int state);
++int (*pm_sysctl_suspend_hook)(int state);
++int pm_use_sbin_pm_helper = 1;
+ static char pm_helper_path[128] = "/sbin/pm_helper";
++extern int exec_usermodehelper(char *path, char **argv, char **envp);
++int debug_pm = 0;
++static int pm_helper_veto = 0;
+ 
+-static void
++static int
+ run_sbin_pm_helper( pm_request_t action )
+ {
+ 	int i;
+ 	char *argv[3], *envp[8];
+ 
+ 	if (!pm_helper_path[0])
+-		return;
++		return 2;
+ 
+ 	if ( action != PM_SUSPEND && action != PM_RESUME )
+-		return;
++		return 1;
++
++	/* Be root */
++	current->uid = current->gid = 0;
+ 
+ 	i = 0;
+ 	argv[i++] = pm_helper_path;
+@@ -771,14 +671,15 @@
+ 	envp[i] = 0;
+ 
+ 	/* other stuff we want to pass to /sbin/hotplug */
+-	call_usermodehelper (argv [0], argv, envp);
++	return exec_usermodehelper (argv [0], argv, envp);
+ }
+ 
++int pm_force_suspend(void);
++
+ int pm_do_suspend(void)
+ {
+-	DPRINTK("suggest\n");
+-	run_sbin_pm_helper(PM_SUSPEND);
+-	return 0;
++	DPRINTK("suspend now\n");
++	return pm_force_suspend();
+ }
+ 
+ #ifdef CONFIG_SA1100_BEAGLE
+@@ -863,9 +764,91 @@
+ }
+ #endif
+ 
++int pm_suggest_suspend(void)
++{
++	int retval;
++
++	if (pm_suggest_suspend_hook) {
++		if (pm_suggest_suspend_hook(PM_SUSPEND))
++			return 0;
++	}
++
++	if (pm_use_sbin_pm_helper) {
++		pid_t pid;
++		int res;
++		int status = 0;
++		unsigned int old_fs;
++
++		pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 );
++		if ( pid < 0 )
++			return pid;
++
++		if (debug_pm)
++			printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid);	
++
++		old_fs = get_fs ();
++		set_fs (get_ds ());
++		res = waitpid(pid, &status, __WCLONE);
++		set_fs (old_fs);
++
++		if ( pid != res ) {
++			if (debug_pm)
++				printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status );
++
++			return -1;
++		}
++
++		/*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/
++		if (( status & 0xff7f ) != 0 ) {
++			if (pm_helper_veto) {
++				if (debug_pm)
++					printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8);
++				return -1;
++			} else {
++				if (debug_pm)
++					printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8);
++			}
++		}
++	}
++
++	if (debug_pm)
++		printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ );
++
++	if (pm_sysctl_suspend_hook) {
++		if (pm_sysctl_suspend_hook(PM_SUSPEND))
++			return 0;
++	}
++
++	retval = pm_do_suspend();
++	if (retval) {
++		if (debug_pm)
++			printk(KERN_CRIT "pm_suspend returned %d\n", retval);
++		return retval;
++	}
++
++	if (pm_use_sbin_pm_helper) {
++		pid_t pid;
++        	
++		if (debug_pm)
++			printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__);
++
++		pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 );
++		if ( pid < 0 )
++			return pid;
++        		
++		if ( pid != waitpid ( pid, NULL, __WCLONE ))
++			return -1;
++	}
++
++	return 0;
++}
++
++EXPORT_SYMBOL(pm_suggest_suspend);
++
++
+ static struct ctl_table pm_table[] =
+ {
+-	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend},
++/*	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0644, NULL, (proc_handler *)&pm_force_suspend}, */
+ 	{2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring},
+ #ifdef CONFIG_SA1100_BEAGLE
+ 	{3, "wakeup_delayed_time", &wakeup_delayed_time, sizeof(wakeup_delayed_time), 0644, NULL, &proc_dointvec },
diff --git a/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch b/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch
index e69de29bb2..f4749ca944 100644
--- a/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch
+++ b/linux/montavista-sa-2.4.17-mvl21/beagle-sound.patch
@@ -0,0 +1,57 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.17_mvl21/drivers/sound/assabet-uda1341.c~beagle-sound.patch
++++ linux-2.4.17_mvl21/drivers/sound/assabet-uda1341.c
+@@ -49,7 +49,9 @@
+ #ifdef CONFIG_SA1100_BEAGLE
+ #include <linux/timer.h>
+ #include <linux/sysctl.h>
+-#include <asm/io.h>
++
++#define CCR_ADDR 0xf2000000
++
+ #endif
+ 
+ #include "sa1100-audio.h"
+@@ -142,15 +144,12 @@
+ 	/* MasterIA support full sampling rate in BEAGLE and
+ 	   provide click from other device */
+ 
+-	unsigned int ccr_addr;
+ 	unsigned int frg_set;
+ 	unsigned int frg_get = -1;
+ 	int count;
+ 
+ 	audio_samplerate = val;
+ 
+-	ccr_addr = (unsigned int)__ioremap((unsigned long)0x18000000, 0x00100000, 0);
+-
+ 	switch(val) {
+    		case  8000: frg_set = 0x01; break;
+ 	    case 11025: frg_set = 0x02; break;
+@@ -165,18 +164,16 @@
+ 	count = 0;
+ 	while(frg_set != frg_get) {
+ 	    /* Ensure CPLD read we gave */
+-	    *((volatile unsigned int*)(ccr_addr+0x04)) = frg_set;
++	    *((volatile unsigned int*)(CCR_ADDR+0x04)) = frg_set;
+ 
+-	    frg_get = *((volatile unsigned int*)(ccr_addr+0x0024)) & 0xFF;
++	    frg_get = *((volatile unsigned int*)(CCR_ADDR+0x0024)) & 0xFF;
+ 	    if ( ++count >= 10 ) {
+ 		schedule_timeout( 1 );
+ 		count = 0;
+ 	    }
+-//	    printk("*** Sound: write %02x[%08x], read %02x[%08x]\n", frg_set, ccr_addr+0x04,
+-//								     frg_get, ccr_addr+0x24);
++//	    printk("*** Sound: write %02x[%08x], read %02x[%08x]\n", frg_set, CCR_ADDR+0x04,
++//								     frg_get, CCR_ADDR+0x24);
+ 	}
+-
+-	__iounmap((void*)ccr_addr);
+ #else
+ 	struct uda1341_cfg cfg;
+ 	u_int clk_ref, clk_div;
diff --git a/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch b/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch
index e69de29bb2..79ba036323 100644
--- a/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch
+++ b/linux/montavista-sa-2.4.17-mvl21/disable-pcmcia-probe.patch
@@ -0,0 +1,17 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe	2003-05-13 11:18:23.000000000 +0200
++++ linux/drivers/pcmcia/Config.in	2004-05-27 13:59:50.000000000 +0200
+@@ -15,9 +15,6 @@
+ tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+ if [ "$CONFIG_PCMCIA" != "n" ]; then
+    # yes, I really mean the following...
+-   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then
+-      define_bool CONFIG_PCMCIA_PROBE y
+-   fi
+    if [ "$CONFIG_PCI" != "n" ]; then
+       bool '  CardBus support' CONFIG_CARDBUS
+    fi
diff --git a/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff b/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff
index e69de29bb2..2ebfd8ec12 100644
--- a/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff
+++ b/linux/montavista-sa-2.4.17-mvl21/iw240_we15-6.diff
@@ -0,0 +1,399 @@
+diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h
+--- linux/include/linux/wireless.14.h	Mon Dec  2 18:51:00 2002
++++ linux/include/linux/wireless.h	Mon Dec  2 18:53:35 2002
+@@ -1,7 +1,7 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	14	25.1.02
++ * Version :	15	12.7.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+@@ -80,7 +80,7 @@
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	14
++#define WIRELESS_EXT	15
+ 
+ /*
+  * Changes :
+@@ -153,17 +153,32 @@
+  *	- Define additional specific event numbers
+  *	- Add "addr" and "param" fields in union iwreq_data
+  *	- AP scanning stuff (SIOCSIWSCAN and friends)
++ *
++ * V14 to V15
++ * ----------
++ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
++ *	- Make struct iw_freq signed (both m & e), add explicit padding
++ *	- Add IWEVCUSTOM for driver specific event/scanning token
++ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
++ *	- Add IW_TXPOW_RANGE for range of Tx Powers
++ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
++ *	- Add IW_MODE_MONITOR for passive monitor
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+ /* -------------------------- IOCTL LIST -------------------------- */
+ 
+-/* Basic operations */
++/* Wireless Identification */
+ #define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
+ #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
+-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
+-#define SIOCGIWNWID	0x8B03		/* get network id */
++/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
++ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
++ * Don't put the name of your driver there, it's useless. */
++
++/* Basic operations */
++#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
++#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
+ #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
+ #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
+ #define SIOCSIWMODE	0x8B06		/* set operation mode */
+@@ -178,16 +193,18 @@
+ #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
+ #define SIOCSIWSTATS	0x8B0E		/* Unused */
+ #define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
++/* SIOCGIWSTATS is strictly used between user space and the kernel, and
++ * is never passed to the driver (i.e. the driver will never see it). */
+ 
+-/* Mobile IP support */
++/* Mobile IP support (statistics per MAC address) */
+ #define SIOCSIWSPY	0x8B10		/* set spy addresses */
+ #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
+ 
+ /* Access Point manipulation */
+ #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
+ #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
+-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
+-#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
++#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
++#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
+ #define SIOCGIWSCAN	0x8B19		/* get scanning results */
+ 
+ /* 802.11 specific support */
+@@ -197,9 +214,7 @@
+ #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
+ /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
+  * within the 'iwreq' structure, so we need to use the 'data' member to
+- * point to a string in user space, like it is done for RANGE...
+- * The "flags" member indicate if the ESSID is active or not (promiscuous).
+- */
++ * point to a string in user space, like it is done for RANGE... */
+ 
+ /* Other parameters useful in 802.11 and some other devices */
+ #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
+@@ -257,7 +272,10 @@
+ /* Most events use the same identifier as ioctl requests */
+ 
+ #define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
+-#define IWEVQUAL	0x8C01		/* Quality part of statistics */
++#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
++#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
++#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
++#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
+ 
+ #define IWEVFIRST	0x8C00
+ 
+@@ -273,7 +291,8 @@
+ #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
+ #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
+ #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
+-#define IW_PRIV_TYPE_FLOAT	0x5000
++#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
++#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
+ 
+ #define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
+ 
+@@ -297,13 +316,16 @@
+ 
+ /* Maximum tx powers in the range struct */
+ #define IW_MAX_TXPOWER		8
++/* Note : if you more than 8 TXPowers, just set the max and min or
++ * a few of them in the struct iw_range. */
+ 
+ /* Maximum of address that you may set with SPY */
+-#define IW_MAX_SPY		8
++#define IW_MAX_SPY		8	/* set */
++#define IW_MAX_GET_SPY		64	/* get */
+ 
+ /* Maximum of address that you may get in the
+    list of access points in range */
+-#define IW_MAX_AP		8
++#define IW_MAX_AP		64
+ 
+ /* Maximum size of the ESSID and NICKN strings */
+ #define IW_ESSID_MAX_SIZE	32
+@@ -315,6 +337,7 @@
+ #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
+ #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
+ #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
++#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
+ 
+ /* Maximum number of size of encoding token available
+  * they are listed in the range structure */
+@@ -350,8 +373,10 @@
+ #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+ 
+ /* Transmit Power flags available */
++#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
+ #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
+ #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
++#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
+ 
+ /* Retry limits and lifetime flags available */
+ #define IW_RETRY_ON		0x0000	/* No details... */
+@@ -376,6 +401,9 @@
+ /* Maximum size of returned data */
+ #define IW_SCAN_MAX_DATA	4096	/* In bytes */
+ 
++/* Max number of char in custom event - use multiple of them if needed */
++#define IW_CUSTOM_MAX		256	/* In bytes */
++
+ /****************************** TYPES ******************************/
+ 
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -411,9 +439,10 @@ struct	iw_point
+  */
+ struct	iw_freq
+ {
+-	__u32		m;		/* Mantissa */
+-	__u16		e;		/* Exponent */
++	__s32		m;		/* Mantissa */
++	__s16		e;		/* Exponent */
+ 	__u8		i;		/* List index (when in range struct) */
++	__u8		pad;		/* Unused - just for alignement */
+ };
+ 
+ /*
+diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h
+--- linux/include/net/iw_handler.14.h	Mon Dec  2 18:51:17 2002
++++ linux/include/net/iw_handler.h	Mon Dec  2 18:54:51 2002
+@@ -1,7 +1,7 @@
+ /*
+  * This file define the new driver API for Wireless Extensions
+  *
+- * Version :	3	17.1.02
++ * Version :	4	21.6.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+@@ -206,7 +206,7 @@
+  * will be needed...
+  * I just plan to increment with each new version.
+  */
+-#define IW_HANDLER_VERSION	3
++#define IW_HANDLER_VERSION	4
+ 
+ /*
+  * Changes :
+@@ -217,6 +217,9 @@
+  *	- Add Wireless Event support :
+  *		o wireless_send_event() prototype
+  *		o iwe_stream_add_event/point() inline functions
++ * V3 to V4
++ * --------
++ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+@@ -233,10 +236,10 @@
+ #define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
+ #define IW_HEADER_TYPE_UINT	4	/* __u32 */
+ #define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
+-#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+-#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+-#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
+-#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
++#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
++#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
++#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
++#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
+ 
+ /* Handling flags */
+ /* Most are not implemented. I just use them as a reminder of some
+diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c
+--- linux/net/core/wireless.14.c	Mon Dec  2 18:51:35 2002
++++ linux/net/core/wireless.c	Mon Dec  2 18:53:10 2002
+@@ -33,8 +33,16 @@
+  *	o Propagate events as rtnetlink IFLA_WIRELESS option
+  *	o Generate event on selected SET requests
+  *
+- * v4 - 18.04.01 - Jean II
++ * v4 - 18.04.02 - Jean II
+  *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
++ *
++ * v5 - 21.06.02 - Jean II
++ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
++ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
++ *	o Add IWEVCUSTOM for driver specific event/scanning token
++ *	o Turn on WE_STRICT_WRITE by default + kernel warning
++ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
++ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
+  */
+ 
+ /***************************** INCLUDES *****************************/
+@@ -50,8 +58,9 @@
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+-/* This will be turned on later on... */
+-#undef WE_STRICT_WRITE		/* Check write buffer size */
++/* Enough lenience, let's make sure things are proper... */
++#define WE_STRICT_WRITE		/* Check write buffer size */
++/* I'll probably drop both the define and kernel message in the next version */
+ 
+ /* Debuging stuff */
+ #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+@@ -106,7 +115,7 @@ static const struct iw_ioctl_description
+ 	/* SIOCSIWSPY */
+ 	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
+ 	/* SIOCGIWSPY */
+-	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
+ 	/* -- hole -- */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* -- hole -- */
+@@ -176,25 +185,41 @@ static const struct iw_ioctl_description
+ 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ 	/* IWEVQUAL */
+ 	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
++	/* IWEVCUSTOM */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
++	/* IWEVREGISTERED */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* IWEVEXPIRED */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ };
+ static const int standard_event_num = (sizeof(standard_event) /
+ 				       sizeof(struct iw_ioctl_description));
+ 
+ /* Size (in bytes) of the various private data types */
+-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++static const char priv_type_size[] = {
++	0,				/* IW_PRIV_TYPE_NONE */
++	1,				/* IW_PRIV_TYPE_BYTE */
++	1,				/* IW_PRIV_TYPE_CHAR */
++	0,				/* Not defined */
++	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
++	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
++	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
++	0,				/* Not defined */
++};
+ 
+ /* Size (in bytes) of various events */
+ static const int event_type_size[] = {
+-	IW_EV_LCP_LEN,
++	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
++	0,
++	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
+ 	0,
+-	IW_EV_CHAR_LEN,
++	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
++	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
++	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
+ 	0,
+-	IW_EV_UINT_LEN,
+-	IW_EV_FREQ_LEN,
+ 	IW_EV_POINT_LEN,		/* Without variable payload */
+-	IW_EV_PARAM_LEN,
+-	IW_EV_ADDR_LEN,
+-	IW_EV_QUAL_LEN,
++	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
++	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
+ };
+ 
+ /************************ COMMON SUBROUTINES ************************/
+@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s
+ 		return -EFAULT;
+ #ifdef WE_STRICT_WRITE
+ 	/* Check if there is enough buffer up there */
+-	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
++	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
++		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
+ 		return -E2BIG;
++	}
+ #endif	/* WE_STRICT_WRITE */
+ 
+ 	/* Set the number of available ioctls. */
+@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st
+ 	const struct iw_ioctl_description *	descr;
+ 	struct iw_request_info			info;
+ 	int					ret = -EINVAL;
++	int					user_size = 0;
+ 
+ 	/* Get the description of the IOCTL */
+ 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st
+ 			/* Check NULL pointer */
+ 			if(iwr->u.data.pointer == NULL)
+ 				return -EFAULT;
+-#ifdef WE_STRICT_WRITE
+-			/* Check if there is enough buffer up there */
+-			if(iwr->u.data.length < descr->max_tokens)
+-				return -E2BIG;
+-#endif	/* WE_STRICT_WRITE */
++			/* Save user space buffer size for checking */
++			user_size = iwr->u.data.length;
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st
+ 
+ 		/* If we have something to return to the user */
+ 		if (!ret && IW_IS_GET(cmd)) {
++#ifdef WE_STRICT_WRITE
++			/* Check if there is enough buffer up there */
++			if(user_size < iwr->u.data.length) {
++				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
++				kfree(extra);
++				return -E2BIG;
++			}
++#endif	/* WE_STRICT_WRITE */
++
+ 			err = copy_to_user(iwr->u.data.pointer, extra,
+ 					   iwr->u.data.length *
+ 					   descr->token_size);
+@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str
+ 	/* Compute the size of the set/get arguments */
+ 	if(descr != NULL) {
+ 		if(IW_IS_SET(cmd)) {
++			int	offset = 0;	/* For sub-ioctls */
++			/* Check for sub-ioctl handler */
++			if(descr->name[0] == '\0')
++				/* Reserve one int for sub-ioctl index */
++				offset = sizeof(__u32);
++
+ 			/* Size of set arguments */
+ 			extra_size = get_priv_size(descr->set_args);
+ 
+ 			/* Does it fits in iwr ? */
+ 			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+-			   (extra_size < IFNAMSIZ))
++			   ((extra_size + offset) <= IFNAMSIZ))
+ 				extra_size = 0;
+ 		} else {
+ 			/* Size of set arguments */
+@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str
+ 
+ 			/* Does it fits in iwr ? */
+ 			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+-			   (extra_size < IFNAMSIZ))
++			   (extra_size <= IFNAMSIZ))
+ 				extra_size = 0;
+ 		}
+ 	}
+@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi
+ 		 * The best the driver could do is to log an error message.
+ 		 * We will do it ourselves instead...
+ 		 */
+-	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
++	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+ 		       dev->name, cmd);
+ 		return;
+ 	}
diff --git a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff
index e69de29bb2..a27a7654a9 100644
--- a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff
+++ b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w13-5.diff
@@ -0,0 +1,1513 @@
+diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h
+--- linux/include/linux-w12/netdevice.h	Thu Nov 22 11:47:09 2001
++++ linux/include/linux/netdevice.h	Thu Jan 17 12:00:39 2002
+@@ -278,6 +278,10 @@ struct net_device
+ 	struct net_device_stats* (*get_stats)(struct net_device *dev);
+ 	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);
+ 
++	/* List of functions to handle Wireless Extensions (instead of ioctl).
++	 * See <net/iw_handler.h> for details. Jean II */
++	struct iw_handler_def *	wireless_handlers;
++
+ 	/*
+ 	 * This marks the end of the "visible" part of the structure. All
+ 	 * fields hereafter are internal to the system, and may change at
+diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h
+--- linux/include/linux-w12/wireless.h	Thu Nov 22 11:47:12 2001
++++ linux/include/linux/wireless.h	Thu Jan 17 12:04:08 2002
+@@ -1,9 +1,10 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	12	5.10.01
++ * Version :	13	6.12.01
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _LINUX_WIRELESS_H
+@@ -11,6 +12,8 @@
+ 
+ /************************** DOCUMENTATION **************************/
+ /*
++ * Initial APIs (1996 -> onward) :
++ * -----------------------------
+  * Basically, the wireless extensions are for now a set of standard ioctl
+  * call + /proc/net/wireless
+  *
+@@ -27,16 +30,27 @@
+  * We have the list of command plus a structure descibing the
+  * data exchanged...
+  * Note that to add these ioctl, I was obliged to modify :
+- *	net/core/dev.c (two place + add include)
+- *	net/ipv4/af_inet.c (one place + add include)
++ *	# net/core/dev.c (two place + add include)
++ *	# net/ipv4/af_inet.c (one place + add include)
+  *
+  * /proc/net/wireless is a copy of /proc/net/dev.
+  * We have a structure for data passed from the driver to /proc/net/wireless
+  * Too add this, I've modified :
+- *	net/core/dev.c (two other places)
+- *	include/linux/netdevice.h (one place)
+- *	include/linux/proc_fs.h (one place)
++ *	# net/core/dev.c (two other places)
++ *	# include/linux/netdevice.h (one place)
++ *	# include/linux/proc_fs.h (one place)
++ *
++ * New driver API (2001 -> onward) :
++ * -------------------------------
++ * This file is only concerned with the user space API and common definitions.
++ * The new driver API is defined and documented in :
++ *	# include/net/iw_handler.h
+  *
++ * Note as well that /proc/net/wireless implementation has now moved in :
++ *	# include/linux/wireless.c
++ *
++ * Other comments :
++ * --------------
+  * Do not add here things that are redundant with other mechanisms
+  * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
+  * wireless specific.
+@@ -54,16 +68,14 @@
+ #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
+ #include <linux/if.h>			/* for IFNAMSIZ and co... */
+ 
+-/**************************** CONSTANTS ****************************/
+-
+-/* --------------------------- VERSION --------------------------- */
++/***************************** VERSION *****************************/
+ /*
+  * This constant is used to know the availability of the wireless
+  * extensions and to know which version of wireless extensions it is
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	12
++#define WIRELESS_EXT	13
+ 
+ /*
+  * Changes :
+@@ -123,12 +135,20 @@
+  *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
+  *	- Add new statistics (frag, retry, beacon)
+  *	- Add average quality (for user space calibration)
++ *
++ * V12 to V13
++ * ----------
++ *	- Document creation of new driver API.
++ *	- Extract union iwreq_data from struct iwreq (for new driver API).
++ *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
+  */
+ 
++/**************************** CONSTANTS ****************************/
++
+ /* -------------------------- IOCTL LIST -------------------------- */
+ 
+ /* Basic operations */
+-#define SIOCSIWNAME	0x8B00		/* Unused */
++#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
+ #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
+ #define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
+ #define SIOCGIWNWID	0x8B03		/* get network id */
+@@ -414,13 +434,49 @@ struct	iw_statistics
+ 
+ /* ------------------------ IOCTL REQUEST ------------------------ */
+ /*
++ * This structure defines the payload of an ioctl, and is used 
++ * below.
++ *
++ * Note that this structure should fit on the memory footprint
++ * of iwreq (which is the same as ifreq), which mean a max size of
++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
++ * You should check this when increasing the structures defined
++ * above in this file...
++ */
++union	iwreq_data
++{
++	/* Config - generic */
++	char		name[IFNAMSIZ];
++	/* Name : used to verify the presence of  wireless extensions.
++	 * Name of the protocol/provider... */
++
++	struct iw_point	essid;		/* Extended network name */
++	struct iw_param	nwid;		/* network id (or domain - the cell) */
++	struct iw_freq	freq;		/* frequency or channel :
++					 * 0-1000 = channel
++					 * > 1000 = frequency in Hz */
++
++	struct iw_param	sens;		/* signal level threshold */
++	struct iw_param	bitrate;	/* default bit rate */
++	struct iw_param	txpower;	/* default transmit power */
++	struct iw_param	rts;		/* RTS threshold threshold */
++	struct iw_param	frag;		/* Fragmentation threshold */
++	__u32		mode;		/* Operation mode */
++	struct iw_param	retry;		/* Retry limits & lifetime */
++
++	struct iw_point	encoding;	/* Encoding stuff : tokens */
++	struct iw_param	power;		/* PM duration/timeout */
++
++	struct sockaddr	ap_addr;	/* Access point address */
++
++	struct iw_point	data;		/* Other large parameters */
++};
++
++/*
+  * The structure to exchange data for ioctl.
+  * This structure is the same as 'struct ifreq', but (re)defined for
+  * convenience...
+- *
+- * Note that it should fit on the same memory footprint !
+- * You should check this when increasing the above structures (16 octets)
+- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
++ * Do I need to remind you about structure size (32 octets) ?
+  */
+ struct	iwreq 
+ {
+@@ -429,35 +485,8 @@ struct	iwreq 
+ 		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
+ 	} ifr_ifrn;
+ 
+-	/* Data part */
+-	union
+-	{
+-		/* Config - generic */
+-		char		name[IFNAMSIZ];
+-		/* Name : used to verify the presence of  wireless extensions.
+-		 * Name of the protocol/provider... */
+-
+-		struct iw_point	essid;	/* Extended network name */
+-		struct iw_param	nwid;	/* network id (or domain - the cell) */
+-		struct iw_freq	freq;	/* frequency or channel :
+-					 * 0-1000 = channel
+-					 * > 1000 = frequency in Hz */
+-
+-		struct iw_param	sens;		/* signal level threshold */
+-		struct iw_param	bitrate;	/* default bit rate */
+-		struct iw_param	txpower;	/* default transmit power */
+-		struct iw_param	rts;		/* RTS threshold threshold */
+-		struct iw_param	frag;		/* Fragmentation threshold */
+-		__u32		mode;		/* Operation mode */
+-		struct iw_param	retry;		/* Retry limits & lifetime */
+-
+-		struct iw_point	encoding;	/* Encoding stuff : tokens */
+-		struct iw_param	power;		/* PM duration/timeout */
+-
+-		struct sockaddr	ap_addr;	/* Access point address */
+-
+-		struct iw_point	data;		/* Other large parameters */
+-	}	u;
++	/* Data part (defined just above) */
++	union	iwreq_data	u;
+ };
+ 
+ /* -------------------------- IOCTL DATA -------------------------- */
+diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h
+--- linux/include/net-w12/iw_handler.h	Wed Dec 31 16:00:00 1969
++++ linux/include/net/iw_handler.h	Thu Jan 17 12:16:46 2002
+@@ -0,0 +1,374 @@
++/*
++ * This file define the new driver API for Wireless Extensions
++ *
++ * Version :	2	6.12.01
++ *
++ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
++ */
++
++#ifndef _IW_HANDLER_H
++#define _IW_HANDLER_H
++
++/************************** DOCUMENTATION **************************/
++/*
++ * Initial driver API (1996 -> onward) :
++ * -----------------------------------
++ * The initial API just sends the IOCTL request received from user space
++ * to the driver (via the driver ioctl handler). The driver has to
++ * handle all the rest...
++ *
++ * The initial API also defines a specific handler in struct net_device
++ * to handle wireless statistics.
++ *
++ * The initial APIs served us well and has proven a reasonably good design.
++ * However, there is a few shortcommings :
++ *	o No events, everything is a request to the driver.
++ *	o Large ioctl function in driver with gigantic switch statement
++ *	  (i.e. spaghetti code).
++ *	o Driver has to mess up with copy_to/from_user, and in many cases
++ *	  does it unproperly. Common mistakes are :
++ *		* buffer overflows (no checks or off by one checks)
++ *		* call copy_to/from_user with irq disabled
++ *	o The user space interface is tied to ioctl because of the use
++ *	  copy_to/from_user.
++ *
++ * New driver API (2001 -> onward) :
++ * -------------------------------
++ * The new driver API is just a bunch of standard functions (handlers),
++ * each handling a specific Wireless Extension. The driver just export
++ * the list of handler it supports, and those will be called apropriately.
++ *
++ * I tried to keep the main advantage of the previous API (simplicity,
++ * efficiency and light weight), and also I provide a good dose of backward
++ * compatibility (most structures are the same, driver can use both API
++ * simultaneously, ...).
++ * Hopefully, I've also addressed the shortcomming of the initial API.
++ *
++ * The advantage of the new API are :
++ *	o Handling of Extensions in driver broken in small contained functions
++ *	o Tighter checks of ioctl before calling the driver
++ *	o Flexible commit strategy (at least, the start of it)
++ *	o Backward compatibility (can be mixed with old API)
++ *	o Driver doesn't have to worry about memory and user-space issues
++ * The last point is important for the following reasons :
++ *	o You are now able to call the new driver API from any API you
++ *		want (including from within other parts of the kernel).
++ *	o Common mistakes are avoided (buffer overflow, user space copy
++ *		with irq disabled and so on).
++ *
++ * The Drawback of the new API are :
++ *	o bloat (especially kernel)
++ *	o need to migrate existing drivers to new API
++ * My initial testing shows that the new API adds around 3kB to the kernel
++ * and save between 0 and 5kB from a typical driver.
++ * Also, as all structures and data types are unchanged, the migration is
++ * quite straightforward (but tedious).
++ *
++ * ---
++ *
++ * The new driver API is defined below in this file. User space should
++ * not be aware of what's happening down there...
++ *
++ * A new kernel wrapper is in charge of validating the IOCTLs and calling
++ * the appropriate driver handler. This is implemented in :
++ *	# net/core/wireless.c
++ *
++ * The driver export the list of handlers in :
++ *	# include/linux/netdevice.h (one place)
++ *
++ * The new driver API is available for WIRELESS_EXT >= 13.
++ * Good luck with migration to the new API ;-)
++ */
++
++/* ---------------------- THE IMPLEMENTATION ---------------------- */
++/*
++ * Some of the choice I've made are pretty controversials. Defining an
++ * API is very much weighting compromises. This goes into some of the
++ * details and the thinking behind the implementation.
++ *
++ * Implementation goals :
++ * --------------------
++ * The implementation goals were as follow :
++ *	o Obvious : you should not need a PhD to understand what's happening,
++ *		the benefit is easier maintainance.
++ *	o Flexible : it should accomodate a wide variety of driver
++ *		implementations and be as flexible as the old API.
++ *	o Lean : it should be efficient memory wise to minimise the impact
++ *		on kernel footprint.
++ *	o Transparent to user space : the large number of user space
++ *		applications that use Wireless Extensions should not need
++ *		any modifications.
++ *
++ * Array of functions versus Struct of functions
++ * ---------------------------------------------
++ * 1) Having an array of functions allow the kernel code to access the
++ * handler in a single lookup, which is much more efficient (think hash
++ * table here).
++ * 2) The only drawback is that driver writer may put their handler in
++ * the wrong slot. This is trivial to test (I set the frequency, the
++ * bitrate changes). Once the handler is in the proper slot, it will be
++ * there forever, because the array is only extended at the end.
++ * 3) Backward/forward compatibility : adding new handler just require
++ * extending the array, so you can put newer driver in older kernel
++ * without having to patch the kernel code (and vice versa).
++ *
++ * All handler are of the same generic type
++ * ----------------------------------------
++ * That's a feature !!!
++ * 1) Having a generic handler allow to have generic code, which is more
++ * efficient. If each of the handler was individually typed I would need
++ * to add a big switch in the kernel (== more bloat). This solution is
++ * more scalable, adding new Wireless Extensions doesn't add new code.
++ * 2) You can use the same handler in different slots of the array. For
++ * hardware, it may be more efficient or logical to handle multiple
++ * Wireless Extensions with a single function, and the API allow you to
++ * do that. (An example would be a single record on the card to control
++ * both bitrate and frequency, the handler would read the old record,
++ * modify it according to info->cmd and rewrite it).
++ *
++ * Functions prototype uses union iwreq_data
++ * -----------------------------------------
++ * Some would have prefered functions defined this way :
++ *	static int mydriver_ioctl_setrate(struct net_device *dev, 
++ *					  long rate, int auto)
++ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
++ * can't do it (different hardware may have different notion of what a
++ * valid frequency is), so we don't pretend that we do it.
++ * 2) The above form is not extendable. If I want to add a flag (for
++ * example to distinguish setting max rate and basic rate), I would
++ * break the prototype. Using iwreq_data is more flexible.
++ * 3) Also, the above form is not generic (see above).
++ * 4) I don't expect driver developper using the wrong field of the
++ * union (Doh !), so static typechecking doesn't add much value.
++ * 5) Lastly, you can skip the union by doing :
++ *	static int mydriver_ioctl_setrate(struct net_device *dev,
++ *					  struct iw_request_info *info,
++ *					  struct iw_param *rrq,
++ *					  char *extra)
++ * And then adding the handler in the array like this :
++ *        (iw_handler) mydriver_ioctl_setrate,             // SIOCSIWRATE
++ *
++ * Using functions and not a registry
++ * ----------------------------------
++ * Another implementation option would have been for every instance to
++ * define a registry (a struct containing all the Wireless Extensions)
++ * and only have a function to commit the registry to the hardware.
++ * 1) This approach can be emulated by the current code, but not
++ * vice versa.
++ * 2) Some drivers don't keep any configuration in the driver, for them
++ * adding such a registry would be a significant bloat.
++ * 3) The code to translate from Wireless Extension to native format is
++ * needed anyway, so it would not reduce significantely the amount of code.
++ * 4) The current approach only selectively translate Wireless Extensions
++ * to native format and only selectively set, whereas the registry approach
++ * would require to translate all WE and set all parameters for any single
++ * change.
++ * 5) For many Wireless Extensions, the GET operation return the current
++ * dynamic value, not the value that was set.
++ *
++ * This header is <net/iw_handler.h>
++ * ---------------------------------
++ * 1) This header is kernel space only and should not be exported to
++ * user space. Headers in "include/linux/" are exported, headers in
++ * "include/net/" are not.
++ *
++ * Mixed 32/64 bit issues
++ * ----------------------
++ * The Wireless Extensions are designed to be 64 bit clean, by using only
++ * datatypes with explicit storage size.
++ * There are some issues related to kernel and user space using different
++ * memory model, and in particular 64bit kernel with 32bit user space.
++ * The problem is related to struct iw_point, that contains a pointer
++ * that *may* need to be translated.
++ * This is quite messy. The new API doesn't solve this problem (it can't),
++ * but is a step in the right direction :
++ * 1) Meta data about each ioctl is easily available, so we know what type
++ * of translation is needed.
++ * 2) The move of data between kernel and user space is only done in a single
++ * place in the kernel, so adding specific hooks in there is possible.
++ * 3) In the long term, it allows to move away from using ioctl as the
++ * user space API.
++ *
++ * So many comments and so few code
++ * --------------------------------
++ * That's a feature. Comments won't bloat the resulting kernel binary.
++ */
++
++/***************************** INCLUDES *****************************/
++
++#include <linux/wireless.h>		/* IOCTL user space API */
++
++/***************************** VERSION *****************************/
++/*
++ * This constant is used to know which version of the driver API is
++ * available. Hopefully, this will be pretty stable and no changes
++ * will be needed...
++ * I just plan to increment with each new version.
++ */
++#define IW_HANDLER_VERSION	2
++
++/**************************** CONSTANTS ****************************/
++
++/* Special error message for the driver to indicate that we
++ * should do a commit after return from the iw_handler */
++#define EIWCOMMIT	EINPROGRESS
++
++/* Flags available in struct iw_request_info */
++#define IW_REQUEST_FLAG_NONE	0x0000	/* No flag so far */
++
++/* Type of headers we know about (basically union iwreq_data) */
++#define IW_HEADER_TYPE_NULL	0	/* Not available */
++#define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
++#define IW_HEADER_TYPE_UINT	4	/* __u32 */
++#define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
++#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
++#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
++#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
++
++/* Handling flags */
++/* Most are not implemented. I just use them as a reminder of some
++ * cool features we might need one day ;-) */
++#define IW_DESCR_FLAG_NONE	0x0000	/* Obvious */
++/* Wrapper level flags */
++#define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
++#define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
++#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
++/* Driver level flags */
++#define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
++
++/****************************** TYPES ******************************/
++
++/* ----------------------- WIRELESS HANDLER ----------------------- */
++/*
++ * A wireless handler is just a standard function, that looks like the
++ * ioctl handler.
++ * We also define there how a handler list look like... As the Wireless
++ * Extension space is quite dense, we use a simple array, which is faster
++ * (that's the perfect hash table ;-).
++ */
++
++/*
++ * Meta data about the request passed to the iw_handler.
++ * Most handlers can safely ignore what's in there.
++ * The 'cmd' field might come handy if you want to use the same handler
++ * for multiple command...
++ * This struct is also my long term insurance. I can add new fields here
++ * without breaking the prototype of iw_handler...
++ */
++struct iw_request_info
++{
++	__u16		cmd;		/* Wireless Extension command */
++	__u16		flags;		/* More to come ;-) */
++};
++
++/*
++ * This is how a function handling a Wireless Extension should look
++ * like (both get and set, standard and private).
++ */
++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
++			  union iwreq_data *wrqu, char *extra);
++
++/*
++ * This define all the handler that the driver export.
++ * As you need only one per driver type, please use a static const
++ * shared by all driver instances... Same for the members...
++ * This will be linked from net_device in <linux/netdevice.h>
++ */
++struct iw_handler_def
++{
++	/* Number of handlers defined (more precisely, index of the
++	 * last defined handler + 1) */
++	__u16			num_standard;
++	__u16			num_private;
++	/* Number of private arg description */
++	__u16			num_private_args;
++
++	/* Array of handlers for standard ioctls
++	 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
++	 */
++	iw_handler *		standard;
++
++	/* Array of handlers for private ioctls
++	 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
++	 */
++	iw_handler *		private;
++
++	/* Arguments of private handler. This one is just a list, so you
++	 * can put it in any order you want and should not leave holes...
++	 * We will automatically export that to user space... */
++	struct iw_priv_args *	private_args;
++
++	/* In the long term, get_wireless_stats will move from
++	 * 'struct net_device' to here, to minimise bloat. */
++};
++
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/*
++ * Currently we don't support events, so let's just plan for the
++ * future...
++ */
++
++/*
++ * A Wireless Event.
++ */
++// How do we define short header ? We don't want a flag on length.
++// Probably a flag on event ? Highest bit to zero...
++struct iw_event
++{
++	__u16		length;			/* Lenght of this stuff */
++	__u16		event;			/* Wireless IOCTL */
++	union	iwreq_data	header;		/* IOCTL fixed payload */
++	char		extra[0];		/* Optional IOCTL data */
++};
++
++/* ---------------------- IOCTL DESCRIPTION ---------------------- */
++/*
++ * One of the main goal of the new interface is to deal entirely with
++ * user space/kernel space memory move.
++ * For that, we need to know :
++ *	o if iwreq is a pointer or contain the full data
++ *	o what is the size of the data to copy
++ *
++ * For private IOCTLs, we use the same rules as used by iwpriv and
++ * defined in struct iw_priv_args.
++ *
++ * For standard IOCTLs, things are quite different and we need to
++ * use the stuctures below. Actually, this struct is also more
++ * efficient, but that's another story...
++ */
++
++/*
++ * Describe how a standard IOCTL looks like.
++ */
++struct iw_ioctl_description
++{
++	__u8	header_type;		/* NULL, iw_point or other */
++	__u8	token_type;		/* Future */
++	__u16	token_size;		/* Granularity of payload */
++	__u16	min_tokens;		/* Min acceptable token number */
++	__u16	max_tokens;		/* Max acceptable token number */
++	__u32	flags;			/* Special handling of the request */
++};
++
++/* Need to think of short header translation table. Later. */
++
++/**************************** PROTOTYPES ****************************/
++/*
++ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
++ * Those may be called only within the kernel.
++ */
++
++/* First : function strictly used inside the kernel */
++
++/* Handle /proc/net/wireless, called in net/code/dev.c */
++extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
++				 int length);
++
++/* Handle IOCTLs, called in net/code/dev.c */
++extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
++
++/* Second : functions that may be called by driver modules */
++/* None yet */
++
++#endif	/* _LINUX_WIRELESS_H */
+diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile
+--- linux/net/core-w12/Makefile	Tue Oct 30 15:08:12 2001
++++ linux/net/core/Makefile	Thu Jan 17 11:06:07 2002
+@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d
+ obj-$(CONFIG_NETFILTER) += netfilter.o
+ obj-$(CONFIG_NET_DIVERT) += dv.o
+ obj-$(CONFIG_NET_PROFILE) += profile.o
++obj-$(CONFIG_NET_RADIO) += wireless.o
++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
+ 
+ include $(TOPDIR)/Rules.make
+diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c
+--- linux/net/core-w12/dev.c	Wed Nov  7 14:39:36 2001
++++ linux/net/core/dev.c	Thu Jan 17 11:06:07 2002
+@@ -102,6 +102,7 @@
+ #include <linux/module.h>
+ #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+ #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
++#include <net/iw_handler.h>
+ #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+ #ifdef CONFIG_PLIP
+ extern int plip_init(void);
+@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, 
+ #endif	/* CONFIG_PROC_FS */
+ 
+ 
+-#ifdef WIRELESS_EXT
+-#ifdef CONFIG_PROC_FS
+-
+-/*
+- * Print one entry of /proc/net/wireless
+- * This is a clone of /proc/net/dev (just above)
+- */
+-static int sprintf_wireless_stats(char *buffer, struct net_device *dev)
+-{
+-	/* Get stats from the driver */
+-	struct iw_statistics *stats = (dev->get_wireless_stats ?
+-				       dev->get_wireless_stats(dev) :
+-				       (struct iw_statistics *) NULL);
+-	int size;
+-
+-	if (stats != (struct iw_statistics *) NULL) {
+-		size = sprintf(buffer,
+-			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
+-			       dev->name,
+-			       stats->status,
+-			       stats->qual.qual,
+-			       stats->qual.updated & 1 ? '.' : ' ',
+-			       stats->qual.level,
+-			       stats->qual.updated & 2 ? '.' : ' ',
+-			       stats->qual.noise,
+-			       stats->qual.updated & 4 ? '.' : ' ',
+-			       stats->discard.nwid,
+-			       stats->discard.code,
+-			       stats->discard.fragment,
+-			       stats->discard.retries,
+-			       stats->discard.misc,
+-			       stats->miss.beacon);
+-		stats->qual.updated = 0;
+-	}
+-	else
+-		size = 0;
+-
+-	return size;
+-}
+-
+-/*
+- * Print info for /proc/net/wireless (print all entries)
+- * This is a clone of /proc/net/dev (just above)
+- */
+-static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+-			  int length)
+-{
+-	int		len = 0;
+-	off_t		begin = 0;
+-	off_t		pos = 0;
+-	int		size;
+-	
+-	struct net_device *	dev;
+-
+-	size = sprintf(buffer,
+-		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
+-		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
+-			);
+-	
+-	pos += size;
+-	len += size;
+-
+-	read_lock(&dev_base_lock);
+-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+-		size = sprintf_wireless_stats(buffer + len, dev);
+-		len += size;
+-		pos = begin + len;
+-
+-		if (pos < offset) {
+-			len = 0;
+-			begin = pos;
+-		}
+-		if (pos > offset + length)
+-			break;
+-	}
+-	read_unlock(&dev_base_lock);
+-
+-	*start = buffer + (offset - begin);	/* Start of wanted data */
+-	len -= (offset - begin);		/* Start slop */
+-	if (len > length)
+-		len = length;			/* Ending slop */
+-	if (len < 0)
+-		len = 0;
+-
+-	return len;
+-}
+-#endif	/* CONFIG_PROC_FS */
+-
+-/*
+- *	Allow programatic access to /proc/net/wireless even if /proc
+- *	doesn't exist... Also more efficient...
+- */
+-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
+-{
+-	/* Get stats from the driver */
+-	struct iw_statistics *stats = (dev->get_wireless_stats ?
+-				       dev->get_wireless_stats(dev) :
+-				       (struct iw_statistics *) NULL);
+-
+-	if (stats != (struct iw_statistics *) NULL) {
+-		struct iwreq *	wrq = (struct iwreq *)ifr;
+-
+-		/* Copy statistics to the user buffer */
+-		if(copy_to_user(wrq->u.data.pointer, stats,
+-				sizeof(struct iw_statistics)))
+-			return -EFAULT;
+-
+-		/* Check if we need to clear the update flag */
+-		if(wrq->u.data.flags != 0)
+-			stats->qual.updated = 0;
+-		return(0);
+-	} else
+-		return -EOPNOTSUPP;
+-}
+-#endif	/* WIRELESS_EXT */
+-
+ /**
+  *	netdev_set_master	-	set up master/slave pair
+  *	@slave: slave device
+@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr,
+ 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+ 			return 0;
+ 
+-#ifdef WIRELESS_EXT
+-		case SIOCGIWSTATS:
+-			return dev_iwstats(dev, ifr);
+-#endif	/* WIRELESS_EXT */
+-
+ 		/*
+ 		 *	Unknown or private ioctl
+ 		 */
+@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr,
+ 				return -EOPNOTSUPP;
+ 			}
+ 
+-#ifdef WIRELESS_EXT
+-			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
+-				if (dev->do_ioctl) {
+-					if (!netif_device_present(dev))
+-						return -ENODEV;
+-					return dev->do_ioctl(dev, ifr, cmd);
+-				}
+-				return -EOPNOTSUPP;
+-			}
+-#endif	/* WIRELESS_EXT */
+-
+ 	}
+ 	return -EINVAL;
+ }
+@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar
+ 				}
+ 				dev_load(ifr.ifr_name);
+ 				rtnl_lock();
+-				ret = dev_ifsioc(&ifr, cmd);
++				/* Follow me in net/core/wireless.c */
++				ret = wireless_process_ioctl(&ifr, cmd);
+ 				rtnl_unlock();
+ 				if (!ret && IW_IS_GET(cmd) &&
+ 				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+@@ -2856,6 +2726,7 @@ int __init net_dev_init(void)
+ 	proc_net_create("dev", 0, dev_get_info);
+ 	create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
+ #ifdef WIRELESS_EXT
++	/* Available in net/core/wireless.c */
+ 	proc_net_create("wireless", 0, dev_get_wireless_info);
+ #endif	/* WIRELESS_EXT */
+ #endif	/* CONFIG_PROC_FS */
+diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c
+--- linux/net/core-w12/wireless.c	Wed Dec 31 16:00:00 1969
++++ linux/net/core/wireless.c	Mon Jan 21 11:13:23 2002
+@@ -0,0 +1,733 @@
++/*
++ * This file implement the Wireless Extensions APIs.
++ *
++ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ *
++ * (As all part of the Linux kernel, this file is GPL)
++ */
++
++/************************** DOCUMENTATION **************************/
++/*
++ * API definition :
++ * --------------
++ * See <linux/wireless.h> for details of the APIs and the rest.
++ *
++ * History :
++ * -------
++ *
++ * v1 - 5.12.01 - Jean II
++ *	o Created this file.
++ *
++ * v2 - 13.12.01 - Jean II
++ *	o Move /proc/net/wireless stuff from net/core/dev.c to here
++ *	o Make Wireless Extension IOCTLs go through here
++ *	o Added iw_handler handling ;-)
++ *	o Added standard ioctl description
++ *	o Initial dumb commit strategy based on orinoco.c
++ */
++
++/***************************** INCLUDES *****************************/
++
++#include <asm/uaccess.h>		/* copy_to_user() */
++#include <linux/config.h>		/* Not needed ??? */
++#include <linux/types.h>		/* off_t */
++#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
++
++#include <linux/wireless.h>		/* Pretty obvious */
++#include <net/iw_handler.h>		/* New driver API */
++
++/**************************** CONSTANTS ****************************/
++
++/* This will be turned on later on... */
++#undef WE_STRICT_WRITE		/* Check write buffer size */
++
++/* Debuging stuff */
++#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
++
++/************************* GLOBAL VARIABLES *************************/
++/*
++ * You should not use global variables, because or re-entrancy.
++ * On our case, it's only const, so it's OK...
++ */
++static const struct iw_ioctl_description	standard_ioctl[] = {
++	/* SIOCSIWCOMMIT (internal) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWNAME */
++	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWNWID */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWNWID */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWFREQ */
++	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWFREQ */
++	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWMODE */
++	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWMODE */
++	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWSENS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWSENS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRANGE */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWRANGE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWPRIV */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWPRIV (handled directly by us) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWSTATS */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWSTATS (handled directly by us) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWSPY */
++	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
++	/* SIOCGIWSPY */
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWAP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* SIOCGIWAP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWAPLIST */
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWESSID */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWESSID */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWNICKN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	/* SIOCGIWNICKN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWRATE */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRATE */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRTS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRTS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWFRAG */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWFRAG */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWTXPOW */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWTXPOW */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRETRY */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRETRY */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWENCODE */
++	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
++	/* SIOCGIWENCODE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
++	/* SIOCSIWPOWER */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWPOWER */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++};
++
++/* Size (in bytes) of the various private data types */
++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++
++/************************ COMMON SUBROUTINES ************************/
++/*
++ * Stuff that may be used in various place or doesn't fit in one
++ * of the section below.
++ */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Return the driver handler associated with a specific Wireless Extension.
++ * Called from various place, so make sure it remains efficient.
++ */
++static inline iw_handler get_handler(struct net_device *dev,
++				     unsigned int cmd)
++{
++	unsigned int	index;		/* MUST be unsigned */
++
++	/* Check if we have some wireless handlers defined */
++	if(dev->wireless_handlers == NULL)
++		return NULL;
++
++	/* Try as a standard command */
++	index = cmd - SIOCIWFIRST;
++	if(index < dev->wireless_handlers->num_standard)
++		return dev->wireless_handlers->standard[index];
++
++	/* Try as a private command */
++	index = cmd - SIOCIWFIRSTPRIV;
++	if(index < dev->wireless_handlers->num_private)
++		return dev->wireless_handlers->private[index];
++
++	/* Not found */
++	return NULL;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Get statistics out of the driver
++ */
++static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
++{
++	return (dev->get_wireless_stats ?
++		dev->get_wireless_stats(dev) :
++		(struct iw_statistics *) NULL);
++	/* In the future, get_wireless_stats may move from 'struct net_device'
++	 * to 'struct iw_handler_def', to de-bloat struct net_device.
++	 * Definitely worse a thought... */
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Call the commit handler in the driver
++ * (if exist and if conditions are right)
++ *
++ * Note : our current commit strategy is currently pretty dumb,
++ * but we will be able to improve on that...
++ * The goal is to try to agreagate as many changes as possible
++ * before doing the commit. Drivers that will define a commit handler
++ * are usually those that need a reset after changing parameters, so
++ * we want to minimise the number of reset.
++ * A cool idea is to use a timer : at each "set" command, we re-set the
++ * timer, when the timer eventually fires, we call the driver.
++ * Hopefully, more on that later.
++ *
++ * Also, I'm waiting to see how many people will complain about the
++ * netif_running(dev) test. I'm open on that one...
++ * Hopefully, the driver will remember to do a commit in "open()" ;-)
++ */
++static inline int call_commit_handler(struct net_device *	dev)
++{
++	if((netif_running(dev)) &&
++	   (dev->wireless_handlers->standard[0] != NULL)) {
++		/* Call the commit handler on the driver */
++		return dev->wireless_handlers->standard[0](dev, NULL,
++							   NULL, NULL);
++	} else
++		return 0;		/* Command completed successfully */
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Number of private arguments
++ */
++static inline int get_priv_size(__u16	args)
++{
++	int	num = args & IW_PRIV_SIZE_MASK;
++	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
++
++	return num * priv_type_size[type];
++}
++
++
++/******************** /proc/net/wireless SUPPORT ********************/
++/*
++ * The /proc/net/wireless file is a human readable user-space interface
++ * exporting various wireless specific statistics from the wireless devices.
++ * This is the most popular part of the Wireless Extensions ;-)
++ *
++ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
++ * The content of the file is basically the content of "struct iw_statistics".
++ */
++
++#ifdef CONFIG_PROC_FS
++
++/* ---------------------------------------------------------------- */
++/*
++ * Print one entry (line) of /proc/net/wireless
++ */
++static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
++{
++	/* Get stats from the driver */
++	struct iw_statistics *stats;
++	int size;
++
++	stats = get_wireless_stats(dev);
++	if (stats != (struct iw_statistics *) NULL) {
++		size = sprintf(buffer,
++			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
++			       dev->name,
++			       stats->status,
++			       stats->qual.qual,
++			       stats->qual.updated & 1 ? '.' : ' ',
++			       stats->qual.level,
++			       stats->qual.updated & 2 ? '.' : ' ',
++			       stats->qual.noise,
++			       stats->qual.updated & 4 ? '.' : ' ',
++			       stats->discard.nwid,
++			       stats->discard.code,
++			       stats->discard.fragment,
++			       stats->discard.retries,
++			       stats->discard.misc,
++			       stats->miss.beacon);
++		stats->qual.updated = 0;
++	}
++	else
++		size = 0;
++
++	return size;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Print info for /proc/net/wireless (print all entries)
++ */
++int dev_get_wireless_info(char * buffer, char **start, off_t offset,
++			  int length)
++{
++	int		len = 0;
++	off_t		begin = 0;
++	off_t		pos = 0;
++	int		size;
++	
++	struct net_device *	dev;
++
++	size = sprintf(buffer,
++		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
++		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
++			);
++	
++	pos += size;
++	len += size;
++
++	read_lock(&dev_base_lock);
++	for (dev = dev_base; dev != NULL; dev = dev->next) {
++		size = sprintf_wireless_stats(buffer + len, dev);
++		len += size;
++		pos = begin + len;
++
++		if (pos < offset) {
++			len = 0;
++			begin = pos;
++		}
++		if (pos > offset + length)
++			break;
++	}
++	read_unlock(&dev_base_lock);
++
++	*start = buffer + (offset - begin);	/* Start of wanted data */
++	len -= (offset - begin);		/* Start slop */
++	if (len > length)
++		len = length;			/* Ending slop */
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++#endif	/* CONFIG_PROC_FS */
++
++/************************** IOCTL SUPPORT **************************/
++/*
++ * The original user space API to configure all those Wireless Extensions
++ * is through IOCTLs.
++ * In there, we check if we need to call the new driver API (iw_handler)
++ * or just call the driver ioctl handler.
++ */
++
++/* ---------------------------------------------------------------- */
++/*
++ *	Allow programatic access to /proc/net/wireless even if /proc
++ *	doesn't exist... Also more efficient...
++ */
++static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
++{
++	/* Get stats from the driver */
++	struct iw_statistics *stats;
++
++	stats = get_wireless_stats(dev);
++	if (stats != (struct iw_statistics *) NULL) {
++		struct iwreq *	wrq = (struct iwreq *)ifr;
++
++		/* Copy statistics to the user buffer */
++		if(copy_to_user(wrq->u.data.pointer, stats,
++				sizeof(struct iw_statistics)))
++			return -EFAULT;
++
++		/* Check if we need to clear the update flag */
++		if(wrq->u.data.flags != 0)
++			stats->qual.updated = 0;
++		return 0;
++	} else
++		return -EOPNOTSUPP;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Export the driver private handler definition
++ * They will be picked up by tools like iwpriv...
++ */
++static inline int ioctl_export_private(struct net_device *	dev,
++				       struct ifreq *		ifr)
++{
++	struct iwreq *				iwr = (struct iwreq *) ifr;
++
++	/* Check if the driver has something to export */
++	if((dev->wireless_handlers->num_private_args == 0) ||
++	   (dev->wireless_handlers->private_args == NULL))
++		return -EOPNOTSUPP;
++
++	/* Check NULL pointer */
++	if(iwr->u.data.pointer == NULL)
++		return -EFAULT;
++#ifdef WE_STRICT_WRITE
++	/* Check if there is enough buffer up there */
++	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
++		return -E2BIG;
++#endif	/* WE_STRICT_WRITE */
++
++	/* Set the number of available ioctls. */
++	iwr->u.data.length = dev->wireless_handlers->num_private_args;
++
++	/* Copy structure to the user buffer. */
++	if (copy_to_user(iwr->u.data.pointer,
++			 dev->wireless_handlers->private_args,
++			 sizeof(struct iw_priv_args) * iwr->u.data.length))
++		return -EFAULT;
++
++	return 0;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Wrapper to call a standard Wireless Extension handler.
++ * We do various checks and also take care of moving data between
++ * user space and kernel space.
++ */
++static inline int ioctl_standard_call(struct net_device *	dev,
++				      struct ifreq *		ifr,
++				      unsigned int		cmd,
++				      iw_handler		handler)
++{
++	struct iwreq *				iwr = (struct iwreq *) ifr;
++	const struct iw_ioctl_description *	descr;
++	struct iw_request_info			info;
++	int					ret = -EINVAL;
++
++	/* Get the description of the IOCTL */
++	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
++
++#ifdef WE_IOCTL_DEBUG
++	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
++	       ifr->ifr_name, cmd);
++	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++#endif	/* WE_IOCTL_DEBUG */
++
++	/* Prepare the call */
++	info.cmd = cmd;
++	info.flags = 0;
++
++	/* Check if we have a pointer to user space data or not */
++	if(descr->header_type != IW_HEADER_TYPE_POINT) {
++		/* No extra arguments. Trivial to handle */
++		ret = handler(dev, &info, &(iwr->u), NULL);
++	} else {
++		char *	extra;
++		int	err;
++
++		/* Check what user space is giving us */
++		if(IW_IS_SET(cmd)) {
++			/* Check NULL pointer */
++			if((iwr->u.data.pointer == NULL) &&
++			   (iwr->u.data.length != 0))
++				return -EFAULT;
++			/* Check if number of token fits within bounds */
++			if(iwr->u.data.length > descr->max_tokens)
++				return -E2BIG;
++			if(iwr->u.data.length < descr->min_tokens)
++				return -EINVAL;
++		} else {
++			/* Check NULL pointer */
++			if(iwr->u.data.pointer == NULL)
++				return -EFAULT;
++#ifdef WE_STRICT_WRITE
++			/* Check if there is enough buffer up there */
++			if(iwr->u.data.length < descr->max_tokens)
++				return -E2BIG;
++#endif	/* WE_STRICT_WRITE */
++		}
++
++#ifdef WE_IOCTL_DEBUG
++		printk(KERN_DEBUG "Malloc %d bytes\n",
++		       descr->max_tokens * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++
++		/* Always allocate for max space. Easier, and won't last
++		 * long... */
++		extra = kmalloc(descr->max_tokens * descr->token_size,
++				GFP_KERNEL);
++		if (extra == NULL) {
++			return -ENOMEM;
++		}
++
++		/* If it is a SET, get all the extra data in here */
++		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
++			err = copy_from_user(extra, iwr->u.data.pointer,
++					     iwr->u.data.length *
++					     descr->token_size);
++			if (err) {
++				kfree(extra);
++				return -EFAULT;
++			}
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Got %d bytes\n",
++			       iwr->u.data.length * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Call the handler */
++		ret = handler(dev, &info, &(iwr->u), extra);
++
++		/* If we have something to return to the user */
++		if (!ret && IW_IS_GET(cmd)) {
++			err = copy_to_user(iwr->u.data.pointer, extra,
++					   iwr->u.data.length *
++					   descr->token_size);
++			if (err)
++				ret =  -EFAULT;				   
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Wrote %d bytes\n",
++			       iwr->u.data.length * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Cleanup - I told you it wasn't that long ;-) */
++		kfree(extra);
++	}
++
++	/* Call commit handler if needed and defined */
++	if(ret == -EIWCOMMIT)
++		ret = call_commit_handler(dev);
++
++	/* Here, we will generate the appropriate event if needed */
++
++	return ret;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Wrapper to call a private Wireless Extension handler.
++ * We do various checks and also take care of moving data between
++ * user space and kernel space.
++ * It's not as nice and slimline as the standard wrapper. The cause
++ * is struct iw_priv_args, which was not really designed for the
++ * job we are going here.
++ *
++ * IMPORTANT : This function prevent to set and get data on the same
++ * IOCTL and enforce the SET/GET convention. Not doing it would be
++ * far too hairy...
++ * If you need to set and get data at the same time, please don't use
++ * a iw_handler but process it in your ioctl handler (i.e. use the
++ * old driver API).
++ */
++static inline int ioctl_private_call(struct net_device *	dev,
++				     struct ifreq *		ifr,
++				     unsigned int		cmd,
++				     iw_handler		handler)
++{
++	struct iwreq *			iwr = (struct iwreq *) ifr;
++	struct iw_priv_args *		descr = NULL;
++	struct iw_request_info		info;
++	int				extra_size = 0;
++	int				i;
++	int				ret = -EINVAL;
++
++	/* Get the description of the IOCTL */
++	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
++		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
++			descr = &(dev->wireless_handlers->private_args[i]);
++			break;
++		}
++
++#ifdef WE_IOCTL_DEBUG
++	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
++	       ifr->ifr_name, cmd);
++	if(descr) {
++		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
++		       descr->name, descr->set_args, descr->get_args);
++	}
++#endif	/* WE_IOCTL_DEBUG */
++
++	/* Compute the size of the set/get arguments */
++	if(descr != NULL) {
++		if(IW_IS_SET(cmd)) {
++			/* Size of set arguments */
++			extra_size = get_priv_size(descr->set_args);
++
++			/* Does it fits in iwr ? */
++			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
++			   (extra_size < IFNAMSIZ))
++				extra_size = 0;
++		} else {
++			/* Size of set arguments */
++			extra_size = get_priv_size(descr->get_args);
++
++			/* Does it fits in iwr ? */
++			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
++			   (extra_size < IFNAMSIZ))
++				extra_size = 0;
++		}
++	}
++
++	/* Prepare the call */
++	info.cmd = cmd;
++	info.flags = 0;
++
++	/* Check if we have a pointer to user space data or not. */
++	if(extra_size == 0) {
++		/* No extra arguments. Trivial to handle */
++		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
++	} else {
++		char *	extra;
++		int	err;
++
++		/* Check what user space is giving us */
++		if(IW_IS_SET(cmd)) {
++			/* Check NULL pointer */
++			if((iwr->u.data.pointer == NULL) &&
++			   (iwr->u.data.length != 0))
++				return -EFAULT;
++
++			/* Does it fits within bounds ? */
++			if(iwr->u.data.length > (descr->set_args &
++						 IW_PRIV_SIZE_MASK))
++				return -E2BIG;
++		} else {
++			/* Check NULL pointer */
++			if(iwr->u.data.pointer == NULL)
++				return -EFAULT;
++		}
++
++#ifdef WE_IOCTL_DEBUG
++		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
++#endif	/* WE_IOCTL_DEBUG */
++
++		/* Always allocate for max space. Easier, and won't last
++		 * long... */
++		extra = kmalloc(extra_size, GFP_KERNEL);
++		if (extra == NULL) {
++			return -ENOMEM;
++		}
++
++		/* If it is a SET, get all the extra data in here */
++		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
++			err = copy_from_user(extra, iwr->u.data.pointer,
++					     extra_size);
++			if (err) {
++				kfree(extra);
++				return -EFAULT;
++			}
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Call the handler */
++		ret = handler(dev, &info, &(iwr->u), extra);
++
++		/* If we have something to return to the user */
++		if (!ret && IW_IS_GET(cmd)) {
++			err = copy_to_user(iwr->u.data.pointer, extra,
++					   extra_size);
++			if (err)
++				ret =  -EFAULT;				   
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Wrote %d elem\n",
++			       iwr->u.data.length);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Cleanup - I told you it wasn't that long ;-) */
++		kfree(extra);
++	}
++
++
++	/* Call commit handler if needed and defined */
++	if(ret == -EIWCOMMIT)
++		ret = call_commit_handler(dev);
++
++	return ret;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Main IOCTl dispatcher. Called from the main networking code
++ * (dev_ioctl() in net/core/dev.c).
++ * Check the type of IOCTL and call the appropriate wrapper...
++ */
++int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
++{
++	struct net_device *dev;
++	iw_handler	handler;
++
++	/* Permissions are already checked in dev_ioctl() before calling us.
++	 * The copy_to/from_user() of ifr is also dealt with in there */
++
++	/* Make sure the device exist */
++	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
++		return -ENODEV;
++
++	/* A bunch of special cases, then the generic case...
++	 * Note that 'cmd' is already filtered in dev_ioctl() with
++	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
++	switch(cmd) 
++	{
++		case SIOCGIWSTATS:
++			/* Get Wireless Stats */
++			return dev_iwstats(dev, ifr);
++
++		case SIOCGIWPRIV:
++			/* Check if we have some wireless handlers defined */
++			if(dev->wireless_handlers != NULL) {
++				/* We export to user space the definition of
++				 * the private handler ourselves */
++				return ioctl_export_private(dev, ifr);
++			}
++			// ## Fall-through for old API ##
++		default:
++			/* Generic IOCTL */
++			/* Basic check */
++			if (!netif_device_present(dev))
++				return -ENODEV;
++			/* New driver API : try to find the handler */
++			handler = get_handler(dev, cmd);
++			if(handler != NULL) {
++				/* Standard and private are not the same */
++				if(cmd < SIOCIWFIRSTPRIV)
++					return ioctl_standard_call(dev,
++								   ifr,
++								   cmd,
++								   handler);
++				else
++					return ioctl_private_call(dev,
++								  ifr,
++								  cmd,
++								  handler);
++			}
++			/* Old driver API : call driver ioctl handler */
++			if (dev->do_ioctl) {
++				return dev->do_ioctl(dev, ifr, cmd);
++			}
++			return -EOPNOTSUPP;
++	}
++	/* Not reached */
++	return -EINVAL;
++}
diff --git a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff
index e69de29bb2..539b160068 100644
--- a/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff
+++ b/linux/montavista-sa-2.4.17-mvl21/iw_handlers.w14-5.diff
@@ -0,0 +1,838 @@
+diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h
+--- linux/include/linux-w13/rtnetlink.h	Thu Jun  6 14:44:08 2002
++++ linux/include/linux/rtnetlink.h	Thu Jun  6 15:47:44 2002
+@@ -440,12 +440,14 @@ enum
+ #define IFLA_COST IFLA_COST
+ 	IFLA_PRIORITY,
+ #define IFLA_PRIORITY IFLA_PRIORITY
+-	IFLA_MASTER
++	IFLA_MASTER,
+ #define IFLA_MASTER IFLA_MASTER
++	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
++#define IFLA_WIRELESS IFLA_WIRELESS
+ };
+ 
+ 
+-#define IFLA_MAX IFLA_MASTER
++#define IFLA_MAX IFLA_WIRELESS
+ 
+ #define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+ #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h
+--- linux/include/linux-w13/wireless.h	Thu Jun  6 15:00:28 2002
++++ linux/include/linux/wireless.h	Thu Jun  6 15:47:44 2002
+@@ -1,10 +1,10 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	13	6.12.01
++ * Version :	14	25.1.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _LINUX_WIRELESS_H
+@@ -40,7 +40,7 @@
+  *	# include/linux/netdevice.h (one place)
+  *	# include/linux/proc_fs.h (one place)
+  *
+- * New driver API (2001 -> onward) :
++ * New driver API (2002 -> onward) :
+  * -------------------------------
+  * This file is only concerned with the user space API and common definitions.
+  * The new driver API is defined and documented in :
+@@ -49,6 +49,11 @@
+  * Note as well that /proc/net/wireless implementation has now moved in :
+  *	# include/linux/wireless.c
+  *
++ * Wireless Events (2002 -> onward) :
++ * --------------------------------
++ * Events are defined at the end of this file, and implemented in :
++ *	# include/linux/wireless.c
++ *
+  * Other comments :
+  * --------------
+  * Do not add here things that are redundant with other mechanisms
+@@ -75,7 +80,7 @@
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	13
++#define WIRELESS_EXT	14
+ 
+ /*
+  * Changes :
+@@ -141,6 +146,13 @@
+  *	- Document creation of new driver API.
+  *	- Extract union iwreq_data from struct iwreq (for new driver API).
+  *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
++ *
++ * V13 to V14
++ * ----------
++ *	- Wireless Events support : define struct iw_event
++ *	- Define additional specific event numbers
++ *	- Add "addr" and "param" fields in union iwreq_data
++ *	- AP scanning stuff (SIOCSIWSCAN and friends)
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+@@ -175,6 +187,8 @@
+ #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
+ #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
+ #define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
++#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
++#define SIOCGIWSCAN	0x8B19		/* get scanning results */
+ 
+ /* 802.11 specific support */
+ #define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
+@@ -238,6 +252,15 @@
+ #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
+ #define IW_IS_GET(cmd)	((cmd) & 0x1)
+ 
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/* Those are *NOT* ioctls, do not issue request on them !!! */
++/* Most events use the same identifier as ioctl requests */
++
++#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
++#define IWEVQUAL	0x8C01		/* Quality part of statistics */
++
++#define IWEVFIRST	0x8C00
++
+ /* ------------------------- PRIVATE INFO ------------------------- */
+ /*
+  * The following is used with SIOCGIWPRIV. It allow a driver to define
+@@ -340,6 +363,19 @@
+ #define IW_RETRY_MAX		0x0002	/* Value is a maximum */
+ #define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+ 
++/* Scanning request flags */
++#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
++#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
++#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
++#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
++#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
++#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
++#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
++#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
++#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
++/* Maximum size of returned data */
++#define IW_SCAN_MAX_DATA	4096	/* In bytes */
++
+ /****************************** TYPES ******************************/
+ 
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -466,9 +502,12 @@ union	iwreq_data
+ 
+ 	struct iw_point	encoding;	/* Encoding stuff : tokens */
+ 	struct iw_param	power;		/* PM duration/timeout */
++	struct iw_quality qual;		/* Quality part of statistics */
+ 
+ 	struct sockaddr	ap_addr;	/* Access point address */
++	struct sockaddr	addr;		/* Destination address (hw) */
+ 
++	struct iw_param	param;		/* Other small parameters */
+ 	struct iw_point	data;		/* Other large parameters */
+ };
+ 
+@@ -595,5 +634,36 @@ struct	iw_priv_args
+ 	__u16		get_args;	/* Type and number of args */
+ 	char		name[IFNAMSIZ];	/* Name of the extension */
+ };
++
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/*
++ * Wireless events are carried through the rtnetlink socket to user
++ * space. They are encapsulated in the IFLA_WIRELESS field of
++ * a RTM_NEWLINK message.
++ */
++
++/*
++ * A Wireless Event. Contains basically the same data as the ioctl...
++ */
++struct iw_event
++{
++	__u16		len;			/* Real lenght of this stuff */
++	__u16		cmd;			/* Wireless IOCTL */
++	union iwreq_data	u;		/* IOCTL fixed payload */
++};
++
++/* Size of the Event prefix (including padding and alignement junk) */
++#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
++/* Size of the various events */
++#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
++#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
++#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
++#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point))
++#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
++#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
++#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
++
++/* Note : in the case of iw_point, the extra data will come at the
++ * end of the event */
+ 
+ #endif	/* _LINUX_WIRELESS_H */
+diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h
+--- linux/include/net-w13/iw_handler.h	Thu Jun  6 15:06:16 2002
++++ linux/include/net/iw_handler.h	Thu Jun  6 15:48:06 2002
+@@ -1,10 +1,10 @@
+ /*
+  * This file define the new driver API for Wireless Extensions
+  *
+- * Version :	2	6.12.01
++ * Version :	3	17.1.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _IW_HANDLER_H
+@@ -33,7 +33,7 @@
+  *	o The user space interface is tied to ioctl because of the use
+  *	  copy_to/from_user.
+  *
+- * New driver API (2001 -> onward) :
++ * New driver API (2002 -> onward) :
+  * -------------------------------
+  * The new driver API is just a bunch of standard functions (handlers),
+  * each handling a specific Wireless Extension. The driver just export
+@@ -206,7 +206,18 @@
+  * will be needed...
+  * I just plan to increment with each new version.
+  */
+-#define IW_HANDLER_VERSION	2
++#define IW_HANDLER_VERSION	3
++
++/*
++ * Changes :
++ *
++ * V2 to V3
++ * --------
++ *	- Move event definition in <linux/wireless.h>
++ *	- Add Wireless Event support :
++ *		o wireless_send_event() prototype
++ *		o iwe_stream_add_event/point() inline functions
++ */
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+@@ -225,6 +236,7 @@
+ #define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+ #define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+ #define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
++#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
+ 
+ /* Handling flags */
+ /* Most are not implemented. I just use them as a reminder of some
+@@ -233,7 +245,8 @@
+ /* Wrapper level flags */
+ #define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
+ #define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
+-#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
++#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
++				/* SET : Omit payload from generated iwevent */
+ /* Driver level flags */
+ #define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
+ 
+@@ -303,25 +316,6 @@ struct iw_handler_def
+ 	 * 'struct net_device' to here, to minimise bloat. */
+ };
+ 
+-/* ----------------------- WIRELESS EVENTS ----------------------- */
+-/*
+- * Currently we don't support events, so let's just plan for the
+- * future...
+- */
+-
+-/*
+- * A Wireless Event.
+- */
+-// How do we define short header ? We don't want a flag on length.
+-// Probably a flag on event ? Highest bit to zero...
+-struct iw_event
+-{
+-	__u16		length;			/* Lenght of this stuff */
+-	__u16		event;			/* Wireless IOCTL */
+-	union	iwreq_data	header;		/* IOCTL fixed payload */
+-	char		extra[0];		/* Optional IOCTL data */
+-};
+-
+ /* ---------------------- IOCTL DESCRIPTION ---------------------- */
+ /*
+  * One of the main goal of the new interface is to deal entirely with
+@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * 
+ extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+ 
+ /* Second : functions that may be called by driver modules */
+-/* None yet */
+ 
+-#endif	/* _LINUX_WIRELESS_H */
++/* Send a single event to user space */
++extern void wireless_send_event(struct net_device *	dev,
++				unsigned int		cmd,
++				union iwreq_data *	wrqu,
++				char *			extra);
++
++/* We may need a function to send a stream of events to user space.
++ * More on that later... */
++
++/************************* INLINE FUNTIONS *************************/
++/*
++ * Function that are so simple that it's more efficient inlining them
++ */
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add an Wireless Event to a stream of events.
++ */
++static inline char *
++iwe_stream_add_event(char *	stream,		/* Stream of events */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     int	event_len)	/* Real size of payload */
++{
++	/* Check if it's possible */
++	if((stream + event_len) < ends) {
++		iwe->len = event_len;
++		memcpy(stream, (char *) iwe, event_len);
++		stream += event_len;
++	}
++	return stream;
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add an short Wireless Event containing a pointer to a
++ * stream of events.
++ */
++static inline char *
++iwe_stream_add_point(char *	stream,		/* Stream of events */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     char *	extra)
++{
++	int	event_len = IW_EV_POINT_LEN + iwe->u.data.length;
++	/* Check if it's possible */
++	if((stream + event_len) < ends) {
++		iwe->len = event_len;
++		memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
++		memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
++		stream += event_len;
++	}
++	return stream;
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add a value to a Wireless Event in a stream of events.
++ * Be careful, this one is tricky to use properly :
++ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
++ */
++static inline char *
++iwe_stream_add_value(char *	event,		/* Event in the stream */
++		     char *	value,		/* Value in event */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     int	event_len)	/* Real size of payload */
++{
++	/* Don't duplicate LCP */
++	event_len -= IW_EV_LCP_LEN;
++
++	/* Check if it's possible */
++	if((value + event_len) < ends) {
++		/* Add new value */
++		memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
++		value += event_len;
++		/* Patch LCP */
++		iwe->len = value - event;
++		memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
++	}
++	return value;
++}
++
++#endif	/* _IW_HANDLER_H */
+diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c
+--- linux/net/netsyms-w13.c	Thu Jun  6 15:46:34 2002
++++ linux/net/netsyms.c	Thu Jun  6 15:47:44 2002
+@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf);
+ EXPORT_SYMBOL(net_call_rx_atomic);
+ EXPORT_SYMBOL(softnet_data);
+ 
++#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
++/* Don't include the whole header mess for a single function */
++extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra);
++EXPORT_SYMBOL(wireless_send_event);
++#endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
++
+ #endif  /* CONFIG_NET */
+diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c
+--- linux/net/core/wireless-w13.c	Thu Jun  6 15:46:45 2002
++++ linux/net/core/wireless.c	Thu Jun  6 15:48:06 2002
+@@ -2,7 +2,7 @@
+  * This file implement the Wireless Extensions APIs.
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+  *
+  * (As all part of the Linux kernel, this file is GPL)
+  */
+@@ -25,6 +25,16 @@
+  *	o Added iw_handler handling ;-)
+  *	o Added standard ioctl description
+  *	o Initial dumb commit strategy based on orinoco.c
++ *
++ * v3 - 19.12.01 - Jean II
++ *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
++ *	o Add event dispatcher function
++ *	o Add event description
++ *	o Propagate events as rtnetlink IFLA_WIRELESS option
++ *	o Generate event on selected SET requests
++ *
++ * v4 - 18.04.01 - Jean II
++ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+  */
+ 
+ /***************************** INCLUDES *****************************/
+@@ -33,6 +43,7 @@
+ #include <linux/config.h>		/* Not needed ??? */
+ #include <linux/types.h>		/* off_t */
+ #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
++#include <linux/rtnetlink.h>		/* rtnetlink stuff */
+ 
+ #include <linux/wireless.h>		/* Pretty obvious */
+ #include <net/iw_handler.h>		/* New driver API */
+@@ -44,14 +55,23 @@
+ 
+ /* Debuging stuff */
+ #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
++#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
++
++/* Options */
++#define WE_EVENT_NETLINK	/* Propagate events using rtnetlink */
++#define WE_SET_EVENT		/* Generate an event on some set commands */
+ 
+ /************************* GLOBAL VARIABLES *************************/
+ /*
+  * You should not use global variables, because or re-entrancy.
+  * On our case, it's only const, so it's OK...
+  */
++/*
++ * Meta-data about all the standard Wireless Extension request we
++ * know about.
++ */
+ static const struct iw_ioctl_description	standard_ioctl[] = {
+-	/* SIOCSIWCOMMIT (internal) */
++	/* SIOCSIWCOMMIT */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* SIOCGIWNAME */
+ 	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+@@ -99,18 +119,18 @@ static const struct iw_ioctl_description
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* SIOCGIWAPLIST */
+ 	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
+-	/* -- hole -- */
+-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+-	/* -- hole -- */
+-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWSCAN */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWSCAN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
+ 	/* SIOCSIWESSID */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
+ 	/* SIOCGIWESSID */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
+ 	/* SIOCSIWNICKN */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+ 	/* SIOCGIWNICKN */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+ 	/* -- hole -- */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* -- hole -- */
+@@ -136,7 +156,7 @@ static const struct iw_ioctl_description
+ 	/* SIOCGIWRETRY */
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ 	/* SIOCSIWENCODE */
+-	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+ 	/* SIOCGIWENCODE */
+ 	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
+ 	/* SIOCSIWPOWER */
+@@ -144,9 +164,38 @@ static const struct iw_ioctl_description
+ 	/* SIOCGIWPOWER */
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ };
++static const int standard_ioctl_num = (sizeof(standard_ioctl) /
++				       sizeof(struct iw_ioctl_description));
++
++/*
++ * Meta-data about all the additional standard Wireless Extension events
++ * we know about.
++ */
++static const struct iw_ioctl_description	standard_event[] = {
++	/* IWEVTXDROP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* IWEVQUAL */
++	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
++};
++static const int standard_event_num = (sizeof(standard_event) /
++				       sizeof(struct iw_ioctl_description));
+ 
+ /* Size (in bytes) of the various private data types */
+-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++
++/* Size (in bytes) of various events */
++static const int event_type_size[] = {
++	IW_EV_LCP_LEN,
++	0,
++	IW_EV_CHAR_LEN,
++	0,
++	IW_EV_UINT_LEN,
++	IW_EV_FREQ_LEN,
++	IW_EV_POINT_LEN,		/* Without variable payload */
++	IW_EV_PARAM_LEN,
++	IW_EV_ADDR_LEN,
++	IW_EV_QUAL_LEN,
++};
+ 
+ /************************ COMMON SUBROUTINES ************************/
+ /*
+@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4,
+ static inline iw_handler get_handler(struct net_device *dev,
+ 				     unsigned int cmd)
+ {
+-	unsigned int	index;		/* MUST be unsigned */
++	/* Don't "optimise" the following variable, it will crash */
++	unsigned int	index;		/* *MUST* be unsigned */
+ 
+ 	/* Check if we have some wireless handlers defined */
+ 	if(dev->wireless_handlers == NULL)
+@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats
+ 			       stats->status,
+ 			       stats->qual.qual,
+ 			       stats->qual.updated & 1 ? '.' : ' ',
+-			       stats->qual.level,
++			       ((__u8) stats->qual.level),
+ 			       stats->qual.updated & 2 ? '.' : ' ',
+-			       stats->qual.noise,
++			       ((__u8) stats->qual.noise),
+ 			       stats->qual.updated & 4 ? '.' : ' ',
+ 			       stats->discard.nwid,
+ 			       stats->discard.code,
+@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st
+ 	int					ret = -EINVAL;
+ 
+ 	/* Get the description of the IOCTL */
++	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
++		return -EOPNOTSUPP;
+ 	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+ 
+ #ifdef WE_IOCTL_DEBUG
+-	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
++	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
+ 	       ifr->ifr_name, cmd);
+-	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 	/* Prepare the call */
+@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st
+ 
+ 	/* Check if we have a pointer to user space data or not */
+ 	if(descr->header_type != IW_HEADER_TYPE_POINT) {
++
+ 		/* No extra arguments. Trivial to handle */
+ 		ret = handler(dev, &info, &(iwr->u), NULL);
++
++#ifdef WE_SET_EVENT
++		/* Generate an event to notify listeners of the change */
++		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
++		   ((ret == 0) || (ret == -EIWCOMMIT)))
++			wireless_send_event(dev, cmd, &(iwr->u), NULL);
++#endif	/* WE_SET_EVENT */
+ 	} else {
+ 		char *	extra;
+ 		int	err;
+@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-		printk(KERN_DEBUG "Malloc %d bytes\n",
+-		       descr->max_tokens * descr->token_size);
++		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
++		       dev->name, descr->max_tokens * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 		/* Always allocate for max space. Easier, and won't last
+@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st
+ 				return -EFAULT;
+ 			}
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Got %d bytes\n",
++			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
++			       dev->name,
+ 			       iwr->u.data.length * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st
+ 			if (err)
+ 				ret =  -EFAULT;				   
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Wrote %d bytes\n",
++			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
++			       dev->name,
+ 			       iwr->u.data.length * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
++#ifdef WE_SET_EVENT
++		/* Generate an event to notify listeners of the change */
++		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
++		   ((ret == 0) || (ret == -EIWCOMMIT))) {
++			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
++				/* If the event is restricted, don't
++				 * export the payload */
++				wireless_send_event(dev, cmd, &(iwr->u), NULL);
++			else
++				wireless_send_event(dev, cmd, &(iwr->u),
++						    extra);
++		}
++#endif	/* WE_SET_EVENT */
++
+ 		/* Cleanup - I told you it wasn't that long ;-) */
+ 		kfree(extra);
+ 	}
+@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
++	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
+ 	       ifr->ifr_name, cmd);
+ 	if(descr) {
+-		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
+-		       descr->name, descr->set_args, descr->get_args);
++		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
++		       dev->name, descr->name,
++		       descr->set_args, descr->get_args);
+ 	}
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
++		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
++		       dev->name, extra_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 		/* Always allocate for max space. Easier, and won't last
+@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str
+ 				return -EFAULT;
+ 			}
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
++			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
++			       dev->name, iwr->u.data.length);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
+@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str
+ 			if (err)
+ 				ret =  -EFAULT;				   
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Wrote %d elem\n",
+-			       iwr->u.data.length);
++			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
++			       dev->name, iwr->u.data.length);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
+@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq 
+ 	}
+ 	/* Not reached */
+ 	return -EINVAL;
++}
++
++/************************* EVENT PROCESSING *************************/
++/*
++ * Process events generated by the wireless layer or the driver.
++ * Most often, the event will be propagated through rtnetlink
++ */
++
++#ifdef WE_EVENT_NETLINK
++/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
++ * It is declared in <linux/rtnetlink.h> */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Fill a rtnetlink message with our event data.
++ * Note that we propage only the specified event and don't dump the
++ * current wireless config. Dumping the wireless config is far too
++ * expensive (for each parameter, the driver need to query the hardware).
++ */
++static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
++					struct net_device *	dev,
++					int			type,
++					char *			event,
++					int			event_len)
++{
++	struct ifinfomsg *r;
++	struct nlmsghdr  *nlh;
++	unsigned char	 *b = skb->tail;
++
++	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
++	r = NLMSG_DATA(nlh);
++	r->ifi_family = AF_UNSPEC;
++	r->ifi_type = dev->type;
++	r->ifi_index = dev->ifindex;
++	r->ifi_flags = dev->flags;
++	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
++
++	/* Add the wireless events in the netlink packet */
++	RTA_PUT(skb, IFLA_WIRELESS,
++		event_len, event);
++
++	nlh->nlmsg_len = skb->tail - b;
++	return skb->len;
++
++nlmsg_failure:
++rtattr_failure:
++	skb_trim(skb, b - skb->data);
++	return -1;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Create and broadcast and send it on the standard rtnetlink socket
++ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
++ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
++ * within a RTM_NEWLINK event.
++ */
++static inline void rtmsg_iwinfo(struct net_device *	dev,
++				char *			event,
++				int			event_len)
++{
++	struct sk_buff *skb;
++	int size = NLMSG_GOODSIZE;
++
++	skb = alloc_skb(size, GFP_ATOMIC);
++	if (!skb)
++		return;
++
++	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
++				  event, event_len) < 0) {
++		kfree_skb(skb);
++		return;
++	}
++	NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
++	netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
++}
++#endif	/* WE_EVENT_NETLINK */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Main event dispatcher. Called from other parts and drivers.
++ * Send the event on the apropriate channels.
++ * May be called from interrupt context.
++ */
++void wireless_send_event(struct net_device *	dev,
++			 unsigned int		cmd,
++			 union iwreq_data *	wrqu,
++			 char *			extra)
++{
++	const struct iw_ioctl_description *	descr = NULL;
++	int extra_len = 0;
++	struct iw_event  *event;		/* Mallocated whole event */
++	int event_len;				/* Its size */
++	int hdr_len;				/* Size of the event header */
++	/* Don't "optimise" the following variable, it will crash */
++	unsigned	cmd_index;		/* *MUST* be unsigned */
++
++	/* Get the description of the IOCTL */
++	if(cmd <= SIOCIWLAST) {
++		cmd_index = cmd - SIOCIWFIRST;
++		if(cmd_index < standard_ioctl_num)
++			descr = &(standard_ioctl[cmd_index]);
++	} else {
++		cmd_index = cmd - IWEVFIRST;
++		if(cmd_index < standard_event_num)
++			descr = &(standard_event[cmd_index]);
++	}
++	/* Don't accept unknown events */
++	if(descr == NULL) {
++		/* Note : we don't return an error to the driver, because
++		 * the driver would not know what to do about it. It can't
++		 * return an error to the user, because the event is not
++		 * initiated by a user request.
++		 * The best the driver could do is to log an error message.
++		 * We will do it ourselves instead...
++		 */
++	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
++		       dev->name, cmd);
++		return;
++	}
++#ifdef WE_EVENT_DEBUG
++	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
++	       dev->name, cmd);
++	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++#endif	/* WE_EVENT_DEBUG */
++
++	/* Check extra parameters and set extra_len */
++	if(descr->header_type == IW_HEADER_TYPE_POINT) {
++		/* Check if number of token fits within bounds */
++		if(wrqu->data.length > descr->max_tokens) {
++		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
++			return;
++		}
++		if(wrqu->data.length < descr->min_tokens) {
++		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
++			return;
++		}
++		/* Calculate extra_len - extra is NULL for restricted events */
++		if(extra != NULL)
++			extra_len = wrqu->data.length * descr->token_size;
++#ifdef WE_EVENT_DEBUG
++		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
++#endif	/* WE_EVENT_DEBUG */
++	}
++
++	/* Total length of the event */
++	hdr_len = event_type_size[descr->header_type];
++	event_len = hdr_len + extra_len;
++
++#ifdef WE_EVENT_DEBUG
++	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
++#endif	/* WE_EVENT_DEBUG */
++
++	/* Create temporary buffer to hold the event */
++	event = kmalloc(event_len, GFP_ATOMIC);
++	if(event == NULL)
++		return;
++
++	/* Fill event */
++	event->len = event_len;
++	event->cmd = cmd;
++	memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
++	if(extra != NULL)
++		memcpy(((char *) event) + hdr_len, extra, extra_len);
++
++#ifdef WE_EVENT_NETLINK
++	/* rtnetlink event channel */
++	rtmsg_iwinfo(dev, (char *) event, event_len);
++#endif	/* WE_EVENT_NETLINK */
++
++	/* Cleanup */
++	kfree(event);
++
++	return;		/* Always success, I guess ;-) */
+ }
diff --git a/linux/montavista-sa-2.4.17-mvl21/machine_name.patch b/linux/montavista-sa-2.4.17-mvl21/machine_name.patch
index e69de29bb2..8b7ad2b143 100644
--- a/linux/montavista-sa-2.4.17-mvl21/machine_name.patch
+++ b/linux/montavista-sa-2.4.17-mvl21/machine_name.patch
@@ -0,0 +1,19 @@
+Change the Name showed by /proc/cpuinfo
+
+
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.17_mvl21/arch/arm/mach-sa1100/assabet.c~machine_name
++++ linux-2.4.17_mvl21/arch/arm/mach-sa1100/assabet.c
+@@ -374,7 +374,7 @@
+ }
+ 
+ 
+-MACHINE_START(ASSABET, "Intel-Assabet")
++MACHINE_START(ASSABET, "Tradesquare.NL Tuxpad 1")
+ 	BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ 	BOOT_PARAMS(0xc0000100)
+ 	FIXUP(fixup_assabet)
diff --git a/linux/montavista-sa-2.4.17-mvl21/mkdep.patch b/linux/montavista-sa-2.4.17-mvl21/mkdep.patch
index e69de29bb2..4daeaa11be 100644
--- a/linux/montavista-sa-2.4.17-mvl21/mkdep.patch
+++ b/linux/montavista-sa-2.4.17-mvl21/mkdep.patch
@@ -0,0 +1,16 @@
+
+#
+# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/Makefile~mkdep	2003-12-19 09:36:51.000000000 -0800
++++ linux/Makefile	2003-12-19 09:57:44.000000000 -0800
+@@ -458,7 +458,7 @@
+ 
+ dep-files: scripts/mkdep archdep include/linux/version.h
+ 	scripts/mkdep -- init/*.c > .depend
+-	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
++	$(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)
+ 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
+ ifdef CONFIG_MODVERSIONS
+ 	$(MAKE) update-modverfile
diff --git a/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch b/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch
index e69de29bb2..0fd0a96659 100644
--- a/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch
+++ b/linux/montavista-sa-2.4.17-mvl21/remove-montavista-init-stupidity.patch
@@ -0,0 +1,23 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.17_mvl21/init/main.c~remove-montavista-init-stupidity
++++ linux-2.4.17_mvl21/init/main.c
+@@ -852,15 +852,11 @@
+ 	 * trying to recover a really broken machine.
+ 	 */
+ 
+-#ifndef CONFIG_SA1100_BEAGLE
+ 	if (execute_command)
+ 		execve(execute_command,argv_init,envp_init);
+ 	execve("/sbin/init",argv_init,envp_init);
+ 	execve("/etc/init",argv_init,envp_init);
+ 	execve("/bin/init",argv_init,envp_init);
+-#else
+-	strcpy( argv_init[0], "--login" );
+-#endif
+ 	execve("/bin/sh",argv_init,envp_init);
+ 	panic("No init found.  Try passing init= option to kernel.");
+ }
diff --git a/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch b/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch
index e69de29bb2..77fdfa6846 100644
--- a/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch
+++ b/linux/montavista-sa-2.4.17-mvl21/ucb1x_kill-zombie.patch
@@ -0,0 +1,15 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.17_mvl21/drivers/misc/beagle-ts.c~ucb1x_kill_daemon
++++ linux-2.4.17_mvl21/drivers/misc/beagle-ts.c
+@@ -372,6 +372,7 @@
+     ts->rtask = tsk;
+     
+     daemonize();
++    reparent_to_init();
+     tsk->tty = NULL;
+     //tsk->policy = SCHED_FIFO;
+     //tsk->rt_priority = 1;
diff --git a/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch b/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch
index e69de29bb2..7c3e538e1e 100644
--- a/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch
+++ b/linux/nslu2-linksys-2.4.22/gcc-registerparanoia.patch
@@ -0,0 +1,57 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.22/include/asm-arm/system.h~gcc-registerparanoia	2004-09-08 19:45:34.000000000 -0500
++++ linux-2.4.22/include/asm-arm/system.h	2004-09-08 19:53:01.000000000 -0500
+@@ -3,6 +3,15 @@
+ 
+ #ifdef __KERNEL__
+ 
++/*
++ * This is used to ensure the compiler did actually allocate the register we
++ * asked it for some inline assembly sequences.  Apparently we can't trust
++ * the compiler from one version to another so a bit of paranoia won't hurt.
++ * This string is meant to be concatenated with the inline asm string and
++ * will cause compilation to stop on mismatch.
++ */
++#define __asmeq(x, y)  ".ifnc " x "," y " ; .err ; .endif\n\t"
++
+ #include <linux/config.h>
+ #include <linux/kernel.h>
+ 
+--- linux-2.4.22/include/asm-arm/uaccess.h~gcc-registerparanoia	2004-09-08 19:45:34.000000000 -0500
++++ linux-2.4.22/include/asm-arm/uaccess.h	2004-09-08 19:59:20.000000000 -0500
+@@ -6,6 +6,7 @@
+  */
+ #include <linux/sched.h>
+ #include <asm/errno.h>
++#include <asm/system.h>
+ 
+ #define VERIFY_READ 0
+ #define VERIFY_WRITE 1
+@@ -71,7 +72,9 @@
+ extern int __get_user_bad(void);
+ 
+ #define __get_user_x(__r1,__p,__e,__s,__i...)				\
+-	   __asm__ __volatile__ ("bl	__get_user_" #__s		\
++	   __asm__ __volatile__ (					\
++		__asmeq("%0", "r0") __asmeq("%1", "r1")			\
++		"bl	__get_user_" #__s				\
+ 		: "=&r" (__e), "=r" (__r1)				\
+ 		: "0" (__p)						\
+ 		: __i)
+@@ -110,7 +113,9 @@
+ extern int __put_user_bad(void);
+ 
+ #define __put_user_x(__r1,__p,__e,__s,__i...)				\
+-	   __asm__ __volatile__ ("bl	__put_user_" #__s		\
++	   __asm__ __volatile__ (					\
++		__asmeq("%0", "r0") __asmeq("%2", "r1")			\
++		"bl	__put_user_" #__s				\
+ 		: "=&r" (__e)						\
+ 		: "0" (__p), "r" (__r1)					\
+ 		: __i)
+--- linux-2.4.22/-~gcc-registerparanoia
++++ linux-2.4.22/-
diff --git a/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch b/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch
index e69de29bb2..54726bf740 100644
--- a/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch
+++ b/linux/nslu2-linksys-2.4.22/gcc3-userfuncs.patch
@@ -0,0 +1,134 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.22/arch/arm/lib/getuser.S~gcc3-userfuncs	2004-09-08 19:14:05.000000000 -0500
++++ linux-2.4.22/arch/arm/lib/getuser.S	2004-09-08 19:49:27.000000000 -0500
+@@ -42,17 +42,17 @@
+ 
+ 	.global	__get_user_2
+ __get_user_2:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #2
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #2
++	cmp	r0, ip
+ 2:	ldrlsbt	r1, [r0], #1
+-3:	ldrlsbt	r2, [r0]
++3:	ldrlsbt	ip, [r0]
+ #ifndef __ARMEB__
+-	orrls	r1, r1, r2, lsl #8
++	orrls	r1, r1, ip, lsl #8
+ #else
+-	orrls	r1, r2, r1, lsl #8
++	orrls	r1, ip, r1, lsl #8
+ #endif
+ 	movls	r0, #0
+ 	movls	pc, lr
+--- linux-2.4.22/arch/arm/lib/putuser.S~gcc3-userfuncs	2004-09-08 19:14:05.000000000 -0500
++++ linux-2.4.22/arch/arm/lib/putuser.S	2004-09-08 19:45:00.000000000 -0500
+@@ -18,7 +18,7 @@
+  * Inputs:	r0 contains the address
+  *		r1, r2 contains the value
+  * Outputs:	r0 is the error code
+- *		lr corrupted
++ *		ip, lr corrupted
+  *
+  * No other registers must be altered.  (see include/asm-arm/uaccess.h
+  * for specific ASM register usage).
+@@ -30,11 +30,11 @@
+ 
+ 	.global	__put_user_1
+ __put_user_1:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #1
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #1
++	cmp	r0, ip
+ 1:	strlsbt	r1, [r0]
+ 	movls	r0, #0
+ 	movls	pc, lr
+@@ -42,20 +42,20 @@
+ 
+ 	.global	__put_user_2
+ __put_user_2:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #2
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #2
++	cmp	r0, ip
+ #ifndef __ARMEB__
+ 2:	strlsbt	r1, [r0], #1
+ 	movls	r1, r1, lsr #8
+ 3:	strlsbt	r1, [r0]
+ #else
+-2:	movls	r2, r1
++2:	movls	ip, r1
+ 	movls	r1, r1, lsr #8
+ 	strlsbt r1, [r0], #1
+-	movls	r1, r2
++	movls	r1, ip
+ 3:	strlsbt	r1, [r0]
+ #endif
+ 	movls	r0, #0
+@@ -64,11 +64,11 @@
+ 
+ 	.global	__put_user_4
+ __put_user_4:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #4
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #4
++	cmp	r0, ip
+ 4:	strlst	r1, [r0]
+ 	movls	r0, #0
+ 	movls	pc, lr
+--- linux-2.4.22/include/asm-arm/uaccess.h~gcc3-userfuncs	2004-09-08 19:36:03.000000000 -0500
++++ linux-2.4.22/include/asm-arm/uaccess.h	2004-09-08 20:03:34.000000000 -0500
+@@ -86,7 +86,7 @@
+ 			__get_user_x(__r1, __p, __e, 1, "lr");		\
+ 	       		break;						\
+ 		case 2:							\
+-			__get_user_x(__r1, __p, __e, 2, "r2", "lr");	\
++			__get_user_x(__r1, __p, __e, 2, "ip", "lr");	\
+ 			break;						\
+ 		case 4:							\
+ 	       		__get_user_x(__r1, __p, __e, 4, "lr");		\
+@@ -122,13 +122,13 @@
+ 		register int __e asm("r0");				\
+ 		switch (sizeof(*(p))) {					\
+ 		case 1:							\
+-			__put_user_x(__r1, __p, __e, 1, "r2", "lr");	\
++			__put_user_x(__r1, __p, __e, 1, "ip", "lr");	\
+ 			break;						\
+ 		case 2:							\
+-			__put_user_x(__r1, __p, __e, 2, "r2", "lr");	\
++			__put_user_x(__r1, __p, __e, 2, "ip", "lr");	\
+ 			break;						\
+ 		case 4:							\
+-			__put_user_x(__r1, __p, __e, 4, "r2", "lr");	\
++			__put_user_x(__r1, __p, __e, 4, "ip", "lr");	\
+ 			break;						\
+ 		case 8:							\
+ 			__put_user_x(__r1, __p, __e, 8, "ip", "lr");	\
diff --git a/linux/nslu2-linksys-2.4.22/gl811e.patch b/linux/nslu2-linksys-2.4.22/gl811e.patch
index e69de29bb2..106c329b4c 100644
--- a/linux/nslu2-linksys-2.4.22/gl811e.patch
+++ b/linux/nslu2-linksys-2.4.22/gl811e.patch
@@ -0,0 +1,43 @@
+--- linux-2.4.22/drivers/usb/storage/transport.c	Fri Jul  9 10:56:27 2004
++++ linux-2.4.22/drivers/usb/storage/transport.c	Fri Jul  9 11:51:14 2004
+@@ -1170,6 +1170,12 @@
+ 
+ 	/* if the command transfered well, then we go to the data stage */
+ 	if (result == 0) {
++
++		/* Genesys Logic interface chips need a 100us delay between
++		 * the command phase and the data phase */
++		if (us->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS)
++			udelay(100);
++
+ 		/* send/receive data payload, if there is any */
+ 		if (bcb->DataTransferLength) {
+ 			usb_stor_transfer(srb, us);
+--- linux-2.4.22/drivers/usb/storage/usb.c	Fri Jul  9 11:44:53 2004
++++ linux-2.4.22/drivers/usb/storage/usb.c	Fri Jul  9 11:49:44 2004
+@@ -996,6 +996,15 @@
+ 		 */
+ 		(struct us_data *)ss->htmplt.proc_dir = ss; 
+ 
++		/* According to the technical support people at Genesys Logic,
++		 * devices using their chips have problems transferring more
++		 * than 32 KB at a time.  In practice people have found that
++		 * 64 KB works okay and that's what Windows does.  But we'll
++		 * be conservative.
++		 */
++		if (ss->pusb_dev->descriptor.idVendor == USB_VENDOR_ID_GENESYS)
++			ss->htmplt.max_sectors = 64;
++
+ 		/* Just before we start our control thread, initialize
+ 		 * the device if it needs initialization */
+ 		if (unusual_dev && unusual_dev->initFunction)
+--- linux-2.4.22/drivers/usb/storage/usb.h	Fri Jul  9 10:56:03 2004
++++ linux-2.4.22/drivers/usb/storage/usb.h	Fri Jul  9 11:45:49 2004
+@@ -193,4 +193,7 @@
+ /* Function to fill an inquiry response. See usb.c for details */
+ extern void fill_inquiry_response(struct us_data *us,
+ 	unsigned char *data, unsigned int data_len);
++
++/* Vendor ID list for devices that require special handling */
++#define USB_VENDOR_ID_GENESYS		0x05e3	/* Genesys Logic */
+ #endif
diff --git a/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch b/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch
index e69de29bb2..2afbe66f0a 100644
--- a/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch
+++ b/linux/nslu2-linksys-2.4.22/linksys_can_bite_me.patch
@@ -0,0 +1,34 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.22/drivers/usb/Config.in~linksys_can_bite_me	2004-09-08 19:14:15.000000000 -0500
++++ linux-2.4.22/drivers/usb/Config.in	2004-09-08 19:19:37.000000000 -0500
+@@ -120,6 +120,4 @@
+    fi
+ fi
+ 
+-source drivers/usb/gadget/Config.in
+-
+ endmenu
+--- linux-2.4.22/drivers/ixp400/Makefile~linksys_can_bite_me	2004-09-08 19:14:08.000000000 -0500
++++ linux-2.4.22/drivers/ixp400/Makefile	2004-09-08 19:32:55.000000000 -0500
+@@ -78,7 +78,9 @@
+ # DAMAGE."
+ #
+ # -- End Intel/GPL Copyright Notice --
++#
+ 
++ifdef CONFIG_IXP425_CSR
+ include $(ROOTDIR)/IXP400lib/ixp400_xscale_sw/buildUtils/environment.linux
+ # IX_XSCALE_SW=$(ROOTDIR)/IXP400lib/ixp400_xscale_sw/
+ # The kernel makefiles override the value of CFLAGS on the make
+@@ -148,6 +150,7 @@
+ # directory. Note that they must be filenames in this directory - the
+ # ramdisk rules cannot handle paths in this list.
+ obj-m := $(IXP400_MODULES)
++endif
+ 
+ # Include the generic kernel build system rules
+ include $(TOPDIR)/Rules.make
diff --git a/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch b/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch
index e69de29bb2..bcf1c10335 100644
--- a/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch
+++ b/linux/nslu2-linksys-2.4.22/linux-2.4.24-attribute-used.patch
@@ -0,0 +1,140 @@
+diff -purN linux-2.4.24-uc0.orig/include/asm-arm/setup.h linux-2.4.24-uc0/include/asm-arm/setup.h
+--- linux-2.4.24-uc0.orig/include/asm-arm/setup.h	2003-08-25 04:44:43.000000000 -0700
++++ linux-2.4.24-uc0/include/asm-arm/setup.h	2004-09-09 04:36:03.000000000 -0700
+@@ -236,7 +236,7 @@ struct tagtable {
+ 	int (*parse)(const struct tag *);
+ };
+ 
+-#define __tag __attribute__((unused, __section__(".taglist")))
++#define __tag __attribute_used__ __attribute__((__section__(".taglist")))
+ #define __tagtable(tag, fn) \
+ static struct tagtable __tagtable_##fn __tag = { tag, fn }
+ 
+diff -purN linux-2.4.24-uc0.orig/include/linux/compiler.h linux-2.4.24-uc0/include/linux/compiler.h
+--- linux-2.4.24-uc0.orig/include/linux/compiler.h	2004-03-31 21:52:49.000000000 -0800
++++ linux-2.4.24-uc0/include/linux/compiler.h	2004-09-09 01:33:29.000000000 -0700
+@@ -13,4 +13,18 @@
+ #define likely(x)	__builtin_expect((x),1)
+ #define unlikely(x)	__builtin_expect((x),0)
+ 
++#if __GNUC__ > 3
++#define __attribute_used__     __attribute__((__used__))
++#elif __GNUC__ == 3
++#if  __GNUC_MINOR__ >= 3
++# define __attribute_used__    __attribute__((__used__))
++#else
++# define __attribute_used__    __attribute__((__unused__))
++#endif /* __GNUC_MINOR__ >= 3 */
++#elif __GNUC__ == 2
++#define __attribute_used__     __attribute__((__unused__))
++#else
++#define __attribute_used__     /* not implemented */
++#endif /* __GNUC__ */
++
+ #endif /* __LINUX_COMPILER_H */
+diff -purN linux-2.4.24-uc0.orig/include/linux/init.h linux-2.4.24-uc0/include/linux/init.h
+--- linux-2.4.24-uc0.orig/include/linux/init.h	2004-03-31 21:52:50.000000000 -0800
++++ linux-2.4.24-uc0/include/linux/init.h	2004-09-09 01:38:11.000000000 -0700
+@@ -2,6 +2,7 @@
+ #define _LINUX_INIT_H
+ 
+ #include <linux/config.h>
++#include <linux/compiler.h>
+ 
+ /* These macros are used to mark some functions or 
+  * initialized data (doesn't apply to uninitialized data)
+@@ -51,7 +52,7 @@ typedef void (*exitcall_t)(void);
+ extern initcall_t __initcall_start, __initcall_end;
+ 
+ #define __initcall(fn)								\
+-	static initcall_t __initcall_##fn __init_call = fn
++	static initcall_t __initcall_##fn __attribute_used__ __init_call = fn
+ #define __exitcall(fn)								\
+ 	static exitcall_t __exitcall_##fn __exit_call = fn
+ 
+@@ -67,7 +68,7 @@ extern struct kernel_param __setup_start
+ 
+ #define __setup(str, fn)								\
+ 	static char __setup_str_##fn[] __initdata = str;				\
+-	static struct kernel_param __setup_##fn __attribute__((unused)) __initsetup = { __setup_str_##fn, fn }
++	static struct kernel_param __setup_##fn __attribute_used__ __initsetup = { __setup_str_##fn, fn }
+ 
+ #endif /* __ASSEMBLY__ */
+ 
+@@ -77,16 +78,16 @@ extern struct kernel_param __setup_start
+  */
+ #ifndef NO_TEXT_SECTIONS
+ #define __init		__attribute__ ((__section__ (".text.init")))
+-#define __exit		__attribute__ ((unused, __section__(".text.exit")))
++#define __exit		__attribute_used__ __attribute__ ((__section__(".text.exit")))
+ #else
+ #define __init
+-#define __exit		__attribute__ ((unused))
++#define __exit		__attribute_used__
+ #endif
+ #define __initdata	__attribute__ ((__section__ (".data.init")))
+-#define __exitdata	__attribute__ ((unused, __section__ (".data.exit")))
+-#define __initsetup	__attribute__ ((unused,__section__ (".setup.init")))
+-#define __init_call	__attribute__ ((unused,__section__ (".initcall.init")))
+-#define __exit_call	__attribute__ ((unused,__section__ (".exitcall.exit")))
++#define __exitdata	__attribute_used__ __attribute__ ((__section__ (".data.exit")))
++#define __initsetup	__attribute_used__ __attribute__ ((__section__ (".setup.init")))
++#define __init_call	__attribute_used__ __attribute__ ((__section__ (".initcall.init")))
++#define __exit_call	__attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
+ 
+ /* For assembly routines */
+ #define __INIT		.section	".text.init","ax"
+diff -purN linux-2.4.24-uc0.orig/include/linux/module.h linux-2.4.24-uc0/include/linux/module.h
+--- linux-2.4.24-uc0.orig/include/linux/module.h	2002-08-02 17:39:45.000000000 -0700
++++ linux-2.4.24-uc0/include/linux/module.h	2004-09-09 03:15:30.000000000 -0700
+@@ -8,6 +8,7 @@
+ #define _LINUX_MODULE_H
+ 
+ #include <linux/config.h>
++#include <linux/compiler.h>
+ #include <linux/spinlock.h>
+ #include <linux/list.h>
+ 
+@@ -254,9 +255,9 @@ __attribute__((section(".modinfo"))) =		
+  */
+ #define MODULE_GENERIC_TABLE(gtype,name)	\
+ static const unsigned long __module_##gtype##_size \
+-  __attribute__ ((unused)) = sizeof(struct gtype##_id); \
++  __attribute_used__ = sizeof(struct gtype##_id); \
+ static const struct gtype##_id * __module_##gtype##_table \
+-  __attribute__ ((unused)) = name
++  __attribute_used__ = name
+ 
+ /*
+  * The following license idents are currently accepted as indicating free
+@@ -284,7 +285,7 @@ static const struct gtype##_id * __modul
+  */
+  
+ #define MODULE_LICENSE(license) 	\
+-static const char __module_license[] __attribute__((section(".modinfo"))) =   \
++static const char __module_license[] __attribute_used__ __attribute__((section(".modinfo"))) =   \
+ "license=" license
+ 
+ /* Define the module variable, and usage macros.  */
+@@ -296,10 +297,10 @@ extern struct module __this_module;
+ #define MOD_IN_USE		__MOD_IN_USE(THIS_MODULE)
+ 
+ #include <linux/version.h>
+-static const char __module_kernel_version[] __attribute__((section(".modinfo"))) =
++static const char __module_kernel_version[] __attribute_used__ __attribute__((section(".modinfo"))) =
+ "kernel_version=" UTS_RELEASE;
+ #ifdef MODVERSIONS
+-static const char __module_using_checksums[] __attribute__((section(".modinfo"))) =
++static const char __module_using_checksums[] __attribute_used__ __attribute__((section(".modinfo"))) =
+ "using_checksums=1";
+ #endif
+ 
+@@ -319,7 +320,7 @@ static const char __module_using_checksu
+  */
+ #define MODULE_GENERIC_TABLE(gtype,name) \
+ static const struct gtype##_id * __module_##gtype##_table \
+-  __attribute__ ((unused, __section__(".data.exit"))) = name
++  __attribute_used__ __attribute__ ((__section__(".data.exit"))) = name
+ 
+ #ifndef __GENKSYMS__
+ 
diff --git a/linux/nslu2-linksys-2.4.22/nofpu.patch b/linux/nslu2-linksys-2.4.22/nofpu.patch
index e69de29bb2..c23eceb506 100644
--- a/linux/nslu2-linksys-2.4.22/nofpu.patch
+++ b/linux/nslu2-linksys-2.4.22/nofpu.patch
@@ -0,0 +1,18 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.22/arch/arm/Makefile~nofpu	2004-09-08 19:34:11.000000000 -0500
++++ linux-2.4.22/arch/arm/Makefile	2004-09-08 20:03:34.000000000 -0500
+@@ -76,7 +76,7 @@
+ 
+ CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+ CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+-AFLAGS		+=$(apcs-y) $(arch-y) -mno-fpu -msoft-float
++AFLAGS		+=$(apcs-y) $(arch-y) -msoft-float
+ 
+ ifeq ($(CONFIG_CPU_26),y)
+ PROCESSOR	:= armo
+--- linux-2.4.22/-~nofpu
++++ linux-2.4.22/-
diff --git a/linux/nslu2-linksys-2.4.22/short_loadbytes.patch b/linux/nslu2-linksys-2.4.22/short_loadbytes.patch
index e69de29bb2..f0b514225c 100644
--- a/linux/nslu2-linksys-2.4.22/short_loadbytes.patch
+++ b/linux/nslu2-linksys-2.4.22/short_loadbytes.patch
@@ -0,0 +1,18 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.22/arch/arm/Makefile~short_loadbytes	2004-09-08 19:34:45.000000000 -0500
++++ linux-2.4.22/arch/arm/Makefile	2004-09-08 19:34:53.000000000 -0500
+@@ -74,8 +74,8 @@
+   tune-$(CONFIG_CPU_XSCALE)	:=-mtune=strongarm
+ endif
+ 
+-CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+-CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
++CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) $(call check_gcc,-malignment-traps,-mshort-load-bytes) -msoft-float -Uarm
++CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) $(call check_gcc,-malignment-traps,-mshort-load-bytes) -msoft-float -Uarm
+ AFLAGS		+=$(apcs-y) $(arch-y) -msoft-float
+ 
+ ifeq ($(CONFIG_CPU_26),y)
diff --git a/linux/nslu2-openslug-2.6.7/arm-Makefile.patch b/linux/nslu2-openslug-2.6.7/arm-Makefile.patch
index e69de29bb2..fa059f29cd 100644
--- a/linux/nslu2-openslug-2.6.7/arm-Makefile.patch
+++ b/linux/nslu2-openslug-2.6.7/arm-Makefile.patch
@@ -0,0 +1,13 @@
+--- linux-2.6.7/arch/arm/Makefile.orig	2004-06-15 22:19:13.000000000 -0700
++++ linux-2.6.7/arch/arm/Makefile	2004-09-19 21:47:58.000000000 -0700
+@@ -55,8 +55,8 @@
+ tune-$(CONFIG_CPU_V6)		:=-mtune=strongarm
+ 
+ # Need -Uarm for gcc < 3.x
+-CFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm
+-AFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -msoft-float -Wa,-mno-fpu
++CFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -msoft-float -Uarm
++AFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -msoft-float
+ 
+ #Default value
+ DATAADDR	:= .
diff --git a/linux/nslu2-openslug-2.6.7/arm-timer.patch b/linux/nslu2-openslug-2.6.7/arm-timer.patch
index e69de29bb2..b36df4fe7c 100644
--- a/linux/nslu2-openslug-2.6.7/arm-timer.patch
+++ b/linux/nslu2-openslug-2.6.7/arm-timer.patch
@@ -0,0 +1,17 @@
+--- linux-2.6.7/arch/arm/mach-ixp4xx/common.c.orig	2004-09-26 15:32:52.000000000 -0400
++++ linux-2.6.7/arch/arm/mach-ixp4xx/common.c	2004-09-26 15:33:34.000000000 -0400
+@@ -223,13 +223,7 @@ static irqreturn_t ixp4xx_timer_interrup
+ 	/* Clear Pending Interrupt by writing '1' to it */
+ 	*IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
+ 
+-	/*
+-	 * Catch up with the real idea of time
+-	 */
+-	do {	
+-		do_timer(regs);
+-		last_jiffy_time += LATCH;
+-	} while((*IXP4XX_OSTS - last_jiffy_time) > LATCH);
++	do_timer(regs);
+ 
+ 	return IRQ_HANDLED;
+ }
diff --git a/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch b/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch
index e69de29bb2..31be5fb874 100644
--- a/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch
+++ b/linux/nslu2-openslug-2.6.7/ipx4xx-pci.patch
@@ -0,0 +1,9 @@
+--- linux-2.6.7/arch/arm/mach-ixp4xx/common-pci.c.orig	2004-09-25 04:06:48.000000000 -0400
++++ linux-2.6.7/arch/arm/mach-ixp4xx/common-pci.c	2004-09-25 04:07:31.000000000 -0400
+@@ -540,4 +540,6 @@
+ EXPORT_SYMBOL(pci_set_dma_mask);
+ EXPORT_SYMBOL(pci_dac_set_dma_mask);
+ EXPORT_SYMBOL(pci_set_consistent_dma_mask);
++EXPORT_SYMBOL(ixp4xx_pci_read);
++EXPORT_SYMBOL(ixp4xx_pci_write);
+ 
diff --git a/linux/nslu2-openslug-2.6.7/x1205-rtc.patch b/linux/nslu2-openslug-2.6.7/x1205-rtc.patch
index e69de29bb2..72c2bf91b9 100644
--- a/linux/nslu2-openslug-2.6.7/x1205-rtc.patch
+++ b/linux/nslu2-openslug-2.6.7/x1205-rtc.patch
@@ -0,0 +1,142 @@
+--- drivers/i2c/chips/Kconfig.orig	2004-06-16 01:19:35.000000000 -0400
++++ drivers/i2c/chips/Kconfig	2004-09-22 18:09:48.454794342 -0400
+@@ -240,6 +240,16 @@
+ 	  This driver can also be built as a module.  If so, the module
+ 	  will be called pcf8591.
+ 
++config SENSORS_X1205
++ 	tristate "Xicor X1205 RTC chip"
++ 	depends on I2C && EXPERIMENTAL
++ 	select I2C_SENSOR
++ 	help
++ 	  If you say yes here you get support for the Xicor x1205 RTC chip.
++ 
++ 	  This driver can also be built as a module.  If so, the module
++ 	  will be called x1205-rtc
++
+ config SENSORS_RTC8564
+ 	tristate "Epson 8564 RTC chip"
+ 	depends on I2C && EXPERIMENTA
+--- drivers/i2c/chips/Makefile.old	2004-06-16 01:20:26.000000000 -0400
++++ drivers/i2c/chips/Makefile	2004-09-22 16:48:06.435580334 -0400
+@@ -25,6 +25,7 @@
+ obj-$(CONFIG_SENSORS_RTC8564)	+= rtc8564.o
+ obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
+ obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
++obj-$(CONFIG_SENSORS_X1205)     += x1205-rtc.o
+ 
+ ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
+ EXTRA_CFLAGS += -DDEBUG
+
+--- arch/arm/mach-ixp4xx/ixp425-time.c.old	1969-12-31 19:00:00.000000000 -0500
++++ arch/arm/mach-ixp4xx/ixp425-time.c	2004-09-22 23:30:54.165988077 -0400
+@@ -0,0 +1,87 @@
++/*
++ * arch/arm/mach-ixp425/ixp425-time.c
++ *
++ * Timer tick for IXP425 based sytems. We use OS timer1 on the CPU.
++ *
++ * Author:  Peter Barry
++ * Copyright:   (C) 2001 Intel Corporation.
++ *
++ * Maintainer: Deepak Saxena <dsaxena@mvista.com>
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/time.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <linux/timex.h>
++#include <asm/hardware.h>
++
++
++extern int setup_arm_irq(int, struct irqaction *);
++
++/* IRQs are disabled before entering here from do_gettimeofday() */
++static unsigned long ixp425_gettimeoffset(void)
++{
++	u32 elapsed, usec, curr, reload;
++
++	/* 
++	 * We need elapsed timer ticks since last interrupt
++	 * 
++	 * Read the CCNT value.  The returned value is 
++	 * between -LATCH and 0, 0 corresponding to a full jiffy 
++	 */
++
++	reload = *IXP425_OSRT1 & ~IXP425_OST_RELOAD_MASK;
++	curr = *IXP425_OST1;
++
++	/* Corner case when rolling over as int disabled ?? */
++	elapsed = reload - curr;
++
++	/* Now convert them to usec */
++	usec = (unsigned long)(elapsed * tick) / LATCH;
++
++	return usec;
++}
++
++static void ixp425_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	/* Clear Pending Interrupt by writing '1' to it */
++	*IXP425_OSST = IXP425_OSST_TIMER_1_PEND;
++
++	do_timer(regs);
++}
++
++extern unsigned long (*gettimeoffset)(void);
++
++static struct irqaction timer_irq = {
++	name: "IXP425 Timer 1",
++};
++
++void __init setup_timer(void)
++{
++	gettimeoffset = ixp425_gettimeoffset;
++	timer_irq.handler = ixp425_timer_interrupt;
++
++	/* Clear Pending Interrupt by writing '1' to it */
++	*IXP425_OSST = IXP425_OSST_TIMER_1_PEND;
++
++	/* Setup the Timer counter value */
++	*IXP425_OSRT1 = (LATCH & ~IXP425_OST_RELOAD_MASK) | IXP425_OST_ENABLE;
++
++	/* Connect the interrupt handler and enable the interrupt */
++	setup_arm_irq(IRQ_IXP425_TIMER1, &ixp4xx_timer_irq);
++}
+--- include/linux/i2c-id.h	2004-06-16 01:18:57.000000000 -0400
++++ include/linux/i2c-id.h.new	2004-09-23 00:56:30.772429217 -0400
+@@ -101,7 +101,7 @@
+ #define I2C_DRIVERID_UDA1342	53	/* UDA1342 audio codec		*/
+ #define I2C_DRIVERID_ADV7170	54	/* video encoder		*/
+ #define I2C_DRIVERID_RADEON	55	/* I2C bus on Radeon boards	*/
+-
++#define I2C_DRIVERID_X1205	0xF0	/* Xicor X1205 RTC         	*/
+ 
+ #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
+ #define I2C_DRIVERID_EXP1	0xF1
+--- archold/arm/kernel/time.c	2004-06-16 01:19:43.000000000 -0400
++++ arch/arm/kernel/time.c	2004-10-14 12:28:51.434231567 -0400
+@@ -58,7 +58,7 @@ static int dummy_set_rtc(void)
+  * hook for setting the RTC's idea of the current time.
+  */
+ int (*set_rtc)(void) = dummy_set_rtc;
+-
++EXPORT_SYMBOL(set_rtc);
+ static unsigned long dummy_gettimeoffset(void)
+ {
+ 	return 0;
diff --git a/linux/nslu2-unslung-kernel-2.3r25/able/defconfig b/linux/nslu2-unslung-kernel-2.3r25/able/defconfig
index e69de29bb2..57730349d9 100644
--- a/linux/nslu2-unslung-kernel-2.3r25/able/defconfig
+++ b/linux/nslu2-unslung-kernel-2.3r25/able/defconfig
@@ -0,0 +1,973 @@
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
+# CONFIG_GENERIC_ISA_DMA is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_ADVANCED_OPTIONS is not set
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_KMOD is not set
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP1200 is not set
+# CONFIG_ARCH_IXP2000 is not set
+CONFIG_ARCH_IXP425=y
+# CONFIG_ARCH_OMAHA is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_MX1ADS is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_RISCSTATION is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_AT91RM9200 is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ACCELENT is not set
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_ADSAGC is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_ADSBITSYPLUS is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CEP is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_H3XXX is not set
+# CONFIG_H3600_SLEEVE is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_FRODO is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SIMPUTER is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+# CONFIG_SA1100_SSP is not set
+
+#
+# IXP425 Implementation Options
+#
+CONFIG_ARCH_IXDP425=y
+# CONFIG_ARCH_IXCDP1100 is not set
+# CONFIG_ARCH_PRPMC1100 is not set
+# CONFIG_ARCH_IXP425_COYOTE is not set
+# CONFIG_ARCH_SE4000 is not set
+CONFIG_IXP425_SDRAM_SIZE=32
+# CONFIG_IXP425_LARGE_SDRAM is not set
+CONFIG_IXP425_PCI_ERRATA=y
+# CONFIG_IXP425_OS_TIMER1 is not set
+# CONFIG_XSCALE_PMU_TIMER is not set
+# CONFIG_IXP425_CSR is not set
+
+#
+# AT91RM9200 Implementations
+#
+# CONFIG_ARCH_AT91RM9200DK is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_AUTCPU12 is not set
+# CONFIG_ARCH_CDB89712 is not set
+# CONFIG_ARCH_CLEP7312 is not set
+# CONFIG_ARCH_EDB7211 is not set
+# CONFIG_ARCH_FORTUNET is not set
+# CONFIG_ARCH_GUIDEA07 is not set
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_EP7211 is not set
+# CONFIG_ARCH_EP7212 is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_ARM1026 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+# CONFIG_CPU_32v3 is not set
+# CONFIG_CPU_32v4 is not set
+CONFIG_CPU_32v5=y
+CONFIG_CPU_XSCALE=y
+CONFIG_ARM_THUMB=y
+# CONFIG_XSCALE_PMU_TIMER is not set
+# CONFIG_XSCALE_CACHE_ERRATA is not set
+# CONFIG_XSCALE_BDI2000 is not set
+# CONFIG_DISCONTIGMEM is not set
+CONFIG_CPU_BIG_ENDIAN=y
+
+#
+# General setup
+#
+CONFIG_PCI=y
+CONFIG_PCI_AUTOCONFIG=y
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+CONFIG_KERNEL_START=0xc0000000
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_PCI_NAMES=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/ram0 initrd=0x01000000,10M mem=32M@0x00000000"
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_DRAGONIX is not set
+# CONFIG_MTD_NETtel is not set
+# CONFIG_MTD_SNAPGEODE is not set
+# CONFIG_MTD_NETteluC is not set
+# CONFIG_MTD_MBVANILLA is not set
+# CONFIG_MTD_KeyTechnology is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_CDB89712 is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_EPXA10DB is not set
+# CONFIG_MTD_FORTUNET is not set
+# CONFIG_MTD_AUTCPU12 is not set
+CONFIG_MTD_IXP425=y
+# CONFIG_MTD_IXP425_COYOTE is not set
+# CONFIG_MTD_SE4000 is not set
+# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_IMPA7 is not set
+# CONFIG_MTD_CEIVA is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_PCMCIA is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_CISS_SCSI_TAPE is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=16384
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_BLK_DEV_RAMDISK_DATA is not set
+# CONFIG_BLK_DEV_BLKMEM is not set
+# CONFIG_BLK_STATS is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=m
+CONFIG_BLK_DEV_MD=m
+# CONFIG_MD_LINEAR is not set
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID5=m
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK_DEV is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_FILTER=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_MULTIPATH_SEQUENTIAL is not set
+# CONFIG_IP_ROUTE_TOS is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_ARP_LIMIT is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_INET_ECN is not set
+# CONFIG_SYN_COOKIES is not set
+
+#
+#   IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
+# CONFIG_IP_NF_COMPAT_IPFWADM is not set
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_IPSEC is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_ETHERTAP is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_ARM_AM79C961A is not set
+# CONFIG_ARM_CIRRUS is not set
+# CONFIG_IXP425_ETH is not set
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_LANCE is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_TULIP is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_DGRS is not set
+# CONFIG_DM9102 is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_EEPRO100_PIO is not set
+# CONFIG_E100 is not set
+# CONFIG_LNE390 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_NE3210 is not set
+# CONFIG_ES3210 is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139CP_EXTERNAL_PHY is not set
+CONFIG_8139CP_PHY_NUM=32
+# CONFIG_8139TOO is not set
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_RTL8139 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_SUNDANCE_MMIO is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_VIA_RHINE_FET is not set
+# CONFIG_VIA_RHINE_MMIO is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_NET_POCKET is not set
+# CONFIG_FEC is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_UCCS8900 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# 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_SCSI_DEBUG_QUEUES is not set
+CONFIG_SCSI_MULTI_LUN=n
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_NCR53C8XX is not set
+# CONFIG_SCSI_SYM53C8XX is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_ISP is not set
+# CONFIG_SCSI_QLOGIC_FC is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# IEEE 1394 (FireWire) support (EXPERIMENTAL)
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_PCI is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+
+#
+# Character devices
+#
+# CONFIG_LEDMAN is not set
+# CONFIG_DS1302 is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL=y
+CONFIG_SERIAL_CONSOLE=y
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_ALGOBIT=y
+# CONFIG_I2C_PHILIPSPAR is not set
+# CONFIG_I2C_ELV is not set
+# CONFIG_I2C_VELLEMAN is not set
+# CONFIG_I2C_MCF_GPIO is not set
+CONFIG_I2C_IXP425=y
+# CONFIG_SCx200_I2C is not set
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_ALGOPCF is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_PROC is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+CONFIG_MOUSE=y
+CONFIG_PSMOUSE=y
+# CONFIG_82C710_MOUSE is not set
+# CONFIG_PC110_PAD is not set
+# CONFIG_MK712_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_INPUT_GAMEPORT is not set
+# CONFIG_QIC02_TAPE is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_IPMI_PANIC_EVENT is not set
+# CONFIG_IPMI_DEVICE_INTERFACE is not set
+# CONFIG_IPMI_KCS is not set
+# CONFIG_IPMI_WATCHDOG is not set
+
+#
+# Controller Area Network Cards/Chips
+#
+# CONFIG_CAN4LINUX is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_SCx200_GPIO is not set
+# CONFIG_AMD_PM768 is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_X1226_RTC=m
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BEFS_DEBUG is not set
+# CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+CONFIG_VFAT_FS=y
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+CONFIG_RAMFS=y
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_DMAPI is not set
+# CONFIG_XFS_TRACE is not set
+# CONFIG_XFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+CONFIG_SMB_FS=y
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_ZISOFS_FS is not set
+# CONFIG_COREDUMP_PRINTK is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+CONFIG_OSF_PARTITION=y
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
+CONFIG_SMB_NLS=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_UHCI=y
+# CONFIG_USB_UHCI_ALT is not set
+CONFIG_USB_OHCI=y
+# CONFIG_USB_SL811HS_ALT is not set
+# CONFIG_USB_SL811HS is not set
+# CONFIG_USB_AUDIO is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_BLUETOOTH is not set
+# CONFIG_USB_MIDI is not set
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_HOTPLUG_SCSIDEV_NUMBER is not set
+CONFIG_USB_STORAGE_MAXTOR_ONETOUCH=y
+CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_DEBUG=y
+# CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_USB_EVENT is not set
+CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_PERSO=y
+CONFIG_USB_STORAGE_MAXTOR_ONETOUCH_PERSO_APP_PATH="/sbin/onetouch"
+# 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_HP8200e is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_HID is not set
+# CONFIG_USB_HIDINPUT is not set
+# CONFIG_USB_HIDDEV is not set
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_DC2XX is not set
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_SCANNER is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_HPUSBSCSI is not set
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+CONFIG_USB_KAWETH=m
+CONFIG_USB_CATC=m
+CONFIG_USB_AX8817X=m
+CONFIG_USB_CDCETHER=m
+CONFIG_USB_USBNET=m
+# CONFIG_USB_USS720 is not set
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_TIGL is not set
+# CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_NO_PGT_CACHE is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_ERRORS is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch b/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch
index e69de29bb2..ba4c606d48 100644
--- a/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch
+++ b/linux/nslu2-unslung-kernel-2.3r25/able/missing_usb_ioctls.patch
@@ -0,0 +1,11 @@
+--- linux-2.4.22/include/linux/usbdevice_fs.h.orig	2004-10-31 20:05:45.989296261 +1100
++++ linux-2.4.22/include/linux/usbdevice_fs.h	2004-10-31 22:55:50.470987905 +1100
+@@ -142,6 +142,8 @@
+ #define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
+ #define USBDEVFS_RESET             _IO('U', 20)
+ #define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)
++#define USBDEVFS_DISCONNECT        _IO('U', 22)
++#define USBDEVFS_CONNECT           _IO('U', 23)
+ 
+ /* --------------------------------------------------------------------- */
+ 
diff --git a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch
index e69de29bb2..b61346c62b 100644
--- a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch
+++ b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-ext3flash.patch
@@ -0,0 +1,28 @@
+--- linux-2.4.22/drivers/scsi/scsi_scan.c.orig	2004-09-23 22:26:35.000000000 +0930
++++ linux-2.4.22/drivers/scsi/scsi_scan.c	2004-09-23 22:38:30.000000000 +0930
+@@ -704,6 +704,7 @@
+         /* restrict device on certain port grant */
+ 	SDpnt->host->hostt->removable = SDpnt->removable;
+ 
++#if 0
+         if ( SDpnt->removable && (USB_DEVPATH_1 == SDpnt->host->hostt->port) )
+         {
+ 		create_proc_read_entry("usb_err",
+@@ -729,6 +730,7 @@
+ 				NULL
+ 			);
+ 	}else {
++#endif
+ 		printk("%x port connect!!!!!\n",SDpnt->host->hostt->port);
+ 		if(0x31 == SDpnt->host->hostt->port){
+ 			*IXP425_GPIO_GPOUTR &= 0xfff7;
+@@ -747,7 +749,9 @@
+ 					NULL
+ 			);
+ 		}
++#if 0
+ 	}
++#endif
+ 		//end
+ 	/*
+ 	 * Check the peripheral qualifier field - this tells us whether LUNS
diff --git a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch
index e69de29bb2..d424daf26a 100644
--- a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch
+++ b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel-vfatdisk2.patch
@@ -0,0 +1,45 @@
+--- linux-2.4.22/drivers/scsi/scsi_scan.c.orig	2004-09-23 22:26:35.000000000 +0930
++++ linux-2.4.22/drivers/scsi/scsi_scan.c	2004-09-23 22:43:16.000000000 +0930
+@@ -657,7 +657,7 @@
+         SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+         
+         
+-#if 1 
++#if 0
+ 	if (!SDpnt->removable)
+        {
+ 		unsigned int the_result;
+@@ -704,6 +704,7 @@
+         /* restrict device on certain port grant */
+ 	SDpnt->host->hostt->removable = SDpnt->removable;
+ 
++#if 0
+         if ( SDpnt->removable && (USB_DEVPATH_1 == SDpnt->host->hostt->port) )
+         {
+ 		create_proc_read_entry("usb_err",
+@@ -729,6 +730,7 @@
+ 				NULL
+ 			);
+ 	}else {
++#endif
+ 		printk("%x port connect!!!!!\n",SDpnt->host->hostt->port);
+ 		if(0x31 == SDpnt->host->hostt->port){
+ 			*IXP425_GPIO_GPOUTR &= 0xfff7;
+@@ -740,14 +742,16 @@
+ 			);
+ 		}else{
+ 			*IXP425_GPIO_GPOUTR &= 0xfffb;
+-			create_proc_read_entry("hd2_conn",
++			create_proc_read_entry("usb_conn",
+ 					0,
+ 					NULL,
+ 					NULL,
+ 					NULL
+ 			);
+ 		}
++#if 0
+ 	}
++#endif
+ 		//end
+ 	/*
+ 	 * Check the peripheral qualifier field - this tells us whether LUNS
diff --git a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch
index e69de29bb2..17f78ef785 100644
--- a/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch
+++ b/linux/nslu2-unslung-kernel-2.3r25/unslung-kernel.patch
@@ -0,0 +1,11 @@
+--- linux-2.4.22/drivers/scsi/scsi_scan.c.orig	2004-09-23 22:26:35.000000000 +0930
++++ linux-2.4.22/drivers/scsi/scsi_scan.c	2004-09-23 22:42:09.000000000 +0930
+@@ -694,7 +694,7 @@
+ 					       (buffer[2] << 8) |
+ 					       buffer[3]);
+ 		printk("The capacity is %d\n",capacity);
+-		if(capacity<20000000){
++		if(capacity<2000000){
+ 			SDpnt->removable = 1;
+ 		}
+ 		kfree(buffer);
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch
index e69de29bb2..df59f13544 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2-pxa1.patch
@@ -0,0 +1,39937 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.25/Documentation/Configure.help~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:08.000000000 +0200
++++ linux-2.4.25/Documentation/Configure.help	2004-03-31 17:15:11.000000000 +0200
+@@ -4526,6 +4526,24 @@
+   building a kernel for install/rescue disks or your system is very
+   limited in memory.
+ 
++Kernel Execute-In-Place from ROM
++CONFIG_XIP_KERNEL
++  Execute-In-Place allows the kernel to run directly from 
++  non-volatile storage, such as flash. This saves RAM space since
++  the text section of the kernel is not loaded from flash to
++  RAM.  Read-write sections, such as the data section and stack,
++  are still copied to RAM.  The XIP kernel is not compressed since it
++  has to run directly from flash, so it will take more space to store 
++  it.  The flash address where the kernel is linked to run from and 
++  is stored is board dependent. Therefore, if you say Y, you must 
++  know the proper physical address where to store the kernel image.
++
++  Also note that the make target becomes "make xipImage" rather than
++  "make zImage" or "make Image".  The final kernel binary to put in
++  ROM memory will be arch/arm/boot/xipImage.
++
++  If unsure, say N.
++
+ # Choice: kcore
+ Kernel core (/proc/kcore) format
+ CONFIG_KCORE_ELF
+@@ -13386,6 +13404,30 @@
+ 
+   If you don't know what this all is, saying Y is a safe choice.
+ 
++Workaround for XScale cache errata
++CONFIG_XSCALE_CACHE_ERRATA
++  There are couple errata that say that the cache may get confused
++  whether some cache lines are dirty or not, resulting in some memory
++  corruptions. The workaround (using the cache only in write through
++  mode) is performance impairing, and the bug _might_ just not be
++  that visible or critical to you depending on many esoteric
++  hardware factors.
++  
++  Not using the workaround makes Linux unreliable. If you're used
++  to some other OSes which requires to be rebooted once in a while
++  then this won't look so bad to you. On the other hand you may
++  stress test the system for hours without seeing any effect of this
++  bug.
++  
++  So this is configurable. Let's hope a future core revision will tell
++  this was just a bad dream. But in the mean time the risk and
++  trade-off is yours to decide.
++  
++  This should apply to all PXA250 up to rev B2 (erratum #120) and
++  possibly other current XScale cores as well.
++  
++  If you don't know what to answer, say Y.
++
+ Support CD-ROM drives that are not SCSI or IDE/ATAPI
+ CONFIG_CD_NO_IDESCSI
+   If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y
+@@ -16568,6 +16610,40 @@
+ 
+   If unsure, say N.
+ 
++Use linear addressing for cramfs
++CONFIG_CRAMFS_LINEAR
++  This option tells the cramfs driver to load data directly from a linear
++  adressed memory range (usually non volatile memory like flash) instead
++  of going through the block device layer.  This saves some memory since
++  no intermediate buffering is necessary.
++
++  This is also a prerequisite for XIP of binaries stored on the filesystem.
++
++  The location of the cramfs image in memory is board dependent. Therefore,
++  if you say Y, you must know the proper physical address where to store
++  the cramfs image and specify it using the physaddr=0x******** mount
++  option (for example: "mount -t cramfs -o physaddr=0x100000 none /mnt").
++
++  If unsure, say N.
++
++Support XIP on linear cramfs
++CONFIG_CRAMFS_LINEAR_XIP
++  You must say Y to this option if you want to be able to run applications
++  directly from non-volatile memory.  XIP applications are marked by
++  setting the sticky bit (ie, "chmod +t <app name>").  A cramfs file system
++  then needs to be created using mkcramfs (with XIP cramfs support
++  in it). Applications marked for XIP execution will not be compressed
++  since they have to run directly from flash.
++
++Root file system on linear cramfs
++CONFIG_ROOT_CRAMFS_LINEAR
++  Say Y if you have enabled linear cramfs, and you want to be able to use
++  the linear cramfs image as a root file system.  To actually have the
++  kernel mount this cramfs image as a root file system, you must also pass
++  the command line parameter "root=/dev/null rootflags=physaddr=0x********"
++  to the kernel (replace 0x******** with the physical address location
++  of the linear cramfs image to boot with).
++
+ CMS file system support
+ CONFIG_CMS_FS
+   Read only support for CMS minidisk file systems found on IBM
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/arm/XScale/PXA/USB-client	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,38 @@
++Date: Wed, 05 Jun 2002 13:38:53 -0700
++From: Frank Becker <fbecker@intrinsyc.com>
++To: Nicolas Pitre <nico@cam.org>
++Subject: [PATCH] PXA-USB
++
++Hi Nicolas,
++
++one more patch...
++
++This patch adds minimal USB client (UDC) support.
++
++Some notes:
++It adds just enough to get usb-eth working. I.e.
++endpoints 0-2, no dma. Performance isn't stellar
++partially due to UDC bug workarounds...
++(~350K @ 100Mhz, ~550K @ 200Mhz).
++
++Endpoint 1&2 have changed direction compared to
++the SA, so the host side requires a change to
++usbnet.c to flip endpoints (in:2/out:1 -> in:1/out:2).
++
++usb-eth and usb-char for PXA are almost identical
++to the SA versions, so they could probably be merged at
++one point. I made some minor changes to the eth driver
++to grab the usb resources at open, rather than at init
++and allow eth&char to be loaded at the same time.
++
++Stuart Lynne was working on his own USB client driver
++(and he was getting higher throughput than my driver).
++Assuming you guys have something in the oven for USB
++as well, there should be good selection for best of
++breed :)
++
++Cheers,
++Frank.
++-- 
++Frank Becker - Intrinsyc Software, Inc. - http://www.intrinsyc.com/
++Need a break? http://criticalmass.sf.net/
+--- linux-2.4.25/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:08.000000000 +0200
++++ linux-2.4.25/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -1,11 +1,13 @@
+ VERSION = 2
+ PATCHLEVEL = 4
+ SUBLEVEL = 25
+-EXTRAVERSION =-vrs2
++EXTRAVERSION =-vrs2-pxa1
+ 
+ KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+ 
+-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
++#ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
++ARCH := arm
++
+ KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g")
+ 
+ CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \
+@@ -19,7 +21,7 @@
+ HOSTCC  	= gcc
+ HOSTCFLAGS	= -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer
+ 
+-CROSS_COMPILE 	=
++CROSS_COMPILE 	= arm-linux-
+ 
+ #
+ # Include the make variables (CC, etc...)
+@@ -168,6 +170,7 @@
+ DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o
+ DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
+ DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
++DRIVERS-$(CONFIG_MMC) += drivers/mmc/mmcdrivers.o
+ DRIVERS-$(CONFIG_PCMCIA) += drivers/pcmcia/pcmcia.o
+ DRIVERS-$(CONFIG_NET_PCMCIA) += drivers/net/pcmcia/pcmcia_net.o
+ DRIVERS-$(CONFIG_NET_WIRELESS) += drivers/net/wireless/wireless_net.o
+--- linux-2.4.25/arch/arm/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:08.000000000 +0200
++++ linux-2.4.25/arch/arm/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -13,10 +13,11 @@
+ CFLAGS		+=-Uarm -fno-common -pipe
+ 
+ ifeq ($(CONFIG_FRAME_POINTER),y)
+-CFLAGS		:=$(CFLAGS:-fomit-frame-pointer=-mapcs -mno-sched-prolog)
++CFLAGS		:=$(CFLAGS:-fomit-frame-pointer=)
++CFLAGS		+=-fno-omit-frame-pointer -mapcs -mno-sched-prolog
+ endif
+ 
+-CFLAGS		:=$(CFLAGS:-O2=-Os)
++#CFLAGS		:=$(CFLAGS:-O2=-Os)
+ 
+ ifeq ($(CONFIG_DEBUG_INFO),y)
+ CFLAGS		+=-g
+@@ -38,6 +39,8 @@
+ arch-$(CONFIG_CPU_32v3)		:=-D__LINUX_ARM_ARCH__=3 -march=armv3
+ arch-$(CONFIG_CPU_32v4)		:=-D__LINUX_ARM_ARCH__=4 -march=armv4
+ arch-$(CONFIG_CPU_32v5)		:=-D__LINUX_ARM_ARCH__=5 -march=armv5
++#arch-$(CONFIG_CPU_XSCALE)	:=-D__LINUX_ARM_ARCH__=5 -mcpu=xscale
++arch-$(CONFIG_CPU_XSCALE)	:=-D__LINUX_ARM_ARCH__=5 -march=armv4 -Wa,-mcpu=xscale
+ 
+ # This selects how we optimise for the processor.
+ tune-y				:=
+@@ -49,6 +52,8 @@
+ tune-$(CONFIG_CPU_ARM926T)	:=-mtune=arm9tdmi
+ tune-$(CONFIG_CPU_SA110)	:=-mtune=strongarm110
+ tune-$(CONFIG_CPU_SA1100)	:=-mtune=strongarm1100
++tune-$(CONFIG_CPU_XSCALE)	:=-mtune=xscale
++#tune-$(CONFIG_CPU_XSCALE)	:=-mtune=strongarm
+ 
+ CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+ CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+@@ -127,6 +132,10 @@
+ MACHINE		 = sa1100
+ endif
+ 
++ifeq ($(CONFIG_ARCH_PXA),y)
++MACHINE		 = pxa
++endif
++
+ ifeq ($(CONFIG_ARCH_L7200),y)
+ MACHINE		 = l7200
+ endif
+@@ -164,6 +173,17 @@
+ MACHINE                = omaha
+ endif
+ 
++ifeq ($(CONFIG_XIP_KERNEL),y) 
++  DATAADDR   := $(TEXTADDR)
++  # Replace phys addr with virt addr while keeping offset from base.
++  # Virt base addr also defined in include/asm-arm/arch-*/hardware.h
++  TEXTADDR    = $(shell echo 0x`echo $(CONFIG_XIP_PHYS_ADDR)|sed -e's/^0x//'` |\
++			awk --non-decimal-data '/[:xdigit:]/ \
++			  {printf("0x%x\n",and($$0,0x001fffff)+0xe8000000)}' )
++  LDSCRIPT    = arch/arm/vmlinux-armv-xip.lds.in
++  export DATAADDR
++endif
++
+ export	MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT OBJCOPYFLAGS
+ 
+ # Only set INCDIR if its not already defined above
+@@ -269,7 +289,7 @@
+ arch/arm/kernel arch/arm/mm arch/arm/lib: dummy
+ 	$(MAKE) CFLAGS="$(CFLAGS) $(CFLAGS_KERNEL)" $(subst $@, _dir_$@, $@)
+ 
+-bzImage zImage zinstall Image bootpImage install: vmlinux
++bzImage zImage zinstall Image xipImage bootpImage install: vmlinux
+ 	@$(MAKEBOOT) $@
+ 
+ CLEAN_FILES	+= \
+--- linux-2.4.25/arch/arm/boot/Makefile~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/boot/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -113,6 +113,10 @@
+ endif
+ endif
+ 
++ifeq ($(CONFIG_ARCH_PXA),y)
++ZRELADDR	 = 0xa0008000
++endif
++
+ ifeq ($(CONFIG_ARCH_ANAKIN),y)
+ ZRELADDR	 = 0x20008000
+ endif
+@@ -140,6 +144,14 @@
+ zImage:	compressed/vmlinux
+ 	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+ 
++ifeq ($(CONFIG_XIP_KERNEL),y)
++xipImage: $(CONFIGURE) $(SYSTEM)
++	$(OBJCOPY) -S -O binary -R .data $(SYSTEM) vmlinux-text.bin
++	$(OBJCOPY) -S -O binary -R .init -R .text -R __ex_table -R __ksymtab $(SYSTEM) vmlinux-data.bin
++	cat vmlinux-text.bin vmlinux-data.bin > $@
++	$(RM) -f vmlinux-text.bin vmlinux-data.bin
++endif
++
+ bootpImage: bootp/bootp
+ 	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
+ 
+@@ -160,7 +172,7 @@
+ 	sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
+ 
+ clean:
+-	$(RM) Image zImage bootpImage
++	$(RM) Image xipImage zImage bootpImage
+ 	@$(MAKE) -C compressed clean
+ 	@$(MAKE) -C bootp clean
+ 
+--- linux-2.4.25/arch/arm/boot/compressed/Makefile~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/boot/compressed/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -71,6 +71,10 @@
+ OBJS		+= head-sa1100.o
+ endif
+ 
++ifeq ($(CONFIG_CPU_XSCALE),y)
++OBJS		+= head-xscale.o
++endif
++
+ SEDFLAGS	= s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/
+ 
+ LIBGCC		:= $(shell $(CC) $(CFLAGS) --print-libgcc-file-name)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/boot/compressed/head-xscale.S	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,50 @@
++/* 
++ * linux/arch/arm/boot/compressed/head-xscale.S
++ * 
++ * XScale specific tweaks.  This is merged into head.S by the linker.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <asm/mach-types.h>
++
++		.section        ".start", #alloc, #execinstr
++
++__XScale_start:
++
++		@ Preserve r8/r7 i.e. kernel entry values
++
++		@ Data cache might be active.
++		@ Be sure to flush kernel binary out of the cache,
++		@ whatever state it is, before it is turned off.
++		@ This is done by fetching through currently executed
++		@ memory to be sure we hit the same cache.
++		bic	r2, pc, #0x1f
++		add	r3, r2, #0x10000	@ 64 kb is quite enough...
++1:		ldr	r0, [r2], #32
++		teq	r2, r3
++		bne	1b
++		mcr	p15, 0, r0, c7, c10, 4	@ drain WB
++		mcr	p15, 0, r0, c7, c7, 0	@ flush I & D caches
++
++		@ disabling MMU and caches
++		mrc	p15, 0, r0, c1, c0, 0	@ read control reg
++		bic	r0, r0, #0x05		@ clear DC, MMU
++		bic	r0, r0, #0x1000		@ clear Icache
++		mcr	p15, 0, r0, c1, c0, 0
++
++#ifdef CONFIG_ARCH_LUBBOCK
++		mov	r7, #MACH_TYPE_LUBBOCK
++#endif
++
++#ifdef CONFIG_ARCH_PXA_IDP
++		mov	r7, #MACH_TYPE_PXA_IDP
++#endif
++
++#ifdef CONFIG_ARCH_TRIZEPS2
++		mov	r7, #(MACH_TYPE_TRIZEPS2 & 0xFF00)
++		add	r7, r7, #(MACH_TYPE_TRIZEPS2 & 0xFF)
++#endif
++
++
+--- linux-2.4.25/arch/arm/boot/compressed/head.S~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:08.000000000 +0200
++++ linux-2.4.25/arch/arm/boot/compressed/head.S	2004-03-31 17:15:11.000000000 +0200
+@@ -351,7 +351,11 @@
+ 		orr	r1, r1, #3 << 10
+ 		add	r2, r3, #16384
+ 1:		cmp	r1, r8			@ if virt > start of RAM
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++		orrhs	r1, r1, #0x08           @ set cacheable, not bufferable
++#else
+ 		orrhs	r1, r1, #0x0c		@ set cacheable, bufferable
++#endif
+ 		cmp	r1, r9			@ if virt > end of RAM
+ 		bichs	r1, r1, #0x0c		@ clear cacheable, bufferable
+ 		str	r1, [r0], #4		@ 1:1 mapping
+@@ -364,7 +368,11 @@
+  * so there is no map overlap problem for up to 1 MB compressed kernel.
+  * If the execution is in RAM then we would only be duplicating the above.
+  */
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++		mov	r1, #0x1a
++#else
+ 		mov	r1, #0x1e
++#endif
+ 		orr	r1, r1, #3 << 10
+ 		mov	r2, pc, lsr #20
+ 		orr	r1, r1, r2, lsl #20
+--- linux-2.4.25/arch/arm/config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:08.000000000 +0200
++++ linux-2.4.25/arch/arm/config.in	2004-03-31 17:15:11.000000000 +0200
+@@ -38,6 +38,7 @@
+ 	 Cirrus-CL-PS7500FE     CONFIG_ARCH_CLPS7500 \
+  	 CLPS711x/EP721x-based	CONFIG_ARCH_CLPS711X \
+ 	 Co-EBSA285		CONFIG_ARCH_CO285 \
++	 PXA250/210-based	CONFIG_ARCH_PXA \
+ 	 EBSA-110		CONFIG_ARCH_EBSA110 \
+  	 Excalibur-ARM          CONFIG_ARCH_CAMELOT \
+ 	 FootBridge		CONFIG_ARCH_FOOTBRIDGE \
+@@ -148,6 +149,47 @@
+ endmenu
+ 
+ mainmenu_option next_comment
++comment 'Intel PXA250/210 Implementations'
++dep_bool '  Intel DBPXA250 Development Platform' CONFIG_ARCH_LUBBOCK $CONFIG_ARCH_PXA
++dep_bool '  Accelent Xscale IDP' CONFIG_ARCH_PXA_IDP $CONFIG_ARCH_PXA
++dep_bool '  Intrinsyc CerfBoard' CONFIG_ARCH_PXA_CERF $CONFIG_ARCH_PXA
++dep_bool '  Trizeps-II MT6N' CONFIG_ARCH_TRIZEPS2 $CONFIG_ARCH_PXA
++
++if [ "$CONFIG_ARCH_PXA_CERF" = "y" ]; then
++   define_bool CONFIG_PXA_CERF y
++
++   choice 'CerfBoard Style' \
++      "PDA   CONFIG_PXA_CERF_PDA \
++       BOARD CONFIG_PXA_CERF_BOARD" PDA
++
++   choice 'CerfBoard RAM Available' \
++      "128MB  CONFIG_PXA_CERF_RAM_128MB \
++        64MB  CONFIG_PXA_CERF_RAM_64MB \
++        32MB  CONFIG_PXA_CERF_RAM_32MB \
++        16MB  CONFIG_PXA_CERF_RAM_16MB" 64MB
++
++   choice 'CerfBoard Flash Available' \
++      "64MB  CONFIG_PXA_CERF_FLASH_64MB \
++       32MB  CONFIG_PXA_CERF_FLASH_32MB \
++       16MB  CONFIG_PXA_CERF_FLASH_16MB \
++        8MB  CONFIG_PXA_CERF_FLASH_8MB" 32MB
++fi
++
++if [ "$CONFIG_ARCH_LUBBOCK" = "y" ]; then
++   define_bool CONFIG_SA1111 y
++fi
++
++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then
++   define_bool CONFIG_TRIZEPS2 y
++fi
++
++dep_tristate 'PXA USB function support' CONFIG_PXA_USB $CONFIG_ARCH_PXA
++dep_tristate '  Support for PXA USB network link function' CONFIG_PXA_USB_NETLINK $CONFIG_PXA_USB
++dep_tristate '  Support for PXA USB character device emulation' CONFIG_PXA_USB_CHAR $CONFIG_PXA_USB
++
++endmenu
++
++mainmenu_option next_comment
+ comment 'CLPS711X/EP721X Implementations'
+ dep_bool '  AUTCPU12' CONFIG_ARCH_AUTCPU12 $CONFIG_ARCH_CLPS711X
+ dep_bool '  CDB89712' CONFIG_ARCH_CDB89712 $CONFIG_ARCH_CLPS711X
+@@ -385,6 +427,12 @@
+    define_bool CONFIG_CPU_SA1100 n
+ fi
+ 
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++   define_bool CONFIG_CPU_32v5 y
++   define_bool CONFIG_CPU_XSCALE y
++   bool 'Workaround for XScale cache errata (see help)' CONFIG_XSCALE_CACHE_ERRATA
++fi
++
+ # Figure out what processor architecture version we should be using.
+ # This defines the compiler instruction set which depends on the machine type.
+ 
+@@ -493,6 +541,7 @@
+ hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0
+ 
+ if [ "$CONFIG_ARCH_SA1100" = "y" -o \
++     "$CONFIG_ARCH_PXA" = "y" -o \
+      "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+    dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL
+ fi
+@@ -501,8 +550,10 @@
+ bool 'Support for hot-pluggable devices' CONFIG_HOTPLUG
+ if [ "$CONFIG_HOTPLUG" = "y" ]; then
+    source drivers/pcmcia/Config.in
++   source drivers/mmc/Config.in
+ else
+    define_bool CONFIG_PCMCIA n
++   define_bool CONFIG_MMC n
+ fi
+ if [ "$CONFIG_SA1100_ACCELENT" = "y" ]; then
+    if [ "$CONFIG_PCMCIA" != "n" ]; then
+@@ -513,6 +564,14 @@
+ bool 'System V IPC' CONFIG_SYSVIPC
+ bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT
+ bool 'Sysctl support' CONFIG_SYSCTL
++
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++    dep_bool 'Kernel Execute-In-Place from ROM (EXPERIMENTAL)' CONFIG_XIP_KERNEL $CONFIG_EXPERIMENTAL
++    if [ "$CONFIG_XIP_KERNEL" = "y" ]; then
++        hex '  Kernel .text physical address' CONFIG_XIP_PHYS_ADDR 0
++    fi    
++fi   
++
+ comment 'At least one math emulation must be selected'
+ tristate 'NWFPE math emulation' CONFIG_FPE_NWFPE
+ if [ "$CONFIG_FPE_NWFPE" != "n" ]; then
+@@ -538,6 +597,9 @@
+      "$CONFIG_ARCH_SHARK" = "y" -o      \
+      "$CONFIG_ARCH_CO285" = "y" -o      \
+      "$CONFIG_ARCH_SA1100" = "y" -o     \
++     "$CONFIG_ARCH_LUBBOCK" = "y" -o    \
++     "$CONFIG_ARCH_PXA_IDP" = "y" -o \
++     "$CONFIG_ARCH_PXA_CERF" = "y" -o \
+      "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+      "$CONFIG_ARCH_CDB89712" = "y" -o   \
+      "$CONFIG_ARCH_P720T" = "y" -o	\
+@@ -549,8 +611,12 @@
+ 	   "$CONFIG_ARCH_SHARK" = "y" -o      \
+ 	   "$CONFIG_ARCH_CO285" = "y" -o      \
+ 	   "$CONFIG_ARCH_SA1100" = "y" -o     \
++           "$CONFIG_ARCH_LUBBOCK" = "y" -o    \
+            "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+ 	   "$CONFIG_ARCH_P720T" = "y" -o      \
++           "$CONFIG_ARCH_LUBBOCK" = "y" -o    \
++	   "$CONFIG_ARCH_PXA_CERF" = "y" -o   \
++	   "$CONFIG_ARCH_PXA_IDP" = "y" -o   \
+ 	   "$CONFIG_ARCH_OMAHA" = "y" ]; then
+          bool '  Timer LED' CONFIG_LEDS_TIMER
+          bool '  CPU usage LED' CONFIG_LEDS_CPU
+@@ -684,6 +750,7 @@
+    if [ "$CONFIG_FOOTBRIDGE_HOST" = "y" -o \
+         "$CONFIG_ARCH_SHARK" = "y" -o      \
+         "$CONFIG_ARCH_SA1100" = "y" -o     \
++        "$CONFIG_ARCH_PXA" = "y" -o        \
+         "$CONFIG_ARCH_INTEGRATOR" = "y" -o \
+         "$CONFIG_ARCH_TBOX" = "y" -o       \
+         "$CONFIG_ARCH_CLPS7500" = "y" -o   \
+@@ -705,6 +772,7 @@
+      "$CONFIG_ARCH_TBOX" = "y" -o \
+      "$CONFIG_ARCH_SHARK" = "y" -o \
+      "$CONFIG_ARCH_SA1100" = "y" -o \
++     "$CONFIG_ARCH_PXA" = "y" -o \
+      "$CONFIG_PCI" = "y" ]; then
+    mainmenu_option next_comment
+    comment 'Sound'
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/cerfboard_pxa	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,857 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_IDP is not set
++CONFIG_ARCH_PXA_CERF=y
++CONFIG_PXA_CERF=y
++# CONFIG_PXA_CERF_PDA is not set
++CONFIG_PXA_CERF_BOARD=y
++# CONFIG_PXA_CERF_RAM_128MB is not set
++CONFIG_PXA_CERF_RAM_64MB=y
++# CONFIG_PXA_CERF_RAM_32MB is not set
++# CONFIG_PXA_CERF_RAM_16MB is not set
++# CONFIG_PXA_CERF_FLASH_64MB is not set
++CONFIG_PXA_CERF_FLASH_32MB=y
++# CONFIG_PXA_CERF_FLASH_16MB is not set
++# CONFIG_PXA_CERF_FLASH_8MB is not set
++CONFIG_PXA_USB=y
++CONFIG_PXA_USB_NETLINK=y
++CONFIG_PXA_USB_CHAR=m
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++CONFIG_XSCALE_CACHE_ERRATA=y
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_CPU_FREQ=y
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc"
++CONFIG_LEDS=y
++# CONFIG_LEDS_TIMER is not set
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++# CONFIG_MTD_CFI_B2 is not set
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++# CONFIG_MTD_CFI_I1 is not set
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++CONFIG_MTD_PXA_CERF=y
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++CONFIG_BLK_DEV_LOOP=m
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++CONFIG_FILTER=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++CONFIG_PPP=m
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++# CONFIG_PPP_SYNC_TTY is not set
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPPOE is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++CONFIG_PCMCIA_3C589=m
++CONFIG_PCMCIA_3C574=m
++CONFIG_PCMCIA_FMVJ18X=m
++CONFIG_PCMCIA_PCNET=m
++CONFIG_PCMCIA_AXNET=m
++CONFIG_PCMCIA_NMCLAN=m
++CONFIG_PCMCIA_SMC91C92=m
++CONFIG_PCMCIA_XIRC2PS=m
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++CONFIG_NET_PCMCIA_RADIO=y
++CONFIG_PCMCIA_RAYCS=m
++CONFIG_PCMCIA_NETWAVE=m
++CONFIG_PCMCIA_WAVELAN=m
++CONFIG_AIRONET4500_CS=m
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# 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
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++CONFIG_I2C_PXA_ALGO=y
++CONFIG_I2C_PXA_ADAP=y
++# CONFIG_I2C_CHARDEV is not set
++# CONFIG_I2C_PROC is not set
++# CONFIG_I2C_DS1307 is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++CONFIG_WATCHDOG=y
++# CONFIG_WATCHDOG_NOWAYOUT is not set
++# CONFIG_ACQUIRE_WDT is not set
++# CONFIG_ADVANTECH_WDT is not set
++# CONFIG_ALIM7101_WDT is not set
++# CONFIG_SC520_WDT is not set
++# CONFIG_PCWATCHDOG is not set
++# CONFIG_21285_WATCHDOG is not set
++# CONFIG_977_WATCHDOG is not set
++# CONFIG_SA1100_WATCHDOG is not set
++CONFIG_PXA_WATCHDOG=m
++# CONFIG_OMAHA_WATCHDOG is not set
++# CONFIG_EUROTECH_WDT is not set
++# CONFIG_IB700_WDT is not set
++# CONFIG_WAFER_WDT is not set
++# CONFIG_I810_TCO is not set
++# CONFIG_MIXCOMWD is not set
++# CONFIG_60XX_WDT is not set
++# CONFIG_SC1200_WDT is not set
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_W83877F_WDT is not set
++# CONFIG_WDT is not set
++# CONFIG_WDTPCI is not set
++# CONFIG_MACHZ_WDT is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++CONFIG_PCMCIA_SERIAL_CS=y
++CONFIG_PCMCIA_CHRDEV=y
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_UMSDOS_FS=m
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++CONFIG_ROMFS_FS=y
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++CONFIG_NLS_CODEPAGE_863=m
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++# CONFIG_FB is not set
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++# CONFIG_MCP_UCB1400_TS is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/cerfpda_pxa	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,962 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_IDP is not set
++CONFIG_ARCH_PXA_CERF=y
++CONFIG_PXA_CERF=y
++CONFIG_PXA_CERF_PDA=y
++# CONFIG_PXA_CERF_BOARD is not set
++# CONFIG_PXA_CERF_RAM_128MB is not set
++CONFIG_PXA_CERF_RAM_64MB=y
++# CONFIG_PXA_CERF_RAM_32MB is not set
++# CONFIG_PXA_CERF_RAM_16MB is not set
++# CONFIG_PXA_CERF_FLASH_64MB is not set
++CONFIG_PXA_CERF_FLASH_32MB=y
++# CONFIG_PXA_CERF_FLASH_16MB is not set
++# CONFIG_PXA_CERF_FLASH_8MB is not set
++CONFIG_PXA_USB=y
++CONFIG_PXA_USB_NETLINK=y
++CONFIG_PXA_USB_CHAR=y
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_ARM_THUMB is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++CONFIG_BSD_PROCESS_ACCT=y
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=1f03 rw console=tty0 console=ttyS0,38400 init=/linuxrc"
++CONFIG_LEDS=y
++# CONFIG_LEDS_TIMER is not set
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++# CONFIG_MTD_CFI_B2 is not set
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++# CONFIG_MTD_CFI_I1 is not set
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++CONFIG_MTD_PXA_CERF=y
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++CONFIG_BLK_DEV_LOOP=m
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++CONFIG_FILTER=y
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++CONFIG_IP_PNP_RARP=y
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++CONFIG_PPP=m
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++# CONFIG_PPP_SYNC_TTY is not set
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPPOE is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++CONFIG_PCMCIA_3C589=m
++CONFIG_PCMCIA_3C574=m
++CONFIG_PCMCIA_FMVJ18X=m
++CONFIG_PCMCIA_PCNET=m
++CONFIG_PCMCIA_AXNET=m
++CONFIG_PCMCIA_NMCLAN=m
++CONFIG_PCMCIA_SMC91C92=m
++CONFIG_PCMCIA_XIRC2PS=m
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++# CONFIG_NET_PCMCIA_RADIO is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++CONFIG_IRDA=y
++CONFIG_IRLAN=y
++# CONFIG_IRNET is not set
++CONFIG_IRCOMM=y
++CONFIG_IRDA_ULTRA=y
++# CONFIG_IRDA_CACHE_LAST_LSAP is not set
++# CONFIG_IRDA_FAST_RR is not set
++CONFIG_IRDA_DEBUG=y
++
++#
++# Infrared-port device drivers
++#
++CONFIG_IRTTY_SIR=y
++# CONFIG_IRPORT_SIR is not set
++# CONFIG_DONGLE is not set
++# CONFIG_USB_IRDA is not set
++# CONFIG_NSC_FIR is not set
++# CONFIG_WINBOND_FIR is not set
++# CONFIG_TOSHIBA_FIR is not set
++# CONFIG_SMC_IRCC_FIR is not set
++# CONFIG_ALI_FIR is not set
++# CONFIG_VLSI_FIR is not set
++
++#
++# ATA/IDE/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# 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_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_VT_CONSOLE=y
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_INTEL_RNG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++CONFIG_PCMCIA_SERIAL_CS=y
++CONFIG_PCMCIA_CHRDEV=y
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_UMSDOS_FS=m
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=m
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++CONFIG_ROMFS_FS=y
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=m
++CONFIG_NLS_CODEPAGE_852=m
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++CONFIG_NLS_CODEPAGE_863=m
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=m
++CONFIG_NLS_ISO8859_2=m
++CONFIG_NLS_ISO8859_3=m
++CONFIG_NLS_ISO8859_4=m
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_PXA_8BPP is not set
++CONFIG_FB_PXA_16BPP=y
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FBCON_ADVANCED is not set
++CONFIG_FBCON_CFB2=y
++CONFIG_FBCON_CFB4=y
++CONFIG_FBCON_CFB8=y
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
++CONFIG_FBCON_FONTS=y
++# CONFIG_FONT_8x8 is not set
++# CONFIG_FONT_8x16 is not set
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++CONFIG_FONT_ACORN_8x8=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=y
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++# CONFIG_USB_UHCI is not set
++# CONFIG_USB_UHCI_ALT is not set
++# CONFIG_USB_OHCI is not set
++# CONFIG_USB_OHCI_SA1111 is not set
++# CONFIG_USB_AUDIO is not set
++# CONFIG_USB_BLUETOOTH is not set
++# CONFIG_USB_STORAGE is not set
++# 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_HP8200e is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_HID is not set
++# CONFIG_USB_HIDDEV is not set
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_DC2XX is not set
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_SCANNER is not set
++# CONFIG_USB_MICROTEK is not set
++# CONFIG_USB_HPUSBSCSI is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_CDCETHER is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_USS720 is not set
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++# CONFIG_USB_SERIAL_GENERIC is not set
++# CONFIG_USB_SERIAL_BELKIN is not set
++# CONFIG_USB_SERIAL_WHITEHEAT is not set
++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
++# CONFIG_USB_SERIAL_EMPEG is not set
++# CONFIG_USB_SERIAL_FTDI_SIO is not set
++# CONFIG_USB_SERIAL_VISOR is not set
++# CONFIG_USB_SERIAL_IPAQ is not set
++# CONFIG_USB_SERIAL_IR is not set
++# CONFIG_USB_SERIAL_EDGEPORT is not set
++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
++# CONFIG_USB_SERIAL_KEYSPAN is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
++# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
++# CONFIG_USB_SERIAL_MCT_U232 is not set
++# CONFIG_USB_SERIAL_KLSI is not set
++# CONFIG_USB_SERIAL_PL2303 is not set
++# CONFIG_USB_SERIAL_CYBERJACK is not set
++# CONFIG_USB_SERIAL_XIRCOM is not set
++# CONFIG_USB_SERIAL_OMNINET is not set
++# CONFIG_USB_RIO500 is not set
++
++#
++# Bluetooth support
++#
++CONFIG_BLUEZ=y
++CONFIG_BLUEZ_L2CAP=y
++
++#
++# Bluetooth device drivers
++#
++# CONFIG_BLUEZ_HCIUSB is not set
++CONFIG_BLUEZ_HCIUART=y
++CONFIG_BLUEZ_HCIVHCI=y
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/csb226	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,615 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_AT91RM9200DK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_HACKKIT is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Board
++#
++# CONFIG_ARCH_PXA_IDP is not set
++# CONFIG_ARCH_INNOKOM is not set
++CONFIG_ARCH_CSB226=y
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_CERF is not set
++# CONFIG_PXA_USB is not set
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++CONFIG_XSCALE_CACHE_ERRATA=y
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++# CONFIG_CPU_FREQ is not set
++# CONFIG_HOTPLUG is not set
++# CONFIG_PCMCIA is not set
++# CONFIG_MMC is not set
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++# CONFIG_XIP_KERNEL is not set
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="console=ttyS0,19200"
++CONFIG_ALIGNMENT_TRAP=y
++CONFIG_ARM_HWTIMER=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++# CONFIG_MTD is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++CONFIG_ARM_CIRRUS=y
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_HD is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++# CONFIG_FAT_FS is not set
++# CONFIG_MSDOS_FS is not set
++# CONFIG_UMSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_EXT2_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++# CONFIG_NFS_V3 is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++# CONFIG_MSDOS_PARTITION is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_SMB_NLS is not set
++# CONFIG_NLS is not set
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++# CONFIG_MCP_UCB1400_TS is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SLAB=y
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_WAITQ=y
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/innokom	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,699 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_AT91RM9200DK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_HACKKIT is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Board
++#
++# CONFIG_ARCH_PXA_IDP is not set
++CONFIG_ARCH_INNOKOM=y
++# CONFIG_ARCH_CSB226 is not set
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_CERF is not set
++# CONFIG_PXA_USB is not set
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++CONFIG_XSCALE_CACHE_ERRATA=y
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++# CONFIG_CPU_FREQ is not set
++# CONFIG_HOTPLUG is not set
++# CONFIG_PCMCIA is not set
++# CONFIG_MMC is not set
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++# CONFIG_XIP_KERNEL is not set
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/nfs mem=32M ip=dhcp console=ttyS0,19200"
++CONFIG_ALIGNMENT_TRAP=y
++CONFIG_ARM_HWTIMER=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_CFI_INTELEXT=y
++CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_FORTUNET is not set
++CONFIG_MTD_INNOKOM=y
++CONFIG_MTD_INNOKOM_16MB=y
++# CONFIG_MTD_INNOKOM_64MB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_CEIVA is not set
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++# CONFIG_IP_PNP_BOOTP is not set
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++CONFIG_SMC91X=y
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_HD is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++CONFIG_I2C_PXA_ALGO=y
++CONFIG_I2C_PXA_ADAP=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_PROC=y
++# CONFIG_I2C_DS1307 is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++# CONFIG_FAT_FS is not set
++# CONFIG_MSDOS_FS is not set
++# CONFIG_UMSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_JFFS2_FS_NAND is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_EXT2_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++# CONFIG_MSDOS_PARTITION is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_SMB_NLS is not set
++# CONFIG_NLS is not set
++
++#
++# Sound
++#
++# CONFIG_SOUND is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++# CONFIG_MCP_UCB1400_TS is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SLAB=y
++CONFIG_MAGIC_SYSRQ=y
++CONFIG_DEBUG_SPINLOCK=y
++CONFIG_DEBUG_WAITQ=y
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/lubbock	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,971 @@
++#
++# Automatically generated make config: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++# CONFIG_KMOD is not set
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_AT91RM9200 is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++
++#
++# Archimedes/A5000 Implementations (select only ONE)
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSAGC is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_ADSBITSYPLUS is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_H3600_SLEEVE is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_HACKKIT is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_SA1100_SSP is not set
++
++#
++# AT91RM9200 Implementations
++#
++# CONFIG_ARCH_AT91RM9200DK is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++CONFIG_ARCH_LUBBOCK=y
++# CONFIG_ARCH_PXA_IDP is not set
++# CONFIG_ARCH_PXA_CERF is not set
++# CONFIG_ARCH_TRIZEPS2 is not set
++CONFIG_SA1111=y
++# CONFIG_PXA_USB is not set
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_GUIDEA07 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++
++#
++# Processor Features
++#
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_CPU_FREQ=y
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++
++#
++# MMC device drivers
++#
++CONFIG_MMC=m
++CONFIG_MMC_PXA=m
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_PARTITIONS=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++# CONFIG_XIP_KERNEL is not set
++
++#
++# At least one math emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++CONFIG_PM=y
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/nfs ip=bootp console=ttyS0,115200 mem=32M"
++CONFIG_LEDS=y
++CONFIG_LEDS_TIMER=y
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++CONFIG_MTD_CFI_B2=y
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++CONFIG_MTD_LUBBOCK=y
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++# CONFIG_MTD_EPXA is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_CEIVA is not set
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_BLK_STATS is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++
++#
++#  
++#
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++CONFIG_SMC91X=y
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++# CONFIG_PCMCIA_3C589 is not set
++# CONFIG_PCMCIA_3C574 is not set
++# CONFIG_PCMCIA_FMVJ18X is not set
++CONFIG_PCMCIA_PCNET=y
++# CONFIG_PCMCIA_AXNET is not set
++# CONFIG_PCMCIA_NMCLAN is not set
++# CONFIG_PCMCIA_SMC91C92 is not set
++# CONFIG_PCMCIA_XIRC2PS is not set
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++# CONFIG_NET_PCMCIA_RADIO is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++CONFIG_BLK_DEV_IDECS=y
++# 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_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++CONFIG_BLK_DEV_IDE_MODES=y
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++# CONFIG_BLK_DEV_ATARAID_SII is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_MX1TS is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_AT91 is not set
++# CONFIG_SERIAL_AT91_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++
++#
++# Other L3 adapters
++#
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++CONFIG_BUSMOUSE=y
++# CONFIG_ATIXL_BUSMOUSE is not set
++# CONFIG_LOGIBUSMOUSE is not set
++# CONFIG_MS_BUSMOUSE is not set
++CONFIG_MOUSE=y
++CONFIG_PSMOUSE=y
++# CONFIG_82C710_MOUSE is not set
++# CONFIG_PC110_PAD is not set
++# CONFIG_MK712_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_IPMI_PANIC_EVENT is not set
++# CONFIG_IPMI_DEVICE_INTERFACE is not set
++# CONFIG_IPMI_KCS is not set
++# CONFIG_IPMI_WATCHDOG is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++CONFIG_PXA_RTC=y
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++# CONFIG_PCMCIA_SERIAL_CS is not set
++# CONFIG_SYNCLINK_CS is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++# CONFIG_UMSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++# CONFIG_CRAMFS_LINEAR is not set
++# CONFIG_CRAMFS_LINEAR_XIP is not set
++# CONFIG_ROOT_CRAMFS_LINEAR is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++# CONFIG_NFS_V3 is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++# CONFIG_FB_DBMX1 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_PXA_8BPP is not set
++CONFIG_FB_PXA_16BPP=y
++# CONFIG_FB_PXA_QVGA is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FBCON_ADVANCED is not set
++CONFIG_FBCON_CFB2=y
++CONFIG_FBCON_CFB4=y
++CONFIG_FBCON_CFB8=y
++CONFIG_FBCON_CFB16=y
++CONFIG_FBCON_FONTWIDTH8_ONLY=y
++# CONFIG_FBCON_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_ALI5455 is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_FORTE is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_VIDC is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=y
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
++
++#
++# Library routines
++#
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/pxa_idp	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,933 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++CONFIG_ARCH_PXA_IDP=y
++# CONFIG_ARCH_PXA_CERF is not set
++CONFIG_PXA_USB=m
++CONFIG_PXA_USB_NETLINK=m
++CONFIG_PXA_USB_CHAR=m
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++CONFIG_PM=y
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/mtdblock2 init=/linuxrc console=ttyS0,115200"
++CONFIG_LEDS=y
++CONFIG_LEDS_TIMER=y
++CONFIG_LEDS_CPU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++CONFIG_MTD_CFI_ADV_OPTIONS=y
++CONFIG_MTD_CFI_NOSWAP=y
++# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
++# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
++CONFIG_MTD_CFI_GEOMETRY=y
++# CONFIG_MTD_CFI_B1 is not set
++# CONFIG_MTD_CFI_B2 is not set
++CONFIG_MTD_CFI_B4=y
++# CONFIG_MTD_CFI_B8 is not set
++# CONFIG_MTD_CFI_I1 is not set
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++CONFIG_MTD_LUBBOCK=y
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++# CONFIG_MTD_PXA_CERF is not set
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++CONFIG_ASI_MTD0_SIZE=40000
++CONFIG_ASI_MTD1_SIZE=100000
++CONFIG_ASI_MTD2_SIZE=1e00000
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=4096
++CONFIG_BLK_DEV_INITRD=y
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++# CONFIG_IP_PNP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++# CONFIG_SMC9194 is not set
++CONFIG_SMC91111=m
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++CONFIG_NET_POCKET=y
++# CONFIG_DE600 is not set
++# CONFIG_DE620 is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++# CONFIG_STRIP is not set
++CONFIG_WAVELAN=m
++# CONFIG_ARLAN is not set
++CONFIG_AIRONET4500=y
++# CONFIG_AIRONET4500_NONCS is not set
++# CONFIG_AIRONET4500_PROC is not set
++CONFIG_HERMES=m
++CONFIG_PCMCIA_HERMES=m
++CONFIG_AIRO_CS=m
++CONFIG_NET_WIRELESS=y
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++# CONFIG_PCMCIA_3C589 is not set
++# CONFIG_PCMCIA_3C574 is not set
++# CONFIG_PCMCIA_FMVJ18X is not set
++CONFIG_PCMCIA_PCNET=m
++# CONFIG_PCMCIA_AXNET is not set
++CONFIG_PCMCIA_NMCLAN=m
++CONFIG_PCMCIA_SMC91C92=m
++CONFIG_PCMCIA_XIRC2PS=m
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++CONFIG_NET_PCMCIA_RADIO=y
++CONFIG_PCMCIA_RAYCS=m
++CONFIG_PCMCIA_NETWAVE=m
++CONFIG_PCMCIA_WAVELAN=m
++CONFIG_AIRONET4500_CS=m
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++CONFIG_IRDA=m
++CONFIG_IRLAN=m
++# CONFIG_IRNET is not set
++CONFIG_IRCOMM=m
++CONFIG_IRDA_ULTRA=y
++# CONFIG_IRDA_CACHE_LAST_LSAP is not set
++# CONFIG_IRDA_FAST_RR is not set
++CONFIG_IRDA_DEBUG=y
++
++#
++# Infrared-port device drivers
++#
++CONFIG_IRTTY_SIR=m
++# CONFIG_IRPORT_SIR is not set
++# CONFIG_DONGLE is not set
++# CONFIG_USB_IRDA is not set
++# CONFIG_NSC_FIR is not set
++# CONFIG_WINBOND_FIR is not set
++# CONFIG_TOSHIBA_FIR is not set
++# CONFIG_SMC_IRCC_FIR is not set
++# CONFIG_ALI_FIR is not set
++# CONFIG_VLSI_FIR is not set
++CONFIG_PXA_FIR=m
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=y
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=y
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# 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
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++CONFIG_INPUT=y
++CONFIG_INPUT_KEYBDEV=m
++CONFIG_INPUT_MOUSEDEV=m
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++# CONFIG_IDP_KEYB is not set
++CONFIG_MATRIX_KEYBOARD=y
++# CONFIG_SA1111_PS2_KEYB is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++# CONFIG_I2C is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++CONFIG_BUSMOUSE=y
++# CONFIG_ATIXL_BUSMOUSE is not set
++# CONFIG_LOGIBUSMOUSE is not set
++# CONFIG_MS_BUSMOUSE is not set
++CONFIG_MOUSE=y
++CONFIG_PSMOUSE=y
++# CONFIG_82C710_MOUSE is not set
++# CONFIG_PC110_PAD is not set
++# CONFIG_MK712_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_INPUT_NS558 is not set
++# CONFIG_INPUT_LIGHTNING is not set
++# CONFIG_INPUT_PCIGAME is not set
++# CONFIG_INPUT_CS461X is not set
++# CONFIG_INPUT_EMU10K1 is not set
++# CONFIG_INPUT_SERIO is not set
++# CONFIG_INPUT_SERPORT is not set
++# CONFIG_INPUT_ANALOG is not set
++# CONFIG_INPUT_A3D is not set
++# CONFIG_INPUT_ADI is not set
++# CONFIG_INPUT_COBRA is not set
++# CONFIG_INPUT_GF2K is not set
++# CONFIG_INPUT_GRIP is not set
++# CONFIG_INPUT_INTERACT is not set
++# CONFIG_INPUT_TMDC is not set
++# CONFIG_INPUT_SIDEWINDER is not set
++# CONFIG_INPUT_IFORCE_USB is not set
++# CONFIG_INPUT_IFORCE_232 is not set
++# CONFIG_INPUT_WARRIOR is not set
++# CONFIG_INPUT_MAGELLAN is not set
++# CONFIG_INPUT_SPACEORB is not set
++# CONFIG_INPUT_SPACEBALL is not set
++# CONFIG_INPUT_STINGER is not set
++# CONFIG_INPUT_DB9 is not set
++# CONFIG_INPUT_GAMECON is not set
++# CONFIG_INPUT_TURBOGRAFX is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_PXA_RTC is not set
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++CONFIG_PCMCIA_SERIAL_CS=m
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=m
++CONFIG_JBD=m
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++# CONFIG_UMSDOS_FS is not set
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_CRAMFS=y
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++CONFIG_ZLIB_FS_INFLATE=y
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FBCON_ADVANCED is not set
++CONFIG_FBCON_CFB2=y
++CONFIG_FBCON_CFB4=y
++CONFIG_FBCON_CFB8=y
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
++# CONFIG_FBCON_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=m
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++CONFIG_DEBUG_SLAB=y
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++# CONFIG_DEBUG_LL is not set
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/trizeps2	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,873 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++CONFIG_ARCH_PXA=y
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_H3600_SLEEVE is not set
++
++#
++# Intel PXA250/210 Implementations
++#
++# CONFIG_ARCH_LUBBOCK is not set
++# CONFIG_ARCH_PXA_IDP is not set
++# CONFIG_ARCH_PXA_CERF is not set
++CONFIG_ARCH_TRIZEPS2=y
++CONFIG_TRIZEPS2=y
++CONFIG_PXA_USB=y
++# CONFIG_PXA_USB_NETLINK is not set
++# CONFIG_PXA_USB_CHAR is not set
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++# CONFIG_CPU_ARM920T is not set
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_PLD is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++CONFIG_CPU_32v5=y
++CONFIG_CPU_XSCALE=y
++# CONFIG_XSCALE_CACHE_ERRATA is not set
++# CONFIG_CPU_32v3 is not set
++# CONFIG_CPU_32v4 is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++CONFIG_HOTPLUG=y
++
++#
++# PCMCIA/CardBus support
++#
++CONFIG_PCMCIA=y
++# CONFIG_I82092 is not set
++# CONFIG_I82365 is not set
++# CONFIG_TCIC is not set
++# CONFIG_PCMCIA_CLPS6700 is not set
++# CONFIG_PCMCIA_SA1100 is not set
++CONFIG_PCMCIA_PXA=y
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="root=/dev/mtdblock3 rw console=ttyS0,38400 mem=32M noinitrd init=/linuxrc"
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_REDBOOT_PARTS=y
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_PHYSMAP is not set
++# CONFIG_MTD_LUBBOCK is not set
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++# CONFIG_MTD_PXA_CERF is not set
++# CONFIG_MTD_EPXA10DB is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++CONFIG_MTD_TRIZEPS2=y
++# CONFIG_MTD_PCI is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++# CONFIG_MTD_NAND is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_BLK_DEV_INITRD is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++# CONFIG_PACKET is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++# CONFIG_IP_PNP_DHCP is not set
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++CONFIG_NET_VENDOR_SMC=y
++# CONFIG_WD80x3 is not set
++# CONFIG_ULTRAMCA is not set
++# CONFIG_ULTRA is not set
++# CONFIG_ULTRA32 is not set
++CONFIG_SMC9194=y
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++CONFIG_PPP=m
++# CONFIG_PPP_MULTILINK is not set
++# CONFIG_PPP_FILTER is not set
++CONFIG_PPP_ASYNC=m
++CONFIG_PPP_SYNC_TTY=m
++CONFIG_PPP_DEFLATE=m
++CONFIG_PPP_BSDCOMP=m
++# CONFIG_PPPOE is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++CONFIG_NET_RADIO=y
++# CONFIG_STRIP is not set
++# CONFIG_WAVELAN is not set
++# CONFIG_ARLAN is not set
++# CONFIG_AIRONET4500 is not set
++# CONFIG_AIRONET4500_NONCS is not set
++# CONFIG_AIRONET4500_PROC is not set
++# CONFIG_HERMES is not set
++# CONFIG_PCMCIA_HERMES is not set
++CONFIG_AIRO_CS=m
++CONFIG_NET_WIRELESS=y
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# PCMCIA network device support
++#
++CONFIG_NET_PCMCIA=y
++# CONFIG_PCMCIA_3C589 is not set
++CONFIG_PCMCIA_3C574=m
++# CONFIG_PCMCIA_FMVJ18X is not set
++# CONFIG_PCMCIA_PCNET is not set
++# CONFIG_PCMCIA_AXNET is not set
++# CONFIG_PCMCIA_NMCLAN is not set
++# CONFIG_PCMCIA_SMC91C92 is not set
++# CONFIG_PCMCIA_XIRC2PS is not set
++# CONFIG_ARCNET_COM20020_CS is not set
++# CONFIG_PCMCIA_IBMTR is not set
++CONFIG_NET_PCMCIA_RADIO=y
++# CONFIG_PCMCIA_RAYCS is not set
++# CONFIG_PCMCIA_NETWAVE is not set
++# CONFIG_PCMCIA_WAVELAN is not set
++# CONFIG_AIRONET4500_CS is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++CONFIG_IDE=m
++
++#
++# IDE, ATA and ATAPI Block devices
++#
++CONFIG_BLK_DEV_IDE=m
++# CONFIG_BLK_DEV_HD_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++CONFIG_BLK_DEV_IDEDISK=m
++# CONFIG_IDEDISK_MULTI_MODE is not set
++# CONFIG_IDEDISK_STROKE is not set
++# CONFIG_BLK_DEV_IDEDISK_VENDOR is not set
++# CONFIG_BLK_DEV_IDEDISK_FUJITSU is not set
++# CONFIG_BLK_DEV_IDEDISK_IBM is not set
++# CONFIG_BLK_DEV_IDEDISK_MAXTOR is not set
++# CONFIG_BLK_DEV_IDEDISK_QUANTUM is not set
++# CONFIG_BLK_DEV_IDEDISK_SEAGATE is not set
++# CONFIG_BLK_DEV_IDEDISK_WD is not set
++# CONFIG_BLK_DEV_COMMERIAL is not set
++# CONFIG_BLK_DEV_TIVO is not set
++CONFIG_BLK_DEV_IDECS=m
++# 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
++# CONFIG_BLK_DEV_CMD640 is not set
++# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
++# CONFIG_BLK_DEV_ISAPNP is not set
++# CONFIG_IDE_CHIPSETS is not set
++# CONFIG_IDEDMA_AUTO is not set
++# CONFIG_DMA_NONPCI is not set
++# CONFIG_BLK_DEV_IDE_MODES is not set
++# CONFIG_BLK_DEV_ATARAID is not set
++# CONFIG_BLK_DEV_ATARAID_PDC is not set
++# CONFIG_BLK_DEV_ATARAID_HPT is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_VT_CONSOLE is not set
++CONFIG_SERIAL=y
++CONFIG_SERIAL_CONSOLE=y
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_UNIX98_PTYS=y
++CONFIG_UNIX98_PTY_COUNT=256
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++CONFIG_I2C_PXA_ALGO=y
++CONFIG_I2C_PXA_ADAP=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_PROC=y
++# CONFIG_I2C_DS1307 is not set
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++
++#
++# Watchdog Cards
++#
++# CONFIG_WATCHDOG is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++CONFIG_PXA_RTC=y
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++# CONFIG_DRM is not set
++
++#
++# PCMCIA character devices
++#
++# CONFIG_PCMCIA_SERIAL_CS is not set
++CONFIG_TRIZEPS2_TTLIO=m
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_BFS_FS is not set
++CONFIG_EXT3_FS=y
++CONFIG_JBD=y
++# CONFIG_JBD_DEBUG is not set
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++# CONFIG_UMSDOS_FS is not set
++CONFIG_VFAT_FS=m
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++# CONFIG_CRAMFS is not set
++CONFIG_TMPFS=y
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++# CONFIG_DEVFS_FS is not set
++# CONFIG_DEVFS_MOUNT is not set
++# CONFIG_DEVFS_DEBUG is not set
++CONFIG_DEVPTS_FS=y
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=m
++# CONFIG_NFS_V3 is not set
++# CONFIG_ROOT_NFS is not set
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++CONFIG_SUNRPC=m
++CONFIG_LOCKD=m
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++# CONFIG_ZLIB_FS_INFLATE is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++CONFIG_NLS=y
++
++#
++# Native Language Support
++#
++CONFIG_NLS_DEFAULT="iso8859-1"
++# CONFIG_NLS_CODEPAGE_437 is not set
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ISO8859_1=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
++
++#
++# Console drivers
++#
++CONFIG_PC_KEYMAP=y
++# CONFIG_VGA_CONSOLE is not set
++
++#
++# Frame-buffer support
++#
++CONFIG_FB=y
++CONFIG_DUMMY_CONSOLE=y
++# CONFIG_FB_ACORN is not set
++# CONFIG_FB_ANAKIN is not set
++# CONFIG_FB_CLPS711X is not set
++# CONFIG_FB_SA1100 is not set
++CONFIG_FB_PXA=y
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_VIRTUAL is not set
++CONFIG_FBCON_ADVANCED=y
++# CONFIG_FBCON_MFB is not set
++# CONFIG_FBCON_CFB2 is not set
++# CONFIG_FBCON_CFB4 is not set
++# CONFIG_FBCON_CFB8 is not set
++CONFIG_FBCON_CFB16=y
++# CONFIG_FBCON_CFB24 is not set
++# CONFIG_FBCON_CFB32 is not set
++# CONFIG_FBCON_AFB is not set
++# CONFIG_FBCON_ILBM is not set
++# CONFIG_FBCON_IPLAN2P2 is not set
++# CONFIG_FBCON_IPLAN2P4 is not set
++# CONFIG_FBCON_IPLAN2P8 is not set
++# CONFIG_FBCON_MAC is not set
++# CONFIG_FBCON_VGA_PLANES is not set
++# CONFIG_FBCON_VGA is not set
++# CONFIG_FBCON_HGA is not set
++CONFIG_FBCON_FONTWIDTH8_ONLY=y
++CONFIG_FBCON_FONTS=y
++# CONFIG_FONT_8x8 is not set
++# CONFIG_FONT_8x16 is not set
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++CONFIG_FONT_ACORN_8x8=y
++
++#
++# Sound
++#
++CONFIG_SOUND=y
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_CMPCI is not set
++# CONFIG_SOUND_EMU10K1 is not set
++# CONFIG_MIDI_EMU10K1 is not set
++# CONFIG_SOUND_FUSION is not set
++# CONFIG_SOUND_CS4281 is not set
++# CONFIG_SOUND_ES1370 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ESSSOLO1 is not set
++# CONFIG_SOUND_MAESTRO is not set
++# CONFIG_SOUND_MAESTRO3 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_RME96XX is not set
++# CONFIG_SOUND_SONICVIBES is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_MIDI_VIA82CXXX is not set
++# CONFIG_SOUND_OSS is not set
++# CONFIG_SOUND_WAVEARTIST is not set
++CONFIG_SOUND_PXA_AC97=y
++# CONFIG_SOUND_TVMIXER is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++CONFIG_MCP=y
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++CONFIG_MCP_UCB1400_TS=y
++CONFIG_MCP_UCB1X00_TS_COMPAT=y
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_INFO=y
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_ERRORS=y
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
+--- linux-2.4.25/arch/arm/kernel/Makefile~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -10,7 +10,7 @@
+ HEAD_OBJ  = head-$(PROCESSOR).o
+ ENTRY_OBJ = entry-$(PROCESSOR).o
+ 
+-AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR)
++AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR)
+ AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR)
+ 
+ # This is depreciated.
+@@ -45,7 +45,7 @@
+ 		   $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \
+ 		   $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \
+ 		   $(CONFIG_ARCH_MX1ADS) $(CONFIG_ARCH_OMAHA) \
+-		   $(CONFIG_ARCH_AT91RM9200)
++		   $(CONFIG_ARCH_AT91RM9200) $(CONFIG_ARCH_PXA)
+ 
+ ifneq ($(findstring y,$(no-irq-arch)),y)
+   obj-y		+= irq-arch.o
+--- linux-2.4.25/arch/arm/kernel/debug-armv.S~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/debug-armv.S	2004-03-31 17:15:11.000000000 +0200
+@@ -221,6 +221,31 @@
+ 		bne	1001b
+ 		.endm
+ 
++#elif defined(CONFIG_ARCH_PXA)
++
++		.macro	addruart,rx
++		mrc	p15, 0, \rx, c1, c0
++		tst	\rx, #1			@ MMU enabled?
++		moveq	\rx, #0x40000000		@ physical
++		movne	\rx, #io_p2v(0x40000000)	@ virtual
++		orr	\rx, \rx, #0x00100000		@ FFUART
++		.endm
++
++		.macro	senduart,rd,rx
++		str	\rd, [\rx, #0]
++		.endm
++
++		.macro	busyuart,rd,rx
++1002:		ldr	\rd, [\rx, #0x14]
++		tst	\rd, #(1 << 6)
++		beq	1002b
++		.endm
++
++		.macro	waituart,rd,rx
++1001:		ldr	\rd, [\rx, #0x14]
++		tst	\rd, #(1 << 5)
++		beq	1001b
++		.endm
+ #elif defined(CONFIG_ARCH_CLPS7500)
+ 		.macro	addruart,rx
+ 		mov	\rx, #0xe0000000
+--- linux-2.4.25/arch/arm/kernel/entry-armv.S~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:08.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/entry-armv.S	2004-03-31 17:15:11.000000000 +0200
+@@ -615,6 +615,27 @@
+ 		.text
+ 		.endm
+ 
++#elif CONFIG_ARCH_PXA
++
++		.macro	disable_fiq
++		.endm
++
++		.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
++		mov	\base, #io_p2v(0x40000000)	@ IIR Ctl = 0x40d00000
++		add	\base, \base, #0x00d00000
++		ldr	\irqstat, [\base, #0]		@ ICIP
++		ldr	\irqnr, [\base, #4]		@ ICMR
++		ands	\irqstat, \irqstat, \irqnr
++		beq	1001f
++		rsb	\irqnr, \irqstat, #0
++		and	\irqstat, \irqstat, \irqnr
++		clz	\irqnr, \irqstat
++		rsb	\irqnr, \irqnr, #(31 - PXA_IRQ_SKIP)
++1001:
++		.endm
++
++		.macro	irq_prio_table
++		.endm
+ #else
+ #error Unknown architecture
+ #endif
+@@ -891,9 +912,17 @@
+ 		stmfd	sp!, {r4 - sl, fp, lr}		@ Store most regs on stack
+ 		mrs	ip, cpsr
+ 		str	ip, [sp, #-4]!			@ Save cpsr_SVC
++#ifdef CONFIG_CPU_XSCALE
++		mra	r4, r5, acc0
++		stmfd	sp!, {r4, r5}
++#endif
+ 		str	sp, [r0, #TSS_SAVE]		@ Save sp_SVC
+ 		ldr	sp, [r1, #TSS_SAVE]		@ Get saved sp_SVC
+ 		ldr	r2, [r1, #TSS_DOMAIN]
++#ifdef CONFIG_CPU_XSCALE
++		ldmfd	sp!, {r4, r5}
++		mar	acc0, r4, r5
++#endif
+ 		ldr	ip, [sp], #4
+ 		mcr	p15, 0, r2, c3, c0		@ Set domain register
+ 		msr	spsr, ip			@ Save tasks CPSR into SPSR for this return
+--- linux-2.4.25/arch/arm/kernel/head-armv.S~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:08.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/head-armv.S	2004-03-31 17:15:11.000000000 +0200
+@@ -30,6 +30,7 @@
+  *
+  * swapper_pg_dir, pgtbl and krnladr are all closely related.
+  */
++#ifndef CONFIG_XIP_KERNEL
+ #if (TEXTADDR & 0xffff) != 0x8000
+ #error TEXTADDR must start at 0xXXXX8000
+ #endif
+@@ -41,6 +42,26 @@
+ 		adr	\reg, stext
+ 		sub	\reg, \reg, #0x4000
+ 		.endm
++#else
++#if (DATAADDR & 0xffff) != 0x8000
++#error DATAADDR must start at 0xXXXX8000
++#endif
++
++#define	PAGE_OFFSET	0xc0000000
++#ifdef CONFIG_ARCH_LUBBOCK
++#define	PHYS_OFFSET	0xa0000000
++#elif CONFIG_ARCH_OMAP
++#define	PHYS_OFFSET	0x10000000
++#endif
++
++		.globl	SYMBOL_NAME(swapper_pg_dir)
++		.equ	SYMBOL_NAME(swapper_pg_dir), DATAADDR - 0x4000
++
++		.macro	pgtbl, reg, rambase
++		ldr	\reg, PGTBL
++		add	\reg, \reg, #PHYS_OFFSET - PAGE_OFFSET
++		.endm
++#endif
+ 
+ /*
+  * Since the page table is closely related to the kernel start address, we
+@@ -131,6 +152,32 @@
+ 		mov	r1, #MACH_TYPE_L7200
+ #endif
+ 
++#ifdef CONFIG_XIP_KERNEL
++
++#if defined(CONFIG_ARCH_LUBBOCK)
++		mov	r1, #MACH_TYPE_LUBBOCK
++#endif
++
++		@ Data cache might be active.
++		@ Be sure to flush kernel binary out of the cache,
++		@ whatever state it is, before it is turned off.
++		@ This is done by fetching through currently executed
++		@ memory to be sure we hit the same cache.
++		bic	r2, pc, #0x1f
++		add	r3, r2, #0x10000	@ 64 kb is quite enough...
++1:		ldr	r0, [r2], #32
++		teq	r2, r3
++		bne	1b
++		mcr	p15, 0, r0, c7, c10, 4	@ drain WB
++		mcr	p15, 0, r0, c7, c7, 0	@ flush I & D caches
++
++		@ disabling MMU and caches
++		mrc	p15, 0, r0, c1, c0, 0	@ read control reg
++		bic	r0, r0, #0x05		@ clear DC, MMU
++		bic	r0, r0, #0x1000		@ clear Icache
++		mcr	p15, 0, r0, c1, c0, 0
++#endif
++
+ 		mov	r0, #F_BIT | I_BIT | MODE_SVC	@ make sure svc mode
+ 		msr	cpsr_c, r0			@ and all irqs disabled
+ 		bl	__lookup_processor_type
+@@ -179,6 +226,17 @@
+  */
+ 		.align	5
+ __mmap_switched:
++#ifdef CONFIG_XIP_KERNEL
++		ldr	r3, ETEXT			@ data section copy
++		ldr	r4, SDATA
++		ldr	r5, EDATA
++1:
++		ldr	r6, [r3], #4
++		str	r6, [r4], #4
++		cmp	r4, r5
++		blo	1b
++#endif
++
+ 		adr	r3, __switch_data + 4
+ 		ldmia	r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat
+ 							@ sp = stack pointer
+@@ -233,6 +291,8 @@
+ 		teq	r0, r2
+ 		bne	1b
+ 
++#ifndef CONFIG_XIP_KERNEL
++
+ 		/*
+ 		 * Create identity mapping for first MB of kernel to
+ 		 * cater for the MMU enable.  This identity mapping
+@@ -271,6 +331,43 @@
+ 		add	r3, r8, r2			@ flags + rambase
+ 		str	r3, [r0]
+ 
++#else	/* CONFIG_XIP_KERNEL */
++
++		mov	r3, pc, lsr #20
++		mov	r3, r3, lsl #20		@ phys kernel start
++
++		add	r0, r4, r3, lsr #18
++		orr	r3, r3, r8
++		str	r3, [r0]
++
++		mov	r0, #TEXTADDR & 0xff000000
++		add	r0, r0, #TEXTADDR & 0x00f00000	@ virt kernel start
++		add	r0, r4, r0, lsr #18
++		add	r2, r3, #4 << 20		@ kernel + 4MB
++
++1:
++		str	r3, [r0], #4
++		add	r3, r3, #1 << 20
++		cmp	r3, r2
++		bne	1b
++
++		bic	r3, r4, #0x000ff000		@ ram start
++		add	r0, r4, r3, lsr #18
++		orr	r3, r3, r8
++		str	r3, [r0], #4
++
++		add	r0, r3, #PAGE_OFFSET - PHYS_OFFSET
++		add	r0, r4, r0, lsr #18
++		add	r2, r3, #4 << 20		@ ram + 4MB
++
++1:
++		str	r3, [r0], #4
++		add	r3, r3, #1 << 20
++		cmp	r3, r2
++		bne	1b
++
++#endif	/* CONFIG_XIP_KERNEL */
++
+ 		bic	r8, r8, #0x0c			@ turn off cacheable
+ 							@ and bufferable bits
+ #ifdef CONFIG_DEBUG_LL
+@@ -433,3 +530,13 @@
+ 		mov	pc, lr
+ 2:		ldmib	r4, {r5, r6, r7}		@ found, get results
+ 		mov	pc, lr
++
++#ifdef CONFIG_XIP_KERNEL
++
++PGTBL:		.long	SYMBOL_NAME(swapper_pg_dir)
++
++ETEXT:		.long	SYMBOL_NAME(_endtext)
++SDATA:		.long	SYMBOL_NAME(_sdata)
++EDATA:		.long	SYMBOL_NAME(__bss_start)
++
++#endif
+--- linux-2.4.25/arch/arm/kernel/setup.c~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/setup.c	2004-03-31 17:15:11.000000000 +0200
+@@ -55,6 +55,10 @@
+ extern void reboot_setup(char *str);
+ extern int root_mountflags;
+ extern int _stext, _text, _etext, _edata, _end;
++#ifdef CONFIG_XIP_KERNEL
++extern int _endtext, _sdata;
++#endif
++
+ 
+ unsigned int processor_id;
+ unsigned int __machine_arch_type;
+@@ -105,6 +109,109 @@
+ #define lp1 io_res[1]
+ #define lp2 io_res[2]
+ 
++#ifdef CONFIG_CPU_32
++static const char *cache_types[16] = {
++	"write-through",
++	"write-back",
++	"write-back",
++	"undefined 3",
++	"undefined 4",
++	"undefined 5",
++	"write-back",
++	"write-back",
++	"undefined 8",
++	"undefined 9",
++	"undefined 10",
++	"undefined 11",
++	"undefined 12",
++	"undefined 13",
++	"undefined 14",
++	"undefined 15",
++};
++
++static const char *cache_clean[16] = {
++	"not required",
++	"read-block",
++	"cp15 c7 ops",
++	"undefined 3",
++	"undefined 4",
++	"undefined 5",
++	"cp15 c7 ops",
++	"cp15 c7 ops",
++	"undefined 8",
++	"undefined 9",
++	"undefined 10",
++	"undefined 11",
++	"undefined 12",
++	"undefined 13",
++	"undefined 14",
++	"undefined 15",
++};
++
++static const char *cache_lockdown[16] = {
++	"not supported",
++	"not supported",
++	"not supported",
++	"undefined 3",
++	"undefined 4",
++	"undefined 5",
++	"format A",
++	"format B",
++	"undefined 8",
++	"undefined 9",
++	"undefined 10",
++	"undefined 11",
++	"undefined 12",
++	"undefined 13",
++	"undefined 14",
++	"undefined 15",
++};
++
++#define CACHE_TYPE(x)	(((x) >> 25) & 15)
++#define CACHE_S(x)	((x) & (1 << 24))
++#define CACHE_DSIZE(x)	(((x) >> 12) & 4095)	/* only if S=1 */
++#define CACHE_ISIZE(x)	((x) & 4095)
++
++#define CACHE_SIZE(y)	(((y) >> 6) & 7)
++#define CACHE_ASSOC(y)	(((y) >> 3) & 7)
++#define CACHE_M(y)	((y) & (1 << 2))
++#define CACHE_LINE(y)	((y) & 3)
++
++static inline void dump_cache(const char *prefix, unsigned int cache)
++{
++	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
++
++	printk("%s size %dK associativity %d line length %d sets %d\n",
++		prefix,
++		mult << (8 + CACHE_SIZE(cache)),
++		(mult << CACHE_ASSOC(cache)) >> 1,
++		8 << CACHE_LINE(cache),
++		1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
++			CACHE_LINE(cache)));
++}
++
++static inline void dump_cpu_cache_id(void)
++{
++	unsigned int cache_info;
++
++	asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info));
++
++	if (cache_info == processor_id)
++		return;
++
++	printk("CPU: D %s cache\n", cache_types[CACHE_TYPE(cache_info)]);
++	if (CACHE_S(cache_info)) {
++		dump_cache("CPU: I cache", CACHE_ISIZE(cache_info));
++		dump_cache("CPU: D cache", CACHE_DSIZE(cache_info));
++	} else {
++		dump_cache("CPU: cache", CACHE_ISIZE(cache_info));
++	}
++}
++
++#else
++#define dump_cpu_cache_id() do { } while (0)
++#endif
++
+ static void __init setup_processor(void)
+ {
+ 	extern struct proc_info_list __proc_info_begin, __proc_info_end;
+@@ -272,7 +379,11 @@
+ 
+ 	kernel_code.start  = __virt_to_phys(init_mm.start_code);
+ 	kernel_code.end    = __virt_to_phys(init_mm.end_code - 1);
++#ifndef CONFIG_XIP_KERNEL
+ 	kernel_data.start  = __virt_to_phys(init_mm.end_code);
++#else
++	kernel_data.start  = __virt_to_phys(init_mm.start_data);
++#endif
+ 	kernel_data.end    = __virt_to_phys(init_mm.brk - 1);
+ 
+ 	for (i = 0; i < mi->nr_banks; i++) {
+@@ -531,7 +642,12 @@
+ 	}
+ 
+ 	init_mm.start_code = (unsigned long) &_text;
++#ifndef CONFIG_XIP_KERNEL
+ 	init_mm.end_code   = (unsigned long) &_etext;
++#else
++	init_mm.end_code   = (unsigned long) &_endtext;
++	init_mm.start_data   = (unsigned long) &_sdata;
++#endif
+ 	init_mm.end_data   = (unsigned long) &_edata;
+ 	init_mm.brk	   = (unsigned long) &_end;
+ 
+@@ -568,6 +684,41 @@
+ 	NULL
+ };
+ 
++static const char *proc_arch[16] = {
++	"undefined 0",
++	"4",
++	"4T",
++	"5",
++	"5T",
++	"5TE",
++	"undefined 6",
++	"undefined 7",
++	"undefined 8",
++	"undefined 9",
++	"undefined 10",
++	"undefined 11",
++	"undefined 12",
++	"undefined 13",
++	"undefined 14",
++	"undefined 15"
++};
++
++static void
++c_show_cache(struct seq_file *m, const char *type, unsigned int cache)
++{
++	unsigned int mult = 2 + (CACHE_M(cache) ? 1 : 0);
++
++	seq_printf(m, "%s size\t\t: %d\n"
++		      "%s assoc\t\t: %d\n"
++		      "%s line length\t: %d\n"
++		      "%s sets\t\t: %d\n",
++		type, mult << (8 + CACHE_SIZE(cache)),
++		type, (mult << CACHE_ASSOC(cache)) >> 1,
++		type, 8 << CACHE_LINE(cache),
++		type, 1 << (6 + CACHE_SIZE(cache) - CACHE_ASSOC(cache) -
++			    CACHE_LINE(cache)));
++}
++
+ static int c_show(struct seq_file *m, void *v)
+ {
+ 	int i;
+@@ -586,7 +737,60 @@
+ 		if (elf_hwcap & (1 << i))
+ 			seq_printf(m, "%s ", hwcap_str[i]);
+ 
+-	seq_puts(m, "\n\n");
++	seq_puts(m, "\n");
++
++	if ((processor_id & 0x0000f000) == 0x00000000) {
++		/* pre-ARM7 */
++		seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4);
++	} else if ((processor_id & 0x0000f000) == 0x00007000) {
++		/* ARM7 */
++		seq_printf(m, "CPU implementor\t: 0x%02x\n"
++			      "CPU architecture: %s\n"
++			      "CPU variant\t: 0x%02x\n"
++			      "CPU part\t: 0x%03x\n",
++			   processor_id >> 24,
++			   processor_id & (1 << 23) ? "4T" : "3",
++			   (processor_id >> 16) & 127,
++			   (processor_id >> 4) & 0xfff);
++	} else {
++		/* post-ARM7 */
++		seq_printf(m, "CPU implementor\t: 0x%02x\n"
++			      "CPU architecture: %s\n"
++			      "CPU variant\t: 0x%x\n"
++			      "CPU part\t: 0x%03x\n",
++			   processor_id >> 24,
++			   proc_arch[(processor_id >> 16) & 15],
++			   (processor_id >> 20) & 15,
++			   (processor_id >> 4) & 0xfff);
++	}
++	seq_printf(m, "CPU revision\t: %d\n", processor_id & 15);
++
++#ifdef CONFIG_CPU_32
++	{
++		unsigned int cache_info;
++
++		asm("mrc p15, 0, %0, c0, c0, 1" : "=r" (cache_info));
++		if (cache_info != processor_id) {
++			seq_printf(m, "Cache type\t: %s\n"
++				      "Cache clean\t: %s\n"
++				      "Cache lockdown\t: %s\n"
++				      "Cache unified\t: %s\n",
++				   cache_types[CACHE_TYPE(cache_info)],
++				   cache_clean[CACHE_TYPE(cache_info)],
++				   cache_lockdown[CACHE_TYPE(cache_info)],
++				   CACHE_S(cache_info) ? "harvard" : "unified");
++
++			if (CACHE_S(cache_info)) {
++				c_show_cache(m, "I", CACHE_ISIZE(cache_info));
++				c_show_cache(m, "D", CACHE_DSIZE(cache_info));
++			} else {
++				c_show_cache(m, "Cache", CACHE_ISIZE(cache_info));
++			}
++		}
++	}
++#endif
++
++	seq_puts(m, "\n");
+ 
+ 	seq_printf(m, "Hardware\t: %s\n", machine_name);
+ 	seq_printf(m, "Revision\t: %04x\n", system_rev);
+--- linux-2.4.25/arch/arm/lib/copy_page.S~2.4.25-vrs2-pxa1.patch	2001-03-07 04:44:35.000000000 +0100
++++ linux-2.4.25/arch/arm/lib/copy_page.S	2004-03-31 17:15:11.000000000 +0200
+@@ -13,6 +13,8 @@
+ #include <asm/assembler.h>
+ #include <asm/constants.h>
+ 
++#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
++
+ 		.text
+ 		.align	5
+ /*
+@@ -23,9 +25,13 @@
+  */
+ ENTRY(copy_page)
+ 		stmfd	sp!, {r4, lr}			@	2
+-		mov	r2, #PAGE_SZ/64			@	1
++	PLD(	pld	[r1, #0]		)
++	PLD(	pld	[r1, #32]		)
++		mov	r2, #COPY_COUNT			@	1
+ 		ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+-1:		stmia	r0!, {r3, r4, ip, lr}		@	4
++1:	PLD(	pld	[r1, #64]		)
++	PLD(	pld	[r1, #96]		)
++2:		stmia	r0!, {r3, r4, ip, lr}		@	4
+ 		ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+ 		stmia	r0!, {r3, r4, ip, lr}		@	4
+ 		ldmia	r1!, {r3, r4, ip, lr}		@	4+1
+@@ -33,6 +39,8 @@
+ 		ldmia	r1!, {r3, r4, ip, lr}		@	4
+ 		subs	r2, r2, #1			@	1
+ 		stmia	r0!, {r3, r4, ip, lr}		@	4
+-		ldmneia	r1!, {r3, r4, ip, lr}		@	4
+-		bne	1b				@	1
++		ldmgtia	r1!, {r3, r4, ip, lr}		@	4
++		bgt	1b				@	1
++	PLD(	ldmeqia r1!, {r3, r4, ip, lr}	)
++	PLD(	beq	2b			)
+ 		LOADREGS(fd, sp!, {r4, pc})		@	3
+--- linux-2.4.25/arch/arm/lib/findbit.S~2.4.25-vrs2-pxa1.patch	2000-09-19 00:15:25.000000000 +0200
++++ linux-2.4.25/arch/arm/lib/findbit.S	2004-03-31 17:15:11.000000000 +0200
+@@ -43,7 +43,15 @@
+ /*
+  * One or more bits in the LSB of r3 are assumed to be set.
+  */
+-.found:		tst	r3, #0x0f
++.found:
++#if __LINUX_ARM_ARCH__ >= 5
++		rsb	r1, r3, #0
++		and	r3, r3, r1
++		clz	r3, r3
++		rsb	r3, r3, #31
++		add	r0, r2, r3
++#else
++		tst	r3, #0x0f
+ 		addeq	r2, r2, #4
+ 		movne	r3, r3, lsl #4
+ 		tst	r3, #0x30
+@@ -52,5 +60,6 @@
+ 		tst	r3, #0x40
+ 		addeq	r2, r2, #1
+ 		mov	r0, r2
++#endif
+ 		RETINSTR(mov,pc,lr)
+ 
+--- linux-2.4.25/arch/arm/lib/getuser.S~2.4.25-vrs2-pxa1.patch	2002-08-03 02:39:42.000000000 +0200
++++ linux-2.4.25/arch/arm/lib/getuser.S	2004-03-31 17:15:11.000000000 +0200
+@@ -18,7 +18,7 @@
+  * Inputs:	r0 contains the address
+  * Outputs:	r0 is the error code
+  *		r1, r2 contains the zero-extended value
+- *		lr corrupted
++ *		ip, lr corrupted
+  *
+  * No other registers must be altered.  (see include/asm-arm/uaccess.h
+  * for specific ASM register usage).
+@@ -42,14 +42,14 @@
+ 
+ 	.global	__get_user_2
+ __get_user_2:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #2
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #2
++	cmp	r0, ip
+ 2:	ldrlsbt	r1, [r0], #1
+-3:	ldrlsbt	r2, [r0]
+-	orrls	r1, r1, r2, lsl #8
++3:	ldrlsbt	ip, [r0]
++	orrls	r1, r1, ip, lsl #8
+ 	movls	r0, #0
+ 	movls	pc, lr
+ 	b	__get_user_bad
+--- linux-2.4.25/arch/arm/lib/memcpy.S~2.4.25-vrs2-pxa1.patch	2001-03-07 04:44:35.000000000 +0100
++++ linux-2.4.25/arch/arm/lib/memcpy.S	2004-03-31 17:15:11.000000000 +0200
+@@ -8,6 +8,9 @@
+  * published by the Free Software Foundation.
+  *
+  *  ASM optimised string functions
++ *
++ *  Big Endian, prefetching and code factorization provided by Nicolas Pitre:
++ *    Copyright (C) 2002-2003 MontaVista Software, Inc.
+  */
+ #include <linux/linkage.h>
+ #include <asm/assembler.h>
+@@ -27,15 +30,16 @@
+ 
+ /*
+  * Prototype: void memcpy(void *to,const void *from,unsigned long n);
+- * ARM3: cant use memcopy here!!!
+  */
+ ENTRY(memcpy)
+ ENTRY(memmove)
+ 		ENTER
+-		cmp	r1, r0
+-		bcc	19f
++		subs	ip, r0, r1
++		cmphi	r2, ip
++		bhi	18f
+ 		subs	r2, r2, #4
+ 		blt	6f
++	PLD(	pld	[r1, #0]		)
+ 		ands	ip, r0, #3
+ 		bne	7f
+ 		ands	ip, r1, #3
+@@ -43,29 +47,59 @@
+ 
+ 1:		subs	r2, r2, #8
+ 		blt	5f
+-		subs	r2, r2, #0x14
+-		blt	3f
+-2:		ldmia	r1!,{r3 - r9, ip}
+-		stmia	r0!,{r3 - r9, ip}
++		subs	r2, r2, #20
++		blt	4f
++
++	PLD(	subs	r2, r2, #65		)
++	PLD(	blt	3f			)
++	PLD(	pld	[r1, #32]		)
++
++	PLD(	@ cache alignment		)
++	PLD(	ands	ip, r1, #31		)
++	PLD(	pld	[r1, #64]		)
++	PLD(	beq	2f			)
++	PLD(	rsb	ip, ip, #32		)
++	PLD(	cmp	r2, ip			)
++	PLD(	pld	[r1, #96]		)
++	PLD(	blt	2f			)
++	PLD(	cmp	ip, #16			)
++	PLD(	sub	r2, r2, ip		)
++	PLD(	ldmgeia	r1!, {r3 - r6}		)
++	PLD(	stmgeia	r0!, {r3 - r6}		)
++	PLD(	beq	2f			)
++	PLD(	and	ip, ip, #15		)
++	PLD(	cmp	ip, #8			)
++	PLD(	ldr	r3, [r1], #4		)
++	PLD(	ldrge	r4, [r1], #4		)
++	PLD(	ldrgt	r5, [r1], #4		)
++	PLD(	str	r3, [r0], #4		)
++	PLD(	strge	r4, [r0], #4		)
++	PLD(	strgt	r5, [r0], #4		)
++
++2:	PLD(	pld	[r1, #96]		)
++3:		ldmia	r1!, {r3 - r9, ip}
+ 		subs	r2, r2, #32
++		stmia	r0!, {r3 - r9, ip}
+ 		bge	2b
+-		cmn	r2, #16
++	PLD(	cmn	r2, #65			)
++	PLD(	bge	3b			)
++	PLD(	add	r2, r2, #65		)
++4:		cmn	r2, #16
+ 		ldmgeia	r1!, {r3 - r6}
++		subge	r2, r2, #16
+ 		stmgeia	r0!, {r3 - r6}
+-		subge	r2, r2, #0x10
+-3:		adds	r2, r2, #0x14
+-4:		ldmgeia	r1!, {r3 - r5}
++		adds	r2, r2, #20
++		ldmgeia	r1!, {r3 - r5}
++		subge	r2, r2, #12
+ 		stmgeia	r0!, {r3 - r5}
+-		subges	r2, r2, #12
+-		bge	4b
+ 5:		adds	r2, r2, #8
+ 		blt	6f
+ 		subs	r2, r2, #4
+ 		ldrlt	r3, [r1], #4
+ 		ldmgeia	r1!, {r4, r5}
++		subge	r2, r2, #4
+ 		strlt	r3, [r0], #4
+ 		stmgeia	r0!, {r4, r5}
+-		subge	r2, r2, #4
+ 
+ 6:		adds	r2, r2, #4
+ 		EXITEQ
+@@ -92,122 +126,175 @@
+ 		beq	1b
+ 
+ 8:		bic	r1, r1, #3
+-		ldr	r7, [r1], #4
+ 		cmp	ip, #2
+-		bgt	15f
+-		beq	11f
++		ldr	lr, [r1], #4
++		bgt	17f
++		beq	16f
++
++
++		.macro	forward_copy_shift pull push
++
+ 		cmp	r2, #12
+-		blt	10f
+-		sub	r2, r2, #12
+-9:		mov	r3, r7, lsr #8
+-		ldmia	r1!, {r4 - r7}
+-		orr	r3, r3, r4, lsl #24
+-		mov	r4, r4, lsr #8
+-		orr	r4, r4, r5, lsl #24
+-		mov	r5, r5, lsr #8
+-		orr	r5, r5, r6, lsl #24
+-		mov	r6, r6, lsr #8
+-		orr	r6, r6, r7, lsl #24
++	PLD(	pld	[r1, #0]		)
++		blt	14f
++		subs	r2, r2, #28
++		blt	12f
++
++	PLD(	subs	r2, r2, #97		)
++	PLD(	blt	11f			)
++	PLD(	pld	[r1, #32]		)
++
++	PLD(	@ cache alignment		)
++	PLD(	rsb	ip, r1, #36		)
++	PLD(	pld	[r1, #64]		)
++	PLD(	ands	ip, ip, #31		)
++	PLD(	pld	[r1, #96]		)
++	PLD(	beq	10f			)
++	PLD(	cmp	r2, ip			)
++	PLD(	pld	[r1, #128]		)
++	PLD(	blt	10f			)
++	PLD(	sub	r2, r2, ip		)
++9:	PLD(	mov	r3, lr, pull #\pull	)
++	PLD(	ldr	lr, [r1], #4		)
++	PLD(	subs	ip, ip, #4		)
++	PLD(	orr	r3, r3, lr, push #\push	)
++	PLD(	str	r3, [r0], #4		)
++	PLD(	bgt	9b			)
++
++10:	PLD(	pld	[r1, #128]		)
++11:		mov	r3, lr, pull #\pull
++		ldmia	r1!, {r4 - r9, ip, lr}
++		subs	r2, r2, #32
++		orr	r3, r3, r4, push #\push
++		mov	r4, r4, pull #\pull
++		orr	r4, r4, r5, push #\push
++		mov	r5, r5, pull #\pull
++		orr	r5, r5, r6, push #\push
++		mov	r6, r6, pull #\pull
++		orr	r6, r6, r7, push #\push
++		mov	r7, r7, pull #\pull
++		orr	r7, r7, r8, push #\push
++		mov	r8, r8, pull #\pull
++		orr	r8, r8, r9, push #\push
++		mov	r9, r9, pull #\pull
++		orr	r9, r9, ip, push #\push
++		mov	ip, ip, pull #\pull
++		orr	ip, ip, lr, push #\push
++		stmia	r0!, {r3 - r9, ip}
++		bge	10b
++	PLD(	cmn	r2, #97			)
++	PLD(	bge	11b			)
++	PLD(	add	r2, r2, #97		)
++		cmn	r2, #16
++		blt	13f
++12:		mov	r3, lr, pull #\pull
++		ldmia	r1!, {r4 - r6, lr}
++		sub	r2, r2, #16
++		orr	r3, r3, r4, push #\push
++		mov	r4, r4, pull #\pull
++		orr	r4, r4, r5, push #\push
++		mov	r5, r5, pull #\pull
++		orr	r5, r5, r6, push #\push
++		mov	r6, r6, pull #\pull
++		orr	r6, r6, lr, push #\push
+ 		stmia	r0!, {r3 - r6}
+-		subs	r2, r2, #16
+-		bge	9b
+-		adds	r2, r2, #12
+-		blt	100f
+-10:		mov	r3, r7, lsr #8
+-		ldr	r7, [r1], #4
++13:		adds	r2, r2, #28
++		blt	15f
++14:		mov	r3, lr, pull #\pull
++		ldr	lr, [r1], #4
+ 		subs	r2, r2, #4
+-		orr	r3, r3, r7, lsl #24
++		orr	r3, r3, lr, push #\push
+ 		str	r3, [r0], #4
+-		bge	10b
+-100:		sub	r1, r1, #3
++		bge	14b
++15:
++		.endm
++
++
++		forward_copy_shift	pull=8	push=24
++		sub	r1, r1, #3
+ 		b	6b
+ 
+-11:		cmp	r2, #12
+-		blt	13f		/* */
+-		sub	r2, r2, #12
+-12:		mov	r3, r7, lsr #16
+-		ldmia	r1!, {r4 - r7}
+-		orr	r3, r3, r4, lsl #16
+-		mov	r4, r4, lsr #16
+-		orr	r4, r4, r5, lsl #16
+-		mov	r5, r5, lsr #16
+-		orr	r5, r5, r6, lsl #16
+-		mov	r6, r6, lsr #16
+-		orr	r6, r6, r7,LSL#16
+-		stmia	r0!, {r3 - r6}
+-		subs	r2, r2, #16
+-		bge	12b
+-		adds	r2, r2, #12
+-		blt	14f
+-13:		mov	r3, r7, lsr #16
+-		ldr	r7, [r1], #4
+-		subs	r2, r2, #4
+-		orr	r3, r3, r7, lsl #16
+-		str	r3, [r0], #4
+-		bge	13b
+-14:		sub	r1, r1, #2
++16:		forward_copy_shift	pull=16	push=16
++		sub	r1, r1, #2
+ 		b	6b
+ 
+-15:		cmp	r2, #12
+-		blt	17f
+-		sub	r2, r2, #12
+-16:		mov	r3, r7, lsr #24
+-		ldmia	r1!,{r4 - r7}
+-		orr	r3, r3, r4, lsl #8
+-		mov	r4, r4, lsr #24
+-		orr	r4, r4, r5, lsl #8
+-		mov	r5, r5, lsr #24
+-		orr	r5, r5, r6, lsl #8
+-		mov	r6, r6, lsr #24
+-		orr	r6, r6, r7, lsl #8
+-		stmia	r0!, {r3 - r6}
+-		subs	r2, r2, #16
+-		bge	16b
+-		adds	r2, r2, #12
+-		blt	18f
+-17:		mov	r3, r7, lsr #24
+-		ldr	r7, [r1], #4
+-		subs	r2, r2, #4
+-		orr	r3, r3, r7, lsl#8
+-		str	r3, [r0], #4
+-		bge	17b
+-18:		sub	r1, r1, #1
++17:		forward_copy_shift	pull=24	push=8
++		sub	r1, r1, #1
+ 		b	6b
+ 
+ 
+-19:		add	r1, r1, r2
++18:		add	r1, r1, r2
+ 		add	r0, r0, r2
+ 		subs	r2, r2, #4
+ 		blt	24f
++	PLD(	pld	[r1, #-4]		)
+ 		ands	ip, r0, #3
+ 		bne	25f
+ 		ands	ip, r1, #3
+ 		bne	26f
+ 
+-20:		subs	r2, r2, #8
++19:		subs	r2, r2, #8
+ 		blt	23f
+-		subs	r2, r2, #0x14
++		subs	r2, r2, #20
+ 		blt	22f
+-21:		ldmdb	r1!, {r3 - r9, ip}
+-		stmdb	r0!, {r3 - r9, ip}
++
++	PLD(	subs	r2, r2, #96		)
++	PLD(	pld	[r1, #-32]		)
++	PLD(	blt	21f			)
++
++	PLD(	@ cache alignment		)
++	PLD(	ands	ip, r1, #31		)
++	PLD(	pld	[r1, #-64]		)
++	PLD(	beq	20f			)
++	PLD(	cmp	r2, ip			)
++	PLD(	pld	[r1, #-96]		)
++	PLD(	blt	20f			)
++	PLD(	cmp	ip, #16			)
++	PLD(	sub	r2, r2, ip		)
++	PLD(	ldmgedb	r1!, {r3 - r6}		)
++	PLD(	stmgedb	r0!, {r3 - r6}		)
++	PLD(	beq	20f			)
++	PLD(	and	ip, ip, #15		)
++	PLD(	cmp	ip, #8			)
++	PLD(	ldr	r3, [r1, #-4]!		)
++	PLD(	ldrge	r4, [r1, #-4]!		)
++	PLD(	ldrgt	r5, [r1, #-4]!		)
++	PLD(	str	r3, [r0, #-4]!		)
++	PLD(	strge	r4, [r0, #-4]!		)
++	PLD(	strgt	r5, [r0, #-4]!		)
++
++20:	PLD(	pld	[r1, #-96]		)
++	PLD(	pld	[r1, #-128]		)
++21:		ldmdb	r1!, {r3 - r6}
+ 		subs	r2, r2, #32
+-		bge	21b
+-22:		cmn	r2, #16
++		stmdb	r0!, {r3 - r6}
++		ldmdb	r1!, {r3 - r6}
++		stmgedb	r0!, {r3 - r6}
+ 		ldmgedb	r1!, {r3 - r6}
+ 		stmgedb	r0!, {r3 - r6}
++		ldmgedb	r1!, {r3 - r6}
++		subges	r2, r2, #32
++		stmdb	r0!, {r3 - r6}
++		bge	20b
++	PLD(	cmn	r2, #96			)
++	PLD(	bge	21b			)
++	PLD(	add	r2, r2, #96		)
++22:		cmn	r2, #16
++		ldmgedb	r1!, {r3 - r6}
+ 		subge	r2, r2, #16
++		stmgedb	r0!, {r3 - r6}
+ 		adds	r2, r2, #20
+ 		ldmgedb	r1!, {r3 - r5}
+-		stmgedb	r0!, {r3 - r5}
+ 		subge	r2, r2, #12
++		stmgedb	r0!, {r3 - r5}
+ 23:		adds	r2, r2, #8
+ 		blt	24f
+ 		subs	r2, r2, #4
+ 		ldrlt	r3, [r1, #-4]!
+ 		ldmgedb	r1!, {r4, r5}
++		subge	r2, r2, #4
+ 		strlt	r3, [r0, #-4]!
+ 		stmgedb	r0!, {r4, r5}
+-		subge	r2, r2, #4
+ 
+ 24:		adds	r2, r2, #4
+ 		EXITEQ
+@@ -230,89 +317,101 @@
+ 		subs	r2, r2, ip
+ 		blt	24b
+ 		ands	ip, r1, #3
+-		beq	20b
++		beq	19b
+ 
+ 26:		bic	r1, r1, #3
+-		ldr	r3, [r1], #0
+ 		cmp	ip, #2
+-		blt	34f
+-		beq	30f
+-		cmp	r2, #12
+-		blt	28f
+-		sub	r2, r2, #12
+-27:		mov	r7, r3, lsl #8
+-		ldmdb	r1!, {r3, r4, r5, r6}
+-		orr	r7, r7, r6, lsr #24
+-		mov	r6, r6, lsl #8
+-		orr	r6, r6, r5, lsr #24
+-		mov	r5, r5, lsl #8
+-		orr	r5, r5, r4, lsr #24
+-		mov	r4, r4, lsl #8
+-		orr	r4, r4, r3, lsr #24
+-		stmdb	r0!, {r4, r5, r6, r7}
+-		subs	r2, r2, #16
+-		bge	27b
+-		adds	r2, r2, #12
+-		blt	29f
+-28:		mov	ip, r3, lsl #8
+-		ldr	r3, [r1, #-4]!
+-		subs	r2, r2, #4
+-		orr	ip, ip, r3, lsr #24
+-		str	ip, [r0, #-4]!
+-		bge	28b
+-29:		add	r1, r1, #3
+-		b	24b
++		ldr	r3, [r1], #0
++		blt	35f
++		beq	34f
+ 
+-30:		cmp	r2, #12
++
++		.macro	backward_copy_shift push pull
++
++		cmp	r2, #12
++	PLD(	pld	[r1, #-4]		)
+ 		blt	32f
+-		sub	r2, r2, #12
+-31:		mov	r7, r3, lsl #16
+-		ldmdb	r1!, {r3, r4, r5, r6}
+-		orr	r7, r7, r6, lsr #16
+-		mov	r6, r6, lsl #16
+-		orr	r6, r6, r5, lsr #16
+-		mov	r5, r5, lsl #16
+-		orr	r5, r5, r4, lsr #16
+-		mov	r4, r4, lsl #16
+-		orr	r4, r4, r3, lsr #16
+-		stmdb	r0!, {r4, r5, r6, r7}
+-		subs	r2, r2, #16
+-		bge	31b
+-		adds	r2, r2, #12
++		subs	r2, r2, #28
++		blt	30f
++
++	PLD(	subs	r2, r2, #96		)
++	PLD(	pld	[r1, #-32]		)
++	PLD(	blt	29f			)
++	PLD(	pld	[r1, #-64]		)
++
++	PLD(	@ cache alignment		)
++	PLD(	ands	ip, r1, #31		)
++	PLD(	pld	[r1, #-96]		)
++	PLD(	beq	28f			)
++	PLD(	cmp	r2, ip			)
++	PLD(	pld	[r1, #-128]		)
++	PLD(	blt	28f			)
++	PLD(	sub	r2, r2, ip		)
++27:	PLD(	mov	r4, r3, push #\push	)
++	PLD(	ldr	r3, [r1, #-4]!		)
++	PLD(	subs	ip, ip, #4		)
++	PLD(	orr	r4, r4, r3, pull #\pull	)
++	PLD(	str	r4, [r0, #-4]!		)
++	PLD(	bgt	27b			)
++
++28:	PLD(	pld	[r1, #-128]		)
++29:		mov	lr, r3, push #\push
++		ldmdb	r1!, {r3 - r9, ip}
++		subs	r2, r2, #32
++		orr	lr, lr, ip, pull #\pull
++		mov	ip, ip, push #\push
++		orr	ip, ip, r9, pull #\pull
++		mov	r9, r9, push #\push
++		orr	r9, r9, r8, pull #\pull
++		mov	r8, r8, push #\push
++		orr	r8, r8, r7, pull #\pull
++		mov	r7, r7, push #\push
++		orr	r7, r7, r6, pull #\pull
++		mov	r6, r6, push #\push
++		orr	r6, r6, r5, pull #\pull
++		mov	r5, r5, push #\push
++		orr	r5, r5, r4, pull #\pull
++		mov	r4, r4, push #\push
++		orr	r4, r4, r3, pull #\pull
++		stmdb	r0!, {r4 - r9, ip, lr}
++		bge	28b
++	PLD(	cmn	r2, #96			)
++	PLD(	bge	29b			)
++	PLD(	add	r2, r2, #96		)
++		cmn	r2, #16
++		blt	31f
++30:		mov	r7, r3, push #\push
++		ldmdb	r1!, {r3 - r6}
++		sub	r2, r2, #16
++		orr	r7, r7, r6, pull #\pull
++		mov	r6, r6, push #\push
++		orr	r6, r6, r5, pull #\pull
++		mov	r5, r5, push #\push
++		orr	r5, r5, r4, pull #\pull
++		mov	r4, r4, push #\push
++		orr	r4, r4, r3, pull #\pull
++		stmdb	r0!, {r4 - r7}
++31:		adds	r2, r2, #28
+ 		blt	33f
+-32:		mov	ip, r3, lsl #16
++32:		mov	r4, r3, push #\push
+ 		ldr	r3, [r1, #-4]!
+ 		subs	r2, r2, #4
+-		orr	ip, ip, r3, lsr #16
+-		str	ip, [r0, #-4]!
++		orr	r4, r4, r3, pull #\pull
++		str	r4, [r0, #-4]!
+ 		bge	32b
+-33:		add	r1, r1, #2
++33:
++		.endm
++
++
++		backward_copy_shift	push=8	pull=24
++		add	r1, r1, #3
+ 		b	24b
+ 
+-34:		cmp	r2, #12
+-		blt	36f
+-		sub	r2, r2, #12
+-35:		mov	r7, r3, lsl #24
+-		ldmdb	r1!, {r3, r4, r5, r6}
+-		orr	r7, r7, r6, lsr #8
+-		mov	r6, r6, lsl #24
+-		orr	r6, r6, r5, lsr #8
+-		mov	r5, r5, lsl #24
+-		orr	r5, r5, r4, lsr #8
+-		mov	r4, r4, lsl #24
+-		orr	r4, r4, r3, lsr #8
+-		stmdb	r0!, {r4, r5, r6, r7}
+-		subs	r2, r2, #16
+-		bge	35b
+-		adds	r2, r2, #12
+-		blt	37f
+-36:		mov	ip, r3, lsl #24
+-		ldr	r3, [r1, #-4]!
+-		subs	r2, r2, #4
+-		orr	ip, ip, r3, lsr #8
+-		str	ip, [r0, #-4]!
+-		bge	36b
+-37:		add	r1, r1, #1
++34:		backward_copy_shift	push=16	pull=16
++		add	r1, r1, #2
++		b	24b
++
++35:		backward_copy_shift	push=24	pull=8
++		add	r1, r1, #1
+ 		b	24b
+ 
+-		.align
+--- linux-2.4.25/arch/arm/lib/uaccess.S~2.4.25-vrs2-pxa1.patch	2000-09-19 00:15:25.000000000 +0200
++++ linux-2.4.25/arch/arm/lib/uaccess.S	2004-03-31 17:15:11.000000000 +0200
+@@ -43,6 +43,8 @@
+ 		stmfd	sp!, {r2, r4 - r7, lr}
+ 		cmp	r2, #4
+ 		blt	.c2u_not_enough
++	PLD(	pld	[r1, #0]		)
++	PLD(	pld	[r0, #0]		)
+ 		ands	ip, r0, #3
+ 		bne	.c2u_dest_not_aligned
+ .c2u_dest_aligned:
+@@ -71,13 +73,26 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #32
+ 		blt	.c2u_0rem8lp
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
++	PLD(	subs	ip, ip, #64			)
++	PLD(	blt	.c2u_0cpynopld		)
++	PLD(	pld	[r1, #60]		)
++	PLD(	pld	[r0, #60]		)
+ 
+-.c2u_0cpy8lp:	ldmia	r1!, {r3 - r6}
++.c2u_0cpy8lp:
++	PLD(	pld	[r1, #92]		)
++	PLD(	pld	[r0, #92]		)
++.c2u_0cpynopld:	ldmia	r1!, {r3 - r6}
+ 		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		ldmia	r1!, {r3 - r6}
+-		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		subs	ip, ip, #32
++		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		bpl	.c2u_0cpy8lp
++	PLD(	cmn	ip, #64			)
++	PLD(	bge	.c2u_0cpynopld		)
++	PLD(	add	ip, ip, #64		)
++
+ .c2u_0rem8lp:	cmn	ip, #16
+ 		ldmgeia	r1!, {r3 - r6}
+ 		stmgeia	r0!, {r3 - r6}			@ Shouldnt fault
+@@ -115,9 +130,9 @@
+ .c2u_1fupi:	subs	r2, r2, #4
+ 		addmi	ip, r2, #4
+ 		bmi	.c2u_1nowords
+-		mov	r3, r7, lsr #8
++		mov	r3, r7, pull #8
+ 		ldr	r7, [r1], #4
+-		orr	r3, r3, r7, lsl #24
++		orr	r3, r3, r7, push #24
+ USER(		strt	r3, [r0], #4)			@ May fault
+ 		mov	ip, r0, lsl #32 - PAGE_SHIFT
+ 		rsb	ip, ip, #0
+@@ -128,50 +143,63 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #16
+ 		blt	.c2u_1rem8lp
++	PLD(	pld	[r1, #12]		)
++	PLD(	pld	[r0, #12]		)
++	PLD(	subs	ip, ip, #32		)
++	PLD(	blt	.c2u_1cpynopld		)
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
+ 
+-.c2u_1cpy8lp:	mov	r3, r7, lsr #8
++.c2u_1cpy8lp:
++	PLD(	pld	[r1, #44]		)
++	PLD(	pld	[r0, #44]		)
++.c2u_1cpynopld:	mov	r3, r7, pull #8
+ 		ldmia	r1!, {r4 - r7}
+-		orr	r3, r3, r4, lsl #24
+-		mov	r4, r4, lsr #8
+-		orr	r4, r4, r5, lsl #24
+-		mov	r5, r5, lsr #8
+-		orr	r5, r5, r6, lsl #24
+-		mov	r6, r6, lsr #8
+-		orr	r6, r6, r7, lsl #24
+-		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		subs	ip, ip, #16
++		orr	r3, r3, r4, push #24
++		mov	r4, r4, pull #8
++		orr	r4, r4, r5, push #24
++		mov	r5, r5, pull #8
++		orr	r5, r5, r6, push #24
++		mov	r6, r6, pull #8
++		orr	r6, r6, r7, push #24
++		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		bpl	.c2u_1cpy8lp
++	PLD(	cmn	ip, #32			)
++	PLD(	bge	.c2u_1cpynopld		)
++	PLD(	add	ip, ip, #32		)
++
+ .c2u_1rem8lp:	tst	ip, #8
+-		movne	r3, r7, lsr #8
++		movne	r3, r7, pull #8
+ 		ldmneia	r1!, {r4, r7}
+-		orrne	r3, r3, r4, lsl #24
+-		movne	r4, r4, lsr #8
+-		orrne	r4, r4, r7, lsl #24
++		orrne	r3, r3, r4, push #24
++		movne	r4, r4, pull #8
++		orrne	r4, r4, r7, push #24
+ 		stmneia	r0!, {r3 - r4}			@ Shouldnt fault
+ 		tst	ip, #4
+-		movne	r3, r7, lsr #8
++		movne	r3, r7, pull #8
+ 		ldrne	r7, [r1], #4
+-		orrne	r3, r3, r7, lsl #24
++		orrne	r3, r3, r7, push #24
+ 		strnet	r3, [r0], #4			@ Shouldnt fault
+ 		ands	ip, ip, #3
+ 		beq	.c2u_1fupi
+-.c2u_1nowords:	mov	r3, r7, lsr #8
++.c2u_1nowords:	mov	r3, r7, lsr #byte(1)
+ 		teq	ip, #0
+ 		beq	.c2u_finished
+ 		cmp	ip, #2
+ USER(		strbt	r3, [r0], #1)			@ May fault
+-		movge	r3, r3, lsr #8
++		movge	r3, r7, lsr #byte(2)
+ USER(		strgebt	r3, [r0], #1)			@ May fault
+-		movgt	r3, r3, lsr #8
++		movgt	r3, r7, lsr #byte(3)
+ USER(		strgtbt	r3, [r0], #1)			@ May fault
+ 		b	.c2u_finished
+ 
+ .c2u_2fupi:	subs	r2, r2, #4
+ 		addmi	ip, r2, #4
+ 		bmi	.c2u_2nowords
+-		mov	r3, r7, lsr #16
++		mov	r3, r7, pull #16
+ 		ldr	r7, [r1], #4
+-		orr	r3, r3, r7, lsl #16
++		orr	r3, r3, r7, push #16
+ USER(		strt	r3, [r0], #4)			@ May fault
+ 		mov	ip, r0, lsl #32 - PAGE_SHIFT
+ 		rsb	ip, ip, #0
+@@ -182,39 +210,52 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #16
+ 		blt	.c2u_2rem8lp
++	PLD(	pld	[r1, #12]		)
++	PLD(	pld	[r0, #12]		)
++	PLD(	subs	ip, ip, #32		)
++	PLD(	blt	.c2u_2cpynopld		)
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
+ 
+-.c2u_2cpy8lp:	mov	r3, r7, lsr #16
++.c2u_2cpy8lp:
++	PLD(	pld	[r1, #44]		)
++	PLD(	pld	[r0, #44]		)
++.c2u_2cpynopld:	mov	r3, r7, pull #16
+ 		ldmia	r1!, {r4 - r7}
+-		orr	r3, r3, r4, lsl #16
+-		mov	r4, r4, lsr #16
+-		orr	r4, r4, r5, lsl #16
+-		mov	r5, r5, lsr #16
+-		orr	r5, r5, r6, lsl #16
+-		mov	r6, r6, lsr #16
+-		orr	r6, r6, r7, lsl #16
+-		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		subs	ip, ip, #16
++		orr	r3, r3, r4, push #16
++		mov	r4, r4, pull #16
++		orr	r4, r4, r5, push #16
++		mov	r5, r5, pull #16
++		orr	r5, r5, r6, push #16
++		mov	r6, r6, pull #16
++		orr	r6, r6, r7, push #16
++		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		bpl	.c2u_2cpy8lp
++	PLD(	cmn	ip, #32			)
++	PLD(	bge	.c2u_2cpynopld		)
++	PLD(	add	ip, ip, #32		)
++
+ .c2u_2rem8lp:	tst	ip, #8
+-		movne	r3, r7, lsr #16
++		movne	r3, r7, pull #16
+ 		ldmneia	r1!, {r4, r7}
+-		orrne	r3, r3, r4, lsl #16
+-		movne	r4, r4, lsr #16
+-		orrne	r4, r4, r7, lsl #16
++		orrne	r3, r3, r4, push #16
++		movne	r4, r4, pull #16
++		orrne	r4, r4, r7, push #16
+ 		stmneia	r0!, {r3 - r4}			@ Shouldnt fault
+ 		tst	ip, #4
+-		movne	r3, r7, lsr #16
++		movne	r3, r7, pull #16
+ 		ldrne	r7, [r1], #4
+-		orrne	r3, r3, r7, lsl #16
++		orrne	r3, r3, r7, push #16
+ 		strnet	r3, [r0], #4			@ Shouldnt fault
+ 		ands	ip, ip, #3
+ 		beq	.c2u_2fupi
+-.c2u_2nowords:	mov	r3, r7, lsr #16
++.c2u_2nowords:	mov	r3, r7, lsr #byte(2)
+ 		teq	ip, #0
+ 		beq	.c2u_finished
+ 		cmp	ip, #2
+ USER(		strbt	r3, [r0], #1)			@ May fault
+-		movge	r3, r3, lsr #8
++		movge	r3, r7, lsr #byte(3)
+ USER(		strgebt	r3, [r0], #1)			@ May fault
+ 		ldrgtb	r3, [r1], #0
+ USER(		strgtbt	r3, [r0], #1)			@ May fault
+@@ -223,9 +264,9 @@
+ .c2u_3fupi:	subs	r2, r2, #4
+ 		addmi	ip, r2, #4
+ 		bmi	.c2u_3nowords
+-		mov	r3, r7, lsr #24
++		mov	r3, r7, pull #24
+ 		ldr	r7, [r1], #4
+-		orr	r3, r3, r7, lsl #8
++		orr	r3, r3, r7, push #8
+ USER(		strt	r3, [r0], #4)			@ May fault
+ 		mov	ip, r0, lsl #32 - PAGE_SHIFT
+ 		rsb	ip, ip, #0
+@@ -236,41 +277,54 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #16
+ 		blt	.c2u_3rem8lp
++	PLD(	pld	[r1, #12]		)
++	PLD(	pld	[r0, #12]		)
++	PLD(	subs	ip, ip, #32		)
++	PLD(	blt	.c2u_3cpynopld		)
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
+ 
+-.c2u_3cpy8lp:	mov	r3, r7, lsr #24
++.c2u_3cpy8lp:
++	PLD(	pld	[r1, #44]		)
++	PLD(	pld	[r0, #44]		)
++.c2u_3cpynopld:	mov	r3, r7, pull #24
+ 		ldmia	r1!, {r4 - r7}
+-		orr	r3, r3, r4, lsl #8
+-		mov	r4, r4, lsr #24
+-		orr	r4, r4, r5, lsl #8
+-		mov	r5, r5, lsr #24
+-		orr	r5, r5, r6, lsl #8
+-		mov	r6, r6, lsr #24
+-		orr	r6, r6, r7, lsl #8
+-		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		subs	ip, ip, #16
++		orr	r3, r3, r4, push #8
++		mov	r4, r4, pull #24
++		orr	r4, r4, r5, push #8
++		mov	r5, r5, pull #24
++		orr	r5, r5, r6, push #8
++		mov	r6, r6, pull #24
++		orr	r6, r6, r7, push #8
++		stmia	r0!, {r3 - r6}			@ Shouldnt fault
+ 		bpl	.c2u_3cpy8lp
++	PLD(	cmn	ip, #32			)
++	PLD(	bge	.c2u_3cpynopld		)
++	PLD(	add	ip, ip, #32		)
++
+ .c2u_3rem8lp:	tst	ip, #8
+-		movne	r3, r7, lsr #24
++		movne	r3, r7, pull #24
+ 		ldmneia	r1!, {r4, r7}
+-		orrne	r3, r3, r4, lsl #8
+-		movne	r4, r4, lsr #24
+-		orrne	r4, r4, r7, lsl #8
++		orrne	r3, r3, r4, push #8
++		movne	r4, r4, pull #24
++		orrne	r4, r4, r7, push #8
+ 		stmneia	r0!, {r3 - r4}			@ Shouldnt fault
+ 		tst	ip, #4
+-		movne	r3, r7, lsr #24
++		movne	r3, r7, pull #24
+ 		ldrne	r7, [r1], #4
+-		orrne	r3, r3, r7, lsl #8
++		orrne	r3, r3, r7, push #8
+ 		strnet	r3, [r0], #4			@ Shouldnt fault
+ 		ands	ip, ip, #3
+ 		beq	.c2u_3fupi
+-.c2u_3nowords:	mov	r3, r7, lsr #24
++.c2u_3nowords:	mov	r3, r7, lsr #byte(3)
+ 		teq	ip, #0
+ 		beq	.c2u_finished
+ 		cmp	ip, #2
+ USER(		strbt	r3, [r0], #1)			@ May fault
+-		ldrge	r3, [r1], #0
++		ldrgeb	r3, [r1], #1
+ USER(		strgebt	r3, [r0], #1)			@ May fault
+-		movgt	r3, r3, lsr #8
++		ldrgtb	r3, [r1], #0
+ USER(		strgtbt	r3, [r0], #1)			@ May fault
+ 		b	.c2u_finished
+ 
+@@ -302,6 +356,8 @@
+ 		stmfd	sp!, {r0, r2, r4 - r7, lr}
+ 		cmp	r2, #4
+ 		blt	.cfu_not_enough
++	PLD(	pld	[r1, #0]		)
++	PLD(	pld	[r0, #0]		)
+ 		ands	ip, r0, #3
+ 		bne	.cfu_dest_not_aligned
+ .cfu_dest_aligned:
+@@ -329,13 +385,26 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #32
+ 		blt	.cfu_0rem8lp
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
++	PLD(	subs	ip, ip, #64			)
++	PLD(	blt	.cfu_0cpynopld		)
++	PLD(	pld	[r1, #60]		)
++	PLD(	pld	[r0, #60]		)
+ 
+-.cfu_0cpy8lp:	ldmia	r1!, {r3 - r6}			@ Shouldnt fault
++.cfu_0cpy8lp:
++	PLD(	pld	[r1, #92]		)
++	PLD(	pld	[r0, #92]		)
++.cfu_0cpynopld:	ldmia	r1!, {r3 - r6}			@ Shouldnt fault
+ 		stmia	r0!, {r3 - r6}
+ 		ldmia	r1!, {r3 - r6}			@ Shouldnt fault
+-		stmia	r0!, {r3 - r6}
+ 		subs	ip, ip, #32
++		stmia	r0!, {r3 - r6}
+ 		bpl	.cfu_0cpy8lp
++	PLD(	cmn	ip, #64			)
++	PLD(	bge	.cfu_0cpynopld		)
++	PLD(	add	ip, ip, #64		)
++
+ .cfu_0rem8lp:	cmn	ip, #16
+ 		ldmgeia	r1!, {r3 - r6}			@ Shouldnt fault
+ 		stmgeia	r0!, {r3 - r6}
+@@ -374,9 +443,9 @@
+ .cfu_1fupi:	subs	r2, r2, #4
+ 		addmi	ip, r2, #4
+ 		bmi	.cfu_1nowords
+-		mov	r3, r7, lsr #8
++		mov	r3, r7, pull #8
+ USER(		ldrt	r7, [r1], #4)			@ May fault
+-		orr	r3, r3, r7, lsl #24
++		orr	r3, r3, r7, push #24
+ 		str	r3, [r0], #4
+ 		mov	ip, r1, lsl #32 - PAGE_SHIFT
+ 		rsb	ip, ip, #0
+@@ -387,50 +456,63 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #16
+ 		blt	.cfu_1rem8lp
++	PLD(	pld	[r1, #12]		)
++	PLD(	pld	[r0, #12]		)
++	PLD(	subs	ip, ip, #32		)
++	PLD(	blt	.cfu_1cpynopld		)
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
+ 
+-.cfu_1cpy8lp:	mov	r3, r7, lsr #8
++.cfu_1cpy8lp:
++	PLD(	pld	[r1, #44]		)
++	PLD(	pld	[r0, #44]		)
++.cfu_1cpynopld:	mov	r3, r7, pull #8
+ 		ldmia	r1!, {r4 - r7}			@ Shouldnt fault
+-		orr	r3, r3, r4, lsl #24
+-		mov	r4, r4, lsr #8
+-		orr	r4, r4, r5, lsl #24
+-		mov	r5, r5, lsr #8
+-		orr	r5, r5, r6, lsl #24
+-		mov	r6, r6, lsr #8
+-		orr	r6, r6, r7, lsl #24
+-		stmia	r0!, {r3 - r6}
+ 		subs	ip, ip, #16
++		orr	r3, r3, r4, push #24
++		mov	r4, r4, pull #8
++		orr	r4, r4, r5, push #24
++		mov	r5, r5, pull #8
++		orr	r5, r5, r6, push #24
++		mov	r6, r6, pull #8
++		orr	r6, r6, r7, push #24
++		stmia	r0!, {r3 - r6}
+ 		bpl	.cfu_1cpy8lp
++	PLD(	cmn	ip, #32			)
++	PLD(	bge	.cfu_1cpynopld		)
++	PLD(	add	ip, ip, #32		)
++
+ .cfu_1rem8lp:	tst	ip, #8
+-		movne	r3, r7, lsr #8
++		movne	r3, r7, pull #8
+ 		ldmneia	r1!, {r4, r7}			@ Shouldnt fault
+-		orrne	r3, r3, r4, lsl #24
+-		movne	r4, r4, lsr #8
+-		orrne	r4, r4, r7, lsl #24
++		orrne	r3, r3, r4, push #24
++		movne	r4, r4, pull #8
++		orrne	r4, r4, r7, push #24
+ 		stmneia	r0!, {r3 - r4}
+ 		tst	ip, #4
+-		movne	r3, r7, lsr #8
++		movne	r3, r7, pull #8
+ USER(		ldrnet	r7, [r1], #4)			@ May fault
+-		orrne	r3, r3, r7, lsl #24
++		orrne	r3, r3, r7, push #24
+ 		strne	r3, [r0], #4
+ 		ands	ip, ip, #3
+ 		beq	.cfu_1fupi
+-.cfu_1nowords:	mov	r3, r7, lsr #8
++.cfu_1nowords:	mov	r3, r7, lsr #byte(1)
+ 		teq	ip, #0
+ 		beq	.cfu_finished
+ 		cmp	ip, #2
+ 		strb	r3, [r0], #1
+-		movge	r3, r3, lsr #8
++		movge	r3, r7, lsr #byte(2)
+ 		strgeb	r3, [r0], #1
+-		movgt	r3, r3, lsr #8
++		movgt	r3, r7, lsr #byte(3)
+ 		strgtb	r3, [r0], #1
+ 		b	.cfu_finished
+ 
+ .cfu_2fupi:	subs	r2, r2, #4
+ 		addmi	ip, r2, #4
+ 		bmi	.cfu_2nowords
+-		mov	r3, r7, lsr #16
++		mov	r3, r7, pull #16
+ USER(		ldrt	r7, [r1], #4)			@ May fault
+-		orr	r3, r3, r7, lsl #16
++		orr	r3, r3, r7, push #16
+ 		str	r3, [r0], #4
+ 		mov	ip, r1, lsl #32 - PAGE_SHIFT
+ 		rsb	ip, ip, #0
+@@ -441,39 +523,52 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #16
+ 		blt	.cfu_2rem8lp
++	PLD(	pld	[r1, #12]		)
++	PLD(	pld	[r0, #12]		)
++	PLD(	subs	ip, ip, #32		)
++	PLD(	blt	.cfu_2cpynopld		)
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
+ 
+-.cfu_2cpy8lp:	mov	r3, r7, lsr #16
++.cfu_2cpy8lp:
++	PLD(	pld	[r1, #44]		)
++	PLD(	pld	[r0, #44]		)
++.cfu_2cpynopld:	mov	r3, r7, pull #16
+ 		ldmia	r1!, {r4 - r7}			@ Shouldnt fault
+-		orr	r3, r3, r4, lsl #16
+-		mov	r4, r4, lsr #16
+-		orr	r4, r4, r5, lsl #16
+-		mov	r5, r5, lsr #16
+-		orr	r5, r5, r6, lsl #16
+-		mov	r6, r6, lsr #16
+-		orr	r6, r6, r7, lsl #16
+-		stmia	r0!, {r3 - r6}
+ 		subs	ip, ip, #16
++		orr	r3, r3, r4, push #16
++		mov	r4, r4, pull #16
++		orr	r4, r4, r5, push #16
++		mov	r5, r5, pull #16
++		orr	r5, r5, r6, push #16
++		mov	r6, r6, pull #16
++		orr	r6, r6, r7, push #16
++		stmia	r0!, {r3 - r6}
+ 		bpl	.cfu_2cpy8lp
++	PLD(	cmn	ip, #32			)
++	PLD(	bge	.cfu_2cpynopld		)
++	PLD(	add	ip, ip, #32		)
++
+ .cfu_2rem8lp:	tst	ip, #8
+-		movne	r3, r7, lsr #16
++		movne	r3, r7, pull #16
+ 		ldmneia	r1!, {r4, r7}			@ Shouldnt fault
+-		orrne	r3, r3, r4, lsl #16
+-		movne	r4, r4, lsr #16
+-		orrne	r4, r4, r7, lsl #16
++		orrne	r3, r3, r4, push #16
++		movne	r4, r4, pull #16
++		orrne	r4, r4, r7, push #16
+ 		stmneia	r0!, {r3 - r4}
+ 		tst	ip, #4
+-		movne	r3, r7, lsr #16
++		movne	r3, r7, pull #16
+ USER(		ldrnet	r7, [r1], #4)			@ May fault
+-		orrne	r3, r3, r7, lsl #16
++		orrne	r3, r3, r7, push #16
+ 		strne	r3, [r0], #4
+ 		ands	ip, ip, #3
+ 		beq	.cfu_2fupi
+-.cfu_2nowords:	mov	r3, r7, lsr #16
++.cfu_2nowords:	mov	r3, r7, lsr #byte(2)
+ 		teq	ip, #0
+ 		beq	.cfu_finished
+ 		cmp	ip, #2
+ 		strb	r3, [r0], #1
+-		movge	r3, r3, lsr #8
++		movge	r3, r7, lsr #byte(3)
+ 		strgeb	r3, [r0], #1
+ USER(		ldrgtbt	r3, [r1], #0)			@ May fault
+ 		strgtb	r3, [r0], #1
+@@ -482,9 +577,9 @@
+ .cfu_3fupi:	subs	r2, r2, #4
+ 		addmi	ip, r2, #4
+ 		bmi	.cfu_3nowords
+-		mov	r3, r7, lsr #24
++		mov	r3, r7, pull #24
+ USER(		ldrt	r7, [r1], #4)			@ May fault
+-		orr	r3, r3, r7, lsl #8
++		orr	r3, r3, r7, push #8
+ 		str	r3, [r0], #4
+ 		mov	ip, r1, lsl #32 - PAGE_SHIFT
+ 		rsb	ip, ip, #0
+@@ -495,41 +590,54 @@
+ 		sub	r2, r2, ip
+ 		subs	ip, ip, #16
+ 		blt	.cfu_3rem8lp
++	PLD(	pld	[r1, #12]		)
++	PLD(	pld	[r0, #12]		)
++	PLD(	subs	ip, ip, #32		)
++	PLD(	blt	.cfu_3cpynopld		)
++	PLD(	pld	[r1, #28]		)
++	PLD(	pld	[r0, #28]		)
+ 
+-.cfu_3cpy8lp:	mov	r3, r7, lsr #24
++.cfu_3cpy8lp:
++	PLD(	pld	[r1, #44]		)
++	PLD(	pld	[r0, #44]		)
++.cfu_3cpynopld:	mov	r3, r7, pull #24
+ 		ldmia	r1!, {r4 - r7}			@ Shouldnt fault
+-		orr	r3, r3, r4, lsl #8
+-		mov	r4, r4, lsr #24
+-		orr	r4, r4, r5, lsl #8
+-		mov	r5, r5, lsr #24
+-		orr	r5, r5, r6, lsl #8
+-		mov	r6, r6, lsr #24
+-		orr	r6, r6, r7, lsl #8
++		orr	r3, r3, r4, push #8
++		mov	r4, r4, pull #24
++		orr	r4, r4, r5, push #8
++		mov	r5, r5, pull #24
++		orr	r5, r5, r6, push #8
++		mov	r6, r6, pull #24
++		orr	r6, r6, r7, push #8
+ 		stmia	r0!, {r3 - r6}
+ 		subs	ip, ip, #16
+ 		bpl	.cfu_3cpy8lp
++	PLD(	cmn	ip, #32			)
++	PLD(	bge	.cfu_3cpynopld		)
++	PLD(	add	ip, ip, #32		)
++
+ .cfu_3rem8lp:	tst	ip, #8
+-		movne	r3, r7, lsr #24
++		movne	r3, r7, pull #24
+ 		ldmneia	r1!, {r4, r7}			@ Shouldnt fault
+-		orrne	r3, r3, r4, lsl #8
+-		movne	r4, r4, lsr #24
+-		orrne	r4, r4, r7, lsl #8
++		orrne	r3, r3, r4, push #8
++		movne	r4, r4, pull #24
++		orrne	r4, r4, r7, push #8
+ 		stmneia	r0!, {r3 - r4}
+ 		tst	ip, #4
+-		movne	r3, r7, lsr #24
++		movne	r3, r7, pull #24
+ USER(		ldrnet	r7, [r1], #4)			@ May fault
+-		orrne	r3, r3, r7, lsl #8
++		orrne	r3, r3, r7, push #8
+ 		strne	r3, [r0], #4
+ 		ands	ip, ip, #3
+ 		beq	.cfu_3fupi
+-.cfu_3nowords:	mov	r3, r7, lsr #24
++.cfu_3nowords:	mov	r3, r7, lsr #byte(3)
+ 		teq	ip, #0
+ 		beq	.cfu_finished
+ 		cmp	ip, #2
+ 		strb	r3, [r0], #1
+-USER(		ldrget	r3, [r1], #0)			@ May fault
++USER(		ldrgebt	r3, [r1], #1)			@ May fault
+ 		strgeb	r3, [r0], #1
+-		movgt	r3, r3, lsr #8
++USER(		ldrgtbt	r3, [r1], #1)			@ May fault
+ 		strgtb	r3, [r0], #1
+ 		b	.cfu_finished
+ 
+@@ -544,7 +652,7 @@
+ 		ldr	r1, [sp], #4			@ unsigned long count
+ 		subs	r4, r1, r2			@ bytes left to copy
+ 		movne	r1, r4
+-		blne	SYMBOL_NAME(__memzero)
++		blne	__memzero
+ 		mov	r0, r4
+ 		LOADREGS(fd,sp!, {r4 - r7, pc})
+ 		.previous
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,56 @@
++#
++# Makefile for the linux kernel.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++USE_STANDARD_AS_RULE := true
++
++O_TARGET		:= pxa.o
++
++obj-y :=
++obj-m :=
++obj-n :=
++obj-  :=
++
++export-objs := generic.o irq.o dma.o sa1111.o \
++               usb_ctl.o usb_recv.o usb_send.o
++
++# Common support (must be linked before board specific support)
++obj-y += generic.o irq.o dma.o
++obj-$(CONFIG_SA1111) += sa1111.o
++
++# Specific board support
++obj-$(CONFIG_ARCH_CSB226) += csb226.o
++obj-$(CONFIG_ARCH_INNOKOM) += innokom.o
++obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
++obj-$(CONFIG_ARCH_PXA_CERF) += cerf.o
++obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
++obj-$(CONFIG_ARCH_TRIZEPS2) += trizeps2.o
++
++# Support for blinky lights
++leds-y := leds.o
++leds-$(CONFIG_ARCH_CSB226) += leds-csb226.o
++leds-$(CONFIG_ARCH_INNOKOM) += leds-innokom.o
++leds-$(CONFIG_ARCH_LUBBOCK) += leds-lubbock.o
++leds-$(CONFIG_ARCH_PXA_IDP) += leds-idp.o
++leds-$(CONFIG_ARCH_PXA_CERF) += leds-cerf.o
++
++obj-$(CONFIG_LEDS) += $(leds-y)
++
++# PXA USB client support
++list-multi += pxausb_core.o
++pxausb_core-objs := usb_ctl.o usb_ep0.o usb_recv.o usb_send.o
++obj-$(CONFIG_PXA_USB) += pxausb_core.o
++obj-$(CONFIG_PXA_USB_NETLINK) += usb-eth.o
++obj-$(CONFIG_PXA_USB_CHAR) += usb-char.o
++
++# Misc features
++obj-$(CONFIG_PM) += pm.o sleep.o
++obj-$(CONFIG_CPU_FREQ) += cpu-pxa.o
++
++include $(TOPDIR)/Rules.make
++
++pxausb_core.o: $(pxausb_core-objs)
++	$(LD) -r -o $@ $(pxausb_core-objs)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/cerf.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,266 @@
++/*
++ *  linux/arch/arm/mach-pxa/cerf.c
++ *  
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/io.h>
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING       1
++
++#if DEBUGGING
++static unsigned int cerf_debug = DEBUGGING;
++#else
++#define cerf_debug       0
++#endif
++
++static void __init cerf_init_irq(void)
++{
++	pxa_init_irq();
++
++	if( cerf_debug > 1)
++	{
++#if 0
++		GPDR0 = 0xc05b9130;
++		GPDR1 = 0xfcffab82;
++		GPDR2 = 0x0001ffff;
++#endif
++
++		printk(KERN_INFO "Pin directions:\n");
++		printk(KERN_INFO "GPDR0 0x%08x\n", GPDR0);
++		printk(KERN_INFO "GPDR1 0x%08x\n", GPDR1);
++		printk(KERN_INFO "GPDR2 0x%08x\n", GPDR2);
++
++		printk(KERN_INFO "Pin State:\n");
++		printk(KERN_INFO "GPLR0 0x%08x\n", GPLR0);
++		printk(KERN_INFO "GPLR1 0x%08x\n", GPLR1);
++		printk(KERN_INFO "GPLR2 0x%08x\n", GPLR2);
++
++		printk(KERN_INFO "Rising Edge:\n");
++		printk(KERN_INFO "GRER0 0x%08x\n", GRER0);
++		printk(KERN_INFO "GRER1 0x%08x\n", GRER1);
++		printk(KERN_INFO "GRER2 0x%08x\n", GRER2);
++
++		printk(KERN_INFO "Falling Edge:\n");
++		printk(KERN_INFO "GFER0 0x%08x\n", GFER0);
++		printk(KERN_INFO "GFER1 0x%08x\n", GFER1);
++		printk(KERN_INFO "GFER2 0x%08x\n", GFER2);
++	}
++
++	/* set_GPIO_IRQ_edge has to be called before an irq can be requested */
++	set_GPIO_IRQ_edge(  0, GPIO_FALLING_EDGE); /* CPLD               */
++#ifdef CONFIG_PXA_CERF_PDA
++	set_GPIO_IRQ_edge(  2, GPIO_RISING_EDGE);  /* UART B Interrupt   */
++	set_GPIO_IRQ_edge(  3, GPIO_RISING_EDGE);  /* UART A Interrupt   */
++	set_GPIO_IRQ_edge( 32, GPIO_RISING_EDGE);  /* UCB1400 Interrupt  */
++#endif
++	set_GPIO_IRQ_edge( 14, GPIO_FALLING_EDGE); /* PCMCIA Card Detect */
++	set_GPIO_IRQ_edge( 21, GPIO_RISING_EDGE);  /* Ethernet Interrupt */
++}
++
++static int __init cerf_init(void)
++{
++	/*
++	 * All of the code that was here was SA1111 init code
++	 * which we do not have.
++	 */
++	return 0;
++}
++
++__initcall(cerf_init);
++
++static void __init
++fixup_cerf(struct machine_desc *desc, struct param_struct *params,
++		char **cmdline, struct meminfo *mi)
++{
++	SET_BANK (0, CERF_RAM_BASE, CERF_RAM_SIZE);
++	mi->nr_banks      = 1;
++
++#if 0 // Enable this stuff if you plan on not using jffs2
++	setup_ramdisk (1, 0, 0, 8192);
++	setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024);
++	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++#endif
++}
++
++/*
++ * IO map for the devices.
++ */
++static struct map_desc cerf_io_desc[] __initdata = {
++ /* virtual           physical          length            domain     r  w  c  b */
++  { CERF_FLASH_BASE , CERF_FLASH_PHYS , CERF_FLASH_SIZE , DOMAIN_IO, 0, 1, 0, 0 },
++  { CERF_ETH_BASE   , CERF_ETH_PHYS   , CERF_ETH_SIZE   , DOMAIN_IO, 0, 1, 0, 0 },
++#ifdef CONFIG_PXA_CERF_PDA
++  { CERF_BT_BASE    , CERF_BT_PHYS    , CERF_BT_SIZE    , DOMAIN_IO, 0, 1, 0, 0 },
++  { CERF_SERIAL_BASE, CERF_SERIAL_PHYS, CERF_SERIAL_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
++  { CERF_CPLD_BASE  , CERF_CPLD_PHYS  , CERF_CPLD_SIZE  , DOMAIN_IO, 0, 1, 0, 0 },
++#endif
++
++  LAST_DESC
++};
++
++static void __init cerf_map_io(void)
++{
++	pxa_map_io();
++	iotable_init(cerf_io_desc);
++
++	if( cerf_debug > 1)
++	{
++		printk(KERN_INFO "origMCS0 = 0x%08x\n", MSC0);
++		printk(KERN_INFO "origMCS1 = 0x%08x\n", MSC1);
++		printk(KERN_INFO "origMCS2 = 0x%08x\n", MSC2);
++	}
++
++	/* setup memory timing for CS0/1 */
++	MSC0 = MSC_CS(0, MSC_RBUFF(MSC_RBUFF_SLOW) | 
++			 MSC_RRR(3) |
++			 MSC_RDN(15) |
++			 MSC_RDF(13) |
++			 MSC_RBW(0) |
++			 MSC_RT(0)) |
++#ifdef CONFIG_PXA_CERF_PDA
++               MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) | 
++			 MSC_RRR(7) |
++			 MSC_RDN(15) |
++			 MSC_RDF(15) |
++			 MSC_RBW(1) |
++			 MSC_RT(0));
++#elif defined(CONFIG_PXA_CERF_BOARD)
++               MSC_CS(1, MSC_RBUFF(MSC_RBUFF_SLOW) | 
++			 MSC_RRR(1) |
++			 MSC_RDN(2) |
++			 MSC_RDF(4) |
++			 MSC_RBW(0) |
++			 MSC_RT(4));
++#endif
++	printk(KERN_INFO "MCS0 = 0x%08x\n", MSC0);
++
++	/* setup memory timing for CS2/3 */
++	MSC1 = MSC_CS(2, MSC_RBUFF(MSC_RBUFF_SLOW) | 
++			 MSC_RRR(5) |
++			 MSC_RDN(10) |
++			 MSC_RDF(10) |
++			 MSC_RBW(1) |
++			 MSC_RT(0)) |
++               MSC_CS(3, MSC_RBUFF(MSC_RBUFF_SLOW) | 
++			 MSC_RRR(5) |
++			 MSC_RDN(10) |
++			 MSC_RDF(10) |
++			 MSC_RBW(1) |
++			 MSC_RT(0));
++	printk(KERN_INFO "MCS1 = 0x%08x\n", MSC1);
++
++	/* setup memory timing for CS4/5 */
++	MSC2 = MSC_CS(4, MSC_RBUFF(MSC_RBUFF_SLOW) | 
++			 MSC_RRR(2) |
++			 MSC_RDN(4) |
++			 MSC_RDF(4) |
++			 MSC_RBW(1) |
++			 MSC_RT(0)) |
++               MSC_CS(5, MSC_RBUFF(MSC_RBUFF_SLOW) | 
++			 MSC_RRR(2) |
++			 MSC_RDN(4) |
++			 MSC_RDF(4) |
++			 MSC_RBW(1) |
++			 MSC_RT(0));
++	printk(KERN_INFO "MCS2 = 0x%08x\n", MSC2);
++
++#ifdef CONFIG_SOUND_PXA_AC97
++	printk(KERN_INFO "Enabling sound amp for pxa cerf pda.\n");
++	outw( CERF_PDA_SOUND_ENABLE, CERF_CPLD_BASE+CERF_PDA_CPLD_SOUND_ENA);
++#endif
++
++#ifdef CONFIG_FB_PXA
++	printk(KERN_INFO "Setting LCD to brightness to %d/15\n", CERF_PDA_DEFAULT_BRIGHTNESS);
++	outw( CERF_PDA_DEFAULT_BRIGHTNESS, CERF_CPLD_BASE+CERF_PDA_CPLD_BRIGHTNESS);
++#endif
++
++#ifdef CONFIG_IRDA
++	/* Enable IrDA UART (SIR)*/
++	CKEN |= CKEN5_STUART;
++
++	/* We want to get our goods from the STUART */
++	set_GPIO_mode(GPIO46_STRXD_MD);
++	set_GPIO_mode(GPIO47_STTXD_MD);
++
++	/* make sure FIR ICP is off */
++	ICCR0 = 0;
++
++	/* configure STUART to for SIR
++	 * NOTE: RCVEIR and XMITIR must not be set at the same time!
++	 * Start with receive in IR mode, and switch transmit to IR only
++	 * when we need to send something in serial driver.
++	 */
++	STISR = IrSR_IR_RECEIVE_ON;
++#endif
++
++#if 0
++	/* Connect FIR ICP to GPIO pins */
++	CKEN |= CKEN13_FICP;
++	set_GPIO_mode(GPIO46_ICPRXD_MD);
++	set_GPIO_mode(GPIO47_ICPTXD_MD);
++	ICCR0 = 0x1 | 0x18; //ICP unit enable
++#endif
++
++#if 0
++	/* Enable BT UART */
++	CKEN |= CKEN7_BTUART;
++	set_GPIO_mode(GPIO42_BTRXD_MD);
++	set_GPIO_mode(GPIO43_BTTXD_MD);
++	set_GPIO_mode(GPIO44_BTCTS_MD);
++	set_GPIO_mode(GPIO45_BTRTS_MD);
++#endif
++
++	if( cerf_debug > 1)
++	{
++		printk(KERN_INFO "GPDR0   0x%08x\n", GPDR0);
++		printk(KERN_INFO "GPDR1   0x%08x\n", GPDR1);
++		printk(KERN_INFO "GPDR2   0x%08x\n", GPDR2);
++		printk(KERN_INFO "GPLR0   0x%08x\n", GPLR0);
++		printk(KERN_INFO "GPLR1   0x%08x\n", GPLR1);
++		printk(KERN_INFO "GPLR2   0x%08x\n", GPLR2);
++		printk(KERN_INFO "GAFR0_L 0x%08x\n", GAFR0_L);
++		printk(KERN_INFO "GAFR0_U 0x%08x\n", GAFR0_U);
++		printk(KERN_INFO "GAFR1_L 0x%08x\n", GAFR1_L);
++		printk(KERN_INFO "GAFR1_U 0x%08x\n", GAFR1_U);
++		printk(KERN_INFO "GAFR2_L 0x%08x\n", GAFR2_L);
++		printk(KERN_INFO "GAFR2_U 0x%08x\n", GAFR2_U);
++		printk(KERN_INFO "CKEN  = 0x%08x\n", CKEN);
++		printk(KERN_INFO "ICCR0 = 0x%08x\n", ICCR0);
++		printk(KERN_INFO "STISR = 0x%08x\n", STISR);
++	}
++}
++
++MACHINE_START(PXA_CERF, "CerfBoard PXA Reference Board")
++	MAINTAINER("Intrinsyc Software Inc.")
++	BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000)
++	BOOT_PARAMS(0xa0000100)
++	FIXUP(fixup_cerf)
++	MAPIO(cerf_map_io)
++	INITIRQ(cerf_init_irq)
++MACHINE_END
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/cpu-pxa.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,240 @@
++/*
++ *  linux/arch/arm/mach-pxa/cpu-pxa.c
++ *
++ *  Copyright (C) 2002,2003 Intrinsyc Software
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * History:
++ *   31-Jul-2002 : Initial version [FB]
++ *   29-Jan-2003 : added PXA255 support [FB]
++ * 
++ * Note:
++ *
++ * Quote from erratum 134: 
++ * ""If the operation of these peripherals would be adversely affected,
++ *   then these peripherals would have to be disabled during a frequency
++ *   change. (MMC,FFUART,STUART,BTUART,IRDA,SSP,UDC,AC97)""
++ *
++ * This sounds like they are not sure what the bug is...
++ * If you run into problems with any of these peripherals, the effected
++ * driver should register with cpu freq notification and disable/enable 
++ * the peripheral on CPUFREQ_PRECHANGE and CPUFREQ_POSTCHANGE.
++ *  
++ * So far I've tested this code only under light load. It works for me.
++ *
++ * TODO: 
++ *   - determine min/max freq at runtime
++ *   - determine pxbus value at runtime
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++
++#include <asm/hardware.h>
++
++#define DEBUGGING	1
++
++#if DEBUGGING
++static unsigned int freq_debug = DEBUGGING;
++#else
++#define freq_debug	0
++#endif  
++
++typedef struct
++{
++	unsigned int khz;
++	unsigned int cccr;
++	unsigned int pxbus;
++} pxa_freqs_t;
++
++#define CCLKCFG_TURBO		0x1
++#define CCLKCFG_FCS		0x2
++
++#define PXA250_REV_A1		0x1
++#define PXA250_REV_B2		0x4
++#define PXA25x_MIN_FREQ		99000
++
++//#define PXA25x_ALLOW_OVERCLOCK
++
++#ifdef PXA25x_ALLOW_OVERCLOCK
++#warning *** Overclocking enabled - this may fry your hardware - you have been warned ***
++#define OC(x...)	x
++#define PXA25x_MAX_FREQ		471000
++#else
++#define OC(x...)
++#define PXA25x_MAX_FREQ		400000
++#endif
++
++/* If CONFIG_CPU_FREQ is turned on but we find (at runtime) 
++ * we can't support scaling, try to handle requests gracefully.
++ */
++static int supported;
++
++static pxa_freqs_t pxa250_valid_freqs[] =
++{
++	{199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
++	{298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
++	{398100, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
++	{0,0}
++};
++
++static pxa_freqs_t pxa255_valid_freqs[] =
++{
++	{ 99000, 0x121, 50}, /* mem= 99, run= 99, turbo= 99, PXbus= 50 */
++OC(	{118000, 0x122, 59},)/* mem=118, run=118, turbo=118, PXbus= 59 OC'd mem */
++	{199100, 0x141, 99}, /* mem= 99, run=199, turbo=199, PXbus= 99 */
++OC(	{236000, 0x142,118},)/* mem=118, run=236, turbo=236, PXbus=118 OC'd mem */
++	{298600, 0x1c1, 99}, /* mem= 99, run=199, turbo=298, PXbus= 99 */
++OC(	{354000, 0x1c2,118},)/* mem=118, run=236, turbo=354, PXbus=118 OC'd mem */
++	{398099, 0x241, 99}, /* mem= 99, run=199, turbo=398, PXbus= 99 */
++	{398100, 0x161,196}, /* mem= 99, run=398, turbo=398, PXbus=196 */
++OC(	{471000, 0x162,236},)/* mem=118, run=471, turbo=471, PXbus=236 OC'd mem/core/bus */
++	{0,0}
++};
++
++static pxa_freqs_t *pxa_valid_freqs;
++
++/* This should be called with a valid freq point that was
++ * obtained via pxa_validate_speed
++ */
++static pxa_freqs_t * pxa_get_freq_info( unsigned int khz)
++{
++	int i=0;
++	while( pxa_valid_freqs[i].khz)
++	{
++		if( pxa_valid_freqs[i].khz == khz) 
++			return &pxa_valid_freqs[i]; 
++		i++;
++	}
++
++	/* shouldn't get here */
++	return 0;
++}
++
++/* find a valid frequency point */
++static unsigned int pxa_validate_speed(unsigned int khz)
++{
++	int i=0;
++	unsigned int vfreq = 0;
++	while( pxa_valid_freqs[i].khz && (khz >= pxa_valid_freqs[i].khz))
++	{
++		vfreq = pxa_valid_freqs[i].khz;
++		i++;
++	}
++	return vfreq;
++}
++
++/* This should be called with a valid freq point that was
++ * obtained via pxa_validate_speed
++ */
++static void pxa_setspeed(unsigned int khz)
++{
++	unsigned long flags;
++	unsigned int unused;
++	void *ramstart = phys_to_virt(0xa0000000);
++	pxa_freqs_t *freq_info;
++
++	if( ! supported) return;
++
++	freq_info = pxa_get_freq_info( khz);
++
++	if( ! freq_info) return;
++
++	CCCR = freq_info->cccr;
++	if( freq_debug)
++		printk(KERN_INFO "Changing CPU frequency to %d Mhz (PXbus=%dMhz).\n", 
++			khz/1000, freq_info->pxbus);
++
++	local_irq_save(flags);
++	__asm__ __volatile__("\
++		ldr	r4, [%1]			@load MDREFR	\n\
++		b	2f						\n\
++		.align  5						\n\
++1:									\n\
++		mcr	p14, 0, %2, c6, c0, 0		@ set CCLKCFG[FCS] \n\
++									\n\
++		@ restart sdcke 0 / 1					\n\
++		bic	r5,  r4,  #(0x00001000 | 0x00008000)	@ MDREFR_E0PIN | MDREFR_E1PIN \n\
++		str	r5,  [%1]			@clear		\n\
++		str	r4,  [%1]			@restore	\n\
++									\n\
++		@ Generate refresh cycles for all banks			\n\
++		ldr	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++		str	r4, [%3]					\n\
++									\n\
++		b	3f						\n\
++2:		b	1b						\n\
++3:		nop							\n\
++		"
++		: "=&r" (unused)
++		: "r" (&MDREFR), "r" (CCLKCFG_TURBO|CCLKCFG_FCS), "r" (ramstart)
++		: "r4", "r5");
++	local_irq_restore(flags);
++}
++
++static int pxa_init_freqs( void)
++{
++	int cpu_ver; 
++	asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver));
++
++	if( (cpu_ver & 0xf) <= PXA250_REV_A1)
++	{
++		return 0;
++	}
++
++	if( (cpu_ver & 0xf) <= PXA250_REV_B2)
++	{
++		if( freq_debug) printk(KERN_INFO "Using PXA250 frequency points.\n");
++		pxa_valid_freqs = pxa250_valid_freqs;
++	}	
++	else /* C0 and above */
++	{
++		if( freq_debug) printk(KERN_INFO "Using PXA255 frequency points.\n");
++		pxa_valid_freqs = pxa255_valid_freqs;
++	}
++	
++	return 1;
++}
++
++static int __init pxa_clk_init(void)
++{
++	if( pxa_init_freqs())
++	{
++		if( freq_debug) printk(KERN_INFO "Registering CPU frequency change support.\n");
++		supported = 1;
++
++		cpufreq_init( get_clk_frequency_khz(0), PXA25x_MIN_FREQ, PXA25x_MAX_FREQ);
++		cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
++	}
++	else
++	{
++		if( freq_debug) printk(KERN_INFO "Disabling CPU frequency change support.\n");
++		/* Note that we have to initialize the generic code in order to 
++		 * release a lock (cpufreq_sem). Any registration for freq changes
++		 * (e.g. lcd driver) will get blocked otherwise.
++		 */
++		cpufreq_init( 0, 0, 0);
++		cpufreq_setfunctions(pxa_validate_speed, pxa_setspeed);
++	}
++
++	return 0;
++}
++
++module_init(pxa_clk_init);
++
++MODULE_AUTHOR ("Intrinsyc Software Inc.");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/csb226.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,180 @@
++/*
++ *  linux/arch/arm/mach-pxa/csb226.c
++ *
++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
++ *
++ * 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/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++#include <asm/arch/irqs.h>
++#include <asm/hardware/sa1111.h>
++
++#include "generic.h"
++
++static unsigned long csb226_irq_en_mask;
++
++static void csb226_mask_and_ack_irq(unsigned int irq)
++{
++	int csb226_irq = (irq - CSB226_IRQ(0));
++	csb226_irq_en_mask &= ~(1 << csb226_irq);
++	CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq);
++	CSB226_IRQ_SET_CLR &= ~(1 << csb226_irq);
++}
++
++static void csb226_mask_irq(unsigned int irq)
++{
++	int csb226_irq = (irq - CSB226_IRQ(0));
++	csb226_irq_en_mask &= ~(1 << csb226_irq);
++	CSB226_IRQ_MASK_EN &= ~(1 << csb226_irq);
++}
++
++static void csb226_unmask_irq(unsigned int irq)
++{
++	int csb226_irq = (irq - CSB226_IRQ(0));
++	csb226_irq_en_mask |= (1 << csb226_irq);
++	CSB226_IRQ_MASK_EN |= (1 << csb226_irq);
++}
++
++void csb226_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned long irq_status;
++	int i;
++
++	while ((irq_status = CSB226_IRQ_SET_CLR & csb226_irq_en_mask)) {
++		for (i = 0; i < 6; i++) {
++			if(irq_status & (1<<i)) 
++				do_IRQ(CSB226_IRQ(i), regs);
++		}
++	}
++}
++
++/* FIXME: this should not be necessary on csb226 */
++static struct irqaction csb226_irq = {
++	name:		"CSB226 FPGA",
++	handler:	csb226_irq_demux,
++	flags:		SA_INTERRUPT
++};
++
++static void __init csb226_init_irq(void)
++{
++	int irq;
++	
++	pxa_init_irq();
++
++	/* setup extra csb226 irqs */
++/* RS: ???
++	for(irq = CSB226_IRQ(0); irq <= CSB226_IRQ(5); irq++)
++	{
++		irq_desc[irq].valid	= 1;
++		irq_desc[irq].probe_ok	= 1;
++		irq_desc[irq].mask_ack	= csb226_mask_and_ack_irq;
++		irq_desc[irq].mask	= csb226_mask_irq;
++		irq_desc[irq].unmask	= csb226_unmask_irq;
++	}
++
++	set_GPIO_IRQ_edge(GPIO_CSB226_IRQ, GPIO_FALLING_EDGE);
++	setup_arm_irq(IRQ_GPIO_CSB226_IRQ, &csb226_irq);
++*/
++}
++
++/* FIXME: not necessary on CSB226? */
++static int __init csb226_init(void)
++{
++	int ret;
++
++	return 0;
++}
++
++__initcall(csb226_init);
++
++static void __init
++fixup_csb226(struct machine_desc *desc, struct param_struct *params,
++		char **cmdline, struct meminfo *mi)
++{
++	SET_BANK (0, 0xa0000000, 64*1024*1024);
++	mi->nr_banks      = 1;
++#if 0
++	setup_ramdisk (1, 0, 0, 8192);
++	setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024);
++	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++#endif
++}
++
++/* FIXME: shouldn't this be moved to arch/arm/mach-pxa/mm.c? [RS] */
++static struct map_desc csb226_io_desc[] __initdata = {
++	/* virtual    physical    length      domain     r  w  c  b */
++//	{ 0xf4000000, 0x04000000, 0x00ffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* HT4562B PS/2 controller */
++	{ 0xf8000000, 0x08000000, 1024*1024,  DOMAIN_IO, 0, 1, 0, 0 }, /* CS8900 LAN controller   */
++//	{ 0xe0000000, 0x20000000, 0x0fffffff, DOMAIN_IO, 1, 1, 0, 0 }, /* CompactFlash            */
++#if 0
++	{ 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD                    */
++	{ 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO             */
++	{ 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr           */
++	{ 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111                  */
++#endif
++  LAST_DESC
++};
++
++static void __init csb226_map_io(void)
++{
++	pxa_map_io();
++	iotable_init(csb226_io_desc);
++
++	/* This enables the BTUART */
++	CKEN |= CKEN7_BTUART;
++	set_GPIO_mode(GPIO42_BTRXD_MD);
++	set_GPIO_mode(GPIO43_BTTXD_MD);
++	set_GPIO_mode(GPIO44_BTCTS_MD);
++	set_GPIO_mode(GPIO45_BTRTS_MD);
++
++	/* This is for the CS8900 chip select */
++	set_GPIO_mode(GPIO78_nCS_2_MD);
++
++	/* setup sleep mode values */
++	PWER  = 0x00000002;
++	PFER  = 0x00000000;
++	PRER  = 0x00000002;
++	PGSR0 = 0x00008000;
++	PGSR1 = 0x003F0202;
++	PGSR2 = 0x0001C000;
++	PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(CSB226, "Cogent CSB226 Development Platform")
++	MAINTAINER("Robert Schwebel, Pengutronix")
++	BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++	BOOT_PARAMS(0xa0000100)
++	FIXUP(fixup_csb226)
++	MAPIO(csb226_map_io)
++	INITIRQ(csb226_init_irq)
++MACHINE_END
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/dma.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,131 @@
++/*
++ *  linux/arch/arm/mach-pxa/dma.c
++ *
++ *  PXA DMA registration and IRQ dispatching
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Nov 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++
++
++static struct dma_channel {
++	char *name;
++	void (*irq_handler)(int, void *, struct pt_regs *);
++	void *data;
++} dma_channels[16];
++
++
++int pxa_request_dma (char *name, pxa_dma_prio prio,
++			 void (*irq_handler)(int, void *, struct pt_regs *),
++		 	 void *data)
++{
++	unsigned long flags;
++	int i, found = 0;
++
++	/* basic sanity checks */
++	if (!name || !irq_handler)
++		return -EINVAL;
++
++	local_irq_save(flags);
++
++	/* try grabbing a DMA channel with the requested priority */
++	for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
++		if (!dma_channels[i].name) {
++			found = 1;
++			break;
++		}
++	}
++
++	if (!found) {
++		/* requested prio group is full, try hier priorities */
++		for (i = prio-1; i >= 0; i--) {
++			if (!dma_channels[i].name) {
++				found = 1;
++				break;
++			}
++		}
++	}
++		
++	if (found) {
++		DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
++		dma_channels[i].name = name;
++		dma_channels[i].irq_handler = irq_handler;
++		dma_channels[i].data = data;
++	} else {
++		printk (KERN_WARNING "No more available DMA channels for %s\n", name);
++		i = -ENODEV;
++	}
++
++	local_irq_restore(flags);
++	return i;
++}
++
++void pxa_free_dma (int dma_ch)
++{
++	unsigned long flags;
++
++	if (!dma_channels[dma_ch].name) {
++		printk (KERN_CRIT __FUNCTION__
++			": trying to free channel %d which is already freed\n",
++			dma_ch);
++		return;
++	}
++
++	local_irq_save(flags);
++	DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
++	dma_channels[dma_ch].name = NULL;
++	local_irq_restore(flags);
++}
++
++static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
++{
++	int i, dint = DINT;
++
++	for (i = 0; i < 16; i++) {
++		if (dint & (1 << i)) {
++			struct dma_channel *channel = &dma_channels[i];
++			if (channel->name && channel->irq_handler) {
++				channel->irq_handler(i, channel->data, regs);
++			} else {
++				/*
++				 * IRQ for an unregistered DMA channel:
++				 * let's clear the interrupts and disable it.
++				 */
++				printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i);
++				DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
++			}
++		}
++	}
++}
++
++static int __init pxa_dma_init (void)
++{
++	int ret;
++
++	ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
++	if (ret)
++		printk (KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
++	return ret;
++}
++
++__initcall(pxa_dma_init);
++
++EXPORT_SYMBOL(pxa_request_dma);
++EXPORT_SYMBOL(pxa_free_dma);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/generic.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,142 @@
++/*
++ *  linux/arch/arm/mach-pxa/generic.c
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ * 
++ * Code common to all PXA machines.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Since this file should be linked before any other machine specific file,
++ * the __initcall() here will be executed first.  This serves as default
++ * initialization stuff for PXA machines which can be overriden later if
++ * need be.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++
++#include <asm/hardware.h>
++#include <asm/system.h>
++#include <asm/pgtable.h>
++#include <asm/mach/map.h>
++
++#include "generic.h"
++
++/*
++ * Various clock factors driven by the CCCR register.
++ */
++
++/* Crystal Frequency to Memory Frequency Multiplier (L) */
++static unsigned char L_clk_mult[32] = { 0, 27, 32, 36, 40, 45, 0, };
++
++/* Memory Frequency to Run Mode Frequency Multiplier (M) */
++static unsigned char M_clk_mult[4] = { 0, 1, 2, 4 };
++
++/* Run Mode Frequency to Turbo Mode Frequency Multiplier (N) */
++/* Note: we store the value N * 2 here. */
++static unsigned char N2_clk_mult[8] = { 0, 0, 2, 3, 4, 0, 6, 0 };
++
++/* Crystal clock */
++#define BASE_CLK	3686400
++
++/*
++ * Get the clock frequency as reflected by CCCR and the turbo flag.
++ * We assume these values have been applied via a fcs.
++ * If info is not 0 we also display the current settings.
++ */
++unsigned int get_clk_frequency_khz( int info)
++{
++	unsigned long cccr, turbo;
++	unsigned int l, L, m, M, n2, N;
++
++	cccr = CCCR;
++	asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (turbo) );
++
++	l  =  L_clk_mult[(cccr >> 0) & 0x1f];
++	m  =  M_clk_mult[(cccr >> 5) & 0x03];
++	n2 = N2_clk_mult[(cccr >> 7) & 0x07];
++
++	L = l * BASE_CLK;
++	M = m * L;
++	N = n2 * M / 2;
++
++	if( info)
++	{
++		L += 5000;
++		printk( KERN_INFO "Memory clock: %d.%02dMHz (*%d)\n",
++			L / 1000000, (L % 1000000) / 10000, l );
++		M += 5000;
++		printk( KERN_INFO "Run Mode clock: %d.%02dMHz (*%d)\n",
++			M / 1000000, (M % 1000000) / 10000, m );
++		N += 5000;
++		printk( KERN_INFO "Turbo Mode clock: %d.%02dMHz (*%d.%d, %sactive)\n",
++			N / 1000000, (N % 1000000) / 10000, n2 / 2, (n2 % 2) * 5,
++			(turbo & 1) ? "" : "in" );
++	}
++
++	return (turbo & 1) ? (N/1000) : (M/1000);
++}
++
++EXPORT_SYMBOL(get_clk_frequency_khz);
++
++/*
++ * Return the current lclk requency in units of 10kHz
++ */
++unsigned int get_lclk_frequency_10khz(void)
++{
++	return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000;
++}
++
++EXPORT_SYMBOL(get_lclk_frequency_10khz);
++
++/*
++ * Handy function to set GPIO alternate functions
++ */
++
++void set_GPIO_mode(int gpio_mode)
++{
++	long flags;
++	int gpio = gpio_mode & GPIO_MD_MASK_NR;
++	int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
++	int gafr;
++
++	local_irq_save(flags);
++	if (gpio_mode & GPIO_MD_MASK_DIR)
++		GPDR(gpio) |= GPIO_bit(gpio);
++	else
++		GPDR(gpio) &= ~GPIO_bit(gpio);
++	gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
++	GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));
++	local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(set_GPIO_mode);
++
++/* 
++ * Note that 0xfffe0000-0xffffffff is reserved for the vector table and
++ * cache flush area.
++ */
++static struct map_desc standard_io_desc[] __initdata = {
++ /* virtual     physical    length      domain     r  w  c  b */
++  { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
++  { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
++  { 0xf8000000, 0x40000000, 0x01800000, DOMAIN_IO, 0, 1, 0, 0 }, /* Devs */
++  { 0xfa000000, 0x44000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */
++  { 0xfc000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Mem Ctl */
++  { 0xff000000, 0x00000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* UNCACHED_PHYS_0 */
++  LAST_DESC
++};
++
++void __init pxa_map_io(void)
++{
++	iotable_init(standard_io_desc);
++	get_clk_frequency_khz( 1);
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/generic.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,19 @@
++/*
++ *  linux/arch/arm/mach-pxa/generic.h
++ *
++ * Author:	Nicolas Pitre
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++extern void __init pxa_map_io(void);
++extern void __init pxa_init_irq(void);
++
++#define SET_BANK(__nr,__start,__size) \
++	mi->bank[__nr].start = (__start), \
++	mi->bank[__nr].size = (__size), \
++	mi->bank[__nr].node = (((unsigned)(__start) - PHYS_OFFSET) >> 27)
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/idp.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,142 @@
++/*
++ *  linux/arch/arm/mach-pxa/idp.c
++ *  
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  Copyright (c) 2001 Cliff Brake, Accelent Systems Inc.
++ * 
++ *  2001-09-13: Cliff Brake <cbrake@accelent.com>
++ *              Initial code
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++#define PXA_IDP_REV02
++
++#ifndef PXA_IDP_REV02
++/* shadow registers for write only registers */
++unsigned int idp_cpld_led_control_shadow = 0x1;
++unsigned int idp_cpld_periph_pwr_shadow = 0xd;
++unsigned int ipd_cpld_cir_shadow = 0;
++unsigned int idp_cpld_kb_col_high_shadow = 0;
++unsigned int idp_cpld_kb_col_low_shadow = 0;
++unsigned int idp_cpld_pccard_en_shadow = 0xC3;
++unsigned int idp_cpld_gpioh_dir_shadow = 0;
++unsigned int idp_cpld_gpioh_value_shadow = 0;
++unsigned int idp_cpld_gpiol_dir_shadow = 0;
++unsigned int idp_cpld_gpiol_value_shadow = 0;
++
++/*
++ * enable all LCD signals -- they should still be on
++ * write protect flash
++ * enable all serial port transceivers
++ */
++
++unsigned int idp_control_port_shadow = ((0x7 << 21) | 		/* LCD power */
++					(0x1 << 19) |		/* disable flash write enable */
++					(0x7 << 9));		/* enable serial port transeivers */
++
++#endif
++
++static int __init idp_init(void)
++{
++	printk("idp_init()\n");
++	return 0;
++}
++
++__initcall(idp_init);
++
++static void __init idp_init_irq(void)
++{
++	pxa_init_irq();
++}
++
++static void __init
++fixup_idp(struct machine_desc *desc, struct param_struct *params,
++		char **cmdline, struct meminfo *mi)
++{
++#ifdef PXA_IDP_REV02
++	SET_BANK (0, 0xa0000000, 64*1024*1024);
++#else
++	SET_BANK (0, 0xa0000000, 32*1024*1024);
++#endif
++	mi->nr_banks      = 1;
++#if 0
++	setup_ramdisk (1, 0, 0, 8192);
++	setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024);
++	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++#endif
++}
++
++static struct map_desc idp_io_desc[] __initdata = {
++ /* virtual     physical    length      domain     r  w  c  b */
++
++
++#ifndef PXA_IDP_REV02
++  { IDP_CTRL_PORT_BASE,
++    IDP_CTRL_PORT_PHYS,
++    IDP_CTRL_PORT_SIZE,
++    DOMAIN_IO,
++    0, 1, 0, 0 },
++#endif
++
++  { IDP_IDE_BASE,
++    IDP_IDE_PHYS,
++    IDP_IDE_SIZE,
++    DOMAIN_IO,
++    0, 1, 0, 0 },
++  { IDP_ETH_BASE,
++    IDP_ETH_PHYS,
++    IDP_ETH_SIZE,
++    DOMAIN_IO,
++    0, 1, 0, 0 },
++  { IDP_COREVOLT_BASE,
++    IDP_COREVOLT_PHYS,
++    IDP_COREVOLT_SIZE,
++    DOMAIN_IO,
++    0, 1, 0, 0 },
++  { IDP_CPLD_BASE,
++    IDP_CPLD_PHYS,
++    IDP_CPLD_SIZE,
++    DOMAIN_IO,
++    0, 1, 0, 0 },
++	
++  LAST_DESC
++};
++
++static void __init idp_map_io(void)
++{
++	pxa_map_io();
++	iotable_init(idp_io_desc);
++
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE);
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO(SMC_IRQ), GPIO_RISING_EDGE);
++}
++
++MACHINE_START(PXA_IDP, "Accelent Xscale IDP")
++	MAINTAINER("Accelent Systems Inc.")
++	BOOT_MEM(0xa0000000, 0x40000000, 0xfc000000)
++	FIXUP(fixup_idp)
++	MAPIO(idp_map_io)
++	INITIRQ(idp_init_irq)
++MACHINE_END
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/innokom.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,129 @@
++/*
++ *  linux/arch/arm/mach-pxa/innokom.c
++ *
++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
++ *
++ * 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/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++#include <asm/arch/irqs.h>
++#include <asm/hardware/sa1111.h>
++
++#include "generic.h"
++
++
++static void __init innokom_init_irq(void)
++{
++	pxa_init_irq();
++}
++
++
++void sw_update_handler( int irq, void* dev_id,struct pt_regs* regs)
++{
++}
++
++
++void reset_handler( int irq, void* dev_id,struct pt_regs* regs)
++{
++}
++
++
++static int __init innokom_init(void)
++{
++	int sw_irq = GPIO_2_80_TO_IRQ(11);	/* software update button */
++	int reset_irq = GPIO_2_80_TO_IRQ(3);	/* reset button           */
++
++	set_GPIO_IRQ_edge(11,GPIO_FALLING_EDGE);
++	if (request_irq(sw_irq,sw_update_handler,SA_INTERRUPT,"software update button",NULL))
++		printk(KERN_INFO "innokom: can't get assigned irq %i\n",sw_irq);
++
++	set_GPIO_IRQ_edge(3,GPIO_FALLING_EDGE);
++	if (request_irq(reset_irq,reset_handler,SA_INTERRUPT,"reset button",NULL))
++		printk(KERN_INFO "innokom: can't get assigned irq %i\n",reset_irq);
++
++	return 0;
++}
++
++
++__initcall(innokom_init);
++
++
++static void __init
++fixup_innokom(struct machine_desc *desc, struct param_struct *params,
++		char **cmdline, struct meminfo *mi)
++{
++	/* we probably want to get this information from the bootloader later */
++	SET_BANK (0, 0xa0000000, 64*1024*1024); 
++	mi->nr_banks      = 1;
++}
++
++
++/* memory mapping */
++static struct map_desc innokom_io_desc[] __initdata = {
++/*  virtual           physical          length            domain     r  w  c  b                      */
++  { INNOKOM_ETH_BASE, INNOKOM_ETH_PHYS, INNOKOM_ETH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* ETH SMSC 91111 */
++  LAST_DESC
++};
++
++static void __init innokom_map_io(void)
++{
++	pxa_map_io();
++	iotable_init(innokom_io_desc);
++
++	/* Enable the BTUART */
++	CKEN |= CKEN7_BTUART;
++	set_GPIO_mode(GPIO42_BTRXD_MD);
++	set_GPIO_mode(GPIO43_BTTXD_MD);
++	set_GPIO_mode(GPIO44_BTCTS_MD);
++	set_GPIO_mode(GPIO45_BTRTS_MD);
++
++	set_GPIO_mode(GPIO33_nCS_5_MD);	/* SMSC network chip */
++
++	/* setup sleep mode values */
++	PWER  = 0x00000002;
++	PFER  = 0x00000000;
++	PRER  = 0x00000002;
++	PGSR0 = 0x00008000;
++	PGSR1 = 0x003F0202;
++	PGSR2 = 0x0001C000;
++	PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(INNOKOM, "Auerswald Innokom")
++	MAINTAINER("Robert Schwebel, Pengutronix")
++	BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++	BOOT_PARAMS(0xa0000100)
++	FIXUP(fixup_innokom)
++	MAPIO(innokom_map_io)
++	INITIRQ(innokom_init_irq)
++MACHINE_END
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/irq.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,282 @@
++/*
++ *  linux/arch/arm/mach-pxa/irq.c
++ *  
++ *  Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc.
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach/irq.h>
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++
++/*
++ * PXA GPIO edge detection for IRQs:
++ * IRQs are generated on Falling-Edge, Rising-Edge, or both.
++ * This must be called *before* the appropriate IRQ is registered.
++ * Use this instead of directly setting GRER/GFER.
++ */
++
++static int GPIO_IRQ_rising_edge[3];
++static int GPIO_IRQ_falling_edge[3];
++
++void set_GPIO_IRQ_edge (int gpio_nr, int edge)
++{
++	long flags;
++	local_irq_save(flags);
++	set_GPIO_mode(gpio_nr | GPIO_IN);
++	if (edge & GPIO_FALLING_EDGE)
++		set_bit (gpio_nr, GPIO_IRQ_falling_edge);
++	else
++		clear_bit (gpio_nr, GPIO_IRQ_falling_edge);
++	if (edge & GPIO_RISING_EDGE)
++		set_bit (gpio_nr, GPIO_IRQ_rising_edge);
++	else
++		clear_bit (gpio_nr, GPIO_IRQ_rising_edge);
++	irq_desc[IRQ_GPIO(gpio_nr)].valid = 1;
++	local_irq_restore(flags);
++}
++
++EXPORT_SYMBOL(set_GPIO_IRQ_edge);
++
++
++/*
++ * We don't need to ACK IRQs on the PXA unless they're GPIOs
++ * this is for IRQs known as PXA_IRQ([10...31]).
++ */
++
++static void pxa_mask_irq(unsigned int irq)
++{
++	ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
++}
++
++static void pxa_unmask_irq(unsigned int irq)
++{
++	ICMR |= (1 << (irq + PXA_IRQ_SKIP));
++}
++
++/*
++ * GPIO IRQs must be acknoledged.  This is for GPIO 0 and 1.
++ */
++
++static void pxa_mask_and_ack_GPIO_0_1_irq(unsigned int irq)
++{
++	ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
++	GEDR0 = (1 << (irq - IRQ_GPIO0));
++}
++
++static void pxa_mask_GPIO_0_1_irq(unsigned int irq)
++{
++	ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
++}
++
++static void pxa_unmask_GPIO_0_1_irq(unsigned int irq)
++{
++	int gpio = irq - IRQ_GPIO0;
++	GRER0 = (GRER0 & ~(1 << gpio))|(GPIO_IRQ_rising_edge[0] & (1 << gpio));
++	GFER0 = (GFER0 & ~(1 << gpio))|(GPIO_IRQ_falling_edge[0] & (1 << gpio));
++	ICMR |= (1 << (irq + PXA_IRQ_SKIP));
++}
++
++/*
++ * Demux handler for GPIO 2-80 edge detect interrupts
++ */
++
++static int GPIO_2_80_enabled[3];	/* enabled i.e. unmasked GPIO IRQs */
++static int GPIO_2_80_spurious[3];	/* GPIOs that triggered when masked */
++
++static void pxa_GPIO_2_80_demux(int irq, void *dev_id,
++				    struct pt_regs *regs)
++{
++	int i, gedr, spurious;
++
++	while ((gedr = (GEDR0 & ~3))) {
++		/*
++		 * We don't want to clear GRER/GFER when the corresponding
++		 * IRQ is masked because we could miss a level transition
++		 * i.e. an IRQ which need servicing as soon as it is
++		 * unmasked.  However, such situation should happen only
++		 * during the loop below.  Thus all IRQs which aren't
++		 * enabled at this point are considered spurious.  Those
++		 * are cleared but only de-activated if they happen twice.
++		 */
++		spurious = gedr & ~GPIO_2_80_enabled[0];
++		if (spurious) {
++			GEDR0 = spurious;
++			GRER0 &= ~(spurious & GPIO_2_80_spurious[0]);
++			GFER0 &= ~(spurious & GPIO_2_80_spurious[0]);
++			GPIO_2_80_spurious[0] |= spurious;
++			gedr ^= spurious;
++			if (!gedr) continue;
++		}
++
++		for (i = 2; i < 32; ++i) {
++			if (gedr & (1<<i)) {
++				do_IRQ (IRQ_GPIO(2) + i - 2, regs);
++			}
++		}
++	}
++	while ((gedr = GEDR1)) {
++		spurious = gedr & ~GPIO_2_80_enabled[1];
++		if (spurious) {
++			GEDR1 = spurious;
++			GRER1 &= ~(spurious & GPIO_2_80_spurious[1]);
++			GFER1 &= ~(spurious & GPIO_2_80_spurious[1]);
++			GPIO_2_80_spurious[1] |= spurious;
++			gedr ^= spurious;
++			if (!gedr) continue;
++		}
++
++		for (i = 0; i < 32; ++i) {
++			if (gedr & (1<<i)) {
++				do_IRQ (IRQ_GPIO(32) + i, regs);
++			}
++		}
++	}
++	while ((gedr = (GEDR2 & 0x0001ffff))) {
++		spurious = gedr & ~GPIO_2_80_enabled[2];
++		if (spurious) {
++			GEDR2 = spurious;
++			GRER2 &= ~(spurious & GPIO_2_80_spurious[2]);
++			GFER2 &= ~(spurious & GPIO_2_80_spurious[2]);
++			GPIO_2_80_spurious[2] |= spurious;
++			gedr ^= spurious;
++			if (!gedr) continue;
++		}
++
++		for (i = 0; i < 17; ++i) {
++			if (gedr & (1<<i)) {
++				do_IRQ (IRQ_GPIO(64) + i, regs);
++			}
++		}
++	}
++}
++
++static struct irqaction GPIO_2_80_irqaction = {
++	name:		"GPIO 2-80",
++	handler:	pxa_GPIO_2_80_demux,
++	flags:		SA_INTERRUPT
++};
++
++#define GRER_x(i)	(*(&GRER0 + (i)))
++#define GFER_x(i)	(*(&GFER0 + (i)))
++#define GEDR_x(i)	(*(&GEDR0 + (i)))
++#define GPLR_x(i)	(*(&GPLR0 + (i)))
++
++static void pxa_mask_and_ack_GPIO_2_80_irq(unsigned int irq)
++{
++	int gpio_nr = IRQ_TO_GPIO_2_80(irq);
++	int mask = 1 << (gpio_nr & 0x1f);
++	int index = gpio_nr >> 5;
++	GPIO_2_80_spurious[index] &= ~mask;
++	GPIO_2_80_enabled[index] &= ~mask;
++	GEDR_x(index) = mask;
++}
++
++static void pxa_mask_GPIO_2_80_irq(unsigned int irq)
++{
++	int gpio_nr = IRQ_TO_GPIO_2_80(irq);
++	int mask = 1 << (gpio_nr & 0x1f);
++	int index = gpio_nr >> 5;
++	GPIO_2_80_spurious[index] &= ~mask;
++	GPIO_2_80_enabled[index] &= ~mask;
++}
++
++static void pxa_unmask_GPIO_2_80_irq(unsigned int irq)
++{
++	int gpio_nr = IRQ_TO_GPIO_2_80(irq);
++	int mask = 1 << (gpio_nr & 0x1f);
++	int index = gpio_nr >> 5;
++	if (GPIO_2_80_spurious[index] & mask) {
++		/*
++		 * We don't want to miss an interrupt that would have occurred
++		 * while it was masked.  Simulate it if it is the case.
++		 */
++		int state = GPLR_x(index);
++		if (((state & GPIO_IRQ_rising_edge[index]) |
++		     (~state & GPIO_IRQ_falling_edge[index])) & mask)
++		{
++			/* just in case it gets referenced: */
++			struct pt_regs dummy;
++
++			memzero(&dummy, sizeof(dummy));
++			do_IRQ(irq, &dummy);
++
++			/* we are being called recursively from do_IRQ() */
++			return;
++		}
++	}
++	GPIO_2_80_enabled[index] |= mask;
++	GRER_x(index) =
++		(GRER_x(index) & ~mask) | (GPIO_IRQ_rising_edge[index] & mask);
++	GFER_x(index) =
++		(GFER_x(index) & ~mask) | (GPIO_IRQ_falling_edge[index] & mask);
++}
++
++
++void __init pxa_init_irq(void)
++{
++	int irq;
++
++	/* disable all IRQs */
++	ICMR = 0;
++
++	/* all IRQs are IRQ, not FIQ */
++	ICLR = 0;
++
++	/* clear all GPIO edge detects */
++	GFER0 = GFER1 = GFER2 = 0;
++	GRER0 = GRER1 = GRER2 = 0;
++	GEDR0 = GEDR0;
++	GEDR1 = GEDR1;
++	GEDR2 = GEDR2;
++
++	/* only unmasked interrupts kick us out of idle */
++	ICCR = 1;
++
++	for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
++		irq_desc[irq].valid	= 1;
++		irq_desc[irq].probe_ok	= 0;
++		irq_desc[irq].mask_ack	= pxa_mask_irq;
++		irq_desc[irq].mask	= pxa_mask_irq;
++		irq_desc[irq].unmask	= pxa_unmask_irq;
++	}
++
++	/*
++	 * Note: GPIO IRQs are initially invalid until set_GPIO_IRQ_edge()
++	 * is called at least once.
++	 */
++
++	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
++		irq_desc[irq].valid	= 0;
++		irq_desc[irq].probe_ok	= 1;
++		irq_desc[irq].mask_ack	= pxa_mask_and_ack_GPIO_0_1_irq;
++		irq_desc[irq].mask	= pxa_mask_GPIO_0_1_irq;
++		irq_desc[irq].unmask	= pxa_unmask_GPIO_0_1_irq;
++	}
++
++	for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) {
++		irq_desc[irq].valid	= 0;
++		irq_desc[irq].probe_ok	= 1;
++		irq_desc[irq].mask_ack	= pxa_mask_and_ack_GPIO_2_80_irq;
++		irq_desc[irq].mask	= pxa_mask_GPIO_2_80_irq;
++		irq_desc[irq].unmask	= pxa_unmask_GPIO_2_80_irq;
++	}
++	setup_arm_irq( IRQ_GPIO_2_80, &GPIO_2_80_irqaction );
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/leds-cerf.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,135 @@
++/*
++ *  linux/arch/arm/mach-pxa/leds-cerf.c
++ *
++ *  Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
++ *
++ *  Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
++ *
++ *  Original (leds-footbridge.c) by Russell King
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/leds.h>
++#include <asm/system.h>
++
++#include "leds.h"
++
++
++#define LED_STATE_ENABLED	1
++#define LED_STATE_CLAIMED	2
++
++static unsigned int led_state;
++static unsigned int hw_led_state;
++
++void pxa_cerf_leds_event(led_event_t evt)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++
++	switch (evt) {
++	case led_start:
++		hw_led_state = CERF_HEARTBEAT_LED;
++		led_state = LED_STATE_ENABLED;
++		break;
++
++	case led_stop:
++		led_state &= ~LED_STATE_ENABLED;
++		break;
++
++	case led_claim:
++		led_state |= LED_STATE_CLAIMED;
++		hw_led_state = CERF_HEARTBEAT_LED;
++		break;
++
++	case led_release:
++		led_state &= ~LED_STATE_CLAIMED;
++		hw_led_state = CERF_HEARTBEAT_LED;
++		break;
++
++#ifdef CONFIG_LEDS_TIMER
++	case led_timer:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state ^= CERF_HEARTBEAT_LED;
++		break;
++#endif
++
++#ifdef CONFIG_LEDS_CPU
++	case led_idle_start:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state |= CERF_SYS_BUSY_LED;
++		break;
++
++	case led_idle_end:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state &= ~CERF_SYS_BUSY_LED;
++		break;
++#endif
++
++	case led_halted:
++		break;
++
++	case led_green_on:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state &= ~CERF_HEARTBEAT_LED;
++		break;
++
++	case led_green_off:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state |= CERF_HEARTBEAT_LED;
++		break;
++
++	case led_amber_on:
++		break;
++
++	case led_amber_off:
++		break;
++
++#ifndef CONFIG_PXA_CERF_PDA
++	case led_red_on:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state &= ~CERF_SYS_BUSY_LED;
++		break;
++
++	case led_red_off:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state |= CERF_SYS_BUSY_LED;
++		break;
++#endif
++	default:
++		break;
++	}
++
++	if  (led_state & LED_STATE_ENABLED)
++	{
++		switch (hw_led_state) {
++		case 0: // all on
++			CERF_HEARTBEAT_LED_ON;
++			CERF_SYS_BUSY_LED_ON;
++			break;
++		case 1: // turn off heartbeat, status on:
++			CERF_HEARTBEAT_LED_OFF;
++			CERF_SYS_BUSY_LED_ON;
++			break;
++		case 2: // status off, heartbeat on:
++			CERF_HEARTBEAT_LED_ON;
++			CERF_SYS_BUSY_LED_OFF;
++			break;
++		case 3: // turn them both off...
++			CERF_HEARTBEAT_LED_OFF;
++			CERF_SYS_BUSY_LED_OFF;
++			break;
++		default:
++			break;
++		}
++	}
++	local_irq_restore(flags);
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/leds-idp.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,112 @@
++/*
++ * linux/arch/arm/mach-pxa/leds-idp.c
++ *
++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
++ *
++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
++ *
++ * Original (leds-footbridge.c) by Russell King
++ * 
++ * Macros for actual LED manipulation should be in machine specific
++ * files in this 'mach' directory.
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/leds.h>
++#include <asm/system.h>
++
++#include "leds.h"
++
++#define LED_STATE_ENABLED	1
++#define LED_STATE_CLAIMED	2
++
++static unsigned int led_state;
++static unsigned int hw_led_state;
++
++void idp_leds_event(led_event_t evt)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++
++	switch (evt) {
++	case led_start:
++		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
++		led_state = LED_STATE_ENABLED;
++		break;
++
++	case led_stop:
++		led_state &= ~LED_STATE_ENABLED;
++		break;
++
++	case led_claim:
++		led_state |= LED_STATE_CLAIMED;
++		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
++		break;
++
++	case led_release:
++		led_state &= ~LED_STATE_CLAIMED;
++		hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
++		break;
++
++#ifdef CONFIG_LEDS_TIMER
++	case led_timer:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state ^= IDP_HB_LED;
++		break;
++#endif
++
++#ifdef CONFIG_LEDS_CPU
++	case led_idle_start:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state |= IDP_BUSY_LED;
++		break;
++
++	case led_idle_end:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state &= ~IDP_BUSY_LED;
++		break;
++#endif
++
++	case led_halted:
++		break;
++
++	case led_green_on:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state &= ~IDP_HB_LED;
++		break;
++
++	case led_green_off:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state |= IDP_HB_LED;
++		break;
++
++	case led_amber_on:
++		break;
++
++	case led_amber_off:
++		break;
++
++	case led_red_on:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state &= ~IDP_BUSY_LED;
++		break;
++
++	case led_red_off:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state |= IDP_BUSY_LED;
++		break;
++
++	default:
++		break;
++	}
++
++	if  (led_state & LED_STATE_ENABLED)
++		IDP_WRITE_LEDS(hw_led_state);
++
++	local_irq_restore(flags);
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/leds-lubbock.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,134 @@
++/*
++ * linux/arch/arm/mach-pxa/leds-lubbock.c
++ *
++ * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
++ *
++ * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
++ *
++ * Original (leds-footbridge.c) by Russell King
++ *
++ * See leds.h for bit definitions.  The first version defines D28 on the
++ * Lubbock dev board as the heartbeat, and D27 as the Sys_busy led.
++ * There's plenty more if you're interested in adding them :)
++ */
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/hardware.h>
++#include <asm/leds.h>
++#include <asm/system.h>
++
++#include "leds.h"
++
++
++#define LED_STATE_ENABLED	1
++#define LED_STATE_CLAIMED	2
++
++static unsigned int led_state;
++static unsigned int hw_led_state;
++
++void lubbock_leds_event(led_event_t evt)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++
++	switch (evt) {
++	case led_start:
++		hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED;
++		led_state = LED_STATE_ENABLED;
++		break;
++
++	case led_stop:
++		led_state &= ~LED_STATE_ENABLED;
++		break;
++
++	case led_claim:
++		led_state |= LED_STATE_CLAIMED;
++		hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED;
++		break;
++
++	case led_release:
++		led_state &= ~LED_STATE_CLAIMED;
++		hw_led_state = HEARTBEAT_LED | SYS_BUSY_LED;
++		break;
++
++#ifdef CONFIG_LEDS_TIMER
++	case led_timer:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state ^= HEARTBEAT_LED;
++		break;
++#endif
++
++#ifdef CONFIG_LEDS_CPU
++	case led_idle_start:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state |= SYS_BUSY_LED;
++		break;
++
++	case led_idle_end:
++		if (!(led_state & LED_STATE_CLAIMED))
++			hw_led_state &= ~SYS_BUSY_LED;
++		break;
++#endif
++
++	case led_halted:
++		break;
++
++	case led_green_on:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state &= ~HEARTBEAT_LED;
++		break;
++
++	case led_green_off:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state |= HEARTBEAT_LED;
++		break;
++
++	case led_amber_on:
++		break;
++
++	case led_amber_off:
++		break;
++
++	case led_red_on:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state &= ~SYS_BUSY_LED;
++		break;
++
++	case led_red_off:
++		if (led_state & LED_STATE_CLAIMED)
++			hw_led_state |= SYS_BUSY_LED;
++		break;
++
++	default:
++		break;
++	}
++
++	if  (led_state & LED_STATE_ENABLED)
++	{
++		switch (hw_led_state) {
++		case 0: // all on
++			HEARTBEAT_LED_ON;
++			SYS_BUSY_LED_ON;
++			break;
++		case 1: // turn off heartbeat, status on:
++			HEARTBEAT_LED_OFF;
++			SYS_BUSY_LED_ON;
++			break;
++		case 2: // status off, heartbeat on:
++			HEARTBEAT_LED_ON;
++			SYS_BUSY_LED_OFF;
++			break;
++		case 3: // turn them both off...
++			HEARTBEAT_LED_OFF;
++			SYS_BUSY_LED_OFF;
++			break;
++		default:
++			break;
++		}
++	}
++	local_irq_restore(flags);
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/leds.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * linux/arch/arm/mach-pxa/leds.c
++ *
++ * xscale LEDs dispatcher
++ * 
++ * Copyright (C) 2001 Nicolas Pitre
++ * 
++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
++ */
++#include <linux/config.h>
++#include <linux/init.h>
++
++#include <asm/leds.h>
++#include <asm/mach-types.h>
++
++#include "leds.h"
++
++static int __init
++pxa_leds_init(void)
++{
++	if (machine_is_lubbock())
++		leds_event = lubbock_leds_event;
++	if (machine_is_pxa_idp())
++		leds_event = idp_leds_event;
++	if (machine_is_pxa_cerf())
++		leds_event = pxa_cerf_leds_event;
++
++	leds_event(led_start);
++	return 0;
++}
++
++__initcall(pxa_leds_init);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/leds.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,12 @@
++/*
++ * include/asm-arm/arch-pxa/leds.h
++ *
++ * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
++ *
++ * blinky lights for various PXA-based systems:
++ *
++ */
++
++extern void lubbock_leds_event(led_event_t evt);
++extern void idp_leds_event(led_event_t evt);
++extern void pxa_cerf_leds_event(led_event_t evt);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/lubbock.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,157 @@
++/*
++ *  linux/arch/arm/mach-pxa/lubbock.c
++ *
++ *  Support for the Intel DBPXA250 Development Platform.
++ *  
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/bitops.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++#include <asm/hardware/sa1111.h>
++
++#include "generic.h"
++
++#ifdef CONFIG_SA1111
++ #include "sa1111.h"
++#endif
++
++
++static unsigned long lubbock_irq_enabled;
++
++static void lubbock_mask_irq(unsigned int irq)
++{
++	int lubbock_irq = (irq - LUBBOCK_IRQ(0));
++	LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
++}
++
++static void lubbock_unmask_irq(unsigned int irq)
++{
++	int lubbock_irq = (irq - LUBBOCK_IRQ(0));
++	/* the irq can be acknowledged only if deasserted, so it's done here */
++	LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
++	LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
++}
++
++void lubbock_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
++	do {
++		GEDR(0) = GPIO_bit(0);  /* clear useless edge notification */
++		if (likely(pending))
++			do_IRQ( LUBBOCK_IRQ(0) + __ffs(pending), regs );
++		pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
++	} while (pending);
++}
++
++static struct irqaction lubbock_irq = {
++	name:		"Lubbock FPGA",
++	handler:	lubbock_irq_demux,
++	flags:		SA_INTERRUPT
++};
++
++static void __init lubbock_init_irq(void)
++{
++	int irq;
++	
++	pxa_init_irq();
++
++	/* setup extra lubbock irqs */
++	for(irq = LUBBOCK_IRQ(0); irq <= LUBBOCK_LAST_IRQ; irq++) {
++		irq_desc[irq].valid	= 1;
++		irq_desc[irq].probe_ok	= 1;
++		irq_desc[irq].mask_ack	= lubbock_mask_irq;
++		irq_desc[irq].mask	= lubbock_mask_irq;
++		irq_desc[irq].unmask	= lubbock_unmask_irq;
++	}
++
++	set_GPIO_IRQ_edge(GPIO_LUBBOCK_IRQ, GPIO_FALLING_EDGE);
++	setup_arm_irq(IRQ_GPIO_LUBBOCK_IRQ, &lubbock_irq);
++}
++
++static int __init lubbock_init(void)
++{
++	int ret;
++
++	ret = sa1111_probe(LUBBOCK_SA1111_BASE);
++	if (ret)
++		return ret;
++	sa1111_wake();
++	sa1111_init_irq(LUBBOCK_SA1111_IRQ);
++	return 0;
++}
++
++__initcall(lubbock_init);
++
++static void __init
++fixup_lubbock(struct machine_desc *desc, struct param_struct *params,
++		char **cmdline, struct meminfo *mi)
++{
++	/* Some boards have 32MB some 64MB.  Let's use a safe default */
++	SET_BANK (0, 0xa0000000, 32*1024*1024);
++	mi->nr_banks      = 1;
++}
++
++static struct map_desc lubbock_io_desc[] __initdata = {
++ /* virtual     physical    length      domain     r  w  c  b */
++  { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
++  { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */
++  { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */
++  { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
++  LAST_DESC
++};
++
++static void __init lubbock_map_io(void)
++{
++	pxa_map_io();
++	iotable_init(lubbock_io_desc);
++
++	/* This enables the BTUART */
++	CKEN |= CKEN7_BTUART;
++	set_GPIO_mode(GPIO42_BTRXD_MD);
++	set_GPIO_mode(GPIO43_BTTXD_MD);
++	set_GPIO_mode(GPIO44_BTCTS_MD);
++	set_GPIO_mode(GPIO45_BTRTS_MD);
++
++	/* This is for the SMC chip select */
++	set_GPIO_mode(GPIO79_nCS_3_MD);
++
++	/* setup sleep mode values */
++	PWER  = 0x00000002;
++	PFER  = 0x00000000;
++	PRER  = 0x00000002;
++	PGSR0 = 0x00008000;
++	PGSR1 = 0x003F0202;
++	PGSR2 = 0x0001C000;
++	PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform")
++	MAINTAINER("MontaVista Software Inc.")
++	BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++	FIXUP(fixup_lubbock)
++	MAPIO(lubbock_map_io)
++	INITIRQ(lubbock_init_irq)
++MACHINE_END
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/pm.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,265 @@
++/*
++ * PXA250/210 Power Management Routines
++ *
++ * Original code for the SA11x0:
++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
++ *
++ * Modified for the PXA250 by Nicolas Pitre:
++ * Copyright (c) 2002 Monta Vista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/sysctl.h>
++#include <linux/errno.h>
++
++#include <asm/hardware.h>
++#include <asm/memory.h>
++#include <asm/system.h>
++#include <asm/leds.h>
++
++
++/*
++ * Debug macros
++ */
++#undef DEBUG
++
++extern void pxa_cpu_suspend(void);
++extern void pxa_cpu_resume(void);
++
++#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
++#define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
++
++/*
++ * List of global PXA peripheral registers to preserve.
++ * More ones like CP and general purpose register values are preserved
++ * with the stack pointer in sleep.S.
++ */
++enum {	SLEEP_SAVE_START = 0,
++
++	SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
++	SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
++
++	SLEEP_SAVE_GPDR0, SLEEP_SAVE_GPDR1, SLEEP_SAVE_GPDR2,
++	SLEEP_SAVE_GRER0, SLEEP_SAVE_GRER1, SLEEP_SAVE_GRER2,
++	SLEEP_SAVE_GFER0, SLEEP_SAVE_GFER1, SLEEP_SAVE_GFER2,
++	SLEEP_SAVE_GAFR0_L, SLEEP_SAVE_GAFR1_L, SLEEP_SAVE_GAFR2_L,
++	SLEEP_SAVE_GAFR0_U, SLEEP_SAVE_GAFR1_U, SLEEP_SAVE_GAFR2_U,
++
++	SLEEP_SAVE_FFIER, SLEEP_SAVE_FFLCR, SLEEP_SAVE_FFMCR,
++	SLEEP_SAVE_FFSPR, SLEEP_SAVE_FFISR,
++	SLEEP_SAVE_FFDLL, SLEEP_SAVE_FFDLH,
++
++	SLEEP_SAVE_ICMR,
++	SLEEP_SAVE_CKEN,
++
++	SLEEP_SAVE_CKSUM,
++
++	SLEEP_SAVE_SIZE
++};
++
++
++int pm_do_suspend(void)
++{
++	unsigned long sleep_save[SLEEP_SAVE_SIZE];
++	unsigned long checksum = 0;
++	int i;
++
++	cli();
++	clf();
++
++	leds_event(led_stop);
++
++	/* preserve current time */
++	RCNR = xtime.tv_sec;
++
++	/* 
++	 * Temporary solution.  This won't be necessary once
++	 * we move pxa support into the serial/* driver
++	 * Save the FF UART 
++	 */
++	SAVE(FFIER);
++	SAVE(FFLCR);
++	SAVE(FFMCR);
++	SAVE(FFSPR);
++	SAVE(FFISR);
++	FFLCR |= 0x80;
++	SAVE(FFDLL);
++	SAVE(FFDLH);
++	FFLCR &= 0xef;
++
++	/* save vital registers */
++	SAVE(OSCR);
++	SAVE(OSMR0);
++	SAVE(OSMR1);
++	SAVE(OSMR2);
++	SAVE(OSMR3);
++	SAVE(OIER);
++
++	SAVE(GPDR0); SAVE(GPDR1); SAVE(GPDR2);
++	SAVE(GRER0); SAVE(GRER1); SAVE(GRER2);
++	SAVE(GFER0); SAVE(GFER1); SAVE(GFER2);
++	SAVE(GAFR0_L); SAVE(GAFR0_U);
++	SAVE(GAFR1_L); SAVE(GAFR1_U);
++	SAVE(GAFR2_L); SAVE(GAFR2_U);
++
++	SAVE(ICMR);
++	ICMR = 0;
++
++	SAVE(CKEN);
++	CKEN = 0;
++
++	/* Note: wake up source are set up in each machine specific files */
++
++	/* clear GPIO transition detect  bits */
++	GEDR0 = GEDR0; GEDR1 = GEDR1; GEDR2 = GEDR2;
++
++	/* Clear sleep reset status */
++	RCSR = RCSR_SMR;
++
++	/* set resume return address */
++	PSPR = virt_to_phys(pxa_cpu_resume);
++
++	/* before sleeping, calculate and save a checksum */
++	for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
++		checksum += sleep_save[i];
++	sleep_save[SLEEP_SAVE_CKSUM] = checksum;
++
++	/* *** go zzz *** */
++	pxa_cpu_suspend();
++
++	/* after sleeping, validate the checksum */
++	checksum = 0;
++	for (i = 0; i < SLEEP_SAVE_SIZE - 1; i++)
++		checksum += sleep_save[i];
++
++	/* if invalid, display message and wait for a hardware reset */
++	if (checksum != sleep_save[SLEEP_SAVE_CKSUM]) {
++#ifdef CONFIG_ARCH_LUBBOCK
++		LUB_HEXLED = 0xbadbadc5;
++#endif
++		while (1);
++	}
++
++	/* ensure not to come back here if it wasn't intended */
++	PSPR = 0;
++
++	/* restore registers */
++	RESTORE(GPDR0); RESTORE(GPDR1); RESTORE(GPDR2);
++	RESTORE(GRER0); RESTORE(GRER1); RESTORE(GRER2);
++	RESTORE(GFER0); RESTORE(GFER1); RESTORE(GFER2);
++	RESTORE(GAFR0_L); RESTORE(GAFR0_U);
++	RESTORE(GAFR1_L); RESTORE(GAFR1_U);
++	RESTORE(GAFR2_L); RESTORE(GAFR2_U);
++
++	PSSR = PSSR_PH;
++
++	RESTORE(OSMR0);
++	RESTORE(OSMR1);
++	RESTORE(OSMR2);
++	RESTORE(OSMR3);
++	RESTORE(OSCR);
++	RESTORE(OIER);
++
++	RESTORE(CKEN);
++
++	ICLR = 0;
++	ICCR = 1;
++	RESTORE(ICMR);
++
++	/* 
++	 * Temporary solution.  This won't be necessary once
++	 * we move pxa support into the serial/* driver.
++	 * Restore the FF UART.
++	 */
++	RESTORE(FFMCR);
++	RESTORE(FFSPR);
++	RESTORE(FFLCR);
++	FFLCR |= 0x80;
++	RESTORE(FFDLH);
++	RESTORE(FFDLL);
++	RESTORE(FFLCR);
++	RESTORE(FFISR);
++	FFFCR = 0x07;
++	RESTORE(FFIER);
++
++	/* restore current time */
++	xtime.tv_sec = RCNR;
++
++#ifdef DEBUG
++	printk(KERN_DEBUG "*** made it back from resume\n");
++#endif
++
++	leds_event(led_start);
++
++	sti();
++
++	return 0;
++}
++
++unsigned long sleep_phys_sp(void *sp)
++{
++	return virt_to_phys(sp);
++}
++
++#ifdef CONFIG_SYSCTL
++/*
++ * ARGH!  ACPI people defined CTL_ACPI in linux/acpi.h rather than
++ * linux/sysctl.h.
++ *
++ * This means our interface here won't survive long - it needs a new
++ * interface.  Quick hack to get this working - use sysctl id 9999.
++ */
++#warning ACPI broke the kernel, this interface needs to be fixed up.
++#define CTL_ACPI 9999
++#define ACPI_S1_SLP_TYP 19
++
++/*
++ * Send us to sleep.
++ */
++static int sysctl_pm_do_suspend(void)
++{
++	int retval;
++
++	retval = pm_send_all(PM_SUSPEND, (void *)3);
++
++	if (retval == 0) {
++		retval = pm_do_suspend();
++
++		pm_send_all(PM_RESUME, (void *)0);
++	}
++
++	return retval;
++}
++
++static struct ctl_table pm_table[] =
++{
++	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_do_suspend},
++	{0}
++};
++
++static struct ctl_table pm_dir_table[] =
++{
++	{CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
++	{0}
++};
++
++/*
++ * Initialize power interface
++ */
++static int __init pm_init(void)
++{
++	register_sysctl_table(pm_dir_table, 1);
++	return 0;
++}
++
++__initcall(pm_init);
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/pxa_usb.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,230 @@
++/*
++ * pxa_usb.h
++ *
++ * Public interface to the pxa USB core. For use by client modules
++ * like usb-eth and usb-char.
++ *
++ * 02-May-2002
++ *   Frank Becker (Intrinsyc) - derived from sa1100_usb.h
++ *
++ */
++
++#ifndef _PXA_USB_H
++#define _PXA_USB_H
++#include <asm/byteorder.h>
++
++typedef void (*usb_callback_t)(int flag, int size);
++
++/* in usb_ctl.c (see also descriptor methods at bottom of file) */
++
++// Open the USB client for client and initialize data structures
++// to default values, but _do not_ start UDC.
++int pxa_usb_open( const char * client_name );
++
++// Start UDC running
++int pxa_usb_start( void );
++
++// Immediately stop udc, fire off completion routines w/-EINTR
++int pxa_usb_stop( void ) ;
++
++// Disconnect client from usb core
++int pxa_usb_close( void ) ;
++
++// set notify callback for when core reaches configured state
++// return previous pointer (if any)
++typedef void (*usb_notify_t)(void);
++usb_notify_t pxa_set_configured_callback( usb_notify_t callback );
++
++/* in usb_send.c */
++int pxa_usb_xmitter_avail( void );
++int pxa_usb_send(char *buf, int len, usb_callback_t callback);
++void sa110a_usb_send_reset(void);
++
++/* in usb_recev.c */
++int pxa_usb_recv(char *buf, int len, usb_callback_t callback);
++void pxa_usb_recv_reset(void);
++
++//////////////////////////////////////////////////////////////////////////////
++// Descriptor Management
++//////////////////////////////////////////////////////////////////////////////
++
++#define DescriptorHeader \
++	__u8 bLength;        \
++	__u8 bDescriptorType
++
++
++// --- Device Descriptor -------------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u16 bcdUSB;		   	/* USB specification revision number in BCD */
++	 __u8  bDeviceClass;	/* USB class for entire device */
++	 __u8  bDeviceSubClass; /* USB subclass information for entire device */
++	 __u8  bDeviceProtocol; /* USB protocol information for entire device */
++	 __u8  bMaxPacketSize0; /* Max packet size for endpoint zero */
++	 __u16 idVendor;        /* USB vendor ID */
++	 __u16 idProduct;       /* USB product ID */
++	 __u16 bcdDevice;       /* vendor assigned device release number */
++	 __u8  iManufacturer;	/* index of manufacturer string */
++	 __u8  iProduct;        /* index of string that describes product */
++	 __u8  iSerialNumber;	/* index of string containing device serial number */
++	 __u8  bNumConfigurations; /* number fo configurations */
++} __attribute__ ((packed)) device_desc_t;
++
++// --- Configuration Descriptor ------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u16 wTotalLength;	    /* total # of bytes returned in the cfg buf 4 this cfg */
++	 __u8  bNumInterfaces;      /* number of interfaces in this cfg */
++	 __u8  bConfigurationValue; /* used to uniquely ID this cfg */
++	 __u8  iConfiguration;      /* index of string describing configuration */
++	 __u8  bmAttributes;        /* bitmap of attributes for ths cfg */
++	 __u8  MaxPower;		    /* power draw in 2ma units */
++} __attribute__ ((packed)) config_desc_t;
++
++// bmAttributes:
++enum { 
++	USB_CONFIG_REMOTEWAKE=0x20, 
++	USB_CONFIG_SELFPOWERED=0x40,
++	USB_CONFIG_BUSPOWERED=0x80 
++};
++
++// MaxPower:
++#define USB_POWER( x)  ((x)>>1) /* convert mA to descriptor units of A for MaxPower */
++
++// --- Interface Descriptor ---------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u8  bInterfaceNumber;   /* Index uniquely identfying this interface */
++	 __u8  bAlternateSetting;  /* ids an alternate setting for this interface */
++	 __u8  bNumEndpoints;      /* number of endpoints in this interface */
++	 __u8  bInterfaceClass;    /* USB class info applying to this interface */
++	 __u8  bInterfaceSubClass; /* USB subclass info applying to this interface */
++	 __u8  bInterfaceProtocol; /* USB protocol info applying to this interface */
++	 __u8  iInterface;         /* index of string describing interface */
++} __attribute__ ((packed)) intf_desc_t;
++
++// --- Endpoint  Descriptor ---------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u8  bEndpointAddress;  /* 0..3 ep num, bit 7: 0 = 0ut 1= in */
++	 __u8  bmAttributes;      /* 0..1 = 0: ctrl, 1: isoc, 2: bulk 3: intr */
++	 __u16 wMaxPacketSize;    /* data payload size for this ep in this cfg */
++	 __u8  bInterval;         /* polling interval for this ep in this cfg */
++} __attribute__ ((packed)) ep_desc_t;
++
++// bEndpointAddress:
++enum { 
++	USB_OUT	=0, 
++	USB_IN	=1 
++};
++
++#define USB_EP_ADDRESS(a,d) (((a)&0xf) | ((d) << 7))
++// bmAttributes:
++enum { 
++	USB_EP_CNTRL	=0, 
++	USB_EP_BULK	=2, 
++	USB_EP_INT	=3, 
++	USB_EP_ISO	=4 
++};
++
++// --- String Descriptor -------------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u16 bString[1];		  /* unicode string .. actaully 'n' __u16s */
++} __attribute__ ((packed)) string_desc_t;
++
++/*=======================================================
++ * Handy helpers when working with above
++ *
++ */
++// these are x86-style 16 bit "words" ...
++#define make_word_c( w ) __constant_cpu_to_le16(w)
++#define make_word( w )   __cpu_to_le16(w)
++
++// descriptor types
++enum { 
++    USB_DESC_DEVICE	= 1,
++    USB_DESC_CONFIG	= 2,
++    USB_DESC_STRING	= 3,
++    USB_DESC_INTERFACE	= 4,
++    USB_DESC_ENDPOINT	= 5
++};
++
++
++/*=======================================================
++ * Default descriptor layout for SA-1100 and SA-1110 UDC
++ */
++
++enum {
++  UNUSED = 0,
++
++  BULK_IN1  =  1,
++  BULK_OUT1 =  2,
++  ISO_IN1   =  3,
++  ISO_OUT1  =  4,
++  INT_IN1   =  5,
++
++  BULK_IN2  =  6,
++  BULK_OUT2 =  7,
++  ISO_IN2   =  8,
++  ISO_OUT2  =  9,
++  INT_IN2   = 10,
++
++  BULK_IN3  = 11,
++  BULK_OUT3 = 12,
++  ISO_IN3   = 13,
++  ISO_OUT3  = 14,
++  INT_IN3   = 15
++} /*endpoint_type*/;
++
++/* "config descriptor buffer" - that is, one config,
++   ..one interface and 2 endpoints */
++struct cdb {
++	 config_desc_t cfg;
++	 intf_desc_t   intf;
++	 ep_desc_t     ep1;
++	 ep_desc_t     ep2;
++} __attribute__ ((packed));
++
++/* all SA device descriptors */
++typedef struct {
++	 device_desc_t dev;   /* device descriptor */
++	 struct cdb b;        /* bundle of descriptors for this cfg */
++} __attribute__ ((packed)) desc_t;
++
++
++/*=======================================================
++ * Descriptor API
++ */
++
++/* Get the address of the statically allocated desc_t structure
++   in the usb core driver. Clients can modify this between
++   the time they call pxa_usb_open() and pxa_usb_start()
++*/
++desc_t *
++pxa_usb_get_descriptor_ptr( void );
++
++
++/* Set a pointer to the string descriptor at "index". The driver
++ ..has room for 8 string indicies internally. Index zero holds
++ ..a LANGID code and is set to US English by default. Inidices
++ ..1-7 are available for use in the config descriptors as client's
++ ..see fit. This pointer is assumed to be good as long as the
++ ..SA usb core is open (so statically allocate them). Returnes -EINVAL
++ ..if index out of range */
++int pxa_usb_set_string_descriptor( int index, string_desc_t * p );
++
++/* reverse of above */
++string_desc_t *
++pxa_usb_get_string_descriptor( int index );
++
++/* kmalloc() a string descriptor and convert "p" to unicode in it */
++string_desc_t *
++pxa_usb_kmalloc_string_descriptor( const char * p );
++
++#endif /* _PXA_USB_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/sa1111.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,3 @@
++#include "../mach-sa1100/sa1111.c"
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/sa1111.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,2 @@
++#include "../mach-sa1100/sa1111.h"
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/sleep.S	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,150 @@
++/*
++ * Low-level PXA250/210 sleep/wakeUp support
++ *
++ * Initial SA1110 code:
++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
++ *
++ * Adapted for PXA by Nicolas Pitre:
++ * Copyright (c) 2002 Monta Vista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++#include <asm/hardware.h>
++
++		.text
++
++/*
++ * pxa_cpu_suspend()
++ *
++ * Forces CPU into sleep state
++ */
++
++ENTRY(pxa_cpu_suspend)
++
++	mra	r2, r3, acc0
++	stmfd	sp!, {r2 - r12, lr}		@ save registers on stack
++
++	@ get coprocessor registers
++	mrc	p15, 0, r4, c15, c1, 0		@ CP access reg
++	mrc	p15, 0, r5, c13, c0, 0		@ PID
++	mrc 	p15, 0, r6, c3, c0, 0		@ domain ID
++	mrc 	p15, 0, r7, c2, c0, 0		@ translation table base addr
++	mrc	p15, 0, r8, c1, c1, 0           @ auxiliary control reg
++	mrc 	p15, 0, r9, c1, c0, 0		@ control reg
++
++	@ store them plus current virtual stack ptr on stack
++	mov	r10, sp
++	stmfd	sp!, {r4 - r10}
++
++	@ preserve phys address of stack
++	mov	r0, sp
++	bl	sleep_phys_sp
++	ldr	r1, =sleep_save_sp
++	str	r0, [r1]
++
++	@ clean data cache 
++	bl	cpu_xscale_cache_clean_invalidate_all
++
++	@ Put the processor to sleep
++	@ (also workaround for sighting 28071)
++
++	@ prepare value for sleep mode
++	mov	r1, #3				@ sleep mode
++
++	@ prepare to put SDRAM into self-refresh manually
++	ldr	r4, =MDREFR
++	ldr	r5, [r4]
++	orr	r5, r5, #MDREFR_SLFRSH
++
++	@ prepare pointer to physical address 0 (virtual mapping in generic.c)
++	mov	r2, #UNCACHED_PHYS_0
++
++	@ align execution to a cache line
++	b	1f
++
++	.ltorg
++	.align	5
++1:
++
++	@ All needed values are now in registers. 
++	@ These last instructions should be in cache
++
++	@ put SDRAM into self-refresh	
++	str	r5, [r4]
++
++	@ force address lines low by reading at physical address 0
++	ldr	r3, [r2]
++
++	@ enter sleep mode
++	mcr	p14, 0, r1, c7, c0, 0
++
++20:	nop
++	b	20b				@ loop waiting for sleep
++
++/*
++ * cpu_pxa_resume()
++ *
++ * entry point from bootloader into kernel during resume
++ *
++ * Note: Yes, part of the following code is located into the .data section.
++ *       This is to allow sleep_save_sp to be accessed with a relative load
++ *       while we can't rely on any MMU translation.  We could have put
++ *       sleep_save_sp in the .text section as well, but some setups might
++ *       insist on it to be truely read-only.
++ */
++
++	.data
++	.align 5
++ENTRY(pxa_cpu_resume)
++	mov	r0, #I_BIT | F_BIT | MODE_SVC	@ set SVC, irqs off
++	msr	cpsr_c, r0
++
++	ldr	r0, sleep_save_sp		@ stack phys addr
++	ldr	r2, =resume_after_mmu		@ its absolute virtual address
++	ldmfd	r0, {r4 - r9, sp}		@ CP regs + virt stack ptr
++
++	mov	r1, #0
++	mcr	p15, 0, r1, c8, c7, 0   	@ invalidate I & D TLBs
++	mcr	p15, 0, r1, c7, c7, 0		@ invalidate I & D caches, BTB
++
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++	bic     r9, r9, #0x0004			@ see cpu_xscale_proc_init
++#endif
++
++	mcr	p15, 0, r4, c15, c1, 0		@ CP access reg
++	mcr	p15, 0, r5, c13, c0, 0		@ PID
++	mcr 	p15, 0, r6, c3, c0, 0		@ domain ID
++	mcr 	p15, 0, r7, c2, c0, 0		@ translation table base addr
++	mcr	p15, 0, r8, c1, c1, 0           @ auxiliary control reg
++	b	resume_turn_on_mmu		@ cache align execution
++
++	.align 5
++resume_turn_on_mmu:
++	mcr 	p15, 0, r9, c1, c0, 0		@ turn on MMU, caches, etc.
++
++	@ Let us ensure we jump to resume_after_mmu only when the mcr above
++	@ actually took effect.  They call it the "cpwait" operation.
++	mrc	p15, 0, r1, c2, c0, 0		@ queue a dependency on CP15
++	sub	pc, r2, r1, lsr #32		@ jump to virtual addr 
++	nop
++	nop
++	nop
++
++sleep_save_sp:
++	.word	0				@ preserve stack phys ptr here
++
++	.text
++resume_after_mmu:
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++	bl	cpu_xscale_proc_init
++#endif
++	ldmfd	sp!, {r2, r3}
++	mar	acc0, r2, r3
++	ldmfd	sp!, {r4 - r12, pc}		@ return to caller
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/trizeps2.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,105 @@
++/*
++ *  linux/arch/arm/mach-pxa/trizeps2.c
++ *
++ *  Support for the Keith&Koep MT6N Development Platform.
++ *  
++ *  Author:	Luc De Cock
++ *  Created:	Jan 13, 2003
++ *  Copyright:	Teradyne DS, Ltd.
++ *  
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#include <linux/init.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++
++#include <asm/types.h>
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++
++#include "generic.h"
++
++static unsigned long trizeps2_irq_en_mask;
++unsigned short trizeps2_bcr_shadow = 0x50; // 0x70
++
++
++static void __init trizeps2_init_irq(void)
++{
++	int irq;
++	
++	pxa_init_irq();
++
++	set_GPIO_IRQ_edge(GPIO_ETHERNET_IRQ, GPIO_RISING_EDGE);
++}
++
++static int __init trizeps2_init(void)
++{
++	/* Configure the BCR register */
++	unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++
++	*bcr = trizeps2_bcr_shadow;
++	return 0;
++}
++
++__initcall(trizeps2_init);
++
++static void __init
++fixup_trizeps2(struct machine_desc *desc, struct param_struct *params,
++		char **cmdline, struct meminfo *mi)
++{
++#ifdef TRIZEPS2_MEM_64MB
++	SET_BANK (0, 0xa0000000, 64*1024*1024);
++#else
++	SET_BANK (0, 0xa0000000, 32*1024*1024);
++#endif
++	mi->nr_banks      = 1;
++}
++
++static struct map_desc trizeps2_io_desc[] __initdata = {
++ /* virtual     physical    length      domain     r  w  c  b */
++  { 0xf0000000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* BCR */
++  { 0xf0100000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA STATUS */
++  { 0xf1000000, 0x0c800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */
++  { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */
++  { 0xf2000000, 0x0d800000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* TTL-IO */
++  LAST_DESC
++};
++
++static void __init trizeps2_map_io(void)
++{
++	pxa_map_io();
++	iotable_init(trizeps2_io_desc);
++
++	/* This is for the SMC chip select */
++	set_GPIO_mode(GPIO79_nCS_3_MD);
++
++	/* setup sleep mode values */
++	PWER  = 0x00000002;
++	PFER  = 0x00000000;
++	PRER  = 0x00000002;
++	PGSR0 = 0x00008000;
++	PGSR1 = 0x003F0202;
++	PGSR2 = 0x0001C000;
++	PCFR |= PCFR_OPDE;
++}
++
++MACHINE_START(TRIZEPS2, "Keith-n-Koep MT6N Development Platform")
++	MAINTAINER("Luc De Cock")
++	BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++	FIXUP(fixup_trizeps2)
++	MAPIO(trizeps2_map_io)
++	INITIRQ(trizeps2_init_irq)
++MACHINE_END
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb-char.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,719 @@
++/*
++ * (C) Copyright 2000-2001 Extenex 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *  usb-char.c
++ *
++ *  Miscellaneous character device interface for SA1100 USB function
++ *	driver.
++ *
++ *  Background:
++ *  The SA1100 function driver ported from the Compaq Itsy project
++ *  has an interface, usb-eth.c, to feed network packets over the
++ *  usb wire and into the Linux TCP/IP stack.
++ *
++ *  This file replaces that one with a simple character device
++ *  interface that allows unstructured "byte pipe" style reads and
++ *  writes over the USB bulk endpoints by userspace programs.
++ *
++ *  A new define, CONFIG_SA1100_USB_NETLINK, has been created that,
++ *  when set, (the default) causes the ethernet interface to be used.
++ *  When not set, this more pedestrian character interface is linked
++ *  in instead.
++ *
++ *  Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ *
++ *  ward.willats@extenex.com
++ *
++ *  To do:
++ *  - Can't dma into ring buffer directly with pci_map/unmap usb_recv
++ *    uses and get bytes out at the same time DMA is going on. Investigate:
++ *    a) changing usb_recv to use alloc_consistent() at client request; or
++ *    b) non-ring-buffer based data structures. In the meantime, I am using
++ *    a bounce buffer. Simple, but wasteful.
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/cache.h>
++#include <linux/poll.h>
++#include <linux/circ_buf.h>
++#include <linux/timer.h>
++
++#include <asm/io.h>
++#include <asm/semaphore.h>
++#include <asm/proc/page.h>
++#include <asm/mach-types.h>
++
++#include "usb-char.h"
++#include "pxa_usb.h"
++
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Driver  Options
++//////////////////////////////////////////////////////////////////////////////
++
++#define VERSION 	"0.4"
++
++
++#define VERBOSITY 1
++
++#if VERBOSITY
++# define	PRINTK(x, a...)	printk (x, ## a)
++#else
++# define	PRINTK(x, a...)	/**/
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals - Macros - Enums - Structures
++//////////////////////////////////////////////////////////////////////////////
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++typedef int bool; enum { false = 0, true = 1 };
++
++static const char pszMe[] = "usbchr: ";
++
++static wait_queue_head_t wq_read;
++static wait_queue_head_t wq_write;
++static wait_queue_head_t wq_poll;
++
++/* Serialze multiple writers onto the transmit hardware
++.. since we sleep the writer during transmit to stay in
++.. sync. (Multiple writers don't make much sense, but..) */
++static DECLARE_MUTEX( xmit_sem );
++
++// size of usb DATA0/1 packets. 64 is standard maximum
++// for bulk transport, though most hosts seem to be able
++// to handle larger.
++#define TX_PACKET_SIZE 64
++#define RX_PACKET_SIZE 64
++#define RBUF_SIZE  (4*PAGE_SIZE)
++
++static struct wcirc_buf {
++  char *buf;
++  int in;
++  int out;
++} rx_ring = { NULL, 0, 0 };
++
++static struct {
++	 unsigned long  cnt_rx_complete;
++	 unsigned long  cnt_rx_errors;
++	 unsigned long  bytes_rx;
++	 unsigned long  cnt_tx_timeouts;
++	 unsigned long  cnt_tx_errors;
++	 unsigned long  bytes_tx;
++} charstats;
++
++
++static char * tx_buf = NULL;
++static char * packet_buffer = NULL;
++static int sending = 0;
++static int usb_ref_count = 0;
++static int last_tx_result = 0;
++static int last_rx_result = 0;
++static int last_tx_size = 0;
++static struct timer_list tx_timer;
++
++//////////////////////////////////////////////////////////////////////////////
++// Prototypes
++//////////////////////////////////////////////////////////////////////////////
++static char * 	what_the_f( int e );
++static void 	free_txrx_buffers( void );
++static void     twiddle_descriptors( void );
++static void     free_string_descriptors( void ) ;
++static int      usbc_open( struct inode *pInode, struct file *pFile );
++static void     rx_done_callback_packet_buffer( int flag, int size );
++
++static void     tx_timeout( unsigned long );
++static void     tx_done_callback( int flag, int size );
++
++static ssize_t  usbc_read( struct file *, char *, size_t, loff_t * );
++static ssize_t  usbc_write( struct file *, const char *, size_t, loff_t * );
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait );
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++                       unsigned int nCmd, unsigned long argument );
++static int      usbc_close( struct inode *pInode, struct file *pFile );
++
++#ifdef CONFIG_SA1100_EXTENEX1
++static void     extenex_configured_notify_proc( void );
++#endif
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++static char * what_the_f( int e )
++{
++	 char * p;
++	 switch( e ) {
++	 case 0:
++		  p = "noErr";
++		  break;
++	 case -ENODEV:
++		  p = "ENODEV - usb not in config state";
++		  break;
++	 case -EBUSY:
++		  p = "EBUSY - another request on the hardware";
++		  break;
++	 case -EAGAIN:
++		  p = "EAGAIN";
++		  break;
++	 case -EINTR:
++		  p = "EINTR - interrupted\n";
++		  break;
++	 case -EPIPE:
++		  p = "EPIPE - zero length xfer\n";
++		  break;
++	 default:
++		  p = "????";
++		  break;
++	 }
++	 return p;
++}
++
++static void free_txrx_buffers( void )
++{
++	 if ( rx_ring.buf != NULL ) {
++		  kfree( rx_ring.buf );
++		  rx_ring.buf = NULL;
++	 }
++	 if ( packet_buffer != NULL ) {
++		  kfree( packet_buffer );
++		  packet_buffer = NULL;
++	 }
++	 if ( tx_buf != NULL ) {
++		  kfree( tx_buf );
++		  tx_buf = NULL;
++	 }
++}
++
++/* twiddle_descriptors()
++ * It is between open() and start(). Setup descriptors.
++ */
++static void twiddle_descriptors( void )
++{
++	 desc_t * pDesc = pxa_usb_get_descriptor_ptr();
++	 string_desc_t * pString;
++
++	 pDesc->b.ep1.wMaxPacketSize = make_word_c( RX_PACKET_SIZE );
++	 pDesc->b.ep1.bmAttributes   = USB_EP_BULK;
++	 pDesc->b.ep2.wMaxPacketSize = make_word_c( TX_PACKET_SIZE );
++	 pDesc->b.ep2.bmAttributes   = USB_EP_BULK;
++
++         if ( machine_is_extenex1() ) {
++#ifdef CONFIG_SA1100_EXTENEX1
++		  pDesc->dev.idVendor = make_word_c( 0xC9F );
++		  pDesc->dev.idProduct = 1;
++		  pDesc->dev.bcdDevice = make_word_c( 0x0001 );
++		  pDesc->b.cfg.bmAttributes = USB_CONFIG_SELFPOWERED;
++		  pDesc->b.cfg.MaxPower = 0;
++
++		  pString = pxa_usb_kmalloc_string_descriptor( "Extenex" );
++		  if ( pString ) {
++			   pxa_usb_set_string_descriptor( 1, pString );
++			   pDesc->dev.iManufacturer = 1;
++		  }
++
++		  pString = pxa_usb_kmalloc_string_descriptor( "Handheld Theater" );
++		  if ( pString ) {
++			   pxa_usb_set_string_descriptor( 2, pString );
++			   pDesc->dev.iProduct = 2;
++		  }
++
++		  pString = pxa_usb_kmalloc_string_descriptor( "00000000" );
++		  if ( pString ) {
++			   pxa_usb_set_string_descriptor( 3, pString );
++			   pDesc->dev.iSerialNumber = 3;
++		  }
++
++		  pString = pxa_usb_kmalloc_string_descriptor( "HHT Bulk Transfer" );
++		  if ( pString ) {
++			   pxa_usb_set_string_descriptor( 4, pString );
++			   pDesc->b.intf.iInterface = 4;
++		  }
++		  pxa_set_configured_callback( extenex_configured_notify_proc );
++#endif
++	 }
++}
++
++static void free_string_descriptors( void )
++{
++	 if ( machine_is_extenex1() ) {
++		  string_desc_t * pString;
++		  int i;
++		  for( i = 1 ; i <= 4 ; i++ ) {
++			   pString = pxa_usb_get_string_descriptor( i );
++			   if ( pString )
++					kfree( pString );
++		  }
++	 }
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// ASYNCHRONOUS
++//////////////////////////////////////////////////////////////////////////////
++static  void kick_start_rx( void )
++{
++	 if ( usb_ref_count ) {
++		  int total_space  = CIRC_SPACE( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  if ( total_space >= RX_PACKET_SIZE ) {
++			   pxa_usb_recv( packet_buffer,
++								RX_PACKET_SIZE,
++								rx_done_callback_packet_buffer
++						      );
++		  }
++	 }
++}
++/*
++ * rx_done_callback_packet_buffer()
++ * We have completed a DMA xfer into the temp packet buffer.
++ * Move to ring.
++ *
++ * flag values:
++ * on init,  -EAGAIN
++ * on reset, -EINTR
++ * on RPE, -EIO
++ * on short packet -EPIPE
++ */
++static void
++rx_done_callback_packet_buffer( int flag, int size )
++{
++	 charstats.cnt_rx_complete++;
++
++	 if ( flag == 0 || flag == -EPIPE ) {
++		  size_t n;
++
++		  charstats.bytes_rx += size;
++
++		  n = CIRC_SPACE_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  n = MIN( n, size );
++		  size -= n;
++
++		  memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer, n );
++		  rx_ring.in = (rx_ring.in + n) & (RBUF_SIZE-1);
++		  memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer + n, size );
++		  rx_ring.in = (rx_ring.in + size) & (RBUF_SIZE-1);
++
++		  wake_up_interruptible( &wq_read );
++		  wake_up_interruptible( &wq_poll );
++
++		  last_rx_result = 0;
++
++		  kick_start_rx();
++
++	 } else if ( flag != -EAGAIN ) {
++		  charstats.cnt_rx_errors++;
++		  last_rx_result = flag;
++		  wake_up_interruptible( &wq_read );
++		  wake_up_interruptible( &wq_poll );
++	 }
++	 else  /* init, start a read */
++		  kick_start_rx();
++}
++
++
++static void tx_timeout( unsigned long unused )
++{
++	printk( "%stx timeout\n", pszMe );
++	pxa_usb_send_reset();
++	charstats.cnt_tx_timeouts++;
++}
++
++
++// on init, -EAGAIN
++// on reset, -EINTR
++// on TPE, -EIO
++static void tx_done_callback( int flags, int size )
++{
++	 if ( flags == 0 )
++		  charstats.bytes_tx += size;
++	 else
++		  charstats.cnt_tx_errors++;
++	 last_tx_size = size;
++	 last_tx_result = flags;
++	 sending = 0;
++	 wake_up_interruptible( &wq_write );
++	 wake_up_interruptible( &wq_poll );
++}
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Workers
++//////////////////////////////////////////////////////////////////////////////
++
++static int usbc_open( struct inode *pInode, struct file *pFile )
++{
++	 int retval = 0;
++
++	 PRINTK( KERN_DEBUG "%sopen()\n", pszMe );
++
++	 /* start usb core */
++	 retval = pxa_usb_open( "usb-char" );
++	 if ( retval ) return retval;
++
++	 /* allocate memory */
++	 if ( usb_ref_count == 0 ) {
++		  tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA );
++		  if ( tx_buf == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++		  rx_ring.buf =
++			(char*) kmalloc( RBUF_SIZE, GFP_KERNEL );
++
++		  if ( rx_ring.buf == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++
++		  packet_buffer =
++			(char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA  );
++
++		  if ( packet_buffer == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++		  rx_ring.in = rx_ring.out = 0;
++		  memset( &charstats, 0, sizeof( charstats ) );
++		  sending = 0;
++		  last_tx_result = 0;
++		  last_tx_size = 0;
++	 }
++
++	 /* modify default descriptors */
++	 twiddle_descriptors();
++
++	 retval = pxa_usb_start();
++	 if ( retval ) {
++		  printk( "%sAGHH! Could not USB core\n", pszMe );
++		  free_txrx_buffers();
++		  return retval;
++	 }
++	 usb_ref_count++;   /* must do _before_ kick_start() */
++	 MOD_INC_USE_COUNT;
++	 kick_start_rx();
++	 return 0;
++
++ malloc_fail:
++	 free_txrx_buffers();
++	 return -ENOMEM;
++}
++
++/*
++ * Read endpoint. Note that you can issue a read to an
++ * unconfigured endpoint. Eventually, the host may come along
++ * and configure underneath this module and data will appear.
++ */
++static ssize_t usbc_read( struct file *pFile, char *pUserBuffer,
++                        size_t stCount, loff_t *pPos )
++{
++	 ssize_t retval;
++	 int flags;
++	 DECLARE_WAITQUEUE( wait, current );
++
++	 PRINTK( KERN_DEBUG "%sread()\n", pszMe );
++
++	 local_irq_save( flags );
++	 if ( last_rx_result == 0 ) {
++		  local_irq_restore( flags );
++	 } else {  /* an error happended and receiver is paused */
++		  local_irq_restore( flags );
++		  last_rx_result = 0;
++		  kick_start_rx();
++	 }
++
++	 add_wait_queue( &wq_read, &wait );
++	 while( 1 ) {
++		  ssize_t bytes_avail;
++		  ssize_t bytes_to_end;
++
++		  set_current_state( TASK_INTERRUPTIBLE );
++
++		  /* snap ring buf state */
++		  local_irq_save( flags );
++		  bytes_avail  = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  local_irq_restore( flags );
++
++		  if ( bytes_avail != 0 ) {
++			   ssize_t bytes_to_move = MIN( stCount, bytes_avail );
++			   retval = 0;		// will be bytes transfered
++			   if ( bytes_to_move != 0 ) {
++					size_t n = MIN( bytes_to_end, bytes_to_move );
++					if ( copy_to_user( pUserBuffer,
++									   &rx_ring.buf[ rx_ring.out ],
++									   n ) ) {
++						 retval = -EFAULT;
++						 break;
++					}
++					bytes_to_move -= n;
++ 					retval += n;
++					// might go 1 char off end, so wrap
++					rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1);
++					if ( copy_to_user( pUserBuffer + n,
++									   &rx_ring.buf[ rx_ring.out ],
++									   bytes_to_move )
++						 ) {
++						 retval = -EFAULT;
++						 break;
++					}
++					rx_ring.out += bytes_to_move;		// cannot wrap
++					retval += bytes_to_move;
++					kick_start_rx();
++			   }
++			   break;
++		  }
++		  else if ( last_rx_result ) {
++			   retval = last_rx_result;
++			   break;
++		  }
++		  else if ( pFile->f_flags & O_NONBLOCK ) {  // no data, can't sleep
++			   retval = -EAGAIN;
++			   break;
++		  }
++		  else if ( signal_pending( current ) ) {   // no data, can sleep, but signal
++			   retval = -ERESTARTSYS;
++			   break;
++		  }
++		  schedule();					   			// no data, can sleep
++	 }
++	 set_current_state( TASK_RUNNING );
++	 remove_wait_queue( &wq_read, &wait );
++
++	 if ( retval < 0 )
++		  printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) );
++	 return retval;
++}
++
++/*
++ * Write endpoint. This routine attempts to break the passed in buffer
++ * into usb DATA0/1 packet size chunks and send them to the host.
++ * (The lower-level driver tries to do this too, but easier for us
++ * to manage things here.)
++ *
++ * We are at the mercy of the host here, in that it must send an IN
++ * token to us to pull this data back, so hopefully some higher level
++ * protocol is expecting traffic to flow in that direction so the host
++ * is actually polling us. To guard against hangs, a 5 second timeout
++ * is used.
++ *
++ * This routine takes some care to only report bytes sent that have
++ * actually made it across the wire. Thus we try to stay in lockstep
++ * with the completion routine and only have one packet on the xmit
++ * hardware at a time. Multiple simultaneous writers will get
++ * "undefined" results.
++ *
++  */
++static ssize_t  usbc_write( struct file *pFile, const char * pUserBuffer,
++							 size_t stCount, loff_t *pPos )
++{
++	 ssize_t retval = 0;
++	 ssize_t stSent = 0;
++
++	 DECLARE_WAITQUEUE( wait, current );
++
++	 PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount );
++
++	 down( &xmit_sem );  // only one thread onto the hardware at a time
++
++	 while( stCount != 0 && retval == 0 ) {
++		  int nThisTime  = MIN( TX_PACKET_SIZE, stCount );
++		  copy_from_user( tx_buf, pUserBuffer, nThisTime );
++		  sending = nThisTime;
++ 		  retval = pxa_usb_send( tx_buf, nThisTime, tx_done_callback );
++		  if ( retval < 0 ) {
++			   char * p = what_the_f( retval );
++			   printk( "%sCould not queue xmission. rc=%d - %s\n",
++					   pszMe, retval, p );
++			   sending = 0;
++			   break;
++		  }
++		  /* now have something on the diving board */
++		  add_wait_queue( &wq_write, &wait );
++		  tx_timer.expires = jiffies + ( HZ * 5 );
++		  add_timer( &tx_timer );
++		  while( 1 ) {
++			   set_current_state( TASK_INTERRUPTIBLE );
++			   if ( sending == 0 ) {  /* it jumped into the pool */
++					del_timer( &tx_timer );
++					retval = last_tx_result;
++					if ( retval == 0 ) {
++						 stSent		 += last_tx_size;
++						 pUserBuffer += last_tx_size;
++						 stCount     -= last_tx_size;
++					}
++					else
++						 printk( "%sxmission error rc=%d - %s\n",
++								 pszMe, retval, what_the_f(retval) );
++					break;
++			   }
++			   else if ( signal_pending( current ) ) {
++					del_timer( &tx_timer );
++					printk( "%ssignal\n", pszMe  );
++					retval = -ERESTARTSYS;
++					break;
++			   }
++			   schedule();
++		  }
++		  set_current_state( TASK_RUNNING );
++		  remove_wait_queue( &wq_write, &wait );
++	 }
++
++	 up( &xmit_sem );
++
++	 if ( 0 == retval )
++		  retval = stSent;
++	 return retval;
++}
++
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait )
++{
++	 unsigned int retval = 0;
++
++	 PRINTK( KERN_DEBUG "%poll()\n", pszMe );
++
++	 poll_wait( pFile, &wq_poll, pWait );
++
++	 if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) )
++		  retval |= POLLIN | POLLRDNORM;
++	 if ( pxa_usb_xmitter_avail() )
++		  retval |= POLLOUT | POLLWRNORM;
++	 return retval;
++}
++
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++                       unsigned int nCmd, unsigned long argument )
++{
++	 int retval = 0;
++
++	 switch( nCmd ) {
++
++	 case USBC_IOC_FLUSH_RECEIVER:
++		  pxa_usb_recv_reset();
++		  rx_ring.in = rx_ring.out = 0;
++		  break;
++
++	 case USBC_IOC_FLUSH_TRANSMITTER:
++		  pxa_usb_send_reset();
++		  break;
++
++	 case USBC_IOC_FLUSH_ALL:
++		  pxa_usb_recv_reset();
++		  rx_ring.in = rx_ring.out = 0;
++		  pxa_usb_send_reset();
++		  break;
++
++	 default:
++		  retval = -ENOIOCTLCMD;
++		  break;
++
++	 }
++	 return retval;
++}
++
++
++static int usbc_close( struct inode *pInode, struct file * pFile )
++{
++	PRINTK( KERN_DEBUG "%sclose()\n", pszMe );
++	if ( --usb_ref_count == 0 ) {
++		 down( &xmit_sem );
++		 pxa_usb_stop();
++		 free_txrx_buffers();
++		 free_string_descriptors();
++		 del_timer( &tx_timer );
++		 pxa_usb_close();
++		 up( &xmit_sem );
++	}
++    MOD_DEC_USE_COUNT;
++    return 0;
++}
++
++#ifdef CONFIG_SA1100_EXTENEX1
++#include "../../../drivers/char/ex_gpio.h"
++void extenex_configured_notify_proc( void )
++{
++	 if ( exgpio_play_string( "440,1:698,1" ) == -EAGAIN )
++		  printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe );
++}
++#endif
++//////////////////////////////////////////////////////////////////////////////
++// Initialization
++//////////////////////////////////////////////////////////////////////////////
++
++static struct file_operations usbc_fops = {
++		owner:      THIS_MODULE,
++		open:		usbc_open,
++		read:		usbc_read,
++		write:		usbc_write,
++		poll:		usbc_poll,
++		ioctl:		usbc_ioctl,
++		release:	usbc_close,
++};
++
++static struct miscdevice usbc_misc_device = {
++    USBC_MINOR, "usb_char", &usbc_fops
++};
++
++/*
++ * usbc_init()
++ */
++
++int __init usbc_init( void )
++{
++	 int rc;
++
++	 if ( (rc = misc_register( &usbc_misc_device )) != 0 ) {
++		  printk( KERN_WARNING "%sCould not register device 10, "
++				  "%d. (%d)\n", pszMe, USBC_MINOR, rc );
++		  return -EBUSY;
++	 }
++
++	 // initialize wait queues
++	 init_waitqueue_head( &wq_read );
++	 init_waitqueue_head( &wq_write );
++	 init_waitqueue_head( &wq_poll );
++
++	 // initialize tx timeout timer
++	 init_timer( &tx_timer );
++	 tx_timer.function = tx_timeout;
++
++	  printk( KERN_INFO "USB Function Character Driver Interface"
++				  " - %s, (C) 2001, Extenex Corp.\n", VERSION
++		   );
++
++	 return rc;
++}
++
++void __exit usbc_exit( void )
++{
++}
++
++EXPORT_NO_SYMBOLS;
++
++module_init(usbc_init);
++module_exit(usbc_exit);
++
++
++
++// end: usb-char.c
++
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb-char.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2001 Extenex Corporation
++ *
++ * usb-char.h
++ *
++ * Character device emulation client for SA-1100 client usb core.
++ *
++ *
++ *
++ */
++#ifndef _USB_CHAR_H
++#define _USB_CHAR_H
++
++#define USBC_MAJOR 10      /* miscellaneous character device */
++#define USBC_MINOR 240     /* in the "reserved for local use" range */
++
++#define USBC_MAGIC 0x8E
++
++/* zap everything in receive ring buffer */
++#define USBC_IOC_FLUSH_RECEIVER    _IO( USBC_MAGIC, 0x01 )
++
++/* reset transmitter */
++#define USBC_IOC_FLUSH_TRANSMITTER _IO( USBC_MAGIC, 0x02 )
++
++/* do both of above */
++#define USBC_IOC_FLUSH_ALL         _IO( USBC_MAGIC, 0x03 )
++
++
++
++
++
++
++#endif /* _USB_CHAR_H */
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb-eth.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,479 @@
++/*
++ * Ethernet driver for the PXA USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original initial ethernet test driver
++ * Copyright (c) Compaq Computer Corporation, 1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This is still work in progress...
++ *
++ * 19/02/2001 - Now we are compatible with generic usbnet driver. green@iXcelerator.com
++ * 09/03/2001 - Dropped 'framing' scheme, as it seems to cause a lot of problems with little benefit.
++ *		Now, since we do not know what size of packet we are receiving
++ *		last usb packet in sequence will always be less than max packet
++ *		receive endpoint can accept.
++ *		Now the only way to check correct start of frame is to compare
++ *		MAC address. Also now we are stalling on each receive error.
++ *
++ * 15/03/2001 - Using buffer to get data from UDC. DMA needs to have 8 byte
++ *		aligned buffer, but this breaks IP code (unaligned access).
++ *
++ * 01/04/2001 - stall endpoint operations appeared to be very unstable, so
++ *              they are disabled now.
++ *
++ * 03/06/2001 - Readded "zerocopy" receive path (tunable).
++ *
++ */
++
++// Define DMA_NO_COPY if you want data to arrive directly into the
++// receive network buffers, instead of arriving into bounce buffer
++// and then get copied to network buffer.
++// This does not work correctly right now.
++#undef DMA_NO_COPY
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/timer.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++
++#include "pxa_usb.h"
++
++
++#define ETHERNET_VENDOR_ID 0x49f
++#define ETHERNET_PRODUCT_ID 0x505A
++#define MAX_PACKET 32768
++#define MIN(a, b) (((a) < (b)) ? (a) : (b))
++
++// Should be global, so that insmod can change these
++int usb_rsize=64;
++int usb_wsize=64;
++
++static struct usbe_info_t {
++  struct net_device *dev;
++  u16 packet_id;
++  struct net_device_stats stats;
++} usbe_info;
++
++static char usb_eth_name[16] = "usbf";
++static struct net_device usb_eth_device;
++static struct sk_buff *cur_tx_skb, *next_tx_skb;
++static struct sk_buff *cur_rx_skb, *next_rx_skb;
++static volatile int terminating;
++#ifndef DMA_NO_COPY
++static char *dmabuf; // we need that, as dma expect it's buffers to be aligned on 8 bytes boundary
++#endif
++
++static int usb_change_mtu (struct net_device *net, int new_mtu)
++{
++	if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET)
++		return -EINVAL;
++	// no second zero-length packet read wanted after mtu-sized packets
++	if (((new_mtu + sizeof (struct ethhdr)) % usb_rsize) == 0)
++		return -EDOM;
++
++	net->mtu = new_mtu;
++	return 0;
++}
++
++static struct sk_buff *
++usb_new_recv_skb(void)
++{
++	struct sk_buff *skb = alloc_skb( 2 + sizeof (struct ethhdr) + usb_eth_device.mtu,GFP_ATOMIC);
++
++	if (skb) {
++		skb_reserve(skb, 2);
++	}
++	return skb;
++}
++
++static u8 bcast_hwaddr[ETH_ALEN]={0xff,0xff,0xff,0xff,0xff,0xff};
++static void
++usb_recv_callback(int flag, int size)
++{
++	struct sk_buff *skb;
++
++	if (terminating)
++		return;
++
++	skb = cur_rx_skb;
++
++	/* flag validation */
++	if (flag == 0) {
++		if ( skb_tailroom (skb) < size ) { // hey! we are overloaded!!!
++			usbe_info.stats.rx_over_errors++;
++			goto error;
++		}
++#ifndef DMA_NO_COPY
++		memcpy(skb->tail,dmabuf,size);
++#endif
++		skb_put(skb, size);
++	} else {
++		if (flag == -EIO) {
++			usbe_info.stats.rx_errors++;
++		}
++		goto error;
++	}
++	
++
++	/*
++	 * If the real size of the packet is divisible by usb_rsize
++	 * an extra byte will be added. Thus size == usb_rsize
++	 * should only happen if more data is to come.
++	 */
++	/* validate packet length */
++	if (size == usb_rsize ) {
++		/* packet not complete yet */
++		skb = NULL;
++	}
++
++	/*
++	 * At this point skb is non null if we have a complete packet.
++	 * If so take a fresh skb right away and restart USB receive without
++	 * further delays, then process the packet.  Otherwise resume USB
++	 * receive on the current skb and exit.
++	 */
++
++	if (skb)
++		cur_rx_skb = next_rx_skb;
++#ifndef DMA_NO_COPY
++	pxa_usb_recv(dmabuf, usb_rsize,
++			usb_recv_callback);
++#else
++	pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)),
++			usb_recv_callback);
++#endif
++	if (!skb)
++		return;
++
++	next_rx_skb = usb_new_recv_skb();
++	if (!next_rx_skb) {
++		/*
++		 * We can't aford loosing buffer space...
++		 * So we drop the current packet and recycle its skb.
++		 */
++		printk("%s: can't allocate new skb\n", __FUNCTION__);
++		usbe_info.stats.rx_dropped++;
++		skb_trim(skb, 0);
++		next_rx_skb = skb;
++		return;
++	}
++	if ( skb->len >= sizeof(struct ethhdr)) {
++		if (memcmp(skb->data,usb_eth_device.dev_addr,ETH_ALEN) && memcmp(skb->data,bcast_hwaddr,ETH_ALEN) ) {
++			// This frame is not for us. nor it is broadcast
++			usbe_info.stats.rx_frame_errors++;
++			kfree_skb(skb);
++			goto error;
++		}
++
++#if 0
++{
++        int i;
++
++        for (i = 0; i < skb->len; i++)
++	{
++                printk("%02X ", skb->data[i]);
++		if( (i%8)==7) printk("\n");
++	}
++        printk("...\n");
++}
++#endif
++
++	}
++
++	if (skb->len) {
++		int     status;
++// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
++
++		skb->dev = &usb_eth_device;
++		skb->protocol = eth_type_trans (skb, &usb_eth_device);
++		usbe_info.stats.rx_packets++;
++		usbe_info.stats.rx_bytes += skb->len;
++		skb->ip_summed = CHECKSUM_NONE;
++		status = netif_rx (skb);
++		if (status != NET_RX_SUCCESS)
++			printk("netif_rx failed with code %d\n",status);
++	} else {
++error:
++//printk("ERROR... tailroom=%d size=%d len=%d flag=%d\n", skb_tailroom(skb), size, skb->len, flag);
++		/*
++		 * Error due to HW addr mismatch, or IO error.
++		 * Recycle the current skb and reset USB reception.
++		 */
++		skb_trim(cur_rx_skb, 0);
++//		if ( flag == -EINTR || flag == -EAGAIN ) // only if we are coming out of stall
++#ifndef DMA_NO_COPY
++			pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback);
++#else
++			pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), usb_recv_callback);
++#endif
++	}
++}
++
++
++static void
++usb_send_callback(int flag, int size)
++{
++	struct net_device *dev = usbe_info.dev;
++	struct net_device_stats *stats;
++	struct sk_buff *skb=cur_tx_skb;
++	int ret;
++
++	if (terminating)
++		return;
++
++	stats = &usbe_info.stats;
++	switch (flag) {
++	    case 0:
++		stats->tx_packets++;
++		stats->tx_bytes += size;
++		break;
++	    case -EIO:
++		stats->tx_errors++;
++		break;
++	    default:
++		stats->tx_dropped++;
++		break;
++	}
++
++	cur_tx_skb = next_tx_skb;
++	next_tx_skb = NULL;
++	dev_kfree_skb_irq(skb);
++	if (!cur_tx_skb)
++		return;
++
++	dev->trans_start = jiffies;
++	ret = pxa_usb_send(cur_tx_skb->data, cur_tx_skb->len, usb_send_callback);
++	if (ret) {
++		/* If the USB core can't accept the packet, we drop it. */
++		dev_kfree_skb_irq(cur_tx_skb);
++		cur_tx_skb = NULL;
++		usbe_info.stats.tx_carrier_errors++;
++	}
++	netif_wake_queue(dev);
++}
++
++static int
++usb_eth_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	int ret;
++	long flags;
++
++	if (next_tx_skb) {
++		printk("%s: called with next_tx_skb != NULL\n", __FUNCTION__);
++		return 1;
++	}
++
++	if (skb_shared (skb)) {
++		struct sk_buff  *skb2 = skb_unshare(skb, GFP_ATOMIC);
++		if (!skb2) {
++			usbe_info.stats.tx_dropped++;
++			dev_kfree_skb(skb);
++			return 1;
++		}
++		skb = skb2;
++	}
++
++	if ((skb->len % usb_wsize) == 0) {
++		skb->len++; // other side will ignore this one, anyway.
++	}
++
++	save_flags_cli(flags);
++	if (cur_tx_skb) {
++		next_tx_skb = skb;
++		netif_stop_queue(dev);
++	} else {
++		cur_tx_skb = skb;
++		dev->trans_start = jiffies;
++		ret = pxa_usb_send(skb->data, skb->len, usb_send_callback);
++		if (ret) {
++			/* If the USB core can't accept the packet, we drop it. */
++			dev_kfree_skb(skb);
++			cur_tx_skb = NULL;
++			usbe_info.stats.tx_carrier_errors++;
++		}
++	}
++	restore_flags(flags);
++	return 0;
++}
++
++static void
++usb_xmit_timeout(struct net_device *dev )
++{
++	pxa_usb_send_reset();
++	dev->trans_start = jiffies;
++	netif_wake_queue(dev);
++}
++
++
++static int
++usb_eth_open(struct net_device *dev)
++{
++	int rc;
++	rc = pxa_usb_open( "usb-eth" );
++	if ( rc == 0 ) {
++		 string_desc_t * pstr;
++		 desc_t * pd = pxa_usb_get_descriptor_ptr();
++
++		 pd->b.ep1.wMaxPacketSize = make_word( usb_rsize );
++		 pd->b.ep2.wMaxPacketSize = make_word( usb_wsize );
++		 pd->dev.idVendor	  = ETHERNET_VENDOR_ID;
++		 pd->dev.idProduct     = ETHERNET_PRODUCT_ID;
++		 pstr = pxa_usb_kmalloc_string_descriptor( "PXA USB NIC" );
++		 if ( pstr ) {
++			  pxa_usb_set_string_descriptor( 1, pstr );
++			  pd->dev.iProduct = 1;
++		 }
++		 rc = pxa_usb_start();
++	}
++
++	if( rc == 0)
++	{
++		terminating = 0;
++		cur_tx_skb = next_tx_skb = NULL;
++		cur_rx_skb = usb_new_recv_skb();
++		next_rx_skb = usb_new_recv_skb();
++		if (!cur_rx_skb || !next_rx_skb) {
++			printk("%s: can't allocate new skb\n", __FUNCTION__);
++			if (cur_rx_skb)
++				kfree_skb(cur_rx_skb);
++			if (next_rx_skb)
++				kfree_skb(next_rx_skb);
++
++			pxa_usb_stop();
++			pxa_usb_close();
++			return -ENOMEM;;
++		}
++
++		MOD_INC_USE_COUNT;
++#ifndef DMA_NO_COPY
++		pxa_usb_recv(dmabuf, usb_rsize, usb_recv_callback);
++#else
++		pxa_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)),
++				usb_recv_callback);
++#endif
++	}
++
++	return rc;
++}
++
++static int
++usb_eth_release(struct net_device *dev)
++{
++	string_desc_t * pstr;
++
++	terminating = 1;
++	pxa_usb_send_reset();
++	pxa_usb_recv_reset();
++	if (cur_tx_skb)
++		kfree_skb(cur_tx_skb);
++	if (next_tx_skb)
++		kfree_skb(next_tx_skb);
++	if (cur_rx_skb)
++		kfree_skb(cur_rx_skb);
++	if (next_rx_skb)
++		kfree_skb(next_rx_skb);
++
++	pxa_usb_stop();
++	pxa_usb_close();
++	if ( (pstr = pxa_usb_get_string_descriptor(1)) != NULL )
++		kfree( pstr );
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static struct net_device_stats *
++usb_eth_stats(struct net_device *dev)
++{
++	struct usbe_info_t *priv =  (struct usbe_info_t*) dev->priv;
++	struct net_device_stats *stats=NULL;
++
++	if (priv)
++		stats = &priv->stats;
++	return stats;
++}
++
++static int
++usb_eth_probe(struct net_device *dev)
++{
++	u8 node_id [ETH_ALEN];
++
++	get_random_bytes (node_id, sizeof node_id);
++	node_id [0] &= 0xfe;    // clear multicast bit
++
++	/*
++	 * Assign the hardware address of the board:
++	 * generate it randomly, as there can be many such
++	 * devices on the bus.
++	 */
++	memcpy (dev->dev_addr, node_id, sizeof node_id);
++
++	dev->open = usb_eth_open;
++	dev->change_mtu = usb_change_mtu;
++	dev->stop = usb_eth_release;
++	dev->hard_start_xmit = usb_eth_xmit;
++	dev->get_stats = usb_eth_stats;
++	dev->watchdog_timeo = 1*HZ;
++	dev->tx_timeout = usb_xmit_timeout;
++	dev->priv = &usbe_info;
++
++	usbe_info.dev = dev;
++
++	/* clear the statistics */
++	memset(&usbe_info.stats, 0, sizeof(struct net_device_stats));
++
++	ether_setup(dev);
++	dev->flags &= ~IFF_MULTICAST;
++	dev->flags &= ~IFF_BROADCAST;
++	//dev->flags |= IFF_NOARP;
++
++	return 0;
++}
++
++#ifdef MODULE
++MODULE_PARM(usb_rsize, "1i");
++MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to pxa");
++MODULE_PARM(usb_wsize, "1i");
++MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from pxa to host");
++#endif
++
++static int __init
++usb_eth_init(void)
++{
++#ifndef DMA_NO_COPY
++	dmabuf = kmalloc( usb_rsize, GFP_KERNEL | GFP_DMA );
++	if (!dmabuf)
++		return -ENOMEM;
++#endif
++	strncpy(usb_eth_device.name, usb_eth_name, IFNAMSIZ);
++	usb_eth_device.init = usb_eth_probe;
++	if (register_netdev(&usb_eth_device) != 0)
++		return -EIO;
++
++	printk( KERN_INFO "USB Function Ethernet Driver Interface\n");
++
++	return 0;
++}
++
++static void __exit
++usb_eth_cleanup(void)
++{
++#ifndef DMA_NO_COPY
++	kfree(dmabuf);
++#endif
++	unregister_netdev(&usb_eth_device);
++}
++
++module_init(usb_eth_init);
++module_exit(usb_eth_cleanup);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb_ctl.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,769 @@
++/*
++ *  Copyright (C) Compaq Computer Corporation, 1998, 1999
++ *  Copyright (C) Extenex Corporation, 2001
++ *  Copyright (C) Intrinsyc, Inc., 2002
++ *
++ *  PXA USB controller core driver.
++ *
++ *  This file provides interrupt routing and overall coordination
++ *  of the endpoints.
++ *
++ *  Please see:
++ *    linux/Documentation/arm/SA1100/SA1100_USB 
++ *  for more info.
++ *
++ *  02-May-2002
++ *   Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/proc_fs.h>
++#include <linux/tqueue.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++
++#include "pxa_usb.h"
++#include "usb_ctl.h"
++
++//#define DEBUG 1
++
++#if DEBUG
++static unsigned int usb_debug = DEBUG;
++#else
++#define usb_debug 0     /* gcc will remove all the debug code for us */
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Prototypes
++//////////////////////////////////////////////////////////////////////////////
++
++int usbctl_next_state_on_event( int event );
++static void udc_int_hndlr(int, void *, struct pt_regs *);
++static void initialize_descriptors( void );
++static void soft_connect_hook( int enable );
++static void udc_disable(void);
++static void udc_enable(void);
++
++#if CONFIG_PROC_FS
++#define PROC_NODE_NAME "driver/pxausb"
++static int usbctl_read_proc(char *page, char **start, off_t off,
++							int count, int *eof, void *data);
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals
++//////////////////////////////////////////////////////////////////////////////
++static const char pszMe[] = "usbctl: ";
++struct usb_info_t usbd_info;  /* global to ep0, usb_recv, usb_send */
++
++/* device descriptors */
++static desc_t desc;
++
++#define MAX_STRING_DESC 8
++static string_desc_t * string_desc_array[ MAX_STRING_DESC ];
++static string_desc_t sd_zero;  /* special sd_zero holds language codes */
++
++// called when configured
++static usb_notify_t configured_callback = NULL;
++
++enum {
++    kStateZombie		= 0,
++    kStateZombieSuspend		= 1,
++    kStateDefault		= 2,
++    kStateDefaultSuspend	= 3,
++    kStateAddr			= 4,
++    kStateAddrSuspend		= 5,
++    kStateConfig		= 6,
++    kStateConfigSuspend		= 7
++};
++
++/*
++ * FIXME: The PXA UDC handles several host device requests without user 
++ * notification/intervention. The table could be collapsed quite a bit...
++ */
++static int device_state_machine[8][6] = {
++//              suspend               reset          resume         adddr       config        deconfig
++/* zombie */  { kStateZombieSuspend , kStateDefault, kStateZombie , kError    , kError      , kError },
++/* zom sus */ { kStateZombieSuspend , kStateDefault, kStateZombie , kError    , kError      , kError },
++/* default */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kStateAddr, kStateConfig, kError },
++/* def sus */ { kStateDefaultSuspend, kStateDefault, kStateDefault, kError    , kError      , kError },
++/* addr */    { kStateAddrSuspend   , kStateDefault, kStateAddr   , kError    , kStateConfig, kError },
++/* addr sus */{ kStateAddrSuspend   , kStateDefault, kStateAddr   , kError    , kError      , kError },
++/* config */  { kStateConfigSuspend , kStateDefault, kStateConfig , kError    , kError      , kStateDefault },
++/* cfg sus */ { kStateConfigSuspend , kStateDefault, kStateConfig , kError    , kError      , kError }
++};
++
++/* "device state" is the usb device framework state, as opposed to the
++   "state machine state" which is whatever the driver needs and is much
++   more fine grained
++*/
++static int sm_state_to_device_state[8] = { 
++//  zombie            zom suspend       
++USB_STATE_POWERED, USB_STATE_SUSPENDED, 
++//  default           default sus
++USB_STATE_DEFAULT, USB_STATE_SUSPENDED,
++//  addr              addr sus         
++USB_STATE_ADDRESS, USB_STATE_SUSPENDED, 
++//  config            config sus
++USB_STATE_CONFIGURED, USB_STATE_SUSPENDED
++};
++
++static char * state_names[8] =
++{ "zombie", "zombie suspended", 
++  "default", "default suspended",
++  "address", "address suspended", 
++  "configured", "config suspended"
++};
++
++static char * event_names[6] =
++{ "suspend", "reset", "resume",
++  "address assigned", "configure", "de-configure"
++};
++
++static char * device_state_names[] =
++{ "not attached", "attached", "powered", "default",
++  "address", "configured", "suspended" };
++
++static int sm_state = kStateZombie;
++
++//////////////////////////////////////////////////////////////////////////////
++// Async
++//////////////////////////////////////////////////////////////////////////////
++
++/* The UDCCR reg contains mask and interrupt status bits,
++ * so using '|=' isn't safe as it may ack an interrupt.
++ */
++
++void udc_set_mask_UDCCR( int mask )
++{
++	UDCCR = (UDCCR & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS);
++}
++
++void udc_clear_mask_UDCCR( int mask)
++{
++	UDCCR = (UDCCR & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS);
++}
++
++void udc_ack_int_UDCCR( int mask)
++{
++	/* udccr contains the bits we dont want to change */
++	__u32 udccr = UDCCR & UDCCR_MASK_BITS; 
++
++	UDCCR = udccr | (mask & ~UDCCR_MASK_BITS);
++}
++
++static void
++udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
++{
++  	__u32 status = UDCCR;
++  	__u32 ir0_status = USIR0;
++  	__u32 ir1_status = USIR1;
++  	__u32 uicr0 = UICR0;
++  	__u32 uicr1 = UICR1;
++
++	//mask ints
++	udc_set_mask_UDCCR( UDCCR_REM | UDCCR_SRM);
++	UICR0 = 0xff;
++	UICR1 = 0xff;
++
++	if( usb_debug > 2)
++	{
++		printk("%s--- udc_int_hndlr\n"
++		   "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n"
++		   "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", 
++		    pszMe, status, UDCCS0, UDCCS1, UDCCS2, ir0_status, ir1_status, uicr0, uicr1);
++	}
++
++	/* SUSpend Interrupt Request */
++	if ( status & UDCCR_SUSIR )
++	{
++		udc_ack_int_UDCCR( UDCCR_SUSIR);
++		if( usb_debug) printk("%sSuspend...\n", pszMe);
++		usbctl_next_state_on_event( kEvSuspend );
++	}
++
++	/* RESume Interrupt Request */
++	if ( status & UDCCR_RESIR )
++	{
++		udc_ack_int_UDCCR( UDCCR_RESIR);
++		if( usb_debug) printk("%sResume...\n", pszMe);
++		usbctl_next_state_on_event( kEvResume );
++	}
++
++	/* ReSeT Interrupt Request - UDC has been reset */
++	if ( status & UDCCR_RSTIR )
++	{
++		/* clear the reset interrupt */
++		udc_ack_int_UDCCR( UDCCR_RSTIR);
++
++		/* check type of reset */
++		if( (UDCCR & UDCCR_UDA) == 0)
++		{
++			/* reset assertion took place, nothing to do */
++			if( usb_debug) printk("%sReset assertion...\n", pszMe);
++		}
++
++		/* ok, it's a reset negation, go on with reset */
++		else if ( usbctl_next_state_on_event( kEvReset ) != kError )
++		{
++			/* starting reset sequence now... */
++			if( usb_debug) printk("%sResetting\n", pszMe);
++
++			ep0_reset();
++			ep_bulk_in1_reset();
++			ep_bulk_out1_reset();
++
++			usbctl_next_state_on_event( kEvConfig );
++		}
++		else
++		{
++			printk("%sUnexpected reset\n", pszMe);
++		}
++	}
++	else
++	{
++		/* ep0 int */
++		if (ir0_status & USIR0_IR0)
++			ep0_int_hndlr();
++
++		/* transmit bulk */
++		if (ir0_status & USIR0_IR1)
++			ep_bulk_in1_int_hndlr(ir0_status);
++
++		/* receive bulk */
++		if ( ir0_status & USIR0_IR2)
++			ep_bulk_out1_int_hndlr(ir0_status);
++
++		while (UDCCS2 & UDCCS_BO_RNE)
++		{
++			if( usb_debug) printk("More Bulk-out data...\n");
++			ep_bulk_out1_int_hndlr(ir0_status);
++		}
++	}
++
++	UICR0 = uicr0;
++	UICR1 = uicr1;
++	udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); /* enable suspend/resume, reset */
++
++	/* clear all endpoint ints */
++	USIR0 |= 0xff;
++	USIR1 |= 0xff;
++
++	if( usb_debug > 2)
++	{
++		printk("%sudc_int_hndlr\n"
++		       "UDCCR=0x%08x UDCCS0=0x%08x UDCCS1=0x%08x UDCCS2=0x%08x\n"
++		       "USIR0=0x%08x USIR1=0x%08x UICR0=0x%08x UICR1=0x%08x\n", 
++			pszMe, UDCCR, UDCCS0, UDCCS1, UDCCS2, USIR0, USIR1, UICR0, UICR1);
++	}
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Public Interface
++//////////////////////////////////////////////////////////////////////////////
++
++/* Open PXA usb core on behalf of a client, but don't start running */
++
++int
++pxa_usb_open( const char * client )
++{
++	if ( usbd_info.client_name != NULL )
++	{
++		printk( "%sUnable to register %s (%s already registered).\n", 
++			pszMe, client, usbd_info.client_name );
++		return -EBUSY;
++	}
++
++	usbd_info.client_name = (char*) client;
++	memset(&usbd_info.stats, 0, sizeof(struct usb_stats_t));
++	memset(string_desc_array, 0, sizeof(string_desc_array));
++
++	/* hack to start in zombie suspended state */
++	sm_state = kStateZombieSuspend;
++	usbd_info.state = USB_STATE_SUSPENDED;
++
++	/* create descriptors for enumeration */
++	initialize_descriptors();
++
++	printk( "%s%s registered.\n", pszMe, client );
++	return 0;
++}
++
++/* Start running. Must have called usb_open (above) first */
++int
++pxa_usb_start( void )
++{
++	if ( usbd_info.client_name == NULL ) {
++		printk( "%s%s - no client registered\n",
++				pszMe, __FUNCTION__ );
++		return -EPERM;
++	}
++
++	/* start UDC internal machinery running */
++	udc_enable();
++	udelay( 100 );
++
++	/* flush DMA and fire through some -EAGAINs */
++	ep_bulk_out1_init( usbd_info.dmach_rx );
++	ep_bulk_in1_init( usbd_info.dmach_tx );
++
++	/* give endpoint notification we are starting */
++	ep_bulk_out1_state_change_notify( USB_STATE_SUSPENDED );
++	ep_bulk_in1_state_change_notify( USB_STATE_SUSPENDED );
++
++	/* enable any platform specific hardware */
++	soft_connect_hook( 1 );
++
++	/* enable suspend/resume, reset */
++	udc_clear_mask_UDCCR( UDCCR_SRM | UDCCR_REM); 
++	/* enable ep0, ep1, ep2 */
++	UICR0 &= ~(UICR0_IM0 | UICR0_IM1 | UICR0_IM2); 
++
++	if( usb_debug) printk( "%sStarted %s\n", pszMe, usbd_info.client_name );
++	return 0;
++}
++
++/* Stop USB core from running */
++int
++pxa_usb_stop( void )
++{
++	if ( usbd_info.client_name == NULL ) {
++		printk( "%s%s - no client registered\n",
++				pszMe, __FUNCTION__ );
++		return -EPERM;
++	}
++	/* mask everything */
++	/* disable suspend/resume, reset */
++	udc_set_mask_UDCCR( UDCCR_SRM | UDCCR_REM); 
++	/* disable ep0, ep1, ep2 */
++	UICR0 |= (UICR0_IM0 | UICR0_IM1 | UICR0_IM2); 
++
++	ep_bulk_out1_reset();
++	ep_bulk_in1_reset();
++
++	udc_disable();
++	if( usb_debug) printk( "%sStopped %s\n", pszMe, usbd_info.client_name );
++	return 0;
++}
++
++/* Tell PXA core client is through using it */
++int
++pxa_usb_close( void )
++{
++	 if ( usbd_info.client_name == NULL ) {
++		  printk( "%s%s - no client registered\n",
++				  pszMe, __FUNCTION__ );
++		  return -EPERM;
++	 }
++	 printk( "%s%s closed.\n", pszMe, (char*)usbd_info.client_name );
++	 usbd_info.client_name = NULL;
++	 return 0;
++}
++
++/* set a proc to be called when device is configured */
++usb_notify_t pxa_set_configured_callback( usb_notify_t func )
++{
++	 usb_notify_t retval = configured_callback;
++	 configured_callback = func;
++	 return retval;
++}
++
++/*====================================================
++ * Descriptor Manipulation.
++ * Use these between open() and start() above to setup
++ * the descriptors for your device.
++ *
++ */
++
++/* get pointer to static default descriptor */
++desc_t *
++pxa_usb_get_descriptor_ptr( void ) { return &desc; }
++
++/* optional: set a string descriptor */
++int
++pxa_usb_set_string_descriptor( int i, string_desc_t * p )
++{
++	 int retval;
++	 if ( i < MAX_STRING_DESC ) {
++		  string_desc_array[i] = p;
++		  retval = 0;
++	 } else {
++		  retval = -EINVAL;
++	 }
++	 return retval;
++}
++
++/* optional: get a previously set string descriptor */
++string_desc_t *
++pxa_usb_get_string_descriptor( int i )
++{
++	 return ( i < MAX_STRING_DESC )
++		    ? string_desc_array[i]
++		    : NULL;
++}
++
++
++/* optional: kmalloc and unicode up a string descriptor */
++string_desc_t *
++pxa_usb_kmalloc_string_descriptor( const char * p )
++{
++	 string_desc_t * pResult = NULL;
++
++	 if ( p ) {
++		  int len = strlen( p );
++		  int uni_len = len * sizeof( __u16 );
++		  pResult = (string_desc_t*) kmalloc( uni_len + 2, GFP_KERNEL ); /* ugh! */
++		  if ( pResult != NULL ) {
++			   int i;
++			   pResult->bLength = uni_len + 2;
++			   pResult->bDescriptorType = USB_DESC_STRING;
++			   for( i = 0; i < len ; i++ ) {
++					pResult->bString[i] = make_word( (__u16) p[i] );
++			   }
++		  }
++	 }
++	 return pResult;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Exports to rest of driver
++//////////////////////////////////////////////////////////////////////////////
++
++/* called by the int handler here and the two endpoint files when interesting
++   .."events" happen */
++
++int
++usbctl_next_state_on_event( int event )
++{
++	int next_state = device_state_machine[ sm_state ][ event ];
++	if ( next_state != kError )
++	{
++		int next_device_state = sm_state_to_device_state[ next_state ];
++		if( usb_debug) printk( "%s%s --> [%s] --> %s. Device in %s state.\n",
++				pszMe, state_names[ sm_state ], event_names[ event ],
++				state_names[ next_state ], device_state_names[ next_device_state ] );
++
++		sm_state = next_state;
++		if ( usbd_info.state != next_device_state )
++		{
++			if ( configured_callback != NULL
++				 &&
++				 next_device_state == USB_STATE_CONFIGURED
++				 &&
++				 usbd_info.state != USB_STATE_SUSPENDED
++			   ) {
++			  configured_callback();
++			}
++			usbd_info.state = next_device_state;
++
++			ep_bulk_out1_state_change_notify( next_device_state );
++			ep_bulk_in1_state_change_notify( next_device_state );
++		}
++	}
++#if 1
++	else
++		printk( "%s%s --> [%s] --> ??? is an error.\n",
++				pszMe, state_names[ sm_state ], event_names[ event ] );
++#endif
++	return next_state;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++/* setup default descriptors */
++
++static void
++initialize_descriptors(void)
++{
++	desc.dev.bLength               = sizeof( device_desc_t );
++	desc.dev.bDescriptorType       = USB_DESC_DEVICE;
++	desc.dev.bcdUSB                = 0x100; /* 1.0 */
++	desc.dev.bDeviceClass          = 0xFF;	/* vendor specific */
++	desc.dev.bDeviceSubClass       = 0;
++	desc.dev.bDeviceProtocol       = 0;
++	desc.dev.bMaxPacketSize0       = 16;	/* ep0 max fifo size */
++	desc.dev.idVendor              = 0;	/* vendor ID undefined */
++	desc.dev.idProduct             = 0; /* product */
++	desc.dev.bcdDevice             = 0; /* vendor assigned device release num */
++	desc.dev.iManufacturer         = 0;	/* index of manufacturer string */
++	desc.dev.iProduct              = 0; /* index of product description string */
++	desc.dev.iSerialNumber         = 0;	/* index of string holding product s/n */
++	desc.dev.bNumConfigurations    = 1;
++
++	desc.b.cfg.bLength             = sizeof( config_desc_t );
++	desc.b.cfg.bDescriptorType     = USB_DESC_CONFIG;
++	desc.b.cfg.wTotalLength        = make_word_c( sizeof(struct cdb) );
++	desc.b.cfg.bNumInterfaces      = 1;
++	desc.b.cfg.bConfigurationValue = 1;
++	desc.b.cfg.iConfiguration      = 0;
++	desc.b.cfg.bmAttributes        = USB_CONFIG_BUSPOWERED;
++	desc.b.cfg.MaxPower            = USB_POWER( 500 );
++
++	desc.b.intf.bLength            = sizeof( intf_desc_t );
++	desc.b.intf.bDescriptorType    = USB_DESC_INTERFACE;
++	desc.b.intf.bInterfaceNumber   = 0; /* unique intf index*/
++	desc.b.intf.bAlternateSetting  = 0;
++	desc.b.intf.bNumEndpoints      = 2;
++	desc.b.intf.bInterfaceClass    = 0xFF; /* vendor specific */
++	desc.b.intf.bInterfaceSubClass = 0;
++	desc.b.intf.bInterfaceProtocol = 0;
++	desc.b.intf.iInterface         = 0;
++
++/*
++ * FIXME...
++ * The host usbnet driver expects EP1=out EP2=in. On the PXA UDC EP1=in, EP2=out
++ */
++	desc.b.ep1.bLength             = sizeof( ep_desc_t );
++	desc.b.ep1.bDescriptorType     = USB_DESC_ENDPOINT;
++	desc.b.ep1.bEndpointAddress    = USB_EP_ADDRESS( 1, USB_IN );
++	desc.b.ep1.bmAttributes        = USB_EP_BULK;
++	desc.b.ep1.wMaxPacketSize      = make_word_c( 64 );
++	desc.b.ep1.bInterval           = 0;
++
++	desc.b.ep2.bLength             = sizeof( ep_desc_t );
++	desc.b.ep2.bDescriptorType     = USB_DESC_ENDPOINT;
++	desc.b.ep2.bEndpointAddress    = USB_EP_ADDRESS( 2, USB_OUT );
++	desc.b.ep2.bmAttributes        = USB_EP_BULK;
++	desc.b.ep2.wMaxPacketSize      = make_word_c( 64 );
++	desc.b.ep2.bInterval           = 0;
++
++// FIXME: Add support for all endpoint...
++
++	/* set language */
++	/* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */
++	sd_zero.bDescriptorType = USB_DESC_STRING;
++	sd_zero.bLength         = sizeof( string_desc_t );
++	sd_zero.bString[0]      = make_word_c( 0x409 ); /* American English */
++	pxa_usb_set_string_descriptor( 0, &sd_zero );
++}
++
++/* soft_connect_hook()
++ * Some devices have platform-specific circuitry to make USB
++ * not seem to be plugged in, even when it is. This allows
++ * software to control when a device 'appears' on the USB bus
++ * (after Linux has booted and this driver has loaded, for
++ * example). If you have such a circuit, control it here.
++ */
++static void
++soft_connect_hook( int enable )
++{
++}
++
++/* disable the UDC at the source */
++static void
++udc_disable(void)
++{
++	soft_connect_hook( 0 );
++	/* clear UDC-enable */
++	udc_clear_mask_UDCCR( UDCCR_UDE); 
++
++        /* Disable clock for USB device */
++        CKEN &= ~CKEN11_USB;
++}
++
++
++/*  enable the udc at the source */
++static void
++udc_enable(void)
++{
++        /* Enable clock for USB device */
++        CKEN |= CKEN11_USB;
++
++	/* try to clear these bits before we enable the udc */
++	udc_ack_int_UDCCR( UDCCR_SUSIR);
++	udc_ack_int_UDCCR( UDCCR_RSTIR);
++	udc_ack_int_UDCCR( UDCCR_RESIR);
++
++	/* set UDC-enable */
++	udc_set_mask_UDCCR( UDCCR_UDE); 
++	if( (UDCCR & UDCCR_UDA) == 0)
++	{
++		/* There's a reset on the bus,
++		 * clear the interrupt bit and keep going
++		 */
++		udc_ack_int_UDCCR( UDCCR_RSTIR);
++	}
++	
++	/* "USB test mode" to work around errata 40-42 (stepping a0, a1) 
++	 * which could result in missing packets and interrupts. 
++	 * Supposedly this turns off double buffering for all endpoints.
++	 */
++	if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3);
++	UDC_RES1 = 0x00;
++	UDC_RES2 = 0x00;
++	if( usb_debug) printk( "USB RES1=%x RES2=%x RES3=%x\n", UDC_RES1, UDC_RES2, UDC_RES3);
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Proc Filesystem Support
++//////////////////////////////////////////////////////////////////////////////
++
++#if CONFIG_PROC_FS
++
++#define SAY( fmt, args... )  p += sprintf(p, fmt, ## args )
++#define SAYV(  num )         p += sprintf(p, num_fmt, "Value", num )
++#define SAYC( label, yn )    p += sprintf(p, yn_fmt, label, yn )
++#define SAYS( label, v )     p += sprintf(p, cnt_fmt, label, v )
++
++static int usbctl_read_proc(char *page, char **start, off_t off,
++			    int count, int *eof, void *data)
++{
++	 const char * num_fmt   = "%25.25s: %8.8lX\n";
++	 const char * cnt_fmt   = "%25.25s: %lu\n";
++	 const char * yn_fmt    = "%25.25s: %s\n";
++	 const char * yes       = "YES";
++	 const char * no        = "NO";
++	 unsigned long v;
++	 char * p = page;
++	 int len;
++
++ 	 SAY( "PXA USB Controller Core\n" );
++ 	 SAY( "Active Client: %s\n", usbd_info.client_name ? usbd_info.client_name : "none");
++	 SAY( "USB state: %s (%s) %d\n",
++		  device_state_names[ sm_state_to_device_state[ sm_state ] ],
++		  state_names[ sm_state ],
++		  sm_state );
++
++	 SAYS( "ep0 bytes read", usbd_info.stats.ep0_bytes_read );
++	 SAYS( "ep0 bytes written", usbd_info.stats.ep0_bytes_written );
++	 SAYS( "ep0 FIFO read failures", usbd_info.stats.ep0_fifo_write_failures );
++	 SAYS( "ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures );
++
++	 SAY( "\n" );
++
++	 v = UDCCR;
++	 SAY( "\nUDC Control Register\n" );
++	 SAYV( v );
++	 SAYC( "UDC Enabled",                ( v & UDCCR_UDE ) ? yes : no );
++	 SAYC( "UDC Active",                ( v & UDCCR_UDA ) ? yes : no );
++	 SAYC( "Suspend/Resume interrupts masked", ( v & UDCCR_SRM ) ? yes : no );
++	 SAYC( "Reset interrupts masked",   ( v & UDCCR_REM ) ? yes : no );
++	 SAYC( "Reset pending",      ( v & UDCCR_RSTIR ) ? yes : no );
++	 SAYC( "Suspend pending",    ( v & UDCCR_SUSIR ) ? yes : no );
++	 SAYC( "Resume pending",     ( v & UDCCR_RESIR ) ? yes : no );
++
++	 len = ( p - page ) - off;
++	 if ( len < 0 )
++		  len = 0;
++	 *eof = ( len <=count ) ? 1 : 0;
++	 *start = page + off;
++	 return len;
++}
++
++#endif  /* CONFIG_PROC_FS */
++
++#if 0
++static void irq_handler(int channel, void *data, struct pt_regs *regs)
++{
++	if( channel == usbd_info.dmach_rx)
++	{
++	    printk( "USB receive DMA\n");
++	}
++	else if( channel == usbd_info.dmach_tx)
++	{
++	    printk( "USB transmit DMA\n");
++	}
++	else
++	{
++	    printk( "USB unknown DMA channel\n");
++	}
++}
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Module Initialization and Shutdown
++//////////////////////////////////////////////////////////////////////////////
++/*
++ * usbctl_init()
++ * Module load time. Allocate dma and interrupt resources. Setup /proc fs
++ * entry. Leave UDC disabled.
++ */
++int __init usbctl_init( void )
++{
++	int retval = 0;
++
++	udc_disable();
++
++	memset( &usbd_info, 0, sizeof( usbd_info ) );
++
++#if CONFIG_PROC_FS
++	create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL);
++#endif
++
++#if 0
++	/* setup rx dma */
++	usbd_info.dmach_rx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/);
++	if (usbd_info.dmach_rx < 0) {
++		printk("%sunable to register for rx dma rc=%d\n", pszMe, usbd_info.dmach_rx );
++		goto err_rx_dma;
++	}
++
++	/* setup tx dma */
++	usbd_info.dmach_tx = pxa_request_dma("USB receive", DMA_PRIO_MEDIUM, irq_handler, 0 /*data; DMA_Ser0UDCRd*/);
++	if (usbd_info.dmach_tx < 0) {
++		printk("%sunable to register for tx dma rc=%d\n",pszMe,usbd_info.dmach_tx);
++		goto err_tx_dma;
++	}
++#endif
++
++	/* now allocate the IRQ. */
++	retval = request_irq(IRQ_USB, udc_int_hndlr, SA_INTERRUPT, "PXA USB core", NULL);
++	if (retval) {
++		printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval);
++		goto err_irq;
++	}
++
++	printk( "PXA USB Controller Core Initialized\n");
++	return 0;
++
++err_irq:
++#if 0
++	pxa_free_dma(usbd_info.dmach_tx);
++	usbd_info.dmach_tx = 0;
++err_tx_dma:
++	pxa_free_dma(usbd_info.dmach_rx);
++	usbd_info.dmach_rx = 0;
++err_rx_dma:
++#endif
++	return retval;
++}
++/*
++ * usbctl_exit()
++ * Release DMA and interrupt resources
++ */
++void __exit usbctl_exit( void )
++{
++	printk("Unloading PXA USB Controller\n");
++
++	udc_disable();
++
++#if CONFIG_PROC_FS
++	remove_proc_entry ( PROC_NODE_NAME, NULL);
++#endif
++
++	pxa_free_dma(usbd_info.dmach_rx);
++	pxa_free_dma(usbd_info.dmach_tx);
++	free_irq(IRQ_USB, NULL);
++}
++
++module_init( usbctl_init );
++module_exit( usbctl_exit );
++
++EXPORT_SYMBOL( pxa_usb_open );
++EXPORT_SYMBOL( pxa_usb_start );
++EXPORT_SYMBOL( pxa_usb_stop );
++EXPORT_SYMBOL( pxa_usb_close );
++EXPORT_SYMBOL( pxa_usb_get_descriptor_ptr );
++EXPORT_SYMBOL( pxa_usb_set_string_descriptor );
++EXPORT_SYMBOL( pxa_usb_get_string_descriptor );
++EXPORT_SYMBOL( pxa_usb_kmalloc_string_descriptor );
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb_ctl.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,89 @@
++/*
++ *  Copyright (C) Compaq Computer Corporation, 1998, 1999
++ *  Copyright (C) Extenex Corporation 2001
++ *  Copyright (C) Intrinsyc, Inc., 2002
++ *
++ *  usb_ctl.h
++ *
++ *  PRIVATE interface used to share info among components of the PXA USB
++ *  core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core
++ *  should use pxa_usb.h.
++ *
++ *  02-May-2002
++ *   Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.h
++ *
++ */
++
++#ifndef _USB_CTL_H
++#define _USB_CTL_H
++
++/* Interrupt mask bits and UDC enable bit */
++#define UDCCR_MASK_BITS         (UDCCR_REM | UDCCR_SRM | UDCCR_UDE)
++
++/*
++ * These states correspond to those in the USB specification v1.0
++ * in chapter 8, Device Framework.
++ */
++enum { 
++	USB_STATE_NOTATTACHED	=0,
++	USB_STATE_ATTACHED	=1,
++	USB_STATE_POWERED	=2,
++	USB_STATE_DEFAULT	=3,
++	USB_STATE_ADDRESS	=4,
++	USB_STATE_CONFIGURED	=5,
++	USB_STATE_SUSPENDED	=6
++};
++
++struct usb_stats_t {
++	 unsigned long ep0_fifo_write_failures;
++	 unsigned long ep0_bytes_written;
++	 unsigned long ep0_fifo_read_failures;
++	 unsigned long ep0_bytes_read;
++};
++
++struct usb_info_t
++{
++	 char * client_name;
++	 dmach_t dmach_tx, dmach_rx;
++	 int state;
++	 unsigned char address;
++	 struct usb_stats_t stats;
++};
++
++/* in usb_ctl.c */
++extern struct usb_info_t usbd_info;
++
++/*
++ * Function Prototypes
++ */
++enum { 
++	kError		=-1,
++	kEvSuspend	=0,
++	kEvReset	=1,
++	kEvResume	=2,
++	kEvAddress	=3,
++	kEvConfig	=4,
++	kEvDeConfig	=5 
++};
++int usbctl_next_state_on_event( int event );
++
++/* endpoint zero */
++void ep0_reset(void);
++void ep0_int_hndlr(void);
++
++/* receiver */
++void ep_bulk_out1_state_change_notify( int new_state );
++int  ep_bulk_out1_recv(void);
++int  ep_bulk_out1_init(int chn);
++void ep_bulk_out1_int_hndlr(int status);
++void ep_bulk_out1_reset(void);
++void ep_bulk_out1_stall(void);
++
++/* xmitter */
++void ep_bulk_in1_state_change_notify( int new_state );
++void ep_bulk_in1_reset(void);
++int  ep_bulk_in1_init(int chn);
++void ep_bulk_in1_int_hndlr(int status);
++void ep_bulk_in1_stall(void);
++
++#endif /* _USB_CTL_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb_ep0.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,556 @@
++/*
++ *  Copyright (C) Extenex Corporation 2001
++ *  Copyright (C) Compaq Computer Corporation, 1998, 1999
++ *  Copyright (C) Intrinsyc, Inc., 2002
++ *
++ *  PXA USB controller driver - Endpoint zero management
++ *
++ *  Please see:
++ *    linux/Documentation/arm/SA1100/SA1100_USB 
++ *  for more info.
++ *
++ *  02-May-2002
++ *   Frank Becker (Intrinsyc) - derived from sa1100 usb_ctl.c
++ * 
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/tqueue.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/irq.h>
++
++#include "pxa_usb.h"  /* public interface */
++#include "usb_ctl.h"  /* private stuff */
++#include "usb_ep0.h"
++
++
++// 1 == lots of trace noise,  0 = only "important' stuff
++#define VERBOSITY 0
++
++enum { true = 1, false = 0 };
++typedef int bool;
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++#if 1 && !defined( ASSERT )
++#  define ASSERT(expr) \
++if(!(expr)) { \
++	printk( "Assertion failed! %s,%s,%s,line=%d\n",\
++#expr,__FILE__,__FUNCTION__,__LINE__); \
++}
++#else
++#  define ASSERT(expr)
++#endif
++
++#if VERBOSITY
++#define PRINTKD(fmt, args...) printk( fmt , ## args)
++#else
++#define PRINTKD(fmt, args...)
++#endif
++
++static EP0_state ep0_state = EP0_IDLE;
++
++/***************************************************************************
++  Prototypes
++ ***************************************************************************/
++/* "setup handlers" -- the main functions dispatched to by the
++   .. isr. These represent the major "modes" of endpoint 0 operation */
++static void sh_setup_begin(void);				/* setup begin (idle) */
++static void sh_write( void );      				/* writing data */
++static int  read_fifo( usb_dev_request_t * p );
++static void write_fifo( void );
++static void get_descriptor( usb_dev_request_t * pReq );
++static void queue_and_start_write( void * p, int req, int act );
++
++/***************************************************************************
++  Inline Helpers
++ ***************************************************************************/
++
++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); }
++
++/* print string descriptor */
++static inline void psdesc( string_desc_t * p )
++{
++	int i;
++	int nchars = ( p->bLength - 2 ) / sizeof( __u16 );
++	printk( "'" );
++	for( i = 0 ; i < nchars ; i++ ) {
++		printk( "%c", (char) p->bString[i] );
++	}
++	printk( "'\n" );
++}
++
++#if VERBOSITY
++/* "pcs" == "print control status" */
++static inline void pcs( void )
++{
++	__u32 foo = UDCCS0;
++	printk( "%08x: %s %s %s %s %s %s\n",
++			foo,
++			foo & UDCCS0_SA   ? "SA" : "",
++			foo & UDCCS0_OPR  ? "OPR" : "",
++			foo & UDCCS0_RNE  ? "RNE" : "",
++			foo & UDCCS0_SST  ? "SST" : "",
++			foo & UDCCS0_FST  ? "FST" : "",
++			foo & UDCCS0_DRWF ? "DRWF" : ""
++	      );
++}
++static inline void preq( usb_dev_request_t * pReq )
++{
++	static char * tnames[] = { "dev", "intf", "ep", "oth" };
++	static char * rnames[] = { "std", "class", "vendor", "???" };
++	char * psz;
++	switch( pReq->bRequest ) {
++		case GET_STATUS:        psz = "get stat"; break;
++		case CLEAR_FEATURE:     psz = "clr feat"; break;
++		case SET_FEATURE:       psz = "set feat"; break;
++		case SET_ADDRESS:       psz = "set addr"; break;
++		case GET_DESCRIPTOR:    psz = "get desc"; break;
++		case SET_DESCRIPTOR:    psz = "set desc"; break;
++		case GET_CONFIGURATION: psz = "get cfg"; break;
++		case SET_CONFIGURATION: psz = "set cfg"; break;
++		case GET_INTERFACE:     psz = "get intf"; break;
++		case SET_INTERFACE:     psz = "set intf"; break;
++		case SYNCH_FRAME:       psz = "synch frame"; break;
++		default:                psz = "unknown"; break;
++	}
++	printk( "- [%s: %s req to %s. dir=%s]\n", psz,
++			rnames[ (pReq->bmRequestType >> 5) & 3 ],
++			tnames[ pReq->bmRequestType & 3 ],
++			( pReq->bmRequestType & 0x80 ) ? "in" : "out" );
++}
++
++#else
++static inline void pcs( void ){}
++static inline void preq( usb_dev_request_t *x){}
++#endif
++
++/***************************************************************************
++  Globals
++ ***************************************************************************/
++static const char pszMe[] = "usbep0: ";
++
++/* pointer to current setup handler */
++static void (*current_handler)(void) = sh_setup_begin;
++
++/* global write struct to keep write
++   ..state around across interrupts */
++static struct {
++	unsigned char *p;
++	int bytes_left;
++} wr;
++
++/***************************************************************************
++  Public Interface
++ ***************************************************************************/
++
++/* reset received from HUB (or controller just went nuts and reset by itself!)
++   so udc core has been reset, track this state here  */
++void ep0_reset(void)
++{
++	PRINTKD( "%sep0_reset\n", pszMe);
++	/* reset state machine */
++	current_handler = sh_setup_begin;
++	wr.p = NULL;
++	wr.bytes_left = 0;
++	usbd_info.address=0;
++}
++
++/* handle interrupt for endpoint zero */
++void ep0_int_hndlr( void )
++{
++	PRINTKD( "%sep0_int_hndlr\n", pszMe);
++	pcs();
++	(*current_handler)();
++}
++
++/***************************************************************************
++  Setup Handlers
++ ***************************************************************************/
++/*
++ * sh_setup_begin()
++ * This setup handler is the "idle" state of endpoint zero. It looks for OPR
++ * (OUT packet ready) to see if a setup request has been been received from the
++ * host. 
++ *
++ */
++static void sh_setup_begin( void )
++{
++	usb_dev_request_t req;
++	int request_type;
++	int n;
++	__u32 cs_reg_in = UDCCS0;
++
++	PRINTKD( "%ssh_setup_begin\n", pszMe);
++
++	/* Be sure out packet ready, otherwise something is wrong */
++	if ( (cs_reg_in & UDCCS0_OPR) == 0 ) {
++		/* we can get here early...if so, we'll int again in a moment  */
++		PRINTKD( "%ssetup begin: no OUT packet available. Exiting\n", pszMe );
++		goto sh_sb_end;
++	}
++
++	if( ((cs_reg_in & UDCCS0_SA) == 0) && (ep0_state == EP0_IN_DATA_PHASE))
++	{
++		PRINTKD( "%ssetup begin: premature status\n", pszMe );
++
++		/* premature status, reset tx fifo and go back to idle state*/
++		UDCCS0 = UDCCS0_OPR | UDCCS0_FTF;
++
++		ep0_state = EP0_IDLE;
++		return;
++	}
++
++	if( (UDCCS0 & UDCCS0_RNE) == 0)
++	{
++		/* zero-length OUT? */
++		printk( "%ssetup begin: zero-length OUT?\n", pszMe );
++		goto sh_sb_end;
++	}
++
++	/* read the setup request */
++	n = read_fifo( &req );
++	if ( n != sizeof( req ) ) {
++		printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. "
++				" Stalling out...\n",
++				pszMe, sizeof( req ), n );
++		/* force stall, serviced out */
++		UDCCS0 = UDCCS0_FST;
++		goto sh_sb_end;
++	}
++
++	/* Is it a standard request? (not vendor or class request) */
++	request_type = type_code_from_request( req.bmRequestType );
++	if ( request_type != 0 ) {
++		printk( "%ssetup begin: unsupported bmRequestType: %d ignored\n",
++				pszMe, request_type );
++		goto sh_sb_end;
++	}
++
++#if VERBOSITY
++	{
++		unsigned char * pdb = (unsigned char *) &req;
++		PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ",
++				pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7]
++		       );
++		preq( &req );
++	}
++#endif
++
++	/* Handle it */
++	switch( req.bRequest ) {
++
++		case SET_ADDRESS:
++			PRINTKD( "%sSET_ADDRESS handled by UDC\n", pszMe);
++			break;
++#if 0 /* NOT_NEEDED */
++
++		case SET_FEATURE:
++			PRINTKD( "%sSET_FEATURE handled by UDC\n", pszMe);
++			break;
++
++		case CLEAR_FEATURE:
++			PRINTKD( "%sCLEAR_FEATURE handled by UDC\n", pszMe);
++			break;
++
++		case GET_CONFIGURATION:
++			PRINTKD( "%sGET_CONFIGURATION handled by UDC\n", pszMe );
++			break;
++
++		case GET_STATUS:
++			PRINTKD( "%s%sGET_STATUS handled by UDC\n", pszMe );
++			break;
++
++		case GET_INTERFACE:
++			PRINTKD( "%sGET_INTERFACE handled by UDC\n", pszMe);
++			break;
++
++		case SYNCH_FRAME:
++			PRINTKD( "%sSYNCH_FRAME handled by UDC\n", pszMe );
++			break;
++#endif
++
++		case GET_DESCRIPTOR:
++			PRINTKD( "%sGET_DESCRIPTOR\n", pszMe );
++			get_descriptor( &req );
++			break;
++
++		case SET_INTERFACE:
++			PRINTKD( "%sSET_INTERFACE TODO...\n", pszMe);
++			break;
++
++		case SET_DESCRIPTOR:
++			PRINTKD( "%sSET_DESCRIPTOR TODO...\n", pszMe );
++			break;
++
++		case SET_CONFIGURATION:
++			PRINTKD( "%sSET_CONFIGURATION %d\n", pszMe, req.wValue);
++
++/*
++ * FIXME: Something is not quite right here... I only ever get a 
++ * de-configure from the host. Ignoring it for now, since usb
++ * ethernet won't do anything unless usb is 'configured'.
++ *
++ */
++#if 0
++			switch( req.wValue)
++			{
++				case 0:
++					/* configured */
++					usbctl_next_state_on_event( kEvConfig );
++					break;
++				case 1:
++					/* de-configured */
++					usbctl_next_state_on_event( kEvDeConfig );
++					break;
++				default:
++					PRINTKD( "%sSET_CONFIGURATION: unknown configuration value (%d)\n", pszMe, req.wValue);
++					break;
++			}
++#endif
++			break;
++		default :
++			printk("%sunknown request 0x%x\n", pszMe, req.bRequest);
++			break;
++	} /* switch( bRequest ) */
++
++sh_sb_end:
++	return;
++}
++
++/*
++ * sh_write()
++ * 
++ * Due to UDC bugs we push everything into the fifo in one go.
++ * Using interrupts just didn't work right...
++ * This should be ok, since control request are small.
++ */
++static void sh_write()
++{
++	PRINTKD( "sh_write\n" );
++	do
++	{
++	    write_fifo();
++	} while( ep0_state != EP0_END_XFER);
++}
++
++/***************************************************************************
++  Other Private Subroutines
++ ***************************************************************************/
++/*
++ * queue_and_start_write()
++ * data == data to send
++ * req == bytes host requested
++ * act == bytes we actually have
++ *
++ * Sets up the global "wr"-ite structure and load the outbound FIFO 
++ * with data.
++ *
++ */
++static void queue_and_start_write( void * data, int req, int act )
++{
++	PRINTKD( "write start: bytes requested=%d actual=%d\n", req, act);
++
++	wr.p = (unsigned char*) data;
++	wr.bytes_left = MIN( act, req );
++
++	ep0_state = EP0_IN_DATA_PHASE;
++	sh_write();
++
++	return;
++}
++/*
++ * write_fifo()
++ * Stick bytes in the endpoint zero FIFO.
++ *
++ */
++static void write_fifo( void )
++{
++	int bytes_this_time = MIN( wr.bytes_left, EP0_FIFO_SIZE );
++	int bytes_written = 0;
++
++	while( bytes_this_time-- ) {
++//		PRINTKD( "%2.2X ", *wr.p );
++		UDDR0 = *wr.p++;
++		bytes_written++;
++	}
++	wr.bytes_left -= bytes_written;
++
++	usbd_info.stats.ep0_bytes_written += bytes_written;
++
++	if( (wr.bytes_left==0))
++	{
++		wr.p = NULL;  				/* be anal */
++
++ 		if(bytes_written < EP0_FIFO_SIZE)
++		{
++			int count;
++			int udccs0;
++
++			/* We always end the transfer with a short or zero length packet */
++			ep0_state = EP0_END_XFER;
++			current_handler = sh_setup_begin;
++
++			/* Let the packet go... */
++			UDCCS0 = UDCCS0_IPR;
++
++			/* Wait until we get to status-stage, then ack.
++			 *
++			 * When the UDC sets the UDCCS0[OPR] bit, an interrupt
++			 * is supposed to be generated (see 12.5.1 step 14ff, PXA Dev Manual).   
++			 * That approach didn't work out. Usually a new SETUP command was
++			 * already in the fifo. I tried many approaches but was always losing 
++			 * at least some OPR interrupts. Thus the polling below...
++			 */
++			count = 1000;
++			udccs0 = UDCCS0;
++			do
++			{
++				if( (UDCCS0 & UDCCS0_OPR)) 
++				{
++					/* clear OPR, generate ack */
++					UDCCS0 = UDCCS0_OPR;
++					break;
++				}
++				count--;	
++				udelay(1);
++			} while( count);
++
++			PRINTKD( "write fifo: count=%d UDCCS0=%x UDCCS0=%x\n", count, udccs0, UDCCS0);
++		}
++	}
++	/* something goes poopy if I dont wait here ... */
++	udelay(500);
++
++	PRINTKD( "write fifo: bytes sent=%d, bytes left=%d\n", bytes_written, wr.bytes_left);
++}
++
++/*
++ * read_fifo()
++ * Read bytes out of FIFO and put in request.
++ * Called to do the initial read of setup requests
++ * from the host. Return number of bytes read.
++ *
++ */
++static int read_fifo( usb_dev_request_t * request )
++{
++	int bytes_read = 0;
++	unsigned char * pOut = (unsigned char*) request;
++
++	int udccs0 = UDCCS0;
++
++	if( (udccs0 & SETUP_READY) == SETUP_READY)
++	{
++		/* ok it's a setup command */
++		while( UDCCS0 & UDCCS0_RNE)
++		{
++			if( bytes_read >= sizeof( usb_dev_request_t))
++			{
++				/* We've already read enought o fill usb_dev_request_t.
++				 * Our tummy is full. Go barf... 
++				 */
++				printk( "%sread_fifo(): read failure\n", pszMe );
++				usbd_info.stats.ep0_fifo_read_failures++;
++				break;
++			}
++
++			*pOut++ = UDDR0;
++			bytes_read++;
++		}
++	}
++	PRINTKD( "read_fifo %d bytes\n", bytes_read );
++
++	/* clear SA & OPR */
++	UDCCS0 = SETUP_READY;
++
++	usbd_info.stats.ep0_bytes_read += bytes_read;
++	return bytes_read;
++}
++
++/*
++ * get_descriptor()
++ * Called from sh_setup_begin to handle data return
++ * for a GET_DESCRIPTOR setup request.
++ */
++static void get_descriptor( usb_dev_request_t * pReq )
++{
++	string_desc_t * pString;
++	ep_desc_t * pEndpoint = 0;
++
++	desc_t * pDesc = pxa_usb_get_descriptor_ptr();
++	int type = pReq->wValue >> 8;
++	int idx  = pReq->wValue & 0xFF;
++
++//	PRINTKD( "%sget_descriptor for %d\n", pszMe, type );
++	switch( type ) {
++		case USB_DESC_DEVICE:
++			queue_and_start_write( &pDesc->dev,
++					pReq->wLength,
++					pDesc->dev.bLength );
++			break;
++
++			// return config descriptor buffer, cfg, intf, 2 ep
++		case USB_DESC_CONFIG:
++			queue_and_start_write( &pDesc->b,
++					pReq->wLength,
++					sizeof( struct cdb ) );
++			break;
++
++			// not quite right, since doesn't do language code checking
++		case USB_DESC_STRING:
++			pString = pxa_usb_get_string_descriptor( idx );
++			if ( pString ) {
++				if ( idx != 0 ) {  // if not language index
++					printk( "%sReturn string %d: ", pszMe, idx );
++					psdesc( pString );
++				}
++				queue_and_start_write( pString,
++						pReq->wLength,
++						pString->bLength );
++			}
++			else {
++				printk("%sunkown string index %d Stall.\n", pszMe, idx );
++			}
++			break;
++
++		case USB_DESC_INTERFACE:
++			if ( idx == pDesc->b.intf.bInterfaceNumber ) {
++				queue_and_start_write( &pDesc->b.intf,
++						pReq->wLength,
++						pDesc->b.intf.bLength );
++			}
++			break;
++
++		case USB_DESC_ENDPOINT: /* correct? 21Feb01ww */
++			if ( idx == 1 )
++				pEndpoint = &pDesc->b.ep1; //[BULK_IN1];
++			else if ( idx == 2 )
++				pEndpoint = &pDesc->b.ep2; //[BULK_OUT1];
++			else
++				pEndpoint = NULL;
++			if ( pEndpoint ) {
++				queue_and_start_write( pEndpoint,
++						pReq->wLength,
++						pEndpoint->bLength );
++			} else {
++				printk("%sunkown endpoint index %d Stall.\n", pszMe, idx );
++			}
++			break;
++
++
++		default :
++			printk("%sunknown descriptor type %d. Stall.\n", pszMe, type );
++			break;
++
++	}
++}
++
++/* end usb_ep0.c - who needs this comment? */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb_ep0.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,66 @@
++/*
++ *  Copyright (C) Intrinsyc, Inc., 2002
++ *
++ *  usb_ep0.h - PXA USB controller driver.
++ *              Endpoint zero management
++ *
++ *  Please see:
++ *    linux/Documentation/arm/SA1100/SA1100_USB
++ *  for details.
++ *
++ *  02-May-2002
++ *   Frank Becker (Intrinsyc) - 
++ * 
++ */
++
++#ifndef __USB_EP0_H
++#define __USB_EP0_H
++
++#define EP0_FIFO_SIZE	16
++#define SETUP_READY (UDCCS0_SA | UDCCS0_OPR)
++
++/*================================================
++ * USB Protocol Stuff
++ */
++
++/* Request Codes   */
++enum { 
++	GET_STATUS		=0,
++	CLEAR_FEATURE		=1,
++	/* reserved		=2 */
++	SET_FEATURE		=3,
++	/* reserved		=4 */
++	SET_ADDRESS		=5,        
++	GET_DESCRIPTOR		=6,
++	SET_DESCRIPTOR		=7,
++	GET_CONFIGURATION	=8,
++	SET_CONFIGURATION	=9,
++	GET_INTERFACE		=10,
++	SET_INTERFACE		=11,
++	SYNCH_FRAME		=12
++};
++
++typedef enum {
++	EP0_IDLE,
++	EP0_IN_DATA_PHASE,
++	EP0_END_XFER,
++	EP0_OUT_DATA_PHASE
++} EP0_state;
++
++/* USB Device Requests */
++typedef struct
++{
++	__u8 bmRequestType;
++	__u8 bRequest;
++	__u16 wValue;
++	__u16 wIndex;
++	__u16 wLength;
++} usb_dev_request_t  __attribute__ ((packed));
++
++/* Data extraction from usb_request_t fields */
++enum { 
++	kTargetDevice	=0,
++	kTargetInterface=1,
++	kTargetEndpoint	=2 
++};
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb_recv.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,173 @@
++/*
++ * Generic receive layer for the PXA USB client function
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * 02-May-2002
++ *   Frank Becker (Intrinsyc) - derived from sa1100 usb_recv.c
++ * 
++ * TODO: Add support for DMA.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++
++#include "pxa_usb.h"
++#include "usb_ctl.h"
++
++#if DEBUG
++static unsigned int usb_debug = DEBUG;
++#else
++#define usb_debug 0     /* gcc will remove all the debug code for us */
++#endif
++
++static char *ep_bulk_out1_buf;
++static int   ep_bulk_out1_len;
++static int   ep_bulk_out1_remain;
++static usb_callback_t ep_bulk_out1_callback;
++static int rx_pktsize;
++
++static void
++ep_bulk_out1_start(void)
++{
++	/* disable DMA */
++	UDCCS2 &= ~UDCCS_BO_DME;
++
++	/* enable interrupts for endpoint 2 (bulk out) */
++        UICR0 &= ~UICR0_IM2;
++}
++
++static void
++ep_bulk_out1_done(int flag)
++{
++	int size = ep_bulk_out1_len - ep_bulk_out1_remain;
++
++	if (!ep_bulk_out1_len)
++		return;
++
++	ep_bulk_out1_len = 0;
++	if (ep_bulk_out1_callback) {
++		ep_bulk_out1_callback(flag, size);
++	}
++}
++
++void
++ep_bulk_out1_state_change_notify( int new_state )
++{
++}
++
++void
++ep_bulk_out1_stall( void )
++{
++	/* SET_FEATURE force stall at UDC */
++	UDCCS2 |= UDCCS_BO_FST;
++}
++
++int
++ep_bulk_out1_init(int chn)
++{
++	desc_t * pd = pxa_usb_get_descriptor_ptr();
++	rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize );
++	ep_bulk_out1_done(-EAGAIN);
++	return 0;
++}
++
++void
++ep_bulk_out1_reset(void)
++{
++	desc_t * pd = pxa_usb_get_descriptor_ptr();
++	rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize );
++	UDCCS2 &= ~UDCCS_BO_FST;
++	ep_bulk_out1_done(-EINTR);
++}
++
++void
++ep_bulk_out1_int_hndlr(int udcsr)
++{
++	int status = UDCCS2;
++	if( usb_debug) printk("ep_bulk_out1_int_hndlr: UDCCS2=%x\n", status);
++
++	if( (status & (UDCCS_BO_RNE | UDCCS_BO_RSP)) == UDCCS_BO_RSP)
++	{
++		/* zero-length packet */
++	}
++
++	if( status & UDCCS_BO_RNE)
++	{
++		int len;
++		int i;
++		char *buf = ep_bulk_out1_buf + ep_bulk_out1_len - ep_bulk_out1_remain;
++
++		/* bytes in FIFO */
++		len = (UBCR2 & 0xff) +1;
++		
++		if( usb_debug) printk("usb_recv: "
++			"len=%d out1_len=%d out1_remain=%d\n",
++			len,ep_bulk_out1_len,ep_bulk_out1_remain);
++
++		if( len > ep_bulk_out1_remain)
++		{
++			/* FIXME: if this happens, we need a temporary overflow buffer */
++			printk("usb_recv: Buffer overwrite warning...\n");
++			len = ep_bulk_out1_remain;
++		}
++
++		/* read data out of fifo */
++		for( i=0; i<len; i++)
++		{
++			*buf++ = UDDR2 & 0xff;
++		}
++
++		ep_bulk_out1_remain -= len;
++		ep_bulk_out1_done((len) ? 0 : -EPIPE);
++	}
++
++	/* ack RPC - FIXME: '|=' we may ack SST here, too */
++	UDCCS2 |= UDCCS_BO_RPC;
++	return;
++}
++
++int
++pxa_usb_recv(char *buf, int len, usb_callback_t callback)
++{
++	int flags;
++
++	if (ep_bulk_out1_len)
++		return -EBUSY;
++
++	local_irq_save(flags);
++	ep_bulk_out1_buf = buf;
++	ep_bulk_out1_len = len;
++	ep_bulk_out1_callback = callback;
++	ep_bulk_out1_remain = len;
++	ep_bulk_out1_start();
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++void
++pxa_usb_recv_reset(void)
++{
++	ep_bulk_out1_reset();
++}
++
++void
++pxa_usb_recv_stall(void)
++{
++	ep_bulk_out1_stall();
++}
++
++EXPORT_SYMBOL(pxa_usb_recv_stall);
++EXPORT_SYMBOL(pxa_usb_recv);
++EXPORT_SYMBOL(pxa_usb_recv_reset);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-pxa/usb_send.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,190 @@
++/*
++ * Generic xmit layer for the PXA USB client function
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * 02-May-2002
++ *   Frank Becker (Intrinsyc) - derived from sa1100 usb_send.c
++ *
++ * TODO: Add support for DMA.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++#include <asm/byteorder.h>
++
++#include "pxa_usb.h"
++#include "usb_ctl.h"
++
++#if DEBUG
++static unsigned int usb_debug = DEBUG;
++#else
++#define usb_debug 0     /* gcc will remove all the debug code for us */
++#endif
++
++static char *ep_bulk_in1_buf;
++static int   ep_bulk_in1_len;
++static int   ep_bulk_in1_remain;
++static usb_callback_t ep_bulk_in1_callback;
++static int tx_pktsize;
++
++/* device state is changing, async */
++void
++ep_bulk_in1_state_change_notify( int new_state )
++{
++}
++
++/* set feature stall executing, async */
++void
++ep_bulk_in1_stall( void )
++{
++	UDCCS1 |= UDCCS_BI_FST;
++}
++
++static void
++ep_bulk_in1_send_packet(void)
++{
++	int i;
++	char *buf = ep_bulk_in1_buf + ep_bulk_in1_len - ep_bulk_in1_remain;
++	int out_size = tx_pktsize;
++
++	if( usb_debug) printk( "ep_bulk_in1_send_packet: UICR0=%x UDCCS1=%x\n", UICR0, UDCCS1);
++
++	if( out_size > ep_bulk_in1_remain) 
++	{
++		out_size = ep_bulk_in1_remain;
++	}
++
++	for( i=0; i<out_size; i++)
++	{
++		UDDR1 = *buf++;	
++	}
++
++	UDCCS1 = UDCCS_BI_TPC;
++	if( out_size < tx_pktsize)
++	{
++		/* short packet */
++		UDCCS1 = UDCCS_BI_TSP;
++	}
++	ep_bulk_in1_remain -= out_size;
++
++	if( usb_debug) printk( "ep_bulk_in1_send_packet: "
++		"UICR0=%x UDCCS1=%x send bytes=%d left=%d\n", 
++		UICR0, UDCCS1, out_size, ep_bulk_in1_remain);
++}
++
++static void
++ep_bulk_in1_start(void)
++{
++	if (!ep_bulk_in1_len)
++		return;
++
++        UICR0 &= ~UICR0_IM1;
++
++	ep_bulk_in1_send_packet();
++}
++
++static void
++ep_bulk_in1_done(int flag)
++{
++	int size = ep_bulk_in1_len - ep_bulk_in1_remain;
++	if (ep_bulk_in1_len) {
++		ep_bulk_in1_len = 0;
++		if (ep_bulk_in1_callback)
++			ep_bulk_in1_callback(flag, size);
++	}
++}
++
++int
++ep_bulk_in1_init(int chn)
++{
++	desc_t * pd = pxa_usb_get_descriptor_ptr();
++	tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize );
++	ep_bulk_in1_done(-EAGAIN);
++	return 0;
++}
++
++void
++ep_bulk_in1_reset(void)
++{
++	desc_t * pd = pxa_usb_get_descriptor_ptr();
++	tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize );
++	UDCCS1 &= ~UDCCS_BI_FST;
++	ep_bulk_in1_done(-EINTR);
++}
++
++void
++ep_bulk_in1_int_hndlr(int usir0)
++{
++	int status = UDCCS1;
++
++	if (ep_bulk_in1_remain != 0) {
++		/* more data to go */
++		ep_bulk_in1_start();
++	} else {
++		if( status & UDCCS_BI_TPC)
++		{
++			UDCCS1 = UDCCS_BI_TPC;
++		}
++		ep_bulk_in1_done(0);
++	}
++}
++
++int
++pxa_usb_send(char *buf, int len, usb_callback_t callback)
++{
++	int flags;
++
++	if( usb_debug) printk( "pxa_usb_send: "
++		"data len=%d state=%d blen=%d\n", 
++		len, usbd_info.state, ep_bulk_in1_len);
++
++	if (usbd_info.state != USB_STATE_CONFIGURED)
++		return -ENODEV;
++
++	if (ep_bulk_in1_len)
++		return -EBUSY;
++
++	local_irq_save(flags);
++	ep_bulk_in1_buf = buf;
++	ep_bulk_in1_len = len;
++	ep_bulk_in1_callback = callback;
++	ep_bulk_in1_remain = len;
++	ep_bulk_in1_start();
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++
++void
++pxa_usb_send_reset(void)
++{
++	ep_bulk_in1_reset();
++}
++
++int 
++pxa_usb_xmitter_avail( void )
++{
++	if (usbd_info.state != USB_STATE_CONFIGURED)
++		return -ENODEV;
++	if (ep_bulk_in1_len)
++		return -EBUSY;
++	return 0;
++}
++
++
++EXPORT_SYMBOL(pxa_usb_xmitter_avail);
++EXPORT_SYMBOL(pxa_usb_send);
++EXPORT_SYMBOL(pxa_usb_send_reset);
+--- linux-2.4.25/arch/arm/mach-sa1100/sa1111-ohci.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/sa1111-ohci.c	2004-03-31 17:15:11.000000000 +0200
+@@ -54,7 +54,7 @@
+ 	 *  address as its return value, and the DMA address via
+ 	 *  the dma_addr_t pointer.
+ 	 */
+-	vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf);
++	vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf, 0);
+ 
+ 	SADTSA = (unsigned long)dma_buf;
+ 	SADTCA = 4;
+--- linux-2.4.25/arch/arm/mach-sa1100/sa1111.c~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/sa1111.c	2004-03-31 17:15:11.000000000 +0200
+@@ -243,9 +243,15 @@
+ 	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
+ 	 * (SA-1110 Developer's Manual, section 9.1.2.1)
+ 	 */
++#if CONFIG_ARCH_SA1100
+ 	GAFR |= GPIO_32_768kHz;
+ 	GPDR |= GPIO_32_768kHz;
+ 	TUCR = TUCR_3_6864MHz;
++#elif CONFIG_ARCH_PXA
++	set_GPIO_mode(GPIO11_3_6MHz_MD);
++#else
++#error missing clock setup
++#endif
+ 
+ 	/*
+ 	 * Turn VCO on, and disable PLL Bypass.
+@@ -300,6 +306,8 @@
+ 	SBI_SMCR = smcr;
+ }
+ 
++#ifdef CONFIG_ARCH_SA1100
++
+ /*
+  * Disable the memory bus request/grant signals on the SA1110 to
+  * ensure that we don't receive spurious memory requests.  We set
+@@ -341,5 +349,7 @@
+ 	local_irq_restore(flags);
+ }
+ 
++#endif
++
+ EXPORT_SYMBOL(sa1111_wake);
+ EXPORT_SYMBOL(sa1111_doze);
+--- linux-2.4.25/arch/arm/mm/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -44,6 +44,7 @@
+ p-$(CONFIG_CPU_ARM1026)	+= proc-arm1026.o
+ p-$(CONFIG_CPU_SA110)	+= proc-sa110.o
+ p-$(CONFIG_CPU_SA1100)	+= proc-sa110.o
++p-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o
+ 
+ # Integrator follows "new style"
+ # Soon, others will do too, and we can get rid of this
+--- linux-2.4.25/arch/arm/mm/consistent.c~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/consistent.c	2004-03-31 17:15:11.000000000 +0200
+@@ -37,7 +37,8 @@
+  *
+  * Note that this does *not* zero the allocated area!
+  */
+-void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle)
++void *consistent_alloc(int gfp, size_t size, dma_addr_t *dma_handle,
++		       unsigned long cache_flags)
+ {
+ 	struct page *page, *end, *free;
+ 	unsigned long order;
+@@ -55,7 +56,7 @@
+ 		goto no_page;
+ 
+ 	*dma_handle = page_to_bus(page);
+-	ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, 0);
++	ret = __ioremap(page_to_pfn(page) << PAGE_SHIFT, size, cache_flags);
+ 	if (!ret)
+ 		goto no_remap;
+ 
+@@ -106,7 +107,7 @@
+ #endif
+ 		gfp |= GFP_DMA;
+ 
+-	return consistent_alloc(gfp, size, handle);
++	return consistent_alloc(gfp, size, handle, 0);
+ }
+ 
+ /*
+--- linux-2.4.25/arch/arm/mm/init.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/init.c	2004-03-31 17:15:11.000000000 +0200
+@@ -49,6 +49,9 @@
+ static unsigned long totalram_pages;
+ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+ extern char _stext, _text, _etext, _end, __init_begin, __init_end;
++#ifdef CONFIG_XIP_KERNEL
++extern char _endtext, _sdata;
++#endif
+ extern unsigned long phys_initrd_start;
+ extern unsigned long phys_initrd_size;
+ 
+@@ -347,7 +350,11 @@
+ 	 * Register the kernel text and data with bootmem.
+ 	 * Note that this can only be in node 0.
+ 	 */
++#ifdef CONFIG_XIP_KERNEL
++	reserve_bootmem_node(pgdat, __pa(&_sdata), &_end - &_sdata);
++#else
+ 	reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
++#endif
+ 
+ #ifdef CONFIG_CPU_32
+ 	/*
+@@ -601,8 +608,13 @@
+ 	unsigned int codepages, datapages, initpages;
+ 	int i, node;
+ 
++#ifndef CONFIG_XIP_KERNEL
+ 	codepages = &_etext - &_text;
+ 	datapages = &_end - &_etext;
++#else
++	codepages = &_endtext - &_text;
++	datapages = &_end - &_sdata;
++#endif
+ 	initpages = &__init_end - &__init_begin;
+ 
+ 	high_memory = (void *)__va(meminfo.end);
+@@ -658,11 +670,13 @@
+ 
+ void free_initmem(void)
+ {
++#ifndef CONFIG_XIP_KERNEL
+ 	if (!machine_is_integrator()) {
+ 		free_area((unsigned long)(&__init_begin),
+ 			  (unsigned long)(&__init_end),
+ 			  "init");
+ 	}
++#endif
+ }
+ 
+ #ifdef CONFIG_BLK_DEV_INITRD
+--- linux-2.4.25/arch/arm/mm/mm-armv.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/mm-armv.c	2004-03-31 17:15:11.000000000 +0200
+@@ -356,6 +356,19 @@
+ 	p ++;
+ #endif
+ 
++#ifdef CONFIG_XIP_KERNEL
++	p->physical   = KERNEL_XIP_BASE_PHYS;
++	p->virtual    = KERNEL_XIP_BASE_VIRT;
++	p->length     = PGDIR_SIZE * 8;
++	p->domain     = DOMAIN_KERNEL;
++	p->prot_read  = 0;	/* r=0, b=0 --> read-only for kernel mode */
++	p->prot_write = 0;
++	p->cacheable  = 1;
++	p->bufferable = 1;
++
++	p ++;
++#endif
++
+ 	/*
+ 	 * Go through the initial mappings, but clear out any
+ 	 * pgdir entries that are not in the description.
+@@ -386,7 +399,7 @@
+ 	init_maps->prot_read  = 0;
+ 	init_maps->prot_write = 0;
+ 	init_maps->cacheable  = 1;
+-	init_maps->bufferable = 0;
++	init_maps->bufferable = 1;
+ 
+ 	create_mapping(init_maps);
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-xscale.S	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,1086 @@
++/*
++ *  linux/arch/arm/mm/proc-xscale.S
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	November 2000
++ *  Copyright:	(C) 2000, 2001 MontaVista Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * MMU functions for the Intel XScale CPUs
++ *
++ * 2001 Aug 21:	
++ *	some contributions by Brett Gaines <brett.w.gaines@intel.com>
++ *	Copyright 2001 by Intel Corp.
++ *
++ * 2001 Sep 08:
++ *	Completely revisited, many important fixes
++ *	Nicolas Pitre <nico@cam.org>
++ */
++
++#include <linux/config.h>
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++#include <asm/constants.h>
++#include <asm/procinfo.h>
++#include <asm/hardware.h>
++#include <asm/proc/pgtable.h>
++
++/*
++ * Some knobs for cache allocation policy.
++ * Allocate on write may or may not be beneficial depending on the memory
++ * usage pattern of your main application.  Write through cache is definitely
++ * a performance loss in most cases, but might be used for special purposes.
++ */
++#define PMD_CACHE_WRITE_ALLOCATE 1
++#define PTE_CACHE_WRITE_ALLOCATE 1
++#define CACHE_WRITE_THROUGH 0
++
++/*
++ * There are errata that say that dirty status bits in the cache may get
++ * corrupted. The workaround significantly affects performance, and the bug
++ * _might_ just not be that visible or critical to you, so it is configurable.
++ * Let's hope a future core revision will tell us this was only a bad dream.
++ * But in the mean time the risk and tradeoff is yours to decide....
++ */
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++#undef CACHE_WRITE_THROUGH
++#define CACHE_WRITE_THROUGH 1
++#endif
++
++/* 
++ * This is the maximum size of an area which will be flushed.  If the area
++ * is larger than this, then we flush the whole cache
++ */
++#define MAX_AREA_SIZE	32768
++
++/*
++ * the cache line size of the I and D cache
++ */
++#define CACHELINESIZE	32
++
++/*
++ * the size of the data cache
++ */
++#define CACHESIZE	32768
++
++/*
++ * and the page size
++ */
++#define PAGESIZE	4096
++
++/*
++ * Virtual address used to allocate the cache when flushed
++ *
++ * This must be an address range which is _never_ used.  It should 
++ * apparently have a mapping in the corresponding page table for 
++ * compatibility with future CPUs that _could_ require it.  For instance we
++ * don't care.
++ *
++ * This must be aligned on a 2*CACHESIZE boundary.  The code selects one of
++ * the 2 areas in alternance each time the clean_d_cache macro is used.
++ * Without this the XScale core exhibits cache eviction problems and no one
++ * knows why.  
++ *
++ * Reminder: the vector table is located at 0xffff0000-0xffff0fff.
++ */
++#define CLEAN_ADDR	0xfffe0000
++
++/*
++ * This macro is used to wait for a CP15 write and is needed
++ * when we have to ensure that the last operation to the co-pro
++ * was completed before continuing with operation.
++ */
++	.macro	cpwait, rd
++	mrc	p15, 0, \rd, c2, c0, 0		@ arbitrary read of cp15
++	mov	\rd, \rd			@ wait for completion
++	sub 	pc, pc, #4			@ flush instruction pipeline
++	.endm	
++
++	.macro	cpwait_ret, lr, rd
++	mrc	p15, 0, \rd, c2, c0, 0		@ arbitrary read of cp15
++	sub	pc, \lr, \rd, LSR #32		@ wait for completion and
++						@ flush instruction pipeline
++	.endm
++
++#if !CACHE_WRITE_THROUGH
++
++/*
++ * This macro cleans the entire dcache using line allocate.
++ * The main loop has been unrolled to reduce loop overhead.
++ * rd and rs are two scratch registers.
++ */
++	.macro  clean_d_cache, rd, rs
++	ldr	\rs, =clean_addr
++	ldr	\rd, [\rs]
++	eor	\rd, \rd, #CACHESIZE
++	str	\rd, [\rs]
++	add	\rs, \rd, #CACHESIZE
++1:	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
++	add	\rd, \rd, #CACHELINESIZE
++	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
++	add	\rd, \rd, #CACHELINESIZE
++	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
++	add	\rd, \rd, #CACHELINESIZE
++	mcr	p15, 0, \rd, c7, c2, 5		@ allocate D cache line
++	add	\rd, \rd, #CACHELINESIZE
++	teq	\rd, \rs
++	bne	1b
++	.endm
++
++	.macro	clean_d_line,	rd
++	mcr	p15, 0, \rd, c7, c10, 1
++	.endm
++
++	.data
++clean_addr:	.word	CLEAN_ADDR
++
++#else
++
++/*
++ * If cache is write-through, there is no need to clean it.
++ * Simply invalidating will do.
++ */
++
++	.macro  clean_d_cache, rd, rs
++	mcr	p15, 0, \rd, c7, c6, 0
++	.endm
++
++	/* let's try to skip this needless operations at least within loops */
++	.macro	clean_d_line,	rd
++	.endm
++
++#endif
++
++	.text
++
++/*
++ * cpu_xscale_data_abort()
++ *
++ * obtain information about current aborted instruction.
++ * Note: we read user space.  This means we might cause a data
++ * abort here if the I-TLB and D-TLB aren't seeing the same
++ * picture.  Unfortunately, this does happen.  We live with it.
++ *
++ *  r2 = address of aborted instruction
++ *  r3 = saved SPSR
++ *
++ * Returns:
++ *  r0 = address of abort
++ *  r1 = FSR, bit 11 = write
++ *  r3 = corrupted
++ */
++	.align	5
++ENTRY(cpu_xscale_data_abort)
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
++	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
++	ldr	r3, [r2]			@ read aborted instruction
++	bic	r1, r1, #1 << 11		@ clear bits 11 of FSR
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
++	mov	pc, lr
++
++/*
++ * cpu_xscale_check_bugs()
++ */
++ENTRY(cpu_xscale_check_bugs)
++	mrs	ip, cpsr
++	bic	ip, ip, #F_BIT
++	msr	cpsr, ip
++	mov	pc, lr
++
++#ifndef CONFIG_XSCALE_CACHE_ERRATA
++/*
++ * cpu_xscale_proc_init()
++ *
++ * Nothing too exciting at the moment
++ */
++ENTRY(cpu_xscale_proc_init)
++	mov	pc, lr
++#else
++/*
++ * We enable the cache here, but we make sure all the status bits for dirty
++ * lines are cleared as well (see PXA250 erratum #120).
++ */
++ENTRY(cpu_xscale_proc_init)
++	@ enable data cache
++	ldr	r0, cr_p
++	ldmia	r0, {r1, r2}
++	orr	r1, r1, #0x4
++	orr	r2, r2, #0x4
++	stmia	r0, {r1, r2}
++	mcr	p15, 0, r1, c1, c0, 0
++	cpwait	r0
++
++	@ invalidate data cache
++	mcr	p15, 0, r0, c7, c6, 0
++
++	@ fill main cache with write-through lines
++	bic	r0, pc, #0x1f
++	add	r1, r0, #CACHESIZE
++1:	ldr	r2, [r0], #32
++	cmp	r0, r1
++	bne	1b
++
++	@ enable test feature to force all fills to the mini-cache
++	mov	r1, #0x8
++	mcr	p15, 0, r1, c15, c15, 3
++
++	@ fill mini-cache with write-through lines (2kbytes, 64 lines)
++	add	r1, r0, #2048
++2:	ldr	r2, [r0], #32
++	cmp	r0, r1
++	bne	2b
++
++	@ disable test feature to force all fills to the mini-cache
++	mov	r1, #0x0
++	mcr	p15, 0, r1, c15, c15, 3
++
++	@ invalidate data cache again
++	mcr	p15, 0, r1, c7, c6, 0
++	mov	pc, lr
++
++cr_p:	.long	SYMBOL_NAME(cr_alignment)
++#endif
++
++/*
++ * cpu_xscale_proc_fin()
++ */
++ENTRY(cpu_xscale_proc_fin)
++	str	lr, [sp, #-4]!
++	mov	r0, #F_BIT|I_BIT|SVC_MODE
++	msr	cpsr_c, r0
++	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
++	bic	r0, r0, #0x1800			@ ...IZ...........
++	bic	r0, r0, #0x0006			@ .............CA.
++	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
++	bl	cpu_xscale_cache_clean_invalidate_all	@ clean caches
++	ldr	pc, [sp], #4
++
++/*
++ * cpu_xscale_reset(loc)
++ *
++ * Perform a soft reset of the system.  Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++	.align	5
++ENTRY(cpu_xscale_reset)
++	mov	r1, #F_BIT|I_BIT|SVC_MODE
++	msr	cpsr_c, r1			@ reset CPSR
++	mrc	p15, 0, r1, c1, c0, 0		@ ctrl register
++	bic	r1, r1, #0x0086			@ ........B....CA.
++	bic	r1, r1, #0x1900			@ ...IZ..S........
++	mcr	p15, 0, r1, c1, c0, 0		@ ctrl register
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches & BTB
++	bic	r1, r1, #0x0001			@ ...............M
++	mcr	p15, 0, r1, c1, c0, 0		@ ctrl register
++	@ CAUTION: MMU turned off from this point. We count on the pipeline 
++	@ already containing those two last instructions to survive.
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++	mov	pc, r0
++
++/*
++ * cpu_xscale_do_idle(type)
++ *
++ * Cause the processor to idle
++ *
++ * type: 
++ *   0 = slow idle
++ *   1 = fast idle
++ *   2 = switch to slow processor clock
++ *   3 = switch to fast processor clock
++ *
++ * For now we do nothing but go to idle mode for every case
++ *
++ * XScale supports clock switching, but using idle mode support
++ * allows external hardware to react to system state changes.
++ */
++	.align	5
++
++ENTRY(cpu_xscale_do_idle)
++	mov	r0, #1
++	mcr	p14, 0, r0, c7, c0, 0		@ Go to IDLE
++	mov	pc, lr
++
++/* ================================= CACHE ================================ */
++
++/*
++ * cpu_xscale_cache_clean_invalidate_all (void)
++ *
++ * clean and invalidate all cache lines
++ *
++ * Note:
++ *  1. We should preserve r0 at all times.
++ *  2. Even if this function implies cache "invalidation" by its name,
++ *     we don't need to actually use explicit invalidation operations
++ *     since the goal is to discard all valid references from the cache
++ *     and the cleaning of it already has that effect.
++ *  3. Because of 2 above and the fact that kernel space memory is always
++ *     coherent across task switches there is no need to worry about
++ *     inconsistencies due to interrupts, ence no irq disabling.
++ */
++	.align	5
++ENTRY(cpu_xscale_cache_clean_invalidate_all)
++	mov	r2, #1
++cpu_xscale_cache_clean_invalidate_all_r2:
++	clean_d_cache r0, r1
++	teq	r2, #0
++	mcrne	p15, 0, ip, c7, c5, 0		@ Invalidate I cache & BTB
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++/*
++ * cpu_xscale_cache_clean_invalidate_range(start, end, flags)
++ *
++ * clean and invalidate all cache lines associated with this area of memory
++ *
++ * start: Area start address
++ * end:   Area end address
++ * flags: nonzero for I cache as well
++ */
++	.align	5
++ENTRY(cpu_xscale_cache_clean_invalidate_range)
++	bic	r0, r0, #CACHELINESIZE - 1	@ round down to cache line
++	sub	r3, r1, r0
++	cmp	r3, #MAX_AREA_SIZE
++	bhi	cpu_xscale_cache_clean_invalidate_all_r2
++1:	clean_d_line r0				@ Clean D cache line
++	mcr	p15, 0, r0, c7, c6, 1		@ Invalidate D cache line
++	add	r0, r0, #CACHELINESIZE
++	cmp	r0, r1
++	blo	1b
++	teq	r2, #0
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	moveq	pc, lr
++	sub	r0, r0, r3
++1:	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I cache line
++	add	r0, r0, #CACHELINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, ip, c7, c5, 6		@ Invalidate BTB
++	mov	pc, lr 
++
++/*
++ * cpu_xscale_flush_ram_page(page)
++ *
++ * clean all cache lines associated with this memory page
++ *
++ * page: page to clean
++ */
++	.align	5
++ENTRY(cpu_xscale_flush_ram_page)
++#if !CACHE_WRITE_THROUGH
++	mov	r1, #PAGESIZE
++1:	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	subs	r1, r1, #2 * CACHELINESIZE
++	bne	1b
++#endif
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++/* ================================ D-CACHE =============================== */
++
++/*
++ * cpu_xscale_dcache_invalidate_range(start, end)
++ *
++ * throw away all D-cached data in specified region without an obligation
++ * to write them back.  Note however that on XScale we must clean all
++ * entries also due to hardware errata (80200 A0 & A1 only).
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ */
++	.align	5
++ENTRY(cpu_xscale_dcache_invalidate_range)
++	mrc	p15, 0, r2, c0, c0, 0		@ Read part no.
++	eor	r2, r2, #0x69000000
++	eor	r2, r2, #0x00052000		@ 80200 XX part no.
++	bics	r2, r2, #0x1			@ Clear LSB in revision field
++	moveq	r2, #0
++	beq	cpu_xscale_cache_clean_invalidate_range	@ An 80200 A0 or A1
++
++	tst	r0, #CACHELINESIZE - 1
++	mcrne	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	tst	r1, #CACHELINESIZE - 1
++	mcrne	p15, 0, r1, c7, c10, 1		@ Clean D cache line
++	bic	r0, r0, #CACHELINESIZE - 1	@ round down to cache line
++1:	mcr	p15, 0, r0, c7, c6, 1		@ Invalidate D cache line
++	add	r0, r0, #CACHELINESIZE
++	cmp	r0, r1
++	blo	1b
++	mov	pc, lr
++
++/*
++ * cpu_xscale_dcache_clean_range(start, end)
++ *
++ * For the specified virtual address range, ensure that all caches contain
++ * clean data, such that peripheral accesses to the physical RAM fetch
++ * correct data.
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ */
++	.align	5
++ENTRY(cpu_xscale_dcache_clean_range)
++#if !CACHE_WRITE_THROUGH
++	bic	r0, r0, #CACHELINESIZE - 1
++	sub	r2, r1, r0
++	cmp	r2, #MAX_AREA_SIZE
++	movhi	r2, #0
++	bhi	cpu_xscale_cache_clean_invalidate_all_r2
++
++1:	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	cmp	r0, r1
++	blo	1b
++#endif
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++/*
++ * cpu_xscale_clean_dcache_page(page)
++ *
++ * Cleans a single page of dcache so that if we have any future aliased
++ * mappings, they will be consistent at the time that they are created.
++ *
++ * Note:
++ *  1. we don't need to flush the write buffer in this case. [really? -Nico]
++ *  2. we don't invalidate the entries since when we write the page
++ *     out to disk, the entries may get reloaded into the cache.
++ */
++	.align	5
++ENTRY(cpu_xscale_dcache_clean_page)
++#if !CACHE_WRITE_THROUGH
++	mov	r1, #PAGESIZE
++1:	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	add	r0, r0, #CACHELINESIZE
++	subs	r1, r1, #4 * CACHELINESIZE
++	bne	1b
++#endif
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++/*
++ * cpu_xscale_dcache_clean_entry(addr)
++ *
++ * Clean the specified entry of any caches such that the MMU
++ * translation fetches will obtain correct data.
++ *
++ * addr: cache-unaligned virtual address
++ */
++	.align	5
++ENTRY(cpu_xscale_dcache_clean_entry)
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++/* ================================ I-CACHE =============================== */
++
++/*
++ * cpu_xscale_icache_invalidate_range(start, end)
++ *
++ * invalidate a range of virtual addresses from the Icache
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ *
++ * Note: This is vaguely defined as supposed to bring the dcache and the 
++ *       icache in sync by the way this function is used.
++ */
++	.align	5
++ENTRY(cpu_xscale_icache_invalidate_range)
++	bic	r0, r0, #CACHELINESIZE - 1
++1:	clean_d_line r0				@ Clean D cache line
++	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I cache line
++	add	r0, r0, #CACHELINESIZE
++	cmp	r0, r1
++	blo	1b
++	mcr	p15, 0, ip, c7, c5, 6		@ Invalidate BTB
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++/*
++ * cpu_xscale_icache_invalidate_page(page)
++ *
++ * invalidate all Icache lines associated with this area of memory
++ *
++ * page: page to invalidate
++ */
++	.align	5
++ENTRY(cpu_xscale_icache_invalidate_page)
++	mov	r1, #PAGESIZE
++1:	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I cache line
++	add	r0, r0, #CACHELINESIZE
++	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I cache line
++	add	r0, r0, #CACHELINESIZE
++	subs	r1, r1, #4 * CACHELINESIZE
++	bne	1b
++	mcr	p15, 0, r0, c7, c5, 6		@ Invalidate BTB
++	mov	pc, lr
++
++/* ================================ CACHE LOCKING============================ 
++ *
++ * The XScale MicroArchitecture implements support for locking entries into
++ * the data and instruction cache.  The following functions implement the core
++ * low level instructions needed to accomplish the locking.  The developer's
++ * manual states that the code that performs the locking must be in non-cached
++ * memory.  To accomplish this, the code in xscale-cache-lock.c copies the
++ * following functions from the cache into a non-cached memory region that
++ * is allocated through consistent_alloc().
++ *
++ */
++	.align	5
++/*
++ * xscale_icache_lock
++ *
++ * r0: starting address to lock
++ * r1: end address to lock
++ */
++ENTRY(xscale_icache_lock)
++
++iLockLoop:
++	bic	r0, r0, #CACHELINESIZE - 1
++	mcr	p15, 0, r0, c9, c1, 0	@ lock into cache
++	cmp	r0, r1			@ are we done?
++	add	r0, r0, #CACHELINESIZE	@ advance to next cache line
++	bls	iLockLoop
++	mov	pc, lr
++
++/*
++ * xscale_icache_unlock
++ */
++ENTRY(xscale_icache_unlock)
++	mcr	p15, 0, r0, c9, c1, 1	@ Unlock icache
++	mov	pc, lr
++	
++/*
++ * xscale_dcache_lock
++ *
++ * r0: starting address to lock
++ * r1: end address to lock
++ */
++ENTRY(xscale_dcache_lock)
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	r2, #1
++	mcr	p15, 0, r2, c9, c2, 0	@ Put dcache in lock mode
++	cpwait	ip			@ Wait for completion
++
++	mrs	r2, cpsr
++	orr	r3, r2, #F_BIT | I_BIT
++dLockLoop:
++	msr	cpsr_c, r3
++	mcr	p15, 0, r0, c7, c10, 1	@ Write back line if it is dirty 
++	mcr	p15, 0, r0, c7, c6, 1	@ Flush/invalidate line
++	msr	cpsr_c, r2
++	ldr	ip, [r0], #CACHELINESIZE @ Preload 32 bytes into cache from 
++					@ location [r0]. Post-increment
++					@ r3 to next cache line
++	cmp	r0, r1			@ Are we done?
++	bls	dLockLoop
++
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	r2, #0
++	mcr	p15, 0, r2, c9, c2, 0	@ Get out of lock mode
++	cpwait_ret lr, ip
++
++/*
++ * xscale_dcache_unlock
++ */
++ENTRY(xscale_dcache_unlock)
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mcr	p15, 0, ip, c9, c2, 1	@ Unlock cache
++	mov	pc, lr
++
++/*
++ * Needed to determine the length of the code that needs to be copied.
++ */
++	.align	5
++ENTRY(xscale_cache_dummy)
++	mov	pc, lr
++
++/* ================================== TLB ================================= */
++
++/*
++ * cpu_xscale_tlb_invalidate_all()
++ *
++ * Invalidate all TLB entries
++ */
++	.align	5
++ENTRY(cpu_xscale_tlb_invalidate_all)
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++	cpwait_ret lr, ip
++
++/*
++ * cpu_xscale_tlb_invalidate_range(start, end)
++ *
++ * invalidate TLB entries covering the specified range
++ *
++ * start: range start address
++ * end:   range end address
++ */
++	.align	5
++ENTRY(cpu_xscale_tlb_invalidate_range)
++	bic	r0, r0, #(PAGESIZE - 1) & 0x00ff
++	bic	r0, r0, #(PAGESIZE - 1) & 0xff00
++	sub	r3, r1, r0
++	cmp	r3, #256 * PAGESIZE		@ arbitrary, should be tuned
++	bhi	cpu_xscale_tlb_invalidate_all
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
++	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
++	add	r0, r0, #PAGESIZE
++	cmp	r0, r1
++	blo	1b
++	cpwait_ret lr, ip
++
++/*
++ * cpu_xscale_tlb_invalidate_page(page, flags)
++ *
++ * invalidate the TLB entries for the specified page.
++ *
++ * page:  page to invalidate
++ * flags: non-zero if we include the I TLB
++ */
++	.align	5
++ENTRY(cpu_xscale_tlb_invalidate_page)
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	teq	r1, #0
++	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
++	mcrne	p15, 0, r3, c8, c5, 1		@ invalidate I TLB entry
++	cpwait_ret lr, ip
++
++/* ================================ TLB LOCKING==============================
++ *
++ * The XScale MicroArchitecture implements support for locking entries into
++ * the Instruction and Data TLBs.  The following functions provide the
++ * low level support for supporting these under Linux.  xscale-lock.c 
++ * implements some higher level management code.  Most of the following
++ * is taken straight out of the Developer's Manual.
++ */
++
++/*
++ * Lock I-TLB entry
++ *
++ * r0: Virtual address to translate and lock
++ */
++	.align	5
++ENTRY(xscale_itlb_lock)
++	mrs	r2, cpsr
++	orr	r3, r2, #F_BIT | I_BIT
++	msr	cpsr_c, r3			@ Disable interrupts
++	mcr	p15, 0, r0, c8, c5, 1		@ Invalidate I-TLB entry
++	mcr	p15, 0, r0, c10, c4, 0		@ Translate and lock
++	msr	cpsr_c, r2			@ Restore interrupts
++	cpwait_ret lr, ip
++
++/*
++ * Lock D-TLB entry
++ *
++ * r0: Virtual address to translate and lock
++ */
++	.align	5
++ENTRY(xscale_dtlb_lock)
++	mrs	r2, cpsr
++	orr	r3, r2, #F_BIT | I_BIT
++	msr	cpsr_c, r3			@ Disable interrupts
++	mcr	p15, 0, r0, c8, c6, 1		@ Invalidate D-TLB entry
++	mcr	p15, 0, r0, c10, c8, 0		@ Translate and lock
++	msr	cpsr_c, r2			@ Restore interrupts
++	cpwait_ret lr, ip
++
++/*
++ * Unlock all I-TLB entries
++ */
++	.align	5
++ENTRY(xscale_itlb_unlock)
++	mcr	p15, 0, ip, c10, c4, 1		@ Unlock I-TLB
++	mcr	p15, 0, ip, c8, c5, 0		@ Invalidate I-TLB
++	cpwait_ret lr, ip
++
++/*
++ * Unlock all D-TLB entries
++ */
++ENTRY(xscale_dtlb_unlock)
++	mcr	p15, 0, ip, c10, c8, 1		@ Unlock D-TBL
++	mcr	p15, 0, ip, c8, c6, 0		@ Invalidate D-TLB
++	cpwait_ret lr, ip
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_xscale_set_pgd(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++	.align	5
++ENTRY(cpu_xscale_set_pgd)
++	clean_d_cache r1, r2
++	mcr	p15, 0, ip, c7, c5, 0		@ Invalidate I cache & BTB
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++	cpwait_ret lr, ip
++
++/*
++ * cpu_xscale_set_pmd(pmdp, pmd)
++ *
++ * Set a level 1 translation table entry, and clean it out of
++ * any caches such that the MMUs can load it correctly.
++ *
++ * pmdp: pointer to PMD entry
++ * pmd:  PMD value to store
++ */
++	.align	5
++ENTRY(cpu_xscale_set_pmd)
++#if PMD_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH
++	and	r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++	cmp	r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++	orreq	r1, r1, #PMD_SECT_TEX(1)
++#elif CACHE_WRITE_THROUGH
++	and	r2, r1, #PMD_TYPE_MASK|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++	cmp	r2, #PMD_TYPE_SECT|PMD_SECT_CACHEABLE|PMD_SECT_BUFFERABLE
++	biceq	r1, r1, #PMD_SECT_BUFFERABLE
++#endif
++	str	r1, [r0]
++	mov	ip, #0
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++/*
++ * cpu_xscale_set_pte(ptep, pte)
++ *
++ * Set a PTE and flush it out
++ *
++ * Errata 40: must set memory to write-through for user read-only pages.
++ */
++	.align	5
++ENTRY(cpu_xscale_set_pte)
++	str	r1, [r0], #-1024		@ linux version
++
++	bic	r2, r1, #0xff0
++	orr	r2, r2, #PTE_TYPE_EXT		@ extended page
++
++	eor	r3, r1, #L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_WRITE | L_PTE_DIRTY
++
++	tst	r3, #L_PTE_USER | L_PTE_EXEC	@ User or Exec?
++	orrne	r2, r2, #PTE_EXT_AP_URO_SRW	@ yes -> user r/o, system r/w
++
++	tst	r3, #L_PTE_WRITE | L_PTE_DIRTY	@ Write and Dirty?
++	orreq	r2, r2, #PTE_EXT_AP_UNO_SRW	@ yes -> user n/a, system r/w
++						@ combined with user -> user r/w
++
++	@
++	@ Handle the X bit.  We want to set this bit for the minicache
++	@ (U = E = B = W = 0, C = 1) or when write allocate is enabled,
++	@ and we have a writeable, cacheable region.  If we ignore the
++	@ U and E bits, we can allow user space to use the minicache as
++	@ well.
++	@
++	@  X = C & ~W & ~B
++	@      | C & W & B & write_allocate
++	@
++	eor	ip, r1, #L_PTE_CACHEABLE
++	tst	ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
++#if PTE_CACHE_WRITE_ALLOCATE && !CACHE_WRITE_THROUGH
++	eorne	ip, r1, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
++	tstne	ip, #L_PTE_CACHEABLE | L_PTE_WRITE | L_PTE_BUFFERABLE
++#endif
++	orreq	r2, r2, #PTE_EXT_TEX(1)
++
++#if CACHE_WRITE_THROUGH
++	tst	r1, #L_PTE_CACHEABLE
++	bicne	r2, r2, #L_PTE_BUFFERABLE	@ clear B only if C is set
++#else
++	@
++	@ Errata 40: The B bit must be cleared for a user read-only
++	@ cacheable page.
++	@
++	@  B = B & ~((U|E) & C & ~W)
++	@
++	and	ip, r1, #L_PTE_USER | L_PTE_EXEC | L_PTE_WRITE | L_PTE_CACHEABLE
++	teq	ip, #L_PTE_USER | L_PTE_CACHEABLE
++	teqne	ip, #L_PTE_EXEC | L_PTE_CACHEABLE
++	teqne	ip, #L_PTE_USER | L_PTE_EXEC | L_PTE_CACHEABLE
++	biceq	r2, r2, #PTE_BUFFERABLE
++#endif
++
++	tst	r3, #L_PTE_PRESENT | L_PTE_YOUNG	@ Present and Young?
++	movne	r2, #0				@ no -> fault
++
++	str	r2, [r0]			@ hardware version
++
++	@ We try to map 64K page entries when possible.  
++	@ We do that for kernel space only since the usage pattern from
++	@ the setting of VM area is quite simple.  User space is not worth
++	@ the implied complexity because of ever randomly changing PTEs 
++	@ (page aging, swapout, etc) requiring constant coherency checks.
++	@ Since PTEs are usually set in increasing order, we test the
++	@ possibility for a large page only when given the last PTE of a
++	@ 64K boundary.
++	tsteq	r1, #L_PTE_USER
++	andeq	r1, r0, #(15 << 2)
++	teqeq	r1, #(15 << 2)
++	beq	1f
++
++	mov	ip, #0
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++	@ See if we have 16 identical PTEs but with consecutive base addresses
++1:	bic	r3, r2, #0x0000f000
++	mov	r1, #0x0000f000
++2:	eor	r2, r2, r3
++	teq	r2, r1
++	bne	4f
++	subs	r1, r1, #0x00001000
++	ldr	r2, [r0, #-4]!
++	bne	2b
++	eors	r2, r2, r3
++	bne	4f
++
++	@ Now create our LARGE PTE from the current EXT one.
++	bic	r3, r3, #PTE_TYPE_MASK
++	orr	r3, r3, #PTE_TYPE_LARGE
++	and	r2, r3, #0x30			@ EXT_AP --> LARGE_AP0
++	orr	r2, r2, r2, lsl #2		@ add LARGE_AP1
++	orr	r2, r2, r2, lsl #4		@ add LARGE_AP3 + LARGE_AP2
++	and	r1, r3, #0x3c0			@ EXT_TEX
++	bic	r3, r3, #0x3c0
++	orr	r2, r2, r1, lsl #(12 - 6)	@ --> LARGE_TEX
++	orr	r2, r2, r3			@ add remaining bits
++
++	@ then put it in the pagetable
++	mov	r3, r2
++3:	strd	r2, [r0], #8
++	tst	r0, #(15 << 2)
++	bne	3b
++
++	@ Then sync the 2 corresponding cache lines
++	sub	r0, r0, #(16 << 2)
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++4:	orr	r0, r0, #(15 << 2)
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D cache line
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mov	pc, lr
++
++	.ltorg
++
++cpu_manu_name:
++	.asciz	"Intel"
++
++cpu_80200_name:
++	.asciz	"XScale-80200"
++
++cpu_pxa210_name:
++	.asciz	"XScale-PXA210"
++
++cpu_pxa250_name:
++	.asciz	"XScale-PXA250"
++
++cpu_pxa255_name:
++	.asciz	"XScale-PXA255"
++
++	.align
++
++	.section ".text.init", #alloc, #execinstr
++
++__xscale_setup:
++	mov	r0, #F_BIT|I_BIT|SVC_MODE
++	msr	cpsr_c, r0
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I, D caches & BTB
++	mcr	p15, 0, ip, c7, c10, 4		@ Drain Write (& Fill) Buffer
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I, D TLBs
++	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
++	mov	r0, #0x1f			@ Domains 0, 1 = client
++	mcr	p15, 0, r0, c3, c0, 0		@ load domain access register
++	mov	r0, #1				@ Allow user space to access
++	mcr	p15, 0, r0, c15, c1, 0		@ ... CP 0 only.
++#if CACHE_WRITE_THROUGH
++	mov	r0, #0x20
++#else
++	mov	r0, #0x00
++#endif
++	mcr	p15, 0, r0, c1, c1, 0		@ set auxiliary control reg
++	mrc	p15, 0, r0, c1, c0, 0		@ get control register
++	bic	r0, r0, #0x0200			@ ......R.........
++	bic	r0, r0, #0x0082			@ ........B.....A.
++	orr	r0, r0, #0x0005			@ .............C.M
++	orr	r0, r0, #0x3900			@ ..VIZ..S........
++#ifdef CONFIG_XSCALE_CACHE_ERRATA
++	bic	r0, r0, #0x0004			@ see cpu_xscale_proc_init
++#endif
++	mov	pc, lr
++
++	.text
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ *	     come through these
++ */
++
++	.type	xscale_processor_functions, #object
++ENTRY(xscale_processor_functions)
++	.word	cpu_xscale_data_abort
++	.word	cpu_xscale_check_bugs
++	.word	cpu_xscale_proc_init
++	.word	cpu_xscale_proc_fin
++	.word	cpu_xscale_reset
++	.word	cpu_xscale_do_idle
++
++	/* cache */
++	.word	cpu_xscale_cache_clean_invalidate_all
++	.word	cpu_xscale_cache_clean_invalidate_range
++	.word	cpu_xscale_flush_ram_page
++
++	/* dcache */
++	.word	cpu_xscale_dcache_invalidate_range
++	.word	cpu_xscale_dcache_clean_range
++	.word	cpu_xscale_dcache_clean_page
++	.word	cpu_xscale_dcache_clean_entry
++
++	/* icache */
++	.word	cpu_xscale_icache_invalidate_range
++	.word	cpu_xscale_icache_invalidate_page
++
++	/* tlb */
++	.word	cpu_xscale_tlb_invalidate_all
++	.word	cpu_xscale_tlb_invalidate_range
++	.word	cpu_xscale_tlb_invalidate_page
++
++	/* pgtable */
++	.word	cpu_xscale_set_pgd
++	.word	cpu_xscale_set_pmd
++	.word	cpu_xscale_set_pte
++	.size	xscale_processor_functions, . - xscale_processor_functions
++
++	.type	cpu_80200_info, #object
++cpu_80200_info:
++	.long	cpu_manu_name
++	.long	cpu_80200_name
++	.size	cpu_80200_info, . - cpu_80200_info
++
++	.type	cpu_pxa210_info, #object
++cpu_pxa210_info:
++	.long	cpu_manu_name
++	.long	cpu_pxa210_name
++	.size	cpu_pxa210_info, . - cpu_pxa210_info
++
++	.type	cpu_pxa250_info, #object
++cpu_pxa250_info:
++	.long	cpu_manu_name
++	.long	cpu_pxa250_name
++	.size	cpu_pxa250_info, . - cpu_pxa250_info
++
++	.type	cpu_pxa255_info, #object
++cpu_pxa255_info:
++	.long	cpu_manu_name
++	.long	cpu_pxa255_name
++	.size	cpu_pxa255_info, . - cpu_pxa255_info
++
++	.type	cpu_arch_name, #object
++cpu_arch_name:
++	.asciz	"armv5te"
++	.size	cpu_arch_name, . - cpu_arch_name
++
++	.type	cpu_elf_name, #object
++cpu_elf_name:
++	.asciz	"v5"
++	.size	cpu_elf_name, . - cpu_elf_name
++	.align
++
++	.section ".proc.info", #alloc, #execinstr
++
++	.type	__80200_proc_info,#object
++__80200_proc_info:
++	.long	0x69052000
++	.long	0xfffffff0
++#if CACHE_WRITE_THROUGH
++	.long	0x00000c0a
++#else
++	.long	0x00000c0e
++#endif
++	b	__xscale_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++	.long	cpu_80200_info
++	.long	xscale_processor_functions
++	.size	__80200_proc_info, . - __80200_proc_info
++
++	.type	__pxa210_proc_info,#object
++__pxa210_proc_info:
++	.long	0x69052120
++	.long	0xfffff3f0
++#if CACHE_WRITE_THROUGH
++	.long	0x00000c0a
++#else
++	.long	0x00000c0e
++#endif
++	b	__xscale_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++	.long	cpu_pxa210_info
++	.long	xscale_processor_functions
++	.size	__pxa210_proc_info, . - __pxa210_proc_info
++
++	.type	__pxa250_proc_info,#object
++__pxa250_proc_info:
++	.long	0x69052100
++	.long	0xfffff7f0
++#if CACHE_WRITE_THROUGH
++	.long	0x00000c0a
++#else
++	.long	0x00000c0e
++#endif
++	b	__xscale_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++	.long	cpu_pxa250_info
++	.long	xscale_processor_functions
++	.size	__pxa250_proc_info, . - __pxa250_proc_info
++
++	.type	__pxa255_proc_info,#object
++__pxa255_proc_info:
++	.long	0x69052d00
++	.long	0xfffffff0
++#if CACHE_WRITE_THROUGH
++	.long	0x00000c0a
++#else
++	.long	0x00000c0e
++#endif
++	b	__xscale_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_XSCALE
++	.long	cpu_pxa255_info
++	.long	xscale_processor_functions
++	.size	__pxa255_proc_info, . - __pxa255_proc_info
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/vmlinux-armv-xip.lds.in	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,125 @@
++/*
++ * ld script to make ARM Linux kernel
++ *
++ * (C) Copyright 2001 Lineo Japan, Inc.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ *
++ * Based on arch/arm/vmlinux-armv.lds.in
++ *
++ * taken from the i386 version by Russell King
++ * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
++ */
++OUTPUT_ARCH(arm)
++ENTRY(stext)
++SECTIONS
++{
++	. = TEXTADDR;
++	.init : {			/* Init code and data		*/
++		_stext = .;
++		__init_begin = .;
++			*(.text.init)
++		__proc_info_begin = .;
++			*(.proc.info)
++		__proc_info_end = .;
++		__arch_info_begin = .;
++			*(.arch.info)
++		__arch_info_end = .;
++		__tagtable_begin = .;
++			*(.taglist)
++		__tagtable_end = .;
++		. = ALIGN(16);
++		__setup_start = .;
++			*(.setup.init)
++		__setup_end = .;
++		__initcall_start = .;
++			*(.initcall.init)
++		__initcall_end = .;
++		. = ALIGN(4096);
++		__init_end = .;
++	}
++
++	/DISCARD/ : {			/* Exit code and data		*/
++		*(.text.exit)
++		*(.data.exit)
++		*(.exitcall.exit)
++	}
++
++	.text : {			/* Real text segment		*/
++		_text = .;		/* Text and read-only data	*/
++			*(.text)
++			*(.fixup)
++			*(.gnu.warning)
++			*(.text.lock)	/* out-of-line lock text */
++			*(.rodata)
++			*(.rodata.*)
++			*(.glue_7)
++			*(.glue_7t)
++			*(.kstrtab)
++		*(.got)			/* Global offset table		*/
++		*(.got.plt)
++
++		_etext = .;		/* End of text section		*/
++	}
++
++	. = ALIGN(16);
++	__ex_table : {			/* Exception table		*/
++		__start___ex_table = .;
++			*(__ex_table)
++		__stop___ex_table = .;
++	}
++
++	__ksymtab : {			/* Kernel symbol table		*/
++		__start___ksymtab = .;
++			*(__ksymtab)
++		__stop___ksymtab = .;
++	}
++
++	_endtext = .;
++
++	. = DATAADDR;
++
++	_sdata = .;
++
++	. = ALIGN(8192);
++
++	.data : {
++		/*
++		 * first, the init task union, aligned
++		 * to an 8192 byte boundary.
++		 */
++		*(.init.task)
++
++		/*
++		 * then the cacheline aligned data
++		 */
++		. = ALIGN(32);
++		*(.data.cacheline_aligned)
++
++		/*
++		 * and the usual data section
++		 */
++		*(.data)
++		CONSTRUCTORS
++
++		*(.data.init)
++
++		_edata = .;
++	}
++
++	.bss : {
++		__bss_start = .;	/* BSS				*/
++		*(.bss)
++		*(COMMON)
++		_end = . ;
++	}
++					/* Stabs debugging sections.	*/
++	.stab 0 : { *(.stab) }
++	.stabstr 0 : { *(.stabstr) }
++	.stab.excl 0 : { *(.stab.excl) }
++	.stab.exclstr 0 : { *(.stab.exclstr) }
++	.stab.index 0 : { *(.stab.index) }
++	.stab.indexstr 0 : { *(.stab.indexstr) }
++	.comment 0 : { *(.comment) }
++}
+--- linux-2.4.25/drivers/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -25,6 +25,7 @@
+ subdir-$(CONFIG_NUBUS)		+= nubus
+ subdir-$(CONFIG_TC)		+= tc
+ subdir-$(CONFIG_VT)		+= video
++subdir-$(CONFIG_MMC)		+= mmc
+ subdir-$(CONFIG_MAC)		+= macintosh
+ subdir-$(CONFIG_PPC32)		+= macintosh
+ subdir-$(CONFIG_USB)		+= usb
+--- linux-2.4.25/drivers/char/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/char/Config.in	2004-03-31 17:15:11.000000000 +0200
+@@ -253,6 +253,7 @@
+       dep_tristate '  DC21285 watchdog' CONFIG_21285_WATCHDOG $CONFIG_FOOTBRIDGE
+       dep_tristate '  NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG $CONFIG_ARCH_NETWINDER
+       dep_tristate '  SA1100 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_SA1100
++      dep_tristate '  PXA250/210 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_PXA
+       dep_tristate '  EPXA watchdog' CONFIG_EPXA_WATCHDOG $CONFIG_ARCH_CAMELOT
+       dep_tristate '  Omaha watchdog' CONFIG_OMAHA_WATCHDOG $CONFIG_ARCH_OMAHA
+       dep_tristate '  AT91RM9200 watchdog' CONFIG_AT91_WATCHDOG $CONFIG_ARCH_AT91RM9200
+@@ -335,6 +336,9 @@
+ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+    tristate 'SA1100 Real Time Clock' CONFIG_SA1100_RTC
+ fi
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++   tristate 'PXA250/210 Real Time Clock' CONFIG_PXA_RTC
++fi
+ if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then
+    tristate 'Omaha Real Time Clock' CONFIG_OMAHA_RTC
+ fi
+@@ -417,4 +421,8 @@
+    dep_tristate 'HP OB600 C/CT Pop-up mouse support' CONFIG_OBMOUSE $CONFIG_INPUT_MOUSEDEV
+ fi
+ 
++if [ "$CONFIG_ARCH_TRIZEPS2" = "y" ]; then
++   tristate ' MT6N TTL I/O suport' CONFIG_TRIZEPS2_TTLIO
++fi
++
+ endmenu
+--- linux-2.4.25/drivers/char/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/char/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -280,6 +280,7 @@
+ obj-$(CONFIG_MIPS_RTC) += mips_rtc.o
+ obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
+ obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o
++obj-$(CONFIG_PXA_RTC) += sa1100-rtc.o
+ obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o
+ ifeq ($(CONFIG_PPC),)
+   obj-$(CONFIG_NVRAM) += nvram.o
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/mt6n_ttl.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,316 @@
++/*
++ *	Trizeps-2 MT6N development board TTL-IO interface for Linux	
++ *
++ *	Copyright (C) 2003 Luc De Cock
++ *
++ * 	This driver allows use of the TTL-IO interface on the MT6N
++ * 	from user space. It exports the /dev/ttlio interface supporting
++ * 	some ioctl() and also the /proc/driver/ttlio pseudo-file
++ * 	for status information.
++ *
++ *	The ioctls can be used to set individual TTL output lines.
++ *	Only ioctls are supported.
++ *
++ *	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.
++ *
++ *	Based on other minimal char device drivers, like Alan's
++ *	watchdog, Ted's random, Paul's rtc, etc. etc.
++ *
++ *	1.00	Luc De Cock: initial version.
++ */
++
++#define TTLIO_VERSION		"1.00"
++
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/miscdevice.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/proc_fs.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++/* Writing to the register sets the output lines
++*  Reading from the register returns the status of the input lines
++*/
++static unsigned short *ttlio_base = (unsigned short *) TRIZEPS2_TTLIO_BASE;
++static unsigned short ttlio_shadow = 0;
++
++/* interrupt stuff */
++static struct fasync_struct *ttlio_async_queue;
++static DECLARE_WAIT_QUEUE_HEAD(ttlio_wait);
++static int ttlio_irq_arrived = 0;
++static spinlock_t ttlio_lock;
++static unsigned short ttlio_in = 0;
++static volatile unsigned long teller = 0;
++
++
++static int ttlio_ioctl(struct inode *inode, struct file *file,
++		       unsigned int cmd, unsigned long arg);
++
++static int ttlio_read_proc(char *page, char **start, off_t off,
++                           int count, int *eof, void *data);
++
++
++static void ttlio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	ttlio_in = *ttlio_base;
++
++	ttlio_irq_arrived = 1;
++	teller++;
++	
++	/* wake up the waiting process */
++	wake_up_interruptible(&ttlio_wait);
++	kill_fasync(&ttlio_async_queue, SIGIO, POLL_IN);
++}
++
++/*
++ *	Now all the various file operations that we export.
++ */
++
++static int ttlio_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++		       unsigned long arg)
++{
++	unsigned long ttlio_val;
++
++	switch (cmd) {
++	case TTLIO_RESET:	/* clear all lines */
++	{
++		*ttlio_base = 0;
++		return 0;
++	}
++	case TTLIO_GET:		/* get state of TTL input lines	*/
++	{
++		ttlio_val = *ttlio_base;
++		return put_user(ttlio_val, (unsigned long *)arg);
++	}
++	case TTLIO_SET:		/* set state of TTL output lines */
++	{
++		unsigned long user_val;
++		if (copy_from_user(&user_val, arg, sizeof(unsigned long)))
++			return -EFAULT;
++		ttlio_shadow |= (unsigned short) user_val;
++		*ttlio_base = ttlio_shadow;
++		return 0;
++	}
++	case TTLIO_UNSET:	/* unset (clear) state of TTL output lines */
++	{
++		unsigned long user_val;
++		if (copy_from_user(&user_val, arg, sizeof(unsigned long)))
++			return -EFAULT;
++		ttlio_shadow &= ~((unsigned short) user_val);
++		*ttlio_base = ttlio_shadow;
++		return 0;
++	}
++	case 100:		/* get counter */
++	{
++		return put_user(teller, (unsigned long *)arg);
++	}
++	case 101:		/* reset counter */
++	{
++		teller = 0;
++		return 0;
++	}
++	default:
++		return -ENOTTY;
++	}
++	return 0;
++}
++
++static ssize_t ttlio_read(struct file *file, char *buf,
++			  size_t count, loff_t *ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned short data;
++	ssize_t retval;
++
++	if (count < sizeof(unsigned short))
++		return -EINVAL;
++
++	if (file->f_flags & O_NONBLOCK) {
++		spin_lock_irq(&ttlio_lock);
++		data = *ttlio_base;
++		spin_unlock_irq(&ttlio_lock);
++		retval = put_user(data, (unsigned short *) buf); 
++		if (!retval)
++			retval = sizeof(unsigned short);
++		return retval;
++	}
++	/* blocking read: wait for interrupt */
++	add_wait_queue(&ttlio_wait, &wait);
++	set_current_state(TASK_INTERRUPTIBLE);
++	for (;;) {
++		spin_lock_irq(&ttlio_lock);
++		data = *ttlio_base;
++		if (ttlio_irq_arrived) {
++			ttlio_irq_arrived = 0;
++			break;
++		}
++		spin_unlock_irq(&ttlio_lock);
++
++		if (signal_pending(current)) {
++			retval = -ERESTARTSYS;
++			goto out;
++		}
++		schedule();
++	}
++
++	spin_unlock_irq(&ttlio_lock);
++	retval = put_user(data, (unsigned short *)buf);
++	if (!retval)
++		retval = sizeof(unsigned short);
++
++out:
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&ttlio_wait, &wait);
++	return retval;
++}
++
++static ssize_t ttlio_write(struct file *file,
++		           const char *buf, size_t count, loff_t *ppos)
++{
++	unsigned short content;
++
++	if (count < sizeof(unsigned short))
++		return -EINVAL;
++	
++	if (copy_from_user (&content, buf, sizeof(unsigned short)))
++		return -EFAULT;
++
++	ttlio_shadow = content;
++	*ttlio_base = ttlio_shadow;
++
++	*ppos += sizeof(unsigned short);
++
++	return sizeof(unsigned short);
++}
++
++static int ttlio_open(struct inode *inode, struct file *file)
++{
++	ttlio_irq_arrived = 0;
++	return 0;
++}
++
++static int ttlio_fasync(int fd, struct file *filp, int on)
++{
++	return fasync_helper(fd, filp, on, &ttlio_async_queue);
++}
++
++static unsigned int ttlio_poll(struct file *file, poll_table *wait)
++{
++	poll_wait(file, &ttlio_wait, wait);
++	return ttlio_irq_arrived ? 0 : POLLIN | POLLRDNORM;
++}
++
++static loff_t ttlio_llseek(struct file *file, loff_t offset, int origin)
++{
++	return -ESPIPE;
++}
++
++/*
++ *	The various file operations we support.
++ */
++
++static struct file_operations ttlio_fops = {
++	owner:		THIS_MODULE,
++	llseek:		ttlio_llseek,
++	read:		ttlio_read,
++	poll:		ttlio_poll,
++	write:		ttlio_write,
++	ioctl:		ttlio_ioctl,
++	open:		ttlio_open,
++	fasync:		ttlio_fasync,
++};
++
++static struct miscdevice ttlio_dev = {
++	TTLIO_MINOR,
++	"ttlio",
++	&ttlio_fops
++};
++
++static int __init ttlio_init(void)
++{
++	printk(KERN_INFO "MT6N TTL-I/O driver (release %s)\n",
++			TTLIO_VERSION);
++	
++	misc_register(&ttlio_dev);
++	create_proc_read_entry ("driver/ttlio", 0, 0, ttlio_read_proc, NULL);
++
++	set_GPIO_IRQ_edge(GPIO_TTLIO_IRQ, GPIO_FALLING_EDGE);
++	if (request_irq(TTLIO_IRQ, ttlio_interrupt, SA_INTERRUPT, "ttlio irq", NULL)) {
++		printk(KERN_ERR "ttlio: irq %d already in use\n", TTLIO_IRQ);
++		return 1;
++	}
++	return 0;
++}
++
++static void __exit ttlio_exit(void)
++{
++	free_irq(TTLIO_IRQ, NULL);
++	remove_proc_entry ("driver/ttlio", NULL);
++	misc_deregister(&ttlio_dev);
++}
++
++module_init(ttlio_init);
++module_exit(ttlio_exit);
++EXPORT_NO_SYMBOLS;
++
++/*
++ *	Info exported via "/proc/driver/ttlio".
++ */
++
++static int ttlio_proc_output(char *buf)
++{
++	char *p;
++	unsigned short val;
++	int i;
++
++	p = buf;
++
++	p += sprintf(p, "input : ");
++	/* write the state of the input lines */
++	val = *ttlio_base;
++	for (i = 0; i < 8*sizeof(unsigned short); i++) {
++		*p++ = (val & 1) ? '1' : '0';
++		val >>= 1;
++	}
++	*p = 0;
++	p += sprintf(p, "\noutput: ");
++	/* write the state of the output lines */
++	val = ttlio_shadow;
++	for (i = 0; i < 8*sizeof(unsigned short); i++) {
++		*p++ = (val & 1) ? '1' : '0';
++		val >>= 1;
++	}
++	*p = 0;
++	p += sprintf(p, "\n");
++
++	return  p - buf;
++}
++
++static int ttlio_read_proc(char *page, char **start, off_t off,
++                           int count, int *eof, void *data)
++{
++        int len = ttlio_proc_output (page);
++        if (len <= off+count) *eof = 1;
++        *start = page + off;
++        len -= off;
++        if (len > count) len = count;
++        if (len < 0) len = 0;
++        return len;
++}
++
++MODULE_AUTHOR("Luc De Cock");
++MODULE_DESCRIPTION("MT6N TTL-I/O driver");
++MODULE_LICENSE("GPL");
+--- linux-2.4.25/drivers/char/sa1100-rtc.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/char/sa1100-rtc.c	2004-03-31 17:15:11.000000000 +0200
+@@ -1,5 +1,6 @@
+ /*
+  *	Real Time Clock interface for Linux on StrongARM SA1100
++ *	and XScale PXA250/210.
+  *
+  *	Copyright (c) 2000 Nils Faerber
+  *
+@@ -470,5 +471,5 @@
+ module_exit(rtc_exit);
+ 
+ MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>");
+-MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)");
++MODULE_DESCRIPTION("SA1100/PXA Realtime Clock Driver (RTC)");
+ EXPORT_NO_SYMBOLS;
+--- linux-2.4.25/drivers/char/sa1100_wdt.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/char/sa1100_wdt.c	2004-03-31 17:15:11.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*
+- *	Watchdog driver for the SA11x0
++ *	Watchdog driver for the SA11x0/PXA
+  *
+  *      (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
+  *          Based on SoftDog driver by Alan Cox <alan@redhat.com>
+@@ -35,13 +35,20 @@
+ 
+ #define TIMER_MARGIN	60		/* (secs) Default is 1 minute */
+ 
+-static int sa1100_margin = TIMER_MARGIN;	/* in seconds */
++static int timer_margin = TIMER_MARGIN;	/* in seconds */
+ static int sa1100wdt_users;
+ static int pre_margin;
+ #ifdef MODULE
+-MODULE_PARM(sa1100_margin,"i");
++MODULE_PARM(timer_margin,"i");
+ #endif
+ 
++static void sa1100dog_ping( void)
++{
++	/* reload counter with (new) margin */
++	pre_margin=3686400 * timer_margin;
++	OSMR3 = OSCR + pre_margin;
++}
++
+ /*
+  *	Allow only one person to hold it open
+  */
+@@ -51,9 +58,7 @@
+ 	if(test_and_set_bit(1,&sa1100wdt_users))
+ 		return -EBUSY;
+ 	MOD_INC_USE_COUNT;
+-	/* Activate SA1100 Watchdog timer */
+-	pre_margin=3686400 * sa1100_margin;
+-	OSMR3 = OSCR + pre_margin;
++	sa1100dog_ping();
+ 	OSSR = OSSR_M3;
+ 	OWER = OWER_WME;
+ 	OIER |= OIER_E3;
+@@ -93,8 +98,11 @@
+ 	unsigned int cmd, unsigned long arg)
+ {
+ 	static struct watchdog_info ident = {
+-		identity: "SA1100 Watchdog",
++		identity: "PXA/SA1100 Watchdog",
++		options: WDIOF_SETTIMEOUT,
++		firmware_version: 0,
+ 	};
++	int new_margin;
+ 
+ 	switch(cmd){
+ 	default:
+@@ -108,6 +116,16 @@
+ 	case WDIOC_KEEPALIVE:
+ 		OSMR3 = OSCR + pre_margin;
+ 		return 0;
++	case WDIOC_SETTIMEOUT:
++		if (get_user(new_margin, (int *)arg))
++			return -EFAULT;
++		if (new_margin < 1)
++			return -EINVAL;
++		timer_margin = new_margin;
++		sa1100dog_ping();
++		/* Fall */
++	case WDIOC_GETTIMEOUT:
++		return put_user(timer_margin, (int *)arg);
+ 	}
+ }
+ 
+@@ -123,7 +141,11 @@
+ static struct miscdevice sa1100dog_miscdev=
+ {
+ 	WATCHDOG_MINOR,
+-	"SA1100 watchdog",
++#if defined(CONFIG_SA1100_WATCHDOG)
++	"SA1100_watchdog",
++#elif defined(CONFIG_PXA_WATCHDOG)
++	"PXA_watchdog",
++#endif
+ 	&sa1100dog_fops
+ };
+ 
+@@ -136,7 +158,7 @@
+ 	if (ret)
+ 		return ret;
+ 
+-	printk("SA1100 Watchdog Timer: timer margin %d sec\n", sa1100_margin);
++	printk("SA1100/PXA Watchdog Timer: timer margin %d sec\n", timer_margin);
+ 
+ 	return 0;
+ }
+--- linux-2.4.25/drivers/char/serial.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/char/serial.c	2004-03-31 17:15:11.000000000 +0200
+@@ -133,6 +133,16 @@
+ #endif
+ #endif
+ 
++#ifdef CONFIG_ARCH_PXA
++#define pxa_port(x) ((x) == PORT_PXA)
++#define pxa_buggy_port(x) ({ \
++	int cpu_ver; asm("mrc%? p15, 0, %0, c0, c0" : "=r" (cpu_ver)); \
++	((x) == PORT_PXA && (cpu_ver & ~1) == 0x69052100); })
++#else
++#define pxa_port(x) (0)
++#define pxa_buggy_port(x) (0)
++#endif
++
+ /* Set of debugging defines */
+ 
+ #undef SERIAL_DEBUG_INTR
+@@ -311,6 +321,7 @@
+ 	{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+ 		  UART_STARTECH },
+ 	{ "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, 
++	{ "PXA UART", 32, UART_CLEAR_FIFO | UART_USE_FIFO },
+ 	{ 0, 0}
+ };
+ 
+@@ -424,6 +435,9 @@
+ 	case SERIAL_IO_MEM:
+ 		return readb((unsigned long) info->iomem_base +
+ 			     (offset<<info->iomem_reg_shift));
++	case SERIAL_IO_MEM32:
++		return readl((unsigned long) info->iomem_base +
++			     (offset<<info->iomem_reg_shift));
+ 	default:
+ 		return inb(info->port + offset);
+ 	}
+@@ -443,6 +457,10 @@
+ 		writeb(value, (unsigned long) info->iomem_base +
+ 			      (offset<<info->iomem_reg_shift));
+ 		break;
++	case SERIAL_IO_MEM32:
++		writel(value, (unsigned long) info->iomem_base +
++			      (offset<<info->iomem_reg_shift));
++		break;
+ 	default:
+ 		outb(value, info->port+offset);
+ 	}
+@@ -1306,6 +1324,16 @@
+ 	}
+ #endif
+ 
++#ifdef CONFIG_ARCH_PXA
++	if (state->type == PORT_PXA) {
++		switch ((long)state->iomem_base) {
++			case (long)&FFUART: CKEN |= CKEN6_FFUART; break;
++			case (long)&BTUART: CKEN |= CKEN7_BTUART; break;
++			case (long)&STUART: CKEN |= CKEN5_STUART; break;
++		}
++	}
++#endif
++
+ 	/*
+ 	 * Clear the FIFO buffers and disable them
+ 	 * (they will be reenabled in change_speed())
+@@ -1403,6 +1431,8 @@
+ 	{
+ 		if (state->irq != 0)
+ 			info->MCR |= UART_MCR_OUT2;
++		if (pxa_buggy_port(state->type) && state->irq != 0)
++			info->MCR ^= UART_MCR_OUT2;
+ 	}
+ 	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
+ 	serial_outp(info, UART_MCR, info->MCR);
+@@ -1411,6 +1441,8 @@
+ 	 * Finally, enable interrupts
+ 	 */
+ 	info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
++	if (pxa_port(state->type))
++		info->IER |= UART_IER_UUE | UART_IER_RTOIE;
+ 	serial_outp(info, UART_IER, info->IER);	/* enable interrupts */
+ 	
+ #ifdef CONFIG_SERIAL_MANY_PORTS
+@@ -1542,6 +1574,8 @@
+ 	} else
+ #endif
+ 		info->MCR &= ~UART_MCR_OUT2;
++		if (pxa_buggy_port(state->type))
++			info->MCR ^= UART_MCR_OUT2;
+ 	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
+ 	
+ 	/* disable break condition */
+@@ -1567,6 +1601,20 @@
+ 		state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+ #endif
+ 	
++#ifdef CONFIG_ARCH_PXA
++	if (state->type == PORT_PXA
++#ifdef CONFIG_SERIAL_CONSOLE
++	    && sercons.index != info->line
++#endif
++	   ) {
++		switch ((long)state->iomem_base) {
++			case (long)&FFUART: CKEN &= ~CKEN6_FFUART; break;
++			case (long)&BTUART: CKEN &= ~CKEN7_BTUART; break;
++			case (long)&STUART: CKEN &= ~CKEN5_STUART; break;
++		}
++	}
++#endif
++
+ 
+ 	(void)serial_in(info, UART_RX);    /* read data port to reset things */
+ 	
+@@ -1857,6 +1905,8 @@
+ 	save_flags(flags); cli();
+ 	info->IER |= UART_IER_THRI;
+ 	serial_out(info, UART_IER, info->IER);
++	if (pxa_buggy_port(info->state->type))
++		rs_interrupt_single(info->state->irq, NULL, NULL);
+ 	restore_flags(flags);
+ }
+ 
+@@ -1933,6 +1983,11 @@
+ 	    && !(info->IER & UART_IER_THRI)) {
+ 		info->IER |= UART_IER_THRI;
+ 		serial_out(info, UART_IER, info->IER);
++		if (pxa_buggy_port(info->state->type)) {
++			save_flags(flags); cli();
++			rs_interrupt_single(info->state->irq, NULL, NULL);
++			restore_flags(flags);
++		}
+ 	}
+ 	return ret;
+ }
+@@ -1990,6 +2045,8 @@
+ 		/* Make sure transmit interrupts are on */
+ 		info->IER |= UART_IER_THRI;
+ 		serial_out(info, UART_IER, info->IER);
++		if (pxa_buggy_port(info->state->type))
++			rs_interrupt_single(info->state->irq, NULL, NULL);
+ 	}
+ }
+ 
+@@ -5517,7 +5574,6 @@
+ 	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ 		state->magic = SSTATE_MAGIC;
+ 		state->line = i;
+-		state->type = PORT_UNKNOWN;
+ 		state->custom_divisor = 0;
+ 		state->close_delay = 5*HZ/10;
+ 		state->closing_wait = 30*HZ;
+@@ -5531,14 +5587,18 @@
+ 		state->irq = irq_cannonicalize(state->irq);
+ 		if (state->hub6)
+ 			state->io_type = SERIAL_IO_HUB6;
+-		if (state->port && check_region(state->port,8))
++		if (state->port && check_region(state->port,8)) {
++			state->type = PORT_UNKNOWN;
+ 			continue;
++		}
+ #ifdef CONFIG_MCA			
+ 		if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
+ 			continue;
+ #endif			
+-		if (state->flags & ASYNC_BOOT_AUTOCONF)
++		if (state->flags & ASYNC_BOOT_AUTOCONF) {
++			state->type = PORT_UNKNOWN;
+ 			autoconfig(state);
++		}
+ 	}
+ 	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+ 		if (state->type == PORT_UNKNOWN)
+@@ -5858,6 +5918,8 @@
+ 	 */
+ 	ier = serial_in(info, UART_IER);
+ 	serial_out(info, UART_IER, 0x00);
++	if (pxa_port(info->state->type))
++		serial_out(info, UART_IER, UART_IER_UUE);
+ 
+ 	/*
+ 	 *	Now, do each character
+@@ -6009,6 +6071,8 @@
+ 	serial_out(info, UART_DLM, quot >> 8);		/* MS of divisor */
+ 	serial_out(info, UART_LCR, cval);		/* reset DLAB */
+ 	serial_out(info, UART_IER, 0);
++	if (pxa_port(info->state->type))
++		serial_out(info, UART_IER, UART_IER_UUE);
+ 	serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+ 
+ 	/*
+--- linux-2.4.25/drivers/i2c/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/i2c/Config.in	2004-03-31 17:15:11.000000000 +0200
+@@ -54,6 +54,11 @@
+       fi
+    fi
+ 
++   if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++      dep_tristate 'PXA I2C Algorithm' CONFIG_I2C_PXA_ALGO $CONFIG_I2C
++      dep_tristate 'PXA I2C Adapter'   CONFIG_I2C_PXA_ADAP $CONFIG_I2C_PXA_ALGO
++   fi
++
+    if [ "$CONFIG_ALL_PPC" = "y" ] ; then
+       dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C
+    fi
+--- linux-2.4.25/drivers/i2c/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/i2c/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -6,7 +6,7 @@
+ 
+ export-objs	:= i2c-core.o i2c-algo-bit.o i2c-algo-pcf.o \
+ 		   i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
+-		   i2c-proc.o
++		   i2c-algo-pxa.o i2c-proc.o
+ 
+ # Init order: core, chardev, bit adapters, pcf adapters
+ 
+@@ -35,6 +35,10 @@
+ obj-$(CONFIG_I2C_MAX1617)	+= i2c-max1617.o
+ obj-$(CONFIG_I2C_ALGO_SGI)	+= i2c-algo-sgi.o
+ 
++# PXA adapters
++obj-$(CONFIG_I2C_PXA_ALGO)	+= i2c-algo-pxa.o
++obj-$(CONFIG_I2C_PXA_ADAP)	+= i2c-adap-pxa.o
++
+ # This is needed for automatic patch generation: sensors code starts here
+ # This is needed for automatic patch generation: sensors code ends here
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/i2c/i2c-adap-pxa.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,396 @@
++/*
++ *  i2c_adap_pxa.c
++ *
++ *  I2C adapter for the PXA I2C bus access.
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Apr 2002: Initial version [CS]
++ *    Jun 2002: Properly seperated algo/adap [FB]
++ *    Jan 2003: Fixed several bugs concerning interrupt handling [Kai-Uwe Bloem]
++ *    Jan 2003: added limited signal handling [Kai-Uwe Bloem]
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-id.h>
++#include <linux/init.h>
++#include <linux/time.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/irqs.h>              /* for IRQ_I2C */
++
++#include "i2c-pxa.h"
++
++/*
++ * Set this to zero to remove all debug statements via dead code elimination.
++ */
++//#define DEBUG       1
++
++#if DEBUG
++static unsigned int i2c_debug = DEBUG;
++#else
++#define i2c_debug	0
++#endif
++
++static int irq = 0;
++static volatile int i2c_pending = 0;             /* interrupt pending when 1 */
++static volatile int bus_error = 0;
++static volatile int tx_finished = 0;
++static volatile int rx_finished = 0;
++
++static wait_queue_head_t i2c_wait;
++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte);
++
++/* place a byte in the transmit register */
++static void i2c_pxa_write_byte(u8 value)
++{
++	IDBR = value;
++}
++
++/* read byte in the receive register */
++static u8 i2c_pxa_read_byte(void)
++{
++	return (u8) (0xff & IDBR);
++}
++
++static void i2c_pxa_start(void)
++{
++	unsigned long icr = ICR;
++	icr |= ICR_START;
++	icr &= ~(ICR_STOP | ICR_ALDIE | ICR_ACKNAK);
++	ICR = icr;
++
++	bus_error=0;            /* clear any bus_error from previous txfers */
++	tx_finished=0;          /* clear rx and tx interrupts from previous txfers */
++	rx_finished=0;
++	i2c_pending = 0;
++}
++
++static void i2c_pxa_repeat_start(void)
++{
++	unsigned long icr = ICR;
++	icr |= ICR_START;
++	icr &= ~(ICR_STOP | ICR_ALDIE);
++	ICR = icr;
++
++	bus_error=0;            /* clear any bus_error from previous txfers */
++	tx_finished=0;          /* clear rx and tx interrupts from previous txfers */
++	rx_finished=0;
++	i2c_pending = 0;
++}
++
++static void i2c_pxa_stop(void)
++{
++	unsigned long icr = ICR;
++	icr |= ICR_STOP;
++	icr &= ~(ICR_START);
++	ICR = icr;
++}
++
++static void i2c_pxa_midbyte(void)
++{
++	unsigned long icr = ICR;
++	icr &= ~(ICR_START | ICR_STOP);
++	ICR = icr;
++}
++
++static void i2c_pxa_abort(void)
++{
++	unsigned long timeout = jiffies + HZ/4;
++
++#ifdef PXA_ABORT_MA
++	while ((long)(timeout - jiffies) > 0 && (ICR & ICR_TB)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++
++	ICR |= ICR_MA;
++	udelay(100);
++#else
++	while ((long)(timeout - jiffies) > 0 && (IBMR & 0x1) == 0) {
++		i2c_pxa_transfer( 1, I2C_RECEIVE, 1);
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++#endif
++	ICR &= ~(ICR_MA | ICR_START | ICR_STOP);
++}
++
++static int i2c_pxa_wait_bus_not_busy( void)
++{
++	int timeout = DEF_TIMEOUT;
++
++	while (timeout-- && (ISR & ISR_IBB)) {
++		udelay(100); /* wait for 100 us */
++	}
++
++	return (timeout<=0);
++}
++
++static void i2c_pxa_wait_for_ite(void){
++	unsigned long flags;
++	if (irq > 0) {
++		save_flags_cli(flags);
++		if (i2c_pending == 0) {
++			interruptible_sleep_on_timeout(&i2c_wait, I2C_SLEEP_TIMEOUT );
++		}
++		i2c_pending = 0;
++		restore_flags(flags);
++	} else {
++		udelay(100);
++	}
++}
++
++static int i2c_pxa_wait_for_int( int wait_type)
++{
++	int timeout = DEF_TIMEOUT;
++#ifdef DEBUG
++	if (bus_error)
++		printk(KERN_INFO"i2c_pxa_wait_for_int: Bus error on enter\n");
++	if (rx_finished)
++		printk(KERN_INFO"i2c_pxa_wait_for_int: Receive interrupt on enter\n");
++	if (tx_finished)
++		printk(KERN_INFO"i2c_pxa_wait_for_int: Transmit interrupt on enter\n");
++#endif
++
++	if (wait_type == I2C_RECEIVE){         /* wait on receive */
++
++		do {
++			i2c_pxa_wait_for_ite();
++		} while (!(rx_finished) && timeout-- && !signal_pending(current));
++
++#ifdef DEBUG
++		if (timeout<0){
++			if (tx_finished)
++				printk("Error: i2c-algo-pxa.o: received a tx"
++						" interrupt while waiting on a rx in wait_for_int");
++		}
++#endif
++	} else {                  /* wait on transmit */
++
++		do {
++			i2c_pxa_wait_for_ite();
++		} while (!(tx_finished) && timeout-- && !signal_pending(current));
++
++#ifdef DEBUG
++		if (timeout<0){
++			if (rx_finished)
++				printk("Error: i2c-algo-pxa.o: received a rx"
++					" interrupt while waiting on a tx in wait_for_int");
++		}
++#endif
++	}
++
++	udelay(ACK_DELAY);      /* this is needed for the bus error */
++
++	tx_finished=0;
++	rx_finished=0;
++
++	if (bus_error){
++		bus_error=0;
++		if( i2c_debug > 2)printk("wait_for_int: error - no ack.\n");
++		return BUS_ERROR;
++	}
++
++	if (signal_pending(current)) {
++		return (-ERESTARTSYS);
++	} else if (timeout < 0) {
++		if( i2c_debug > 2)printk("wait_for_int: timeout.\n");
++		return(-EIO);
++	} else
++		return(0);
++}
++
++static void i2c_pxa_transfer( int lastbyte, int receive, int midbyte)
++{
++	if( lastbyte)
++	{
++		if( receive==I2C_RECEIVE) ICR |= ICR_ACKNAK;
++		i2c_pxa_stop();
++	}
++	else if( midbyte)
++	{
++		i2c_pxa_midbyte();
++	}
++	ICR |= ICR_TB;
++}
++
++static void i2c_pxa_reset( void)
++{
++#ifdef DEBUG
++	printk("Resetting I2C Controller Unit\n");
++#endif
++
++	/* abort any transfer currently under way */
++	i2c_pxa_abort();
++
++	/* reset according to 9.8 */
++	ICR = ICR_UR;
++	ISR = I2C_ISR_INIT;
++	ICR &= ~ICR_UR;
++
++	/* set the global I2C clock on */
++	CKEN |= CKEN14_I2C;
++
++	/* set our slave address */
++	ISAR = I2C_PXA_SLAVE_ADDR;
++
++	/* set control register values */
++	ICR = I2C_ICR_INIT;
++
++	/* clear any leftover states from prior transmissions */
++	i2c_pending = rx_finished = tx_finished = bus_error = 0;
++
++	/* enable unit */
++	ICR |= ICR_IUE;
++	udelay(100);
++}
++
++static void i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
++{
++	int status, wakeup = 0;
++	status = (ISR);
++
++	if (status & ISR_BED){
++		(ISR) |= ISR_BED;
++		bus_error=ISR_BED;
++		wakeup = 1;
++	}
++	if (status & ISR_ITE){
++		(ISR) |= ISR_ITE;
++		tx_finished=ISR_ITE;
++		wakeup = 1;
++	}
++	if (status & ISR_IRF){
++		(ISR) |= ISR_IRF;
++		rx_finished=ISR_IRF;
++		wakeup = 1;
++	}
++	if (wakeup) {
++		i2c_pending = 1;
++		wake_up_interruptible(&i2c_wait);
++	}
++}
++
++static int i2c_pxa_resource_init( void)
++{
++	init_waitqueue_head(&i2c_wait);
++
++	if (request_irq(IRQ_I2C, &i2c_pxa_handler, SA_INTERRUPT, "I2C_PXA", 0) < 0) {
++		irq = 0;
++		if( i2c_debug)
++			printk(KERN_INFO "I2C: Failed to register I2C irq %i\n", IRQ_I2C);
++		return -ENODEV;
++	}else{
++		irq = IRQ_I2C;
++		enable_irq(irq);
++	}
++	return 0;
++}
++
++static void i2c_pxa_resource_release( void)
++{
++	if( irq > 0)
++	{
++		disable_irq(irq);
++		free_irq(irq,0);
++		irq=0;
++	}
++}
++
++static void i2c_pxa_inc_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++	MOD_INC_USE_COUNT;
++#endif
++}
++
++static void i2c_pxa_dec_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++	MOD_DEC_USE_COUNT;
++#endif
++}
++
++static int i2c_pxa_client_register(struct i2c_client *client)
++{
++	return 0;
++}
++
++static int i2c_pxa_client_unregister(struct i2c_client *client)
++{
++	return 0;
++}
++
++static struct i2c_algo_pxa_data i2c_pxa_data = {
++	write_byte:		i2c_pxa_write_byte,
++	read_byte:		i2c_pxa_read_byte,
++
++	start:			i2c_pxa_start,
++	repeat_start:		i2c_pxa_repeat_start,
++	stop:			i2c_pxa_stop,
++	abort:			i2c_pxa_abort,
++
++	wait_bus_not_busy:	i2c_pxa_wait_bus_not_busy,
++	wait_for_interrupt:	i2c_pxa_wait_for_int,
++	transfer:		i2c_pxa_transfer,
++	reset:			i2c_pxa_reset,
++
++	udelay:			10,
++	timeout:		DEF_TIMEOUT,
++};
++
++static struct i2c_adapter i2c_pxa_ops = {
++	name:                   "PXA-I2C-Adapter",
++	id:                     I2C_ALGO_PXA,
++	algo_data:              &i2c_pxa_data,
++	inc_use:                i2c_pxa_inc_use,
++	dec_use:                i2c_pxa_dec_use,
++	client_register:        i2c_pxa_client_register,
++	client_unregister:      i2c_pxa_client_unregister,
++	retries:                2,
++};
++
++extern int i2c_pxa_add_bus(struct i2c_adapter *);
++extern int i2c_pxa_del_bus(struct i2c_adapter *);
++
++static int __init i2c_adap_pxa_init(void)
++{
++	if( i2c_pxa_resource_init() == 0) {
++
++		if (i2c_pxa_add_bus(&i2c_pxa_ops) < 0) {
++			i2c_pxa_resource_release();
++			printk(KERN_INFO "I2C: Failed to add bus\n");
++			return -ENODEV;
++		}
++	} else {
++		return -ENODEV;
++	}
++
++	printk(KERN_INFO "I2C: Successfully added bus\n");
++
++	return 0;
++}
++
++static void i2c_adap_pxa_exit(void)
++{
++	i2c_pxa_del_bus( &i2c_pxa_ops);
++	i2c_pxa_resource_release();
++
++	printk(KERN_INFO "I2C: Successfully removed bus\n");
++}
++
++module_init(i2c_adap_pxa_init);
++module_exit(i2c_adap_pxa_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/i2c/i2c-algo-pxa.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,376 @@
++/*
++ *  i2c-algo-pxa.c
++ *
++ *  I2C algorithm for the PXA I2C bus access.
++ *  Byte driven algorithm similar to pcf.
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Apr 2002: Initial version [CS]
++ *    Jun 2002: Properly seperated algo/adap [FB]
++ *    Jan 2003: added limited signal handling [Kai-Uwe Bloem]
++ *    Jan 2003: allow SMBUS_QUICK as valid msg [FB]
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/i2c.h>          /* struct i2c_msg and others */
++#include <linux/i2c-id.h>
++
++#include "i2c-pxa.h"
++
++/*
++ * Set this to zero to remove all the debug statements via dead code elimination.
++ */
++//#define DEBUG		1
++
++#if DEBUG
++static unsigned int i2c_debug = DEBUG;
++#else
++#define i2c_debug	0
++#endif
++
++static int pxa_scan = 1;
++
++static int i2c_pxa_valid_messages( struct i2c_msg msgs[], int num)
++{
++	int i;
++	if (num < 1 || num > MAX_MESSAGES){
++		if( i2c_debug)
++			printk(KERN_INFO "Invalid number of messages (max=%d, num=%d)\n",
++				MAX_MESSAGES, num);
++		return -EINVAL;
++	}
++
++	/* check consistency of our messages */
++	for (i=0;i<num;i++){
++		if (&msgs[i]==NULL){
++			if( i2c_debug) printk(KERN_INFO "Msgs is NULL\n");
++			return -EINVAL;
++		} else {
++			if (msgs[i].len < 0 || msgs[i].buf == NULL){
++				if( i2c_debug)printk(KERN_INFO "Length is less than zero");
++				return -EINVAL;
++			}
++		}
++	}
++
++	return 1;
++}
++
++static int i2c_pxa_readbytes(struct i2c_adapter *i2c_adap, char *buf,
++			int count, int last)
++{
++
++	int i, timeout=0;
++	struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++
++	/* increment number of bytes to read by one -- read dummy byte */
++	for (i = 0; i <= count; i++) {
++		if (i!=0){
++			/* set ACK to NAK for last received byte ICR[ACKNAK] = 1
++			   only if not a repeated start */
++
++			if ((i == count) && last) {
++				adap->transfer( last, I2C_RECEIVE, 0);
++			}else{
++				adap->transfer( 0, I2C_RECEIVE, 1);
++			}
++
++			timeout = adap->wait_for_interrupt(I2C_RECEIVE);
++
++#ifdef DEBUG
++			if (timeout==BUS_ERROR){
++				printk(KERN_INFO "i2c_pxa_readbytes: bus error -> forcing reset\n");
++				adap->reset();
++				return I2C_RETRY;
++			} else
++#endif
++			if (timeout == -ERESTARTSYS) {
++				adap->abort();
++				return timeout;
++			} else
++			if (timeout){
++#ifdef DEBUG
++				printk(KERN_INFO "i2c_pxa_readbytes: timeout -> forcing reset\n");
++#endif
++				adap->reset();
++				return I2C_RETRY;
++			}
++
++		}
++
++		if (i) {
++			buf[i - 1] = adap->read_byte();
++		} else {
++			adap->read_byte(); /* dummy read */
++		}
++	}
++	return (i - 1);
++}
++
++static int i2c_pxa_sendbytes(struct i2c_adapter *i2c_adap, const char *buf,
++                         int count, int last)
++{
++
++	struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++	int wrcount, timeout;
++
++	for (wrcount=0; wrcount<count; ++wrcount) {
++
++		adap->write_byte(buf[wrcount]);
++		if ((wrcount==(count-1)) && last) {
++			adap->transfer( last, I2C_TRANSMIT, 0);
++		}else{
++			adap->transfer( 0, I2C_TRANSMIT, 1);
++		}
++
++		timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
++
++#ifdef DEBUG
++		if (timeout==BUS_ERROR) {
++			printk(KERN_INFO "i2c_pxa_sendbytes: bus error -> forcing reset.\n");
++			adap->reset();
++			return I2C_RETRY;
++		} else
++#endif
++		if (timeout == -ERESTARTSYS) {
++			adap->abort();
++			return timeout;
++		} else
++		if (timeout) {
++#ifdef DEBUG
++			printk(KERN_INFO "i2c_pxa_sendbytes: timeout -> forcing reset\n");
++#endif
++			adap->reset();
++			return I2C_RETRY;
++		}
++	}
++	return (wrcount);
++}
++
++
++static inline int i2c_pxa_set_ctrl_byte(struct i2c_algo_pxa_data * adap, struct i2c_msg *msg)
++{
++	u16 flags = msg->flags;
++	u8 addr;
++	addr = (u8) ( (0x7f & msg->addr) << 1 );
++	if (flags & I2C_M_RD )
++		addr |= 1;
++	if (flags & I2C_M_REV_DIR_ADDR )
++		addr ^= 1;
++	adap->write_byte(addr);
++	return 0;
++}
++
++static int i2c_pxa_do_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++{
++	struct i2c_algo_pxa_data * adap;
++	struct i2c_msg *pmsg=NULL;
++	int i;
++	int ret=0, timeout;
++
++	adap = i2c_adap->algo_data;
++
++	timeout = adap->wait_bus_not_busy();
++
++	if (timeout) {
++		return I2C_RETRY;
++	}
++
++	for (i = 0;ret >= 0 && i < num; i++) {
++		int last = i + 1 == num;
++		pmsg = &msgs[i];
++
++		ret = i2c_pxa_set_ctrl_byte(adap,pmsg);
++
++		/* Send START */
++		if (i == 0) {
++			adap->start();
++		}else{
++			adap->repeat_start();
++		}
++
++		adap->transfer(0, I2C_TRANSMIT, 0);
++
++		/* Wait for ITE (transmit empty) */
++		timeout = adap->wait_for_interrupt(I2C_TRANSMIT);
++
++#ifdef DEBUG
++		/* Check for ACK (bus error) */
++		if (timeout==BUS_ERROR){
++			printk(KERN_INFO "i2c_pxa_do_xfer: bus error -> forcing reset\n");
++			adap->reset();
++			return I2C_RETRY;
++		} else
++#endif
++		if (timeout == -ERESTARTSYS) {
++			adap->abort();
++			return timeout;
++		} else
++		if (timeout) {
++#ifdef DEBUG
++			printk(KERN_INFO "i2c_pxa_do_xfer: timeout -> forcing reset\n");
++#endif
++			adap->reset();
++			return I2C_RETRY;
++		}
++/* FIXME: handle arbitration... */
++#if 0
++		/* Check for bus arbitration loss */
++		if (adap->arbitration_loss()){
++			printk("Arbitration loss detected \n");
++			adap->reset();
++			return I2C_RETRY;
++		}
++#endif
++
++		/* Read */
++		if (pmsg->flags & I2C_M_RD) {
++			/* read bytes into buffer*/
++			ret = i2c_pxa_readbytes(i2c_adap, pmsg->buf, pmsg->len, last);
++#if DEBUG > 2
++			if (ret != pmsg->len) {
++				printk(KERN_INFO"i2c_pxa_do_xfer: read %d/%d bytes.\n",
++					ret, pmsg->len);
++			} else {
++				printk(KERN_INFO"i2c_pxa_do_xfer: read %d bytes.\n",ret);
++			}
++#endif
++		} else { /* Write */
++			ret = i2c_pxa_sendbytes(i2c_adap, pmsg->buf, pmsg->len, last);
++#if DEBUG > 2
++			if (ret != pmsg->len) {
++				printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d/%d bytes.\n",
++					ret, pmsg->len);
++			} else {
++				printk(KERN_INFO"i2c_pxa_do_xfer: wrote %d bytes.\n",ret);
++			}
++#endif
++		}
++	}
++
++	if (ret<0){
++		return ret;
++	}else{
++		return i;
++	}
++}
++
++static int i2c_pxa_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
++{
++	int retval = i2c_pxa_valid_messages( msgs, num);
++	if( retval > 0)
++	{
++		int i;
++		for (i=i2c_adap->retries; i>=0; i--){
++			int retval = i2c_pxa_do_xfer(i2c_adap,msgs,num);
++			if (retval!=I2C_RETRY){
++				return retval;
++			}
++			if( i2c_debug)printk(KERN_INFO"Retrying transmission \n");
++			udelay(100);
++		}
++		if( i2c_debug)printk(KERN_INFO"Retried %i times\n",i2c_adap->retries);
++		return -EREMOTEIO;
++
++	}
++	return retval;
++}
++
++struct i2c_algorithm i2c_pxa_algorithm  = {
++	name:                   "PXA-I2C-Algorithm",
++	id:                     I2C_ALGO_PXA,
++	master_xfer:            i2c_pxa_xfer,
++	smbus_xfer:             NULL,
++	slave_send:             NULL,
++	slave_recv:             NULL,
++	algo_control:           NULL,
++};
++
++/*
++ * registering functions to load algorithms at runtime
++ */
++int i2c_pxa_add_bus(struct i2c_adapter *i2c_adap)
++{
++	struct i2c_algo_pxa_data *adap = i2c_adap->algo_data;
++
++	printk(KERN_INFO"I2C: Adding %s.\n", i2c_adap->name);
++
++	i2c_adap->algo = &i2c_pxa_algorithm;
++
++	MOD_INC_USE_COUNT;
++
++	/* register new adapter to i2c module... */
++	i2c_add_adapter(i2c_adap);
++
++	adap->reset();
++
++	/* scan bus */
++	if (pxa_scan) {
++		int i;
++		printk(KERN_INFO "I2C: Scanning bus ");
++		for (i = 0x02; i < 0xff; i+=2) {
++			if( i==(I2C_PXA_SLAVE_ADDR<<1)) continue;
++
++			if (adap->wait_bus_not_busy()) {
++				printk(KERN_INFO "I2C: scanning bus %s - TIMEOUTed.\n",
++						i2c_adap->name);
++				return -EIO;
++			}
++			adap->write_byte(i);
++			adap->start();
++			adap->transfer(0, I2C_TRANSMIT, 0);
++
++			if ((adap->wait_for_interrupt(I2C_TRANSMIT) != BUS_ERROR)) {
++				printk("(%02x)",i>>1);
++				adap->abort();
++			} else {
++//				printk(".");
++				adap->stop();
++			}
++			udelay(adap->udelay);
++		}
++		printk("\n");
++	}
++	return 0;
++}
++
++int i2c_pxa_del_bus(struct i2c_adapter *i2c_adap)
++{
++	int res;
++	if ((res = i2c_del_adapter(i2c_adap)) < 0)
++		return res;
++
++	MOD_DEC_USE_COUNT;
++
++	printk(KERN_INFO "I2C: Removing %s.\n", i2c_adap->name);
++
++	return 0;
++}
++
++static int __init i2c_algo_pxa_init (void)
++{
++	printk(KERN_INFO "I2C: PXA algorithm module loaded.\n");
++	return 0;
++}
++
++EXPORT_SYMBOL(i2c_pxa_add_bus);
++EXPORT_SYMBOL(i2c_pxa_del_bus);
++
++MODULE_PARM(pxa_scan, "i");
++MODULE_PARM_DESC(pxa_scan, "Scan for active chips on the bus");
++
++MODULE_AUTHOR("Intrinsyc Software Inc.");
++MODULE_LICENSE("GPL");
++
++module_init(i2c_algo_pxa_init);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/i2c/i2c-pxa.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,76 @@
++/*
++ *  i2c_pxa.h
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ * 
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ */
++#ifndef _I2C_PXA_H_
++#define _I2C_PXA_H_
++
++struct i2c_algo_pxa_data
++{
++        void (*write_byte) (u8 value);
++        u8   (*read_byte) (void);
++        void (*start) (void);
++        void (*repeat_start) (void);
++        void (*stop) (void);
++        void (*abort) (void);
++        int  (*wait_bus_not_busy) (void);
++        int  (*wait_for_interrupt) (int wait_type);
++        void (*transfer) (int lastbyte, int receive, int midbyte);
++        void (*reset) (void);
++
++	int udelay;
++	int timeout;
++};
++
++#define DEF_TIMEOUT             3
++#define BUS_ERROR               (-EREMOTEIO)
++#define ACK_DELAY               0       /* time to delay before checking bus error */
++#define MAX_MESSAGES            65536   /* maximum number of messages to send */
++
++#define I2C_SLEEP_TIMEOUT       2       /* time to sleep for on i2c transactions */
++#define I2C_RETRY               (-2000) /* an error has occurred retry transmit */
++#define I2C_TRANSMIT		1
++#define I2C_RECEIVE		0
++#define I2C_PXA_SLAVE_ADDR      0x1    /* slave pxa unit address */
++#define I2C_ICR_INIT            (ICR_BEIE | ICR_IRFIE | ICR_ITEIE | ICR_GCD | ICR_SCLE) /* ICR initialization value */
++/* ICR initialize bit values 
++*                       
++*  15. FM       0 (100 Khz operation)
++*  14. UR       0 (No unit reset)
++*  13. SADIE    0 (Disables the unit from interrupting on slave addresses 
++*                                       matching its slave address)
++*  12. ALDIE    0 (Disables the unit from interrupt when it loses arbitration 
++*                                       in master mode)
++*  11. SSDIE    0 (Disables interrupts from a slave stop detected, in slave mode)  
++*  10. BEIE     1 (Enable interrupts from detected bus errors, no ACK sent)
++*  9.  IRFIE    1 (Enable interrupts from full buffer received)
++*  8.  ITEIE    1 (Enables the I2C unit to interrupt when transmit buffer empty)
++*  7.  GCD      1 (Disables i2c unit response to general call messages as a slave) 
++*  6.  IUE      0 (Disable unit until we change settings)
++*  5.  SCLE     1 (Enables the i2c clock output for master mode (drives SCL)   
++*  4.  MA       0 (Only send stop with the ICR stop bit)
++*  3.  TB       0 (We are not transmitting a byte initially)
++*  2.  ACKNAK   0 (Send an ACK after the unit receives a byte)
++*  1.  STOP     0 (Do not send a STOP)
++*  0.  START    0 (Do not send a START)
++*
++*/
++
++#define I2C_ISR_INIT            0x7FF  /* status register init */
++/* I2C status register init values 
++ *
++ * 10. BED      1 (Clear bus error detected)
++ * 9.  SAD      1 (Clear slave address detected)
++ * 7.  IRF      1 (Clear IDBR Receive Full)
++ * 6.  ITE      1 (Clear IDBR Transmit Empty)
++ * 5.  ALD      1 (Clear Arbitration Loss Detected)
++ * 4.  SSD      1 (Clear Slave Stop Detected)
++ */
++
++#endif
+--- linux-2.4.25/drivers/misc/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/misc/Config.in	2004-03-31 17:15:11.000000000 +0200
+@@ -13,5 +13,6 @@
+ dep_tristate 'Support for UCB1200 / UCB1300' CONFIG_MCP_UCB1200 $CONFIG_MCP
+ dep_tristate '  Audio / Telephony interface support' CONFIG_MCP_UCB1200_AUDIO $CONFIG_MCP_UCB1200 $CONFIG_SOUND
+ dep_tristate '  Touchscreen interface support' CONFIG_MCP_UCB1200_TS $CONFIG_MCP_UCB1200
++dep_tristate '  UCB1400 Touchscreen support' CONFIG_MCP_UCB1400_TS $CONFIG_ARCH_PXA $CONFIG_SOUND
+ 
+ endmenu
+--- linux-2.4.25/drivers/misc/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/misc/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -11,13 +11,15 @@
+ 
+ O_TARGET := misc.o
+ 
+-export-objs			:= mcp-core.o mcp-sa1100.o ucb1x00-core.o
++export-objs			:= mcp-core.o mcp-sa1100.o mcp-pxa.o \
++				   ucb1x00-core.o 
+ 
+-obj-$(CONFIG_MCP)		+= mcp-core.o
+-obj-$(CONFIG_MCP_SA1100)	+= mcp-sa1100.o
++obj-$(CONFIG_MCP_SA1100)	+= mcp-core.o mcp-sa1100.o
+ obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
+ obj-$(CONFIG_MCP_UCB1200_AUDIO)	+= ucb1x00-audio.o
+ obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-ts.o
++obj-$(CONFIG_MCP_UCB1400_TS)	+= mcp-pxa.o ucb1x00-core.o ucb1x00-ts.o
++obj-$(CONFIG_PXA_CERF_PDA)	+= cerf_ucb1400gpio.o
+ 
+ include $(TOPDIR)/Rules.make
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/cerf_ucb1400gpio.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,189 @@
++/*
++ *  cerf_ucb1400gpio.c
++ *
++ *  UCB1400 GPIO control stuff for the cerf.
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Mar 2002: Initial version [FB]
++ *    Jun 2002: Removed ac97 dependency [FB]
++ * 
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++
++#include "ucb1x00.h"
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING       0
++
++#if DEBUGGING
++static unsigned int ucb_debug = DEBUGGING;
++#else
++#define ucb_debug       0
++#endif
++
++#define UP	1
++#define DOWN	0
++
++/* -- -- */
++
++void cerf_ucb1400gpio_lcd_enable( void)
++{
++	struct ucb1x00 * ucb = ucb1x00_get();
++	if( ucb_debug > 2) printk( KERN_INFO "Enabling LCD.\n");
++	/* Enable [not] LCD_RESET to enable the LCD display */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET);
++	ucb1x00_io_write( ucb, UCB1400_GPIO_LCD_RESET, 0);
++
++	/* Enable the Contrast circuit */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA);
++	ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_ENA, 0);
++}
++
++void cerf_ucb1400gpio_lcd_disable( void)
++{
++	struct ucb1x00 * ucb = ucb1x00_get();
++	if( ucb_debug > 2) printk( KERN_INFO "Disabling LCD.\n");
++	/* Disable the Contrast circuit  */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_CONT_ENA);
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_ENA);
++
++	/* Disable [not] LCD_RESET to enable the LCD display */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_LCD_RESET);
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_LCD_RESET);
++}
++
++void cerf_ucb1400gpio_lcd_contrast_step( int direction)
++{
++	struct ucb1x00 * ucb = ucb1x00_get();
++        // Assert the chip select and the up modifier
++        ucb1x00_io_set_dir( ucb, 0, 
++			(UCB1400_GPIO_CONT_CS |
++                         UCB1400_GPIO_CONT_DOWN |
++                         UCB1400_GPIO_CONT_INC));
++
++	if( direction == DOWN)
++	{
++		if( ucb_debug > 3)
++			printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: "
++				"stepping up\n");
++		//goin' up
++		ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_DOWN, 0);
++	}
++	else
++	{
++		if( ucb_debug > 3)
++			printk(KERN_INFO "cerf_ucb1400gpio_lcd_contrast_step: "
++				"stepping down\n");
++		//goin' down
++		ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN);
++	}
++
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_CS);
++
++        // Assert the line up, down then up again
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC);
++        udelay(1);
++	ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_INC, 0);
++        udelay(1);
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_INC);
++
++        // Deassert the chip select and the up modifier
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_CONT_DOWN);
++	ucb1x00_io_write( ucb, UCB1400_GPIO_CONT_CS, 0);
++}
++
++/* -- -- */
++
++void cerf_ucb1400gpio_irda_enable( void)
++{
++	struct ucb1x00 * ucb = ucb1x00_get();
++	printk( KERN_INFO "Enabling IRDA.\n");
++	/* Enable IRDA (active low) */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE);
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_IRDA_ENABLE);
++}
++
++void cerf_ucb1400gpio_irda_disable( void)
++{
++	struct ucb1x00 * ucb = ucb1x00_get();
++	printk( KERN_INFO "Disabling IRDA.\n");
++	/* Disable IRDA (active low) */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_IRDA_ENABLE);
++	ucb1x00_io_write( ucb, UCB1400_GPIO_IRDA_ENABLE, 0);
++}
++
++/* -- -- */
++
++void cerf_ucb1400gpio_bt_enable( void)
++{
++	struct ucb1x00 * ucb = ucb1x00_get();
++	printk( KERN_INFO "Enabling Bluetooth.\n");
++	/* Enable BT (active low) */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE);
++	ucb1x00_io_write( ucb, 0, UCB1400_GPIO_BT_ENABLE);
++}
++
++void cerf_ucb1400gpio_bt_disable( void)
++{
++	struct ucb1x00 * ucb = ucb1x00_get();
++	printk( KERN_INFO "Disabling Bluetooth.\n");
++	/* Disable BT (active low) */
++	ucb1x00_io_set_dir( ucb, 0, UCB1400_GPIO_BT_ENABLE);
++	ucb1x00_io_write( ucb, UCB1400_GPIO_BT_ENABLE, 0);
++}
++
++/* -- -- */
++
++/* -- Enable Bluetooth and IRDA automatically via pseudo module -- */
++#if defined(CONFIG_BLUEZ) || defined(CONFIG_IRDA)
++static int __init cerf_ucb1400gpio_module_init (void)
++{
++#ifdef CONFIG_BLUEZ
++        cerf_ucb1400gpio_bt_enable();
++#endif
++
++#ifdef CONFIG_IRDA
++        cerf_ucb1400gpio_irda_enable();
++#endif
++	return 0;
++}
++
++static void __exit cerf_ucb1400gpio_module_exit (void)
++{
++#ifdef CONFIG_BLUEZ
++        cerf_ucb1400gpio_bt_disable();
++#endif
++
++#ifdef CONFIG_IRDA
++        cerf_ucb1400gpio_irda_disable();
++#endif
++}
++
++module_init(cerf_ucb1400gpio_module_init);
++module_exit(cerf_ucb1400gpio_module_exit);
++#endif
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/mcp-pxa.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,57 @@
++/*
++ *  linux/drivers/misc/mcp-pxa.c
++ *
++ *  2002-01-10 Jeff Sutherland <jeffs@accelent.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.
++ *
++ * NOTE: This is a quick hack to gain access to the aclink codec's
++ *       touch screen facility.  Its audio is handled by a separate
++ *       (non-mcp) driver at the present time.
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/ac97_codec.h>
++
++#include "mcp.h"
++
++
++extern int pxa_ac97_get(struct ac97_codec **codec);
++extern void pxa_ac97_put(void);
++
++
++struct mcp *mcp_get(void)
++{
++	struct ac97_codec *codec;
++	if (pxa_ac97_get(&codec) < 0)
++		return NULL;
++	return (struct mcp *)codec;
++}
++
++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
++{
++	struct ac97_codec *codec = (struct ac97_codec *)mcp;
++	codec->codec_write(codec, reg, val);
++}
++
++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
++{
++	struct ac97_codec *codec = (struct ac97_codec *)mcp;
++	return codec->codec_read(codec, reg);
++}
++
++void mcp_enable(struct mcp *mcp)
++{
++	/* 
++	 * Should we do something here to make sure the aclink
++	 * codec is alive???
++	 * A: not for now  --NP
++	*/
++}
++
++void mcp_disable(struct mcp *mcp)
++{
++}
+--- linux-2.4.25/drivers/misc/mcp.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/misc/mcp.h	2004-03-31 17:15:11.000000000 +0200
+@@ -10,16 +10,22 @@
+ #ifndef MCP_H
+ #define MCP_H
+ 
++#ifdef CONFIG_ARCH_SA1100
++#include <asm/dma.h>
++#endif
++
+ struct mcp {
+ 	struct module	*owner;
+ 	spinlock_t	lock;
+ 	int		use_count;
+ 	unsigned int	sclk_rate;
+ 	unsigned int	rw_timeout;
++#ifdef CONFIG_ARCH_SA1100
+ 	dma_device_t	dma_audio_rd;
+ 	dma_device_t	dma_audio_wr;
+ 	dma_device_t	dma_telco_rd;
+ 	dma_device_t	dma_telco_wr;
++#endif
+ 	void		(*set_telecom_divisor)(struct mcp *, unsigned int);
+ 	void		(*set_audio_divisor)(struct mcp *, unsigned int);
+ 	void		(*reg_write)(struct mcp *, unsigned int, unsigned int);
+--- linux-2.4.25/drivers/misc/ucb1x00-core.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00-core.c	2004-03-31 17:15:11.000000000 +0200
+@@ -23,12 +23,18 @@
+ #include <linux/errno.h>
+ #include <linux/interrupt.h>
+ #include <linux/pm.h>
++#include <linux/tqueue.h>
++#include <linux/config.h>
+ 
+-#include <asm/dma.h>
+-#include <asm/hardware.h>
+ #include <asm/irq.h>
+ #include <asm/mach-types.h>
++
++#ifdef CONFIG_ARCH_SA1100
++#include <asm/arch/assabet.h>
+ #include <asm/arch/shannon.h>
++#endif
++
++#include <asm/hardware.h>
+ 
+ #include "ucb1x00.h"
+ 
+@@ -155,6 +161,10 @@
+  *
+  *	If called for a synchronised ADC conversion, it may sleep
+  *	with the ADC semaphore held.
++ *	
++ *	See ucb1x00.h for definition of the UCB_ADC_DAT macro.  It
++ *	addresses a bug in the ucb1200/1300 which, of course, Philips
++ *	decided to finally fix in the ucb1400 ;-) -jws
+  */
+ unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
+ {
+@@ -218,22 +228,75 @@
+  * Since we need to read an internal register, we must re-enable
+  * SIBCLK to talk to the chip.  We leave the clock running until
+  * we have finished processing all interrupts from the chip.
++ *
++ * A restriction with interrupts exists when using the ucb1400, as
++ * the codec read/write routines may sleep while waiting for codec
++ * access completion and uses semaphores for access control to the
++ * AC97 bus.  A complete codec read cycle could take  anywhere from
++ * 60 to 100uSec so we *definitely* don't want to spin inside the
++ * interrupt handler waiting for codec access.  So, we handle the
++ * interrupt by scheduling a RT kernel thread to run in process
++ * context instead of interrupt context.
+  */
+-static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
++
++static int ucb1x00_thread(void *_ucb)
+ {
+-	struct ucb1x00 *ucb = devid;
++	struct task_struct *tsk = current;
++	DECLARE_WAITQUEUE(wait, tsk);
++	struct ucb1x00 *ucb = _ucb;
+ 	struct ucb1x00_irq *irq;
+ 	unsigned int isr, i;
+ 
+-	ucb1x00_enable(ucb);
+-	isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
+-	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
+-	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++	ucb->rtask = tsk;
+ 
+-	for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
+-		if (isr & 1 && irq->fn)
+-			irq->fn(i, irq->devid);
+-	ucb1x00_disable(ucb);
++	daemonize();
++	reparent_to_init();
++	tsk->tty = NULL;
++	tsk->policy = SCHED_FIFO;
++	tsk->rt_priority = 1;
++	strcpy(tsk->comm, "kUCB1x00d");
++
++	/* only want to receive SIGKILL */
++	spin_lock_irq(&tsk->sigmask_lock);
++	siginitsetinv(&tsk->blocked, sigmask(SIGKILL));
++	recalc_sigpending(tsk);
++	spin_unlock_irq(&tsk->sigmask_lock);
++
++	add_wait_queue(&ucb->irq_wait, &wait);
++	set_task_state(tsk, TASK_INTERRUPTIBLE);
++	complete(&ucb->complete);
++
++	for (;;) {
++		if (signal_pending(tsk))
++			break;
++		enable_irq(ucb->irq);
++		schedule();
++
++		ucb1x00_enable(ucb);
++		isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++		for (i = 0, irq = ucb->irq_handler;
++		     i < 16 && isr; 
++		     i++, isr >>= 1, irq++)
++			if (isr & 1 && irq->fn)
++				irq->fn(i, irq->devid);
++		ucb1x00_disable(ucb);
++
++		set_task_state(tsk, TASK_INTERRUPTIBLE);
++	}
++
++	remove_wait_queue(&ucb->irq_wait, &wait);
++	ucb->rtask = NULL;
++	complete_and_exit(&ucb->complete, 0);
++}
++
++static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
++{
++	struct ucb1x00 *ucb = devid;
++	disable_irq(irqnr);
++	wake_up(&ucb->irq_wait);
+ }
+ 
+ /**
+@@ -291,6 +354,11 @@
+ 		spin_lock_irqsave(&ucb->lock, flags);
+ 
+ 		ucb1x00_enable(ucb);
++
++		/* This prevents spurious interrupts on the UCB1400 */
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 1 << idx);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
+ 		if (edges & UCB_RISING) {
+ 			ucb->irq_ris_enbl |= 1 << idx;
+ 			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
+@@ -456,6 +524,7 @@
+ 	unsigned int irq_gpio_pin = 0;
+ 	int irq, default_irq = NO_IRQ;
+ 
++#ifdef CONFIG_ARCH_SA1100
+ 	if (machine_is_adsbitsy())
+ 		default_irq = IRQ_GPCIN4;
+ 
+@@ -514,12 +583,40 @@
+ 	}
+ #endif
+ 
++#endif /* CONFIG_ARCH_SA1100 */
++
++#ifdef CONFIG_ARCH_PXA_IDP
++	if (machine_is_pxa_idp()) {
++		default_irq = TOUCH_PANEL_IRQ;
++		irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ);
++		GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
++	}
++#endif
++
++#ifdef CONFIG_ARCH_TRIZEPS2
++	if (machine_is_trizeps2()) {
++		default_irq = TOUCH_PANEL_IRQ;
++		irq_gpio_pin = IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ);
++		GPDR(irq_gpio_pin) &= ~GPIO_bit(irq_gpio_pin);
++	}
++#endif
++
++
++#ifdef CONFIG_PXA_CERF_PDA
++	if (machine_is_pxa_cerf()) {
++		irq_gpio_pin = CERF_GPIO_UCB1400_IRQ;
++	}
++#endif
++
+ 	/*
+ 	 * Eventually, this will disappear.
+ 	 */
+ 	if (irq_gpio_pin)
++#ifdef CONFIG_ARCH_PXA_IDP
++		set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_FALLING_EDGE);
++#else
+ 		set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE);
+-
++#endif
+ 	irq = ucb1x00_detect_irq(ucb);
+ 	if (irq != NO_IRQ) {
+ 		if (default_irq != NO_IRQ && irq != default_irq)
+@@ -541,21 +638,7 @@
+ 
+ struct ucb1x00 *my_ucb;
+ 
+-/**
+- *	ucb1x00_get - get the UCB1x00 structure describing a chip
+- *	@ucb: UCB1x00 structure describing chip
+- *
+- *	Return the UCB1x00 structure describing a chip.
+- *
+- *	FIXME: Currently very noddy indeed, which currently doesn't
+- *	matter since we only support one chip.
+- */
+-struct ucb1x00 *ucb1x00_get(void)
+-{
+-	return my_ucb;
+-}
+-
+-static int __init ucb1x00_init(void)
++static int ucb1x00_init_helper(void)
+ {
+ 	struct mcp *mcp;
+ 	unsigned int id;
+@@ -568,23 +651,28 @@
+ 	mcp_enable(mcp);
+ 	id = mcp_reg_read(mcp, UCB_ID);
+ 
+-	if (id != UCB_ID_1200 && id != UCB_ID_1300) {
++	if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_1400) {
+ 		printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
+ 		goto out;
+ 	}
+ 
++	/* distinguish between UCB1400 revs 1B and 2A */
++	if (id == UCB_ID_1400 && mcp_reg_read(mcp, 0x00) == 0x002a)
++		id = UCB_ID_1400_BUGGY;
++
+ 	my_ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
+ 	ret = -ENOMEM;
+ 	if (!my_ucb)
+ 		goto out;
+ 
++#ifdef CONFIG_ARCH_SA1100
+ 	if (machine_is_shannon()) {
+ 		/* reset the codec */
+ 		GPDR |= SHANNON_GPIO_CODEC_RESET;
+ 		GPCR = SHANNON_GPIO_CODEC_RESET;
+ 		GPSR = SHANNON_GPIO_CODEC_RESET;
+-
+ 	}
++#endif
+ 
+ 	memset(my_ucb, 0, sizeof(struct ucb1x00));
+ 
+@@ -599,13 +687,12 @@
+ 	if (ret)
+ 		goto out;
+ 
++	init_waitqueue_head(&my_ucb->irq_wait);
+ 	ret = request_irq(my_ucb->irq, ucb1x00_irq, 0, "UCB1x00", my_ucb);
+ 	if (ret) {
+ 		printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
+ 			my_ucb->irq, ret);
+-		kfree(my_ucb);
+-		my_ucb = NULL;
+-		goto out;
++		goto irq_err;
+ 	}
+ 
+ #ifdef CONFIG_PM
+@@ -616,16 +703,55 @@
+ 		my_ucb->pmdev->data = my_ucb;
+ #endif
+ 
++	init_completion(&my_ucb->complete);
++	ret = kernel_thread(ucb1x00_thread, my_ucb, CLONE_FS | CLONE_FILES);
++	if (ret >= 0) {
++		wait_for_completion(&my_ucb->complete);
++		ret = 0;
++		goto out;
++	}
++
++	free_irq(my_ucb->irq, my_ucb);
++irq_err:
++	kfree(my_ucb);
++	my_ucb = NULL;
+ out:
+ 	mcp_disable(mcp);
+ no_mcp:
+ 	return ret;
+ }
+ 
++/**
++ *	ucb1x00_get - get the UCB1x00 structure describing a chip
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Return the UCB1x00 structure describing a chip.
++ *
++ *	FIXME: Currently very noddy indeed, which currently doesn't
++ *	matter since we only support one chip.
++ */
++struct ucb1x00 *ucb1x00_get(void)
++{
++	if( !my_ucb) ucb1x00_init_helper();
++
++	return my_ucb;
++}
++
++static int __init ucb1x00_init(void)
++{
++	/* check if driver is already initialized */
++	if( my_ucb) return 0;
++
++	return ucb1x00_init_helper();
++}
++
+ static void __exit ucb1x00_exit(void)
+ {
++	send_sig(SIGKILL, my_ucb->rtask, 1);
++	wait_for_completion(&my_ucb->complete);
+ 	free_irq(my_ucb->irq, my_ucb);
+ 	kfree(my_ucb);
++	my_ucb = 0;
+ }
+ 
+ module_init(ucb1x00_init);
+--- linux-2.4.25/drivers/misc/ucb1x00-ts.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00-ts.c	2004-03-31 17:15:11.000000000 +0200
+@@ -35,7 +35,11 @@
+ /*
+  * Define this if you want the UCB1x00 stuff to talk to the input layer
+  */
++#ifdef CONFIG_INPUT
++#define USE_INPUT
++#else
+ #undef USE_INPUT
++#endif
+ 
+ #ifndef USE_INPUT
+ 
+@@ -73,7 +77,7 @@
+ 	struct pm_dev		*pmdev;
+ #endif
+ 
+-	wait_queue_head_t	irq_wait;
++	struct semaphore	irq_wait;
+ 	struct semaphore	sem;
+ 	struct completion	init_exit;
+ 	struct task_struct	*rtask;
+@@ -259,6 +263,11 @@
+ 	input_report_abs(&ts->idev, ABS_PRESSURE, pressure);
+ }
+ 
++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
++{
++	input_report_abs(&ts->idev, ABS_PRESSURE, 0);
++}
++
+ static int ucb1x00_ts_open(struct input_dev *idev)
+ {
+ 	struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
+@@ -304,10 +313,15 @@
+  */
+ static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
+ {
+-	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+-			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+-			UCB_TS_CR_MODE_INT);
++	if (ts->ucb->id == UCB_ID_1400_BUGGY)
++		ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++				UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++				UCB_TS_CR_MODE_INT);
++	else
++		ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++				UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++				UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++				UCB_TS_CR_MODE_INT);
+ }
+ 
+ /*
+@@ -397,13 +411,13 @@
+ /*
+  * This is a RT kernel thread that handles the ADC accesses
+  * (mainly so we can use semaphores in the UCB1200 core code
+- * to serialise accesses to the ADC).
++ * to serialise accesses to the ADC).  The UCB1400 access
++ * functions are expected to be able to sleep as well.
+  */
+ static int ucb1x00_thread(void *_ts)
+ {
+ 	struct ucb1x00_ts *ts = _ts;
+ 	struct task_struct *tsk = current;
+-	DECLARE_WAITQUEUE(wait, tsk);
+ 	int valid;
+ 
+ 	ts->rtask = tsk;
+@@ -429,10 +443,8 @@
+ 
+ 	valid = 0;
+ 
+-	add_wait_queue(&ts->irq_wait, &wait);
+ 	for (;;) {
+ 		unsigned int x, y, p, val;
+-		signed long timeout;
+ 
+ 		ts->restart = 0;
+ 
+@@ -457,8 +469,6 @@
+ 		val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
+ 
+ 		if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) {
+-			set_task_state(tsk, TASK_INTERRUPTIBLE);
+-
+ 			ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+ 			ucb1x00_disable(ts->ucb);
+ 
+@@ -471,7 +481,15 @@
+ 				valid = 0;
+ 			}
+ 
+-			timeout = MAX_SCHEDULE_TIMEOUT;
++			/*
++			 * Since ucb1x00_enable_irq() might sleep due
++			 * to the way the UCB1400 regs are accessed, we
++			 * can't use set_task_state() before that call,
++			 * and not changing state before enabling the
++			 * interrupt is racy.  A semaphore solves all
++			 * those issues quite nicely.
++			 */
++			down_interruptible(&ts->irq_wait);
+ 		} else {
+ 			ucb1x00_disable(ts->ucb);
+ 
+@@ -486,16 +504,13 @@
+ 			}
+ 
+ 			set_task_state(tsk, TASK_INTERRUPTIBLE);
+-			timeout = HZ / 100;
++			schedule_timeout(HZ / 100);
+ 		}
+ 
+-		schedule_timeout(timeout);
+ 		if (signal_pending(tsk))
+ 			break;
+ 	}
+ 
+-	remove_wait_queue(&ts->irq_wait, &wait);
+-
+ 	ts->rtask = NULL;
+ 	ucb1x00_ts_evt_clear(ts);
+ 	complete_and_exit(&ts->init_exit, 0);
+@@ -509,7 +524,7 @@
+ {
+ 	struct ucb1x00_ts *ts = id;
+ 	ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+-	wake_up(&ts->irq_wait);
++	up(&ts->irq_wait);
+ }
+ 
+ static int ucb1x00_ts_startup(struct ucb1x00_ts *ts)
+@@ -525,7 +540,7 @@
+ 	if (ts->rtask)
+ 		panic("ucb1x00: rtask running?");
+ 
+-	init_waitqueue_head(&ts->irq_wait);
++	sema_init(&ts->irq_wait, 0);
+ 	ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
+ 	if (ret < 0)
+ 		goto out;
+@@ -585,7 +600,7 @@
+ 		 * after sleep.
+ 		 */
+ 		ts->restart = 1;
+-		wake_up(&ts->irq_wait);
++		up(&ts->irq_wait);
+ 	}
+ 	return 0;
+ }
+--- linux-2.4.25/drivers/misc/ucb1x00.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00.h	2004-03-31 17:15:11.000000000 +0200
+@@ -10,8 +10,47 @@
+ #ifndef UCB1200_H
+ #define UCB1200_H
+ 
++#ifdef CONFIG_ARCH_PXA
++
++/* ucb1400 aclink register mappings: */
++
++#define UCB_IO_DATA	0x5a
++#define UCB_IO_DIR	0x5c
++#define UCB_IE_RIS	0x5e
++#define UCB_IE_FAL	0x60
++#define UCB_IE_STATUS	0x62
++#define UCB_IE_CLEAR	0x62
++#define UCB_TS_CR	0x64
++#define UCB_ADC_CR	0x66
++#define UCB_ADC_DATA	0x68
++#define UCB_ID		0x7e /* 7c is mfr id, 7e part id (from aclink spec) */
++
++#define UCB_ADC_DAT(x)		((x) & 0x3ff)
++
++#else
++
++/* ucb1x00 SIB register mappings: */
++
+ #define UCB_IO_DATA	0x00
+ #define UCB_IO_DIR	0x01
++#define UCB_IE_RIS	0x02
++#define UCB_IE_FAL	0x03
++#define UCB_IE_STATUS	0x04
++#define UCB_IE_CLEAR	0x04
++#define UCB_TC_A	0x05
++#define UCB_TC_B	0x06
++#define UCB_AC_A	0x07
++#define UCB_AC_B	0x08
++#define UCB_TS_CR	0x09
++#define UCB_ADC_CR	0x0a
++#define UCB_ADC_DATA	0x0b
++#define UCB_ID		0x0c
++#define UCB_MODE	0x0d
++
++#define UCB_ADC_DAT(x)		(((x) & 0x7fe0) >> 5)
++
++#endif
++
+ 
+ #define UCB_IO_0		(1 << 0)
+ #define UCB_IO_1		(1 << 1)
+@@ -24,10 +63,6 @@
+ #define UCB_IO_8		(1 << 8)
+ #define UCB_IO_9		(1 << 9)
+ 
+-#define UCB_IE_RIS	0x02
+-#define UCB_IE_FAL	0x03
+-#define UCB_IE_STATUS	0x04
+-#define UCB_IE_CLEAR	0x04
+ #define UCB_IE_ADC		(1 << 11)
+ #define UCB_IE_TSPX		(1 << 12)
+ #define UCB_IE_TSMX		(1 << 13)
+@@ -36,11 +71,9 @@
+ 
+ #define UCB_IRQ_TSPX		12
+ 
+-#define UCB_TC_A	0x05
+ #define UCB_TC_A_LOOP		(1 << 7)	/* UCB1200 */
+ #define UCB_TC_A_AMPL		(1 << 7)	/* UCB1300 */
+ 
+-#define UCB_TC_B	0x06
+ #define UCB_TC_B_VOICE_ENA	(1 << 3)
+ #define UCB_TC_B_CLIP		(1 << 4)
+ #define UCB_TC_B_ATT		(1 << 6)
+@@ -49,14 +82,11 @@
+ #define UCB_TC_B_IN_ENA		(1 << 14)
+ #define UCB_TC_B_OUT_ENA	(1 << 15)
+ 
+-#define UCB_AC_A	0x07
+-#define UCB_AC_B	0x08
+ #define UCB_AC_B_LOOP		(1 << 8)
+ #define UCB_AC_B_MUTE		(1 << 13)
+ #define UCB_AC_B_IN_ENA		(1 << 14)
+ #define UCB_AC_B_OUT_ENA	(1 << 15)
+ 
+-#define UCB_TS_CR	0x09
+ #define UCB_TS_CR_TSMX_POW	(1 << 0)
+ #define UCB_TS_CR_TSPX_POW	(1 << 1)
+ #define UCB_TS_CR_TSMY_POW	(1 << 2)
+@@ -72,7 +102,6 @@
+ #define UCB_TS_CR_TSPX_LOW	(1 << 12)
+ #define UCB_TS_CR_TSMX_LOW	(1 << 13)
+ 
+-#define UCB_ADC_CR	0x0a
+ #define UCB_ADC_SYNC_ENA	(1 << 0)
+ #define UCB_ADC_VREFBYP_CON	(1 << 1)
+ #define UCB_ADC_INP_TSPX	(0 << 2)
+@@ -87,15 +116,13 @@
+ #define UCB_ADC_START		(1 << 7)
+ #define UCB_ADC_ENA		(1 << 15)
+ 
+-#define UCB_ADC_DATA	0x0b
+ #define UCB_ADC_DAT_VAL		(1 << 15)
+-#define UCB_ADC_DAT(x)		(((x) & 0x7fe0) >> 5)
+ 
+-#define UCB_ID		0x0c
+ #define UCB_ID_1200		0x1004
+ #define UCB_ID_1300		0x1005
++#define UCB_ID_1400		0x4304
++#define UCB_ID_1400_BUGGY	0x4303	/* fake ID */
+ 
+-#define UCB_MODE	0x0d
+ #define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
+ #define UCB_MODE_AUD_OFF_CAN	(1 << 13)
+ 
+@@ -115,6 +142,9 @@
+ 	unsigned int		irq;
+ 	struct semaphore	adc_sem;
+ 	spinlock_t		io_lock;
++	wait_queue_head_t	irq_wait;
++	struct completion	complete;
++	struct task_struct	*rtask;
+ 	u16			id;
+ 	u16			io_dir;
+ 	u16			io_out;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/Config.in	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,12 @@
++mainmenu_option next_comment
++comment 'MMC device drivers'
++tristate 'Multi Media Card support' CONFIG_MMC
++if [ "$CONFIG_MMC" = "y" -o "$CONFIG_MMC" = "m" ]; then
++   dep_tristate 'PXA250 MMC driver' CONFIG_MMC_PXA  $CONFIG_MMC
++   dep_tristate 'MMC block driver' CONFIG_MMC_BLOCK  $CONFIG_MMC
++   if [ "$CONFIG_MMC_BLOCK" = "y" -o "$CONFIG_MMC_BLOCK" = "m" ]; then
++      bool '  MMC partitioning support' CONFIG_MMC_PARTITIONS
++   fi
++fi				       
++endmenu
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,14 @@
++#
++# Makefile for MMC drivers
++#
++
++export-objs	:= mmc_core.o
++
++obj-$(CONFIG_MMC)	+= mmc_core.o # mmc_test.o
++obj-$(CONFIG_MMC_BLOCK)	+= mmc_block.o
++obj-$(CONFIG_MMC_PXA)	+= mmc_pxa.o
++# EXTRA_CFLAGS += -DCONFIG_MMC_DEBUG -DCONFIG_MMC_DEBUG_VERBOSE=2
++
++O_TARGET := mmcdrivers.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/error.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,70 @@
++/*
++ *  linux/include/linux/mmc/error.h 
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *	$Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#ifndef __MMC_ERROR_H__
++#define __MMC_ERROR_H__
++
++/* MMC protocol card error codes */
++#define MMC_CARD_STATUS_OUT_OF_RANGE (1<<31)
++#define MMC_CARD_STATUS_ADDRESS_ERROR (1<<30)
++#define MMC_CARD_STATUS_BLOCK_LEN_ERROR (1<<29)
++#define MMC_CARD_STATUS_ERASE_SEQ_ERROR (1<<28)
++#define MMC_CARD_STATUS_ERASE_PARAM (1<<27)
++#define MMC_CARD_STATUS_WP_VIOLATION (1<<26)
++#define MMC_CARD_STATUS_CARD_IS_LOCKED (1<<25)
++#define MMC_CARD_STATUS_LOCK_UNLOCK_FAILED (1<<24)
++#define MMC_CARD_STATUS_COM_CRC_ERROR (1<<23)
++#define MMC_CARD_STATUS_ILLEGAL_COMMAND (1<<22)
++#define MMC_CARD_STATUS_CARD_ECC_FAILED (1<<21)
++#define MMC_CARD_STATUS_CC_ERROR (1<<20)
++#define MMC_CARD_STATUS_ERROR (1<<19)
++#define MMC_CARD_STATUS_UNDERRUN (1<<18)
++#define MMC_CARD_STATUS_OVERRUN (1<<17)
++#define MMC_CARD_STATUS_CID_CSD_OVERWRITE (1<<16)
++#define MMC_CARD_STATUS_ERASE_RESET (1<<13)
++
++#define MMC_ERROR( fmt, args... ) printk( KERN_ERR "%s(): " fmt, __FUNCTION__, ##args )
++
++/* 
++ * Error codes returned by MMC subsystem functions and
++ * error reporting function prototypes 
++ */
++enum _mmc_error {
++/* controller errors */
++	MMC_ERROR_GENERIC = -10000,
++	MMC_ERROR_CRC_WRITE_ERROR = -10001,
++	MMC_ERROR_CRC_READ_ERROR = -10002,
++	MMC_ERROR_RES_CRC_ERROR = -10003,
++	MMC_ERROR_READ_TIME_OUT = -10004,
++	MMC_ERROR_TIME_OUT_RESPONSE = -10005,
++	MMC_ERROR_INVAL = -10006,
++/* protocol errors reported in card status (R1 response) */		
++	MMC_ERROR_OUT_OF_RANGE = -10007,
++	MMC_ERROR_ADDRESS_ERROR = -10008,
++	MMC_ERROR_BLOCK_LEN_ERROR = -10009,
++	MMC_ERROR_ERASE_SEQ_ERROR = -10010,
++	MMC_ERROR_ERASE_PARAM = -10011,
++	MMC_ERROR_WP_VIOLATION = -10012,
++	MMC_ERROR_CARD_IS_LOCKED = -10013,
++	MMC_ERROR_LOCK_UNLOCK_FAILED = -10014,
++	MMC_ERROR_COM_CRC_ERROR = -10015,
++	MMC_ERROR_ILLEGAL_COMMAND = -10016,
++	MMC_ERROR_CARD_ECC_FAILED = -10017,
++	MMC_ERROR_CC_ERROR = -10018,
++	MMC_ERROR_ERROR = -10019,
++	MMC_ERROR_UNDERRUN = -10020,
++	MMC_ERROR_OVERRUN = -10021,
++	MMC_ERROR_CID_CSD_OVERWRITE = -10022,
++	/* FIXME: incomplete */
++	MMC_ERROR_ERASE_RESET = -10025
++};
++#endif /* __MMC_ERROR_H__ */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/mmc.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,463 @@
++/*
++ *  linux/drivers/mmc/mmc.h
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ *  $Id$
++ *  
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#ifndef __MMC_P_H__
++#define __MMC_P_H__
++
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++#include <linux/slab.h>
++
++#include <linux/spinlock.h>
++
++#ifdef CONFIG_PROC_FS
++#include <linux/proc_fs.h>
++#endif
++
++#include <asm/semaphore.h>
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++
++#include "types.h"
++
++#include "error.h"
++
++#define MMC_CONTROLLERS_MAX (4)
++#define MMC_CARDS_MAX (16)
++
++/* test device */
++#define MMC_TEST_MAJOR (240)
++#define MMC_TEST_TRANSFER_MODE_DEFAULT MMC_TRANSFER_MODE_BLOCK_SINGLE
++
++/* block device */
++#define MMC_BLOCK_MAJOR (241) /* FIXME: MMC_MAJOR */
++#define MMC_BLOCK_DEVICES_MAX (1<<MINORBITS) /* FIXME */
++#define MMC_BLOCK_SECT_SIZE (512) /* FIXME */
++#define MMC_BLOCK_PARTNBITS (3)
++
++/* Device minor number encoding:
++ *   [7:6] - host
++ *   [5:3] - card slot number
++ *   [2:0] - partition number 
++ */
++#define MMC_MINOR_HOST_SHIFT (6)
++#define MMC_MINOR_CARD_MASK (0x07)
++
++/*
++ *  MMC controller abstraction
++ */
++enum _mmc_controller_state {
++	MMC_CONTROLLER_ABSENT = 0,
++	MMC_CONTROLLER_FOUND,
++	MMC_CONTROLLER_INITIALIZED,
++	MMC_CONTROLLER_UNPLUGGED
++};
++
++enum _mmc_dir {
++	MMC_READ = 1,
++	MMC_WRITE
++};
++
++enum _mmc_buftype {
++	MMC_USER = 1,
++	MMC_KERNEL
++};
++
++struct _mmc_data_transfer_req_rec {
++	mmc_dir_t cmd; /* read or write operation requested */
++	mmc_transfer_mode_t mode; /* requested data transfer mode */
++	mmc_buftype_t type; /* whether supplied buffer resides in user or kernel space */
++	char *buf; /* poiner to the caller's buffer */
++	ssize_t cnt; /* number of bytes to transfer */
++	loff_t addr; /* card address */
++	ssize_t blksz; /* block size as for CSD[READ_BL_LEN] or CSD[WRITE_BL_LEN] */
++	ssize_t nob; /* number of blocks to transfer */
++};
++
++struct _mmc_controller_tmpl_rec {
++	struct module *owner;	/* driver module */
++	char name[16];
++
++	const ssize_t block_size_max; /* max acceptable block size */
++	const ssize_t nob_max; /* max blocks per one data transfer */
++
++	int (*probe)( mmc_controller_t ); /* hardware probe */
++	int (*init)( mmc_controller_t ); /* initialize, e.g. request irq, DMA and allocate buffers */
++	void (*remove)( mmc_controller_t ); /* free resources */
++#if 0 /* CONFIG_HOTPLUG */
++	void (*attach)( void ); /|* controller hotplug callbacks *|/
++	void (*detach)( void );
++#endif
++#ifdef CONFIG_PM 
++	int (*suspend)( mmc_controller_t ); /* power management callbacks */
++	void (*resume)( mmc_controller_t );
++#endif
++	
++/* MMC protocol macros, v3.4, p.120 */
++	int (*init_card_stack)( mmc_controller_t );
++	int (*update_acq)( mmc_controller_t ); /* update card stack management data */
++	int (*single_card_acq)( mmc_controller_t );
++	int (*check_card_stack)( mmc_controller_t );
++	int (*setup_card)( mmc_controller_t, mmc_card_t );
++	int (*stream_read)( mmc_controller_t, mmc_data_transfer_req_t );
++	int (*read_block)( mmc_controller_t,  mmc_data_transfer_req_t ); 
++	int (*read_mblock)( mmc_controller_t, mmc_data_transfer_req_t  );
++	int (*stream_write)( mmc_controller_t, mmc_data_transfer_req_t  );
++	int (*write_block)( mmc_controller_t, mmc_data_transfer_req_t );
++	int (*write_mblock)( mmc_controller_t, mmc_data_transfer_req_t  );
++/* TODO:
++	int (*sg_io)( mmc_controller_t, sg_list_t );
++*/
++/* TODO: 
++ *	1) erase group macros 
++ *	   int (*erase_group)( mmc_controller_t, mmc_erase_group_info_t );
++ * 	2) write protection macros;
++ * 	   int (*set_write_prot)( mmc_controller_t, mmc_write_protection_info_t )
++ * 	3) lock/password management macros;
++ */
++};
++
++#ifndef MMC_CTRLR_BLKSZ_DEFAULT 
++#define MMC_CTRLR_BLKSZ_DEFAULT (512)
++#endif
++
++#ifndef MMC_CTRLR_NOB_DEFAULT 
++#define MMC_CTRLR_NOB_DEFAULT (1)
++#endif
++
++struct _mmc_card_rec {
++/* public card interface */
++	struct _mmc_card_info_rec info; /* see <linux/mmc/mmc.h> */
++
++/* private kernel specific data */
++	mmc_state_t state;  /* card's state as per last operation */
++	mmc_card_t next;     /* link to the stack */
++	mmc_controller_t ctrlr;		/* back reference to the controller */
++	int usage;			/* reference count */
++	int slot;			/* card's number for device reference */
++/* TODO: async I/O queue */
++#ifdef CONFIG_PROC_FS
++	proc_dir_entry_t proc;
++	char proc_name[16];
++#endif
++	unsigned long card_data[0]	/* card specific data */
++	__attribute__((aligned (sizeof(unsigned long))));
++};
++
++struct _mmc_card_stack_rec {
++	mmc_card_t first;	/* first card on the stack */
++	mmc_card_t last;	/* last card on the stack */
++	mmc_card_t selected;    /* currently selected card */
++	int ncards;
++};
++
++struct _mmc_controller_rec {
++	mmc_controller_state_t state; /* found, initialized, unplugged... */
++	int usage;		     /* reference count */
++	int slot;		     /* host's number for device reference */
++	semaphore_t io_sem;	     /* I/O serialization */
++	rwsemaphore_t update_sem;    /* card stack check/update serialization */
++
++	mmc_controller_tmpl_t tmpl; /* methods provided by the driver */
++	mmc_card_stack_rec_t stack; /* card stack management data */
++
++	u32 rca_next;  /* next RCA to assign */
++	int slot_next; /* next slot number to assign */
++#ifdef CONFIG_PROC_FS
++	char proc_name[16];
++	proc_dir_entry_t proc;
++#endif
++	unsigned long host_data[0]  /* driver can request some extra space */
++	__attribute__((aligned (sizeof(unsigned long))));
++};
++
++/*
++ * MMC core interface
++ */
++enum _mmc_reg_type {
++	MMC_REG_TYPE_USER = 1,
++	MMC_REG_TYPE_HOST,
++	MMC_REG_TYPE_CARD
++};
++
++struct _mmc_notifier_rec {
++	struct _mmc_notifier_rec *next;
++	mmc_notifier_fn_t add;
++	mmc_notifier_fn_t remove;
++};
++
++enum _mmc_response {
++	MMC_NORESPONSE = 1,
++	MMC_R1,
++	MMC_R2,
++	MMC_R3,
++	MMC_R4,
++	MMC_R5
++};
++
++#undef EXTERN
++#ifndef __MMC_CORE_IMPLEMENTATION__
++#define EXTERN extern
++#else
++#define EXTERN /* empty */
++#endif
++
++EXTERN void *mmc_register( mmc_reg_type_t, void *, size_t ); 
++EXTERN void mmc_unregister( mmc_reg_type_t, void * );
++EXTERN int mmc_update_card_stack( int );
++
++EXTERN mmc_card_t mmc_get_card( int, int );/* get reference to the card */
++EXTERN void mmc_put_card( mmc_card_t );  /* release card reference */
++
++EXTERN int mmc_notify_add( mmc_card_t ); /* user notification */
++EXTERN int mmc_notify_remove( mmc_card_t );
++
++EXTERN ssize_t mmc_read( mmc_card_t, mmc_transfer_mode_t, char *, size_t, loff_t * ); /* generic read */
++EXTERN ssize_t mmc_write( mmc_card_t, mmc_transfer_mode_t, const char *, size_t, loff_t * ); /* generic write */
++EXTERN int mmc_ioctl( mmc_card_t, unsigned int, unsigned long ); /* generic ioctl */ 
++/*
++ * TODO: [?m.b. ioctl()] to erase, lock and write protect
++ *    1) mmc_erase
++ *    2) mmc_write_prot
++ *    3) mmc_lock
++ */
++#undef EXTERN
++
++static inline mmc_card_t __mmc_card_alloc( size_t extra )
++{
++	mmc_card_t ret = kmalloc( sizeof( mmc_card_rec_t ) + extra, GFP_KERNEL );
++	
++	if ( ret ) {
++		memset( ret, 0, sizeof( mmc_card_rec_t ) + extra );
++	}
++	
++	return ret;
++}
++
++static inline void __mmc_card_free( mmc_card_t card )
++{
++	if ( card ) {
++		kfree( card );
++	}
++}
++
++static inline mmc_card_stack_t __mmc_card_stack_init( mmc_card_stack_t stack )
++{
++	mmc_card_stack_t ret = NULL;
++	if ( stack ) {
++		memset( stack, 0, sizeof( mmc_card_stack_rec_t ) );
++		ret = stack;
++	}
++	return ret;
++}
++
++static inline mmc_card_stack_t __mmc_card_stack_add( mmc_card_stack_t stack, mmc_card_t card )
++{
++	mmc_card_stack_t ret = NULL;
++	
++	if ( stack && card ) {
++		card->next = NULL;
++		
++		if ( stack->first ) {
++			stack->last->next = card;
++			stack->last = card;
++		} else 
++			stack->first = stack->last = card;
++		
++		++stack->ncards;
++		ret = stack;
++	}
++	return ret;
++}
++
++static inline mmc_card_stack_t __mmc_card_stack_remove( mmc_card_stack_t stack, mmc_card_t card )
++{
++	mmc_card_stack_t ret = NULL;
++	register mmc_card_t prev;
++	int found = FALSE;
++
++	if ( !stack || !card )
++		goto error;
++	
++	if ( stack->ncards > 0 ) {
++		if ( stack->first == card ) {
++			stack->first = stack->first->next;
++			if ( stack->last == card )
++				stack->last = stack->last->next;
++			found = TRUE;		
++		} else {
++			for ( prev = stack->first; prev; prev = prev->next )
++				if ( prev->next == card ) {
++					found = TRUE;
++					break;
++				}
++			if ( found ) {
++				if ( prev->next == stack->last )
++					stack->last = prev->next;
++				prev->next = prev->next->next;
++			}
++		}
++		if ( found ) {
++			--stack->ncards;
++			ret = stack;
++		}
++	}
++error:
++	return ret;
++}
++
++static inline void __mmc_card_stack_free( mmc_card_stack_t stack )
++{
++	mmc_card_t card, next;
++	
++	if ( stack && (stack->ncards > 0) ) {
++		card = stack->first;
++		while ( card ) {
++			next = card->next;
++			kfree( card );
++			card = next;
++		}
++		__mmc_card_stack_init( stack );
++	}
++}
++
++static inline int __mmc_card_stack_foreach( mmc_card_stack_t stack, mmc_notifier_fn_t fn, int unplugged_also )
++{
++	int ret = 0;
++	register mmc_card_t card = NULL;
++
++	if ( stack && fn ) {
++		for ( card = stack->first; card; card = card->next ) 
++			if ( (card->state != MMC_CARD_STATE_UNPLUGGED) 
++					|| unplugged_also )
++				if ( fn( card ) ) {
++					ret = -card->slot;
++					break;
++				}
++	}
++	
++	return ret;	
++}
++
++/*
++ * Debugging macros
++ */
++#ifdef CONFIG_MMC_DEBUG
++
++#define MMC_DEBUG_LEVEL0 (0)     /* major */
++#define MMC_DEBUG_LEVEL1 (1)
++#define MMC_DEBUG_LEVEL2 (2)     /* device */
++#define MMC_DEBUG_LEVEL3 (3)     /* protocol */
++#define MMC_DEBUG_LEVEL4 (4)     /* everything */
++
++#define MMC_DEBUG(n, args...) \
++if (n <=  CONFIG_MMC_DEBUG_VERBOSE) { \
++	printk(KERN_INFO __FUNCTION__ "(): " args); \
++}
++#define __ENTER0( )	MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry\n" );
++#define __LEAVE0( )	MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit\n" );
++#define __ENTER( format, args... )	MMC_DEBUG( MMC_DEBUG_LEVEL2, "entry: " format "\n", args );
++#define __LEAVE( format, args... )	MMC_DEBUG( MMC_DEBUG_LEVEL2, "exit: " format "\n", args );
++
++#define MMC_DUMP_CSD( card ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"CSD register:\n" \
++"    csd_structure=%u\n" \
++"    spec_vers=%u\n" \
++"    taac=%x\n" \
++"    nsac=%x\n" \
++"    tran_speed=%x\n" \
++"    ccc=%x\n" \
++"    read_bl_len=%u\n" \
++"    read_bl_partial=%u\n" \
++"    write_blk_misalign=%u\n" \
++"    read_blk_misalign=%u\n" \
++"    dsr_imp=%u\n" \
++"    c_size=%u\n" \
++"    vdd_r_curr_min=%u\n" \
++"    vdd_r_curr_max=%u\n" \
++"    vdd_w_curr_min=%u\n" \
++"    vdd_w_curr_max=%u\n" \
++"    c_size_mult=%u\n" \
++"    erase_grp_size=%u\n" \
++"    erase_grp_mult=%u\n" \
++"    wp_grp_size=%u\n" \
++"    wp_grp_enable=%u\n" \
++"    default_ecc=%u\n" \
++"    r2w_factor=%u\n" \
++"    write_bl_len=%u\n" \
++"    write_bl_partial=%u\n" \
++"    content_prot_app=%u\n" \
++"    file_format_grp=%u\n" \
++"    copy=%u\n" \
++"    perm_write_protect=%d\n" \
++"    tmp_write_protect=%d\n" \
++"    file_format=%d\n" \
++"    ecc=%d\n", \
++card->info.csd.csd_structure, \
++card->info.csd.spec_vers, \
++card->info.csd.taac, \
++card->info.csd.nsac, \
++card->info.csd.tran_speed, \
++card->info.csd.ccc, \
++card->info.csd.read_bl_len, \
++card->info.csd.read_bl_partial, \
++card->info.csd.write_blk_misalign, \
++card->info.csd.read_blk_misalign, \
++card->info.csd.dsr_imp, \
++card->info.csd.c_size, \
++card->info.csd.vdd_r_curr_min, \
++card->info.csd.vdd_r_curr_max, \
++card->info.csd.vdd_w_curr_min, \
++card->info.csd.vdd_w_curr_max, \
++card->info.csd.c_size_mult, \
++card->info.csd.erase_grp_size, \
++card->info.csd.erase_grp_mult, \
++card->info.csd.wp_grp_size, \
++card->info.csd.wp_grp_enable, \
++card->info.csd.default_ecc, \
++card->info.csd.r2w_factor, \
++card->info.csd.write_bl_len, \
++card->info.csd.write_bl_partial, \
++card->info.csd.content_prot_app, \
++card->info.csd.file_format_grp, \
++card->info.csd.copy, \
++card->info.csd.perm_write_protect, \
++card->info.csd.tmp_write_protect, \
++card->info.csd.file_format, \
++card->info.csd.ecc );
++
++#else /* CONFIG_MMC_DEBUG */
++#define MMC_DEBUG(n, args...)	/* empty */
++#define __ENTER0( )	/* empty */
++#define __LEAVE0( )	/* empty */
++#define __ENTER( args... )	/* empty */
++#define __LEAVE( args... )	/* empty */
++#define MMC_DUMP_CSD( card ) /* empty */
++#endif /* CONFIG_MMC_DEBUG */
++
++/* 
++ * Miscellaneous defines
++ */
++#ifndef MMC_DUMP_R1
++#define MMC_DUMP_R1( ctrlr ) /* empty */
++#endif
++#ifndef MMC_DUMP_R2
++#define MMC_DUMP_R2( ctrlr ) /* empty */
++#endif
++#ifndef MMC_DUMP_R3
++#define MMC_DUMP_R3( ctrlr ) /* empty */
++#endif
++
++#endif /* __KERNEL__ */
++
++#endif /* __MMC_P_H__ */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/mmc_block.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,989 @@
++/*
++ *  linux/drivers/mmc/mmc_block.c 
++ *  	 driver for the block device on the MMC card
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *	$Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/devfs_fs_kernel.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/hdreg.h>
++#include <linux/blkpg.h>
++#include <asm/uaccess.h>
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++
++#include "types.h"
++#include "mmc.h"
++#include "error.h"
++
++#define MAJOR_NR MMC_BLOCK_MAJOR
++#define MAJOR_NAME "mmc"
++#define DEVICE_NAME "mmc_block"
++#define DEVICE_REQUEST mmc_block_request
++#define DEVICE_NR(device) (device)
++#define DEVICE_ON(device)
++#define DEVICE_OFF(device)
++#define DEVICE_NO_RANDOM
++#include <linux/blk.h>
++/* for old kernels... */
++#ifndef QUEUE_EMPTY
++#define QUEUE_EMPTY  (!CURRENT)
++#endif
++#if LINUX_VERSION_CODE < 0x20300
++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)
++#else
++#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)
++#endif
++
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
++#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
++#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
++#else
++#define BLK_INC_USE_COUNT do {} while(0)
++#define BLK_DEC_USE_COUNT do {} while(0)
++#endif
++
++#define MMC_BLOCK_RAW_DEVICE( device ) ((device>>MMC_BLOCK_PARTNBITS)<<MMC_BLOCK_PARTNBITS)
++#define MMC_BLOCK_MKDEV( host, slot ) \
++	MKDEV( MMC_BLOCK_MAJOR, \
++	(host<<MMC_MINOR_HOST_SHIFT) \
++	| (slot<<MMC_BLOCK_PARTNBITS) )
++
++typedef struct _mmc_block_device mmc_block_device_rec_t;
++typedef struct _mmc_block_device *mmc_block_device_t;
++
++struct _mmc_block_device {
++	mmc_card_t card;
++	int host;
++	int slot;
++	kdev_t rdev;
++	int usage;
++	semaphore_t sem;
++};
++
++static int mmc_block_blk_sizes[1<<MINORBITS];
++static int mmc_block_blk_blksizes[1<<MINORBITS];
++static int mmc_block_hardsect_sizes[1<<MINORBITS];
++static struct hd_struct mmc_block_partitions[1<<MINORBITS];
++
++/* Accessed under device table lock */
++static gendisk_rec_t mmc_block_gendisk = {
++	major:		MMC_BLOCK_MAJOR,
++	major_name:	MAJOR_NAME,
++	minor_shift:	MMC_BLOCK_PARTNBITS,
++	max_p:		(1<<MMC_BLOCK_PARTNBITS),
++	sizes:		mmc_block_blk_sizes,
++	part:		mmc_block_partitions
++};
++
++static mmc_block_device_rec_t mmc_block_device[1<<MINORBITS];
++static rwsemaphore_t mmc_block_device_sem;
++
++static inline void __mmc_block_rdlock_devices( void )
++{
++	down_read( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_rdunlock_devices( void )
++{
++	up_read( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_wrlock_devices( void )
++{
++	down_write( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_wrunlock_devices( void )
++{
++	up_write( &mmc_block_device_sem );
++}
++
++static inline void __mmc_block_lock_device( kdev_t rdev )
++{
++	__mmc_block_rdlock_devices();
++	down( &mmc_block_device[MINOR( rdev )].sem );
++}
++
++static inline void __mmc_block_unlock_device( kdev_t rdev )
++{
++	up( &mmc_block_device[MINOR( rdev )].sem );
++	__mmc_block_rdunlock_devices();
++}
++
++static inline void __mmc_block_device_init( int minor )
++{
++	mmc_block_device_t dev = &mmc_block_device[minor];
++	
++	dev->usage = 0;
++	dev->card = NULL;
++	dev->host = minor >> MMC_MINOR_HOST_SHIFT;
++	dev->slot = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS;
++	dev->rdev = MKDEV( MMC_BLOCK_MAJOR, minor );
++}
++
++static inline int __mmc_block_validate_device( kdev_t rdev )
++{
++	int ret = -1;
++	int minor = MINOR( rdev );
++	
++	if ( mmc_block_device[minor].card 
++			&& (mmc_block_gendisk.part[minor].nr_sects > 0) )
++		ret = 0;
++
++	return ret;
++}
++
++static inline int __mmc_block_invalidate_card( mmc_card_t card, int invalidate )
++{
++	int ret = 0;
++	kdev_t start;
++	int minor;
++
++	__ENTER( "card = 0x%p", card );
++	
++	if ( card && card->ctrlr ) {
++		register int i;
++		
++		start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot );
++		minor = MINOR( start );
++
++		__mmc_block_wrlock_devices();
++		for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++			if ( invalidate )
++				invalidate_device( start + i, 0 );
++			
++			__mmc_block_device_init( minor + i );
++			
++			mmc_block_gendisk.part[minor + i].nr_sects = 0;
++			mmc_block_gendisk.part[minor + i].start_sect = 0;
++		}
++		__mmc_block_wrunlock_devices();
++	}
++	
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static inline int mmc_block_invalidate_card( int host, int slot, int invalidate )
++{
++	int ret = 0;
++	kdev_t start;
++	int minor;
++
++	__ENTER( "host=%d slot=%d", host, slot );
++	
++	if ( (host >= 0) && (slot >= 0) ) {
++		register int i;
++		mmc_card_t card = NULL;
++		
++		start = MMC_BLOCK_MKDEV( host, slot );
++		minor = MINOR( start );
++
++		__mmc_block_wrlock_devices();
++		for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++			if ( !card ) 
++				card = mmc_block_device[minor + i].card;
++			
++			if ( invalidate )
++				invalidate_device( start + i, 0 );
++			
++			__mmc_block_device_init( minor + i );
++			
++			mmc_block_gendisk.part[minor + i].nr_sects = 0;
++			mmc_block_gendisk.part[minor + i].start_sect = 0;
++		}
++		if ( card )
++			mmc_put_card( card );
++		__mmc_block_wrunlock_devices();
++	}
++	
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++/* Get device reference locked for writing */
++static inline mmc_block_device_t __mmc_block_get_device( kdev_t rdev )
++{
++	mmc_block_device_t ret = NULL;
++	u8 minor = MINOR( rdev );
++	int host_no, card_no;
++
++	__ENTER( "rdev=%x:%x", MAJOR( rdev ), MINOR( rdev ) );
++
++	host_no = minor >> MMC_MINOR_HOST_SHIFT;
++	if ( host_no >= MMC_CONTROLLERS_MAX )
++		goto error;
++
++	card_no = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS;
++	if ( card_no >= MMC_CARDS_MAX )
++		goto error;
++	
++	__mmc_block_lock_device( rdev );
++	if ( __mmc_block_validate_device( rdev ) ) {
++		__mmc_block_unlock_device( rdev );	
++		goto error;
++	}
++
++	ret = &mmc_block_device[minor];
++	MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n",
++			MAJOR( ret->rdev ), MINOR( ret->rdev ), 
++			ret->card, ret->usage );
++error:
++	__LEAVE( "ret=0x%p", ret );
++	return ret;
++}
++
++/* Unlocks the device */
++static inline void __mmc_block_put_device( mmc_block_device_t dev )
++{
++	__ENTER0();
++	
++	if ( dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n",
++				MAJOR( dev->rdev ), MINOR( dev->rdev ), 
++				dev->card, dev->usage );
++		__mmc_block_unlock_device( dev->rdev );
++	}
++	
++	__LEAVE0();
++}
++
++/* Atomically increases use count of the valid device */
++static inline mmc_block_device_t mmc_block_get_device( kdev_t rdev )
++{
++	mmc_block_device_t ret = NULL;
++	
++	__ENTER0();
++	
++	ret = __mmc_block_get_device( rdev );
++	if ( !ret )
++		goto error;
++	
++	ret->usage++;
++	__mmc_block_put_device( ret );
++error:
++	__LEAVE( "ret=0x%p dusage=%d card=0x%p cusage=%d",
++			ret, ret ? ret->usage : -1, 
++			ret ? ret->card : NULL, 
++			ret ? (ret->card ? ret->card->usage : -1) : -1 );
++	return ret;
++}
++
++/* Check is there references to the card */
++static inline int __mmc_block_check_card( kdev_t rdev ) 
++{
++	int ret = TRUE;
++	int start = MINOR( MMC_BLOCK_RAW_DEVICE( rdev ) );
++	register int i;
++
++	for ( i = 0; i < mmc_block_gendisk.max_p; i++ )
++		if ( mmc_block_device[start + i].usage > 0 ) {
++			ret = FALSE;
++			break;
++		}
++
++	return ret;
++}
++
++/* Atomically decreases device use count */
++static inline void mmc_block_put_device( mmc_block_device_t dev )
++{
++	__ENTER0();
++	
++	if ( dev ) {
++		int invalidate = FALSE;
++		
++		__mmc_block_get_device( dev->rdev );
++		if ( dev->usage > 0 )
++			--dev->usage;
++		
++		if ( dev->usage ) {
++			__mmc_block_put_device( dev );
++			goto out;
++
++		} else {
++			int host, slot;
++			mmc_card_t card = NULL;
++			
++			invalidate = __mmc_block_check_card( dev->rdev );	
++			if ( invalidate ) {
++				host = dev->card->ctrlr->slot;
++				slot = dev->card->slot;
++
++				if ( dev->card ) {
++					card = dev->card;
++					mmc_put_card( dev->card );
++					dev->card = NULL;
++				}
++			}
++			__mmc_block_put_device( dev );
++
++			if ( invalidate )
++				__mmc_block_invalidate_card( card, TRUE );
++		}
++		
++	}
++out:
++	__LEAVE0();
++}
++
++static int mmc_block_open( struct inode *inode, struct file *file )
++{
++	int ret = -ENODEV;
++	mmc_block_device_t dev = NULL;
++	
++	__ENTER0();
++
++	if ( !inode || !file )
++		goto error;
++	
++	BLK_INC_USE_COUNT;
++	
++	check_disk_change( inode->i_rdev );
++	
++	dev = mmc_block_get_device( inode->i_rdev );
++	if ( !dev )
++		goto error;
++	
++	dev = __mmc_block_get_device( inode->i_rdev );
++	if ( !dev )
++		goto error;
++	
++	if ( file->f_mode & FMODE_WRITE ) { /* FIXME */
++		if ( dev->usage > 1 ) {
++			ret = -EBUSY;
++			__mmc_block_put_device( dev );
++			mmc_block_put_device( dev );
++			goto error;
++		}
++	}
++	
++	__mmc_block_put_device( dev );
++	
++	if ( file )
++		file->private_data = dev;
++
++	ret = 0;
++	goto out;
++error:
++	BLK_DEC_USE_COUNT;
++out:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static int mmc_block_release( struct inode *inode, struct file *file )
++{
++	int ret = -EINVAL;
++	mmc_block_device_t dev = NULL;
++	
++	__ENTER( "inode=0x%p file=0x%p rdev=(%x:%x)", inode, file,
++			inode ? MAJOR( inode->i_rdev ) : 0xff,
++			inode ? MINOR( inode->i_rdev ) : 0xff );
++
++	if ( !file && !inode )
++		goto error;
++	
++	if ( file )
++		dev = file->private_data;
++	else
++		dev = __mmc_block_get_device( inode->i_rdev );
++
++	if ( !dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" );
++		goto error;
++	}
++	
++	if ( file ) {
++		mmc_block_put_device( dev );
++		file->private_data = NULL;
++
++	} else {
++		int invalidate = FALSE;
++		
++		if ( dev->usage > 0 )
++			--dev->usage;
++		
++		if ( dev->usage ) {
++			__mmc_block_put_device( dev );
++			goto out;
++			
++		} else {
++			int host, slot;
++			mmc_card_t card = NULL;
++			
++			invalidate = __mmc_block_check_card( dev->rdev );	
++			if ( invalidate ) {
++				host = dev->card->ctrlr->slot;
++				slot = dev->card->slot;
++
++				if ( dev->card ) {
++					card = dev->card;
++					mmc_put_card( dev->card );
++					dev->card = NULL;
++				}
++			}
++			__mmc_block_put_device( dev );
++
++			if ( invalidate )
++				__mmc_block_invalidate_card( card, TRUE );
++	
++		}
++	}
++	
++out:
++	BLK_DEC_USE_COUNT;
++	ret = 0;
++error:
++	__LEAVE0();
++	return ret;
++}  
++
++static int mmc_block_check_disk_change( kdev_t rdev )
++{
++	int ret = 0;
++#if 0
++	mmc_block_device_t dev = &mmc_block_device[MINOR( rdev )];
++	
++	__mmc_block_lock_device( rdev );
++	if ( !dev->card )
++		ret = 1;
++	__mmc_block_unlock_device( rdev );
++#else
++	ret = 1;
++#endif
++	return ret;
++}
++
++static int mmc_block_revalidate( kdev_t rdev )
++{
++	int ret = 1;
++	mmc_card_t card;
++	mmc_block_device_t dev;
++	kdev_t start = MMC_BLOCK_RAW_DEVICE( rdev );
++	int minor = MINOR( start );
++	int host, slot;
++	int i;
++	
++	__ENTER0();
++
++	(void)mmc_update_card_stack( MINOR( start )>>MMC_MINOR_HOST_SHIFT );
++
++	__mmc_block_wrlock_devices();
++
++	dev = &mmc_block_device[minor];
++	host = dev->host;
++	slot = dev->slot;
++
++	if ( dev->card ) { /* card has not been changed actually */
++		__mmc_block_wrunlock_devices();
++		goto out;
++		
++	} else {
++		card = mmc_get_card( host, slot );
++		if ( !card ) {
++			MMC_DEBUG( MMC_DEBUG_LEVEL2, "failed to get card: "
++					"host=%d, slot=%d\n", host, slot );
++			__mmc_block_wrunlock_devices();
++			goto error;
++		}
++		dev->card = card;
++	}
++	__mmc_block_wrunlock_devices();
++ 	/* FIXME */
++	__mmc_block_rdlock_devices(); /* handle the request for sector 0 */
++	grok_partitions( &mmc_block_gendisk, MINOR( start ),
++			 mmc_block_gendisk.max_p,
++			 card->info.capacity>>9 /* sectors */
++		       );
++	__mmc_block_rdunlock_devices();
++	/* FIXME */
++	__mmc_block_wrlock_devices();
++	for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++		int minor = MINOR( i );
++		
++		dev = &mmc_block_device[minor];
++		if ( mmc_block_gendisk.part[minor].nr_sects > 0 )
++			dev->card = card;
++	}
++	__mmc_block_wrunlock_devices();
++out:
++error:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static void mmc_block_handle_request( void )
++{
++	struct request *request;
++	mmc_block_device_t dev;
++	mmc_card_t card;
++	char *buf;
++	loff_t pos;
++	unsigned int result = 0;
++
++	for (;;) {
++		int minor;
++		
++		INIT_REQUEST;
++		request = CURRENT;
++		spin_unlock_irq( &io_request_lock );
++		
++		minor = MINOR( request->rq_dev );
++		dev = __mmc_block_get_device( request->rq_dev );
++		if ( !dev ) {
++			MMC_DEBUG( MMC_DEBUG_LEVEL2, "invalid device (%x:%x)\n",
++					MAJOR( request->rq_dev ), minor );
++				
++			goto end_req;
++		}
++		
++		card = dev->card;
++		(void)__mmc_block_put_device( dev );
++		
++		MMC_DEBUG( MMC_DEBUG_LEVEL2, 
++//		printk( KERN_INFO __FUNCTION__"(): "
++				"request %p: cmd %i sec %li (nr. %li)\n", 
++				CURRENT, CURRENT->cmd, CURRENT->sector, 
++				CURRENT->current_nr_sectors );
++		
++		if ( request->current_nr_sectors >
++				mmc_block_gendisk.part[minor].nr_sects )
++			goto end_req;
++		
++		// Handle the request
++		// TODO: handle clusterred requests in multiple block transfer mode 
++		buf = request->buffer;
++		pos = (mmc_block_gendisk.part[minor].start_sect +
++			request->sector) * MMC_BLOCK_SECT_SIZE;
++		
++		switch ( request->cmd )
++		{
++			int i, ret;
++			
++			case READ:
++#if 0
++				ret = mmc_read( card, 
++					(request->current_nr_sectors > 1) ?
++					MMC_TRANSFER_MODE_BLOCK_MULTIPLE :
++					MMC_TRANSFER_MODE_BLOCK_SINGLE,
++					buf, 
++					request->current_nr_sectors 
++					     * MMC_BLOCK_SECT_SIZE, /* FIXME */
++					&pos );
++				if ( ret < 0 ) 
++					goto end_req;
++				
++#else
++				for ( i = 0;
++				      i < request->current_nr_sectors;
++				      i++ ) {
++					ret = mmc_read( card,
++						MMC_TRANSFER_MODE_BLOCK_SINGLE,
++						buf,
++						MMC_BLOCK_SECT_SIZE, /* FIXME */
++						&pos );
++					if ( ret < 0 )
++						goto end_req;
++					else
++						buf += ret;
++				}
++#endif
++				result = 1;
++				break;
++
++			case WRITE:
++			// TODO: Read only device
++#if 0
++				ret = mmc_write( card, 
++					(request->current_nr_sectors > 1) ?
++					MMC_TRANSFER_MODE_BLOCK_MULTIPLE :
++					MMC_TRANSFER_MODE_BLOCK_SINGLE,
++					buf, 
++					request->current_nr_sectors 
++					    * MMC_BLOCK_SECT_SIZE, /* FIXME */
++					&pos );
++				if ( ret < 0 ) 
++					goto end_req;
++				
++#else
++				for ( i = 0;
++				      i < request->current_nr_sectors;
++				      i++ ) {
++					ret = mmc_write( card,
++						MMC_TRANSFER_MODE_BLOCK_SINGLE,
++						buf,
++						MMC_BLOCK_SECT_SIZE, /* FIXME */
++						&pos ); 
++					if ( ret < 0 )
++						goto end_req;
++					else
++						buf += ret;
++				}
++#endif
++				result = 1;
++				break;
++		}
++
++end_req:
++		__LEAVE( "result=%d", result );
++		spin_lock_irq( &io_request_lock );
++		end_request( result );
++	}
++}
++
++static volatile int leaving = 0;
++static DECLARE_MUTEX_LOCKED( thread_sem );
++static DECLARE_WAIT_QUEUE_HEAD( thr_wq );
++static pid_t thr_id = -1;
++
++int mmc_block_thread( void *arg )
++{
++	struct task_struct *task = current;
++	DECLARE_WAITQUEUE(wait, task);
++
++	__ENTER0();
++	
++	task->session = 1;
++	task->pgrp = 1;
++	task->flags |= PF_MEMALLOC;
++	strcpy( task->comm, "mmcblockd" );
++	task->tty = NULL;
++	spin_lock_irq( &task->sigmask_lock );
++	sigfillset( &task->blocked );
++	recalc_sigpending( task );
++	spin_unlock_irq( &task->sigmask_lock );
++	exit_mm( task );
++	exit_files( task );
++	exit_sighand( task );
++	exit_fs( task );
++
++	while ( !leaving ) {
++		add_wait_queue( &thr_wq, &wait);
++		set_current_state( TASK_INTERRUPTIBLE );
++		spin_lock_irq( &io_request_lock );
++		if ( QUEUE_EMPTY || QUEUE_PLUGGED ) {
++			spin_unlock_irq( &io_request_lock );
++			schedule();
++			remove_wait_queue( &thr_wq, &wait ); 
++		} else {
++			remove_wait_queue( &thr_wq, &wait ); 
++			set_current_state( TASK_RUNNING );
++			mmc_block_handle_request(); /* handle the request */
++			spin_unlock_irq( &io_request_lock );
++		}
++	}
++
++	up( &thread_sem );
++	
++	__LEAVE0();
++	return 0;
++}
++
++#if LINUX_VERSION_CODE < 0x20300
++#define RQFUNC_ARG void
++#else
++#define RQFUNC_ARG request_queue_t *q
++#endif
++
++static void mmc_block_request( RQFUNC_ARG )
++{
++	wake_up( &thr_wq );
++}
++
++static int mmc_block_ioctl( struct inode * inode, struct file * file,
++		      unsigned int cmd, unsigned long arg )
++{
++	int ret = -ENODEV;
++	mmc_block_device_t dev;
++	mmc_card_t card;
++	int minor;
++	__ENTER0();
++	
++	if ( !inode || !file ) {
++		ret = -EINVAL;
++		goto error;
++	}
++	minor = MINOR( inode->i_rdev );
++	
++	dev = __mmc_block_get_device( inode->i_rdev );
++	if ( !dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" );
++		goto error;
++	}
++	
++	card = dev->card; 
++	__mmc_block_put_device( dev );
++	
++	switch ( cmd ) {
++	case BLKGETSIZE:   /* Return device size */
++		{
++			unsigned long value;
++			
++			__mmc_block_rdlock_devices();
++			value = mmc_block_gendisk.part[minor].nr_sects;
++			__mmc_block_rdunlock_devices();
++			
++			if ( put_user( value, (unsigned long *) arg) ) {
++				ret = -EFAULT;
++				goto error;
++			}
++		}
++		break;
++
++#ifdef BLKGETSIZE64
++	case BLKGETSIZE64:
++		{
++			unsigned long value;
++			
++			__mmc_block_rdlock_devices();
++			value = mmc_block_gendisk.part[minor].nr_sects;
++			__mmc_block_rdunlock_devices();
++			
++			if ( put_user( (u64)value, (u64 *) arg) ) {
++				ret = -EFAULT;
++				goto error;
++			}
++		}
++		break;
++#endif
++
++	case HDIO_GETGEO:
++		{
++			struct hd_geometry geo;
++			
++			ret = !access_ok( VERIFY_WRITE, arg, sizeof( geo ) );
++			if ( ret ) {
++				ret = -EFAULT;
++				goto error;
++			}
++
++			geo.heads = 1;
++			geo.sectors = 1;
++
++			__mmc_block_rdlock_devices();
++			geo.cylinders = mmc_block_gendisk.part[minor].nr_sects;
++			geo.start = mmc_block_gendisk.part[minor].start_sect;
++			__mmc_block_rdunlock_devices();
++
++			if ( copy_to_user( (int *)arg, &geo, sizeof( geo ) ) ) {
++				ret = -EFAULT;
++				goto error;
++			}
++		}
++		break;
++		
++	case BLKRRPART:
++		if ( !capable( CAP_SYS_ADMIN ) ) {
++			ret = -EACCES;
++			goto error;
++		}
++		(void)mmc_block_revalidate( inode->i_rdev );
++		break;
++		
++	default:
++		ret = blk_ioctl( inode->i_rdev, cmd, arg );
++		goto out;
++	}
++
++	ret = 0;
++error:	
++out:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++#if LINUX_VERSION_CODE < 0x20326
++static struct file_operations mmc_block_fops =
++{
++	open: 			mmc_block_open,
++	ioctl:			mmc_block_ioctl,
++	release:		mmc_block_release,
++	check_media_change:	mmc_block_check_disk_change,
++	revalidate:		mmc_block_revalidate,
++	read:			block_read,
++	write:			block_write
++};
++#else
++static struct block_device_operations mmc_block_fops = 
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
++	owner:			THIS_MODULE,
++#endif
++	open:			mmc_block_open,
++	release:		mmc_block_release,
++	ioctl:			mmc_block_ioctl,
++	check_media_change:	mmc_block_check_disk_change,
++	revalidate:		mmc_block_revalidate
++};
++#endif
++
++
++static int mmc_block_notify_add( mmc_card_t card )
++{
++	int ret = -1;
++	mmc_block_device_t dev;
++	kdev_t start;
++	int minor;
++
++	__ENTER0();
++	
++	if ( !card || !card->ctrlr ) 
++		goto error;
++	
++	start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot );
++	dev = &mmc_block_device[MINOR( start )];
++		
++	__mmc_block_wrlock_devices();
++	if ( !dev->card ) {
++		dev->card = card;
++		ret = 0;
++	}
++	__mmc_block_wrunlock_devices();
++
++	if ( !ret ) {
++		int i;
++
++		/* allow to read partition table */
++		__mmc_block_rdlock_devices(); 
++		grok_partitions( &mmc_block_gendisk, MINOR( start ),
++			 mmc_block_gendisk.max_p,
++			 card->info.capacity>>9 /* sectors */
++		);
++		__mmc_block_rdunlock_devices();
++		
++		__mmc_block_wrlock_devices();
++		for ( i = start + mmc_block_gendisk.max_p - 1; i >= 0; --i ) {
++			minor = MINOR( i );
++			dev = &mmc_block_device[minor];
++			if ( mmc_block_gendisk.part[minor].nr_sects > 0 )
++				dev->card = card;
++		}
++		__mmc_block_wrunlock_devices();
++	}
++error:	
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++
++static int mmc_block_notify_remove( mmc_card_t card )
++{
++	int ret = -1;
++	
++	__ENTER( "card=0x%p", card );
++	
++	if ( card && card->ctrlr )
++		ret = __mmc_block_invalidate_card( card, FALSE );
++	
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static mmc_notifier_rec_t mmc_block_notifier = {
++	add: mmc_block_notify_add,
++	remove: mmc_block_notify_remove
++};
++
++static int __init mmc_block_module_init( void )
++{
++	int ret = -ENODEV;
++	int i;
++
++	__ENTER0();
++	
++	init_rwsem( &mmc_block_device_sem );
++	
++	if ( devfs_register_blkdev( MAJOR_NR, MAJOR_NAME, &mmc_block_fops ) ) {
++		MMC_ERROR( "Can't allocate major number %d for MMC block devices.\n", MMC_BLOCK_MAJOR );
++		ret = -EAGAIN;
++		goto error;
++	}
++	
++	for ( i = 0; i < (1<<MINORBITS); i++ ) {
++		__mmc_block_device_init( i );
++		init_MUTEX( &mmc_block_device[i].sem );
++
++		/* We fill it in at open() time. */
++		mmc_block_blk_sizes[i] = 0;
++		mmc_block_blk_blksizes[i] = BLOCK_SIZE;
++		mmc_block_hardsect_sizes[i] = 0;
++	}
++	
++	init_waitqueue_head( &thr_wq );
++	/* Allow the block size to default to BLOCK_SIZE. */
++	blksize_size[MAJOR_NR] = mmc_block_blk_blksizes;
++	hardsect_size[MAJOR_NR] = mmc_block_hardsect_sizes;
++	/* Gendisk stuff */
++	memset( mmc_block_partitions, 0, sizeof( mmc_block_partitions ) );
++	add_gendisk( &mmc_block_gendisk );
++
++/* FIXME: per controller request queue, I/O and card stack update threads */	
++	blk_init_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ), &mmc_block_request );
++	thr_id = kernel_thread( mmc_block_thread, NULL, 
++			CLONE_FS|CLONE_FILES|CLONE_SIGHAND );
++
++	if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_block_notifier, 0 ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" );
++		goto error;
++	}
++
++	ret = 0;
++	goto out;
++error:
++	if ( thr_id != -1 ) {
++/* quit the thread */
++		leaving = 1;
++		wake_up(&thr_wq);
++	
++		down(&thread_sem);
++	}
++	blksize_size[MAJOR_NR] = NULL;
++	blk_size[MAJOR_NR] = NULL;
++	hardsect_size[MAJOR_NR] = NULL;
++out:	
++	__LEAVE0();
++	return ret;
++}
++
++static void __exit mmc_block_module_cleanup( void )
++{
++/* quit the thread */
++	leaving = 1;
++	wake_up(&thr_wq);
++	
++	down(&thread_sem);
++	
++	mmc_unregister( MMC_REG_TYPE_USER, &mmc_block_notifier );
++	del_gendisk( &mmc_block_gendisk );
++	devfs_unregister_blkdev( MAJOR_NR, MAJOR_NAME );
++	
++	blk_cleanup_queue( BLK_DEFAULT_QUEUE( MAJOR_NR ) );
++	blksize_size[MAJOR_NR] = NULL;
++	blk_size[MAJOR_NR] = NULL;
++	hardsect_size[MAJOR_NR] = NULL;
++}
++
++EXPORT_NO_SYMBOLS;
++
++module_init( mmc_block_module_init );
++module_exit( mmc_block_module_cleanup );
++
++
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/mmc_core.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,1124 @@
++/*
++ *  linux/drivers/mmc/mmc_core.c 
++ *  	MultiMediaCard subsystem core implementation
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *	$Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++
++#include <linux/slab.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#ifdef CONFIG_PM
++#include <linux/pm.h>
++#endif
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++#include <mmc/ioctl.h>
++
++#include "types.h"
++
++#define __MMC_CORE_IMPLEMENTATION__
++#include "mmc.h"
++
++/* MMC controllers registered in the system */ 
++static mmc_controller_t mmc_controller[MMC_CONTROLLERS_MAX];
++static int mmc_ncontrollers = 0;
++static rwsemaphore_t mmc_controller_sem; /* controller table lock */
++#ifdef CONFIG_PM
++static struct pm_dev *mmc_pm_dev = NULL;
++#endif
++
++/* users' notification list */
++static mmc_notifier_t mmc_notifier = NULL;
++static rwsemaphore_t mmc_notifier_sem; /* notifiers' list lock */ 
++#ifdef CONFIG_PROC_FS
++static proc_dir_entry_t mmc_proc_dir = NULL;
++#endif
++
++/************************************************
++ * service function prototypes and declarations *
++ ************************************************/
++static inline int mmc_acquire_io( mmc_controller_t ctrlr, mmc_card_t card )
++{
++	int ret = -EIO;
++
++	__ENTER0();
++	
++	if ( !card || !ctrlr ) {
++		ret = -EINVAL;
++		goto error;
++	}
++#ifdef CONFIG_HOTPLUG
++/* TODO: account for controller removal */
++#endif
++	down( &ctrlr->io_sem );
++#if 0	
++	down_read( &ctrlr->update_sem ); /* FIXME */
++	if ( card->state != MMC_CARD_STATE_UNPLUGGED )
++		ret = 0;
++	up_read( &ctrlr->update_sem );
++	
++	if ( ret )
++		up( &ctrlr->io_sem );
++#else
++	ret = 0;
++#endif
++
++error:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static inline void mmc_release_io( mmc_controller_t ctrlr, mmc_card_t card )
++{
++	__ENTER0();
++#ifdef CONFIG_HOTPLUG
++/* TODO: account for controller removal */
++#endif
++	if ( !card && !ctrlr ) { /* FIXME */
++		MMC_DEBUG( MMC_DEBUG_LEVEL2, "bad card reference\n" );
++		goto error;
++	}
++	up( &ctrlr->io_sem );	
++error:
++	__LEAVE0();
++}
++
++/* TODO: there should be a separate context to be awaken 
++ * by the card intertion interrupt; called under ctrlr->update_sem
++ * held down by now */
++static int __mmc_update_card_stack( mmc_controller_t ctrlr )
++{
++	int ret = -1;
++	mmc_card_t card, prev;
++	
++	__ENTER0();
++	
++	if ( !ctrlr || !ctrlr->tmpl )
++		goto error;
++	
++	/* check unplugged cards first... */
++	if ( (ret = ctrlr->tmpl->check_card_stack( ctrlr )) )
++		goto error;
++	
++	/* unregister unplugged cards and free 'em immediately */
++	if ( ctrlr->stack.ncards > 0 ) {
++		prev = ctrlr->stack.first;
++		/* process the stack tail first */
++		if ( prev->next ) {
++			card = prev->next; 
++			while ( card ) {
++				if ( card->state == MMC_CARD_STATE_UNPLUGGED ) {
++					if ( ctrlr->stack.selected == card )
++						ctrlr->stack.selected = NULL;
++#ifdef CONFIG_PROC_FS
++					if ( card->proc ) {
++						remove_proc_entry( card->proc_name, ctrlr->proc );
++						card->proc = NULL;
++					}
++#endif
++					ctrlr->slot_next = card->slot; /* FIXME */
++					prev->next = card->next;
++					if ( ctrlr->stack.last == card )
++						ctrlr->stack.last = prev;
++					/* FIXME: controller use count */
++					mmc_notify_remove( card );
++					--ctrlr->stack.ncards;
++					if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) {
++						--ctrlr->usage;
++						MMC_DEBUG( MMC_DEBUG_LEVEL2,
++							"'%s' use count "
++							"decreased (%d)\n",
++							ctrlr->tmpl->name,
++							ctrlr->usage );
++						__MOD_DEC_USE_COUNT( 
++							ctrlr->tmpl->owner );
++					}
++					__mmc_card_free( card );
++				
++					card = prev->next;
++				}
++			}
++		}
++		/* then the head */		
++		card = ctrlr->stack.first;
++		if ( card && (card->state == MMC_CARD_STATE_UNPLUGGED) ) {
++			if ( ctrlr->stack.selected == card )
++				ctrlr->stack.selected = NULL;
++#ifdef CONFIG_PROC_FS
++			if ( card->proc ) {
++				remove_proc_entry( card->proc_name, ctrlr->proc );
++				card->proc = NULL;
++			}
++#endif
++			ctrlr->slot_next = card->slot; /* FIXME */
++			mmc_notify_remove( card ); /* FIXME: should unregister here */
++			ctrlr->stack.first = card->next;
++			if ( ctrlr->stack.last == card )
++				ctrlr->stack.last = NULL;
++			/* FIXME: controller use count */
++			--ctrlr->stack.ncards;
++			if ( (ctrlr->usage > 0) && ctrlr->tmpl->owner ) {
++				--ctrlr->usage;
++				MMC_DEBUG( MMC_DEBUG_LEVEL2, "'%s' use count "
++					"decreased (%d)\n", ctrlr->tmpl->name,
++					ctrlr->usage );
++				__MOD_DEC_USE_COUNT( ctrlr->tmpl->owner );
++			}
++			__mmc_card_free( card );
++		}
++	}
++	MMC_DEBUG( MMC_DEBUG_LEVEL2, "after stack check: ncards=%d"
++			" first=0x%x last=0x%x\n", ctrlr->stack.ncards,
++			ctrlr->stack.first, ctrlr->stack.last );
++	/* ...then add newly inserted ones */
++	if ( (ret = ctrlr->tmpl->update_acq( ctrlr )) )
++		goto error;
++	/* ret = 0; */
++error:			
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++/*
++ * 	1) check error code returned by controller; it's up to
++ * 	   controller to detect error conditions reported by the card
++ * 	   and to abort data transfer requests properly (e.g. send
++ * 	   CMD12(STOP_TRANSMISSION) to abort ADDRESS_ERROR multiple
++ * 	   block transfers)
++ * 	2) arrange for card stack update when necessary
++ *	   (all pending i/o requests must be held pending,
++ *	   update procedure must start immediately after 
++ *	   error has been detected)
++ */
++static inline int __mmc_check_error( mmc_card_t card, int err )
++{
++	int ret = -EIO;
++	mmc_controller_t ctrlr;
++	
++	__ENTER0();
++
++	if ( !card || !card->ctrlr )
++		goto error;
++	
++	ctrlr = card->ctrlr;
++	
++	if ( err < 0 ) {
++		switch ( err ) {
++		/* bus error occurred */
++		case MMC_ERROR_CRC_WRITE_ERROR:
++		case MMC_ERROR_CRC_READ_ERROR:
++		case MMC_ERROR_RES_CRC_ERROR:
++		case MMC_ERROR_READ_TIME_OUT:
++		case MMC_ERROR_TIME_OUT_RESPONSE:
++			down_write( &ctrlr->update_sem ); /* FIXME */
++			if ( !__mmc_update_card_stack( ctrlr ) )
++				ret = -ENXIO;
++			up_write( &ctrlr->update_sem );
++			break;
++		}
++	} else
++		ret = err;
++error:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static inline void __mmc_free_controller( mmc_controller_t ctrlr )
++{
++	if ( ctrlr ) {
++		if ( ctrlr->stack.ncards > 0 )
++			__mmc_card_stack_free( &ctrlr->stack );
++		kfree( ctrlr );
++	}
++}
++
++#ifdef CONFIG_PROC_FS
++static int mmc_proc_read_card_info( char *page, char **start, off_t off, int count, int *eof, void *data )
++{
++	int ret = -EINVAL;
++	mmc_card_t card = (mmc_card_t)data;
++	char *cp = page;
++	
++	if ( !card )
++		goto error;
++	
++	down_read( &card->ctrlr->update_sem );
++/* TODO: proc report
++ * Type: RO, RW or IO (by CCC)
++ * MID: 0x%02x card->info.cid.mid
++ * OID: 0x%04x card->info.cid.oid
++ * PNM: %s card->info.pnm
++ * PRV: %s card->info.prv
++ * PSN: 0x%08x card->info.cid.psn
++ * MDT: %s card->info.mdt
++ * Capacity: card->info.capacity (Bytes)
++ */
++#if 1
++	cp += sprintf( cp, "Capacity: %dKb.\n\n", (card->info.capacity>>10) );
++#else /* TODO */
++	cp += sprintf( cp, "Type    : %s\n", card->info.type );
++	cp += sprintf( cp, "MID     : 0x%02x\n", card->info.cid.mid );
++	cp += sprintf( cp, "OID     : 0x%04x\n", card->info.cid.oid );
++	cp += sprintf( cp, "PNM     : %s\n", card->info.pnm );
++	cp += sprintf( cp, "PRV     : %s\n", card->info.prv );
++	cp += sprintf( cp, "PSN     : 0x%08x\n", card->info.cid.psn );
++	cp += sprintf( cp, "MDT     : %s\n", card->info.mdt );
++	cp += sprintf( cp, "Capacity: %dKB\n", 
++			(card->info.capacity>>10) );
++#endif
++	up_read( &card->ctrlr->update_sem );
++	
++	ret = cp - page;
++error:
++	return ret;
++}
++#endif
++
++/*************************************
++ * MMC core interface implementation *
++ *************************************/
++int mmc_notify_add( mmc_card_t card )
++{
++	int ret = 0;
++	mmc_notifier_t notifier;
++	
++	__ENTER0();
++	if ( card ) {
++		for ( notifier = mmc_notifier; notifier;
++		      notifier = notifier->next )
++			if ( notifier->add )
++				if ( (ret = notifier->add( card )) )
++					break;
++	}
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++EXPORT_SYMBOL( mmc_notify_add );
++
++int mmc_notify_remove( mmc_card_t card )
++{
++	int ret = 0;
++	mmc_notifier_t notifier;
++	
++	__ENTER0();
++	if ( card ) {
++		for ( notifier = mmc_notifier; notifier; 
++		      notifier = notifier->next )
++			if ( notifier->remove )
++				if ( (ret = notifier->remove( card )) )
++					break;
++	}
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++EXPORT_SYMBOL( mmc_notify_remove );
++
++int mmc_update_card_stack( int host )
++{
++	int ret = -EINVAL;
++	mmc_controller_t ctrlr;
++
++	__ENTER0();
++	
++	if ( (host < 0) || (host >= MMC_CONTROLLERS_MAX) )
++		goto error;
++	
++	down_read( &mmc_controller_sem );
++	if ( (ctrlr = mmc_controller[host]) ) {
++		down_write( &ctrlr->update_sem );
++		(void)__mmc_update_card_stack( ctrlr );
++		up_write( &ctrlr->update_sem );
++	}
++	up_read( &mmc_controller_sem );
++	ret = 0;
++error:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++EXPORT_SYMBOL( mmc_update_card_stack );
++
++ssize_t mmc_read( mmc_card_t card, mmc_transfer_mode_t mode, char *buf, size_t size, loff_t *paddr )
++{
++	ssize_t ret = -EIO;
++	mmc_controller_t ctrlr;	
++	mmc_data_transfer_req_rec_t transfer; 
++		
++	if ( !paddr ) {
++		ret = -EINVAL;
++		goto error;
++	}
++	
++	if ( !card ) {
++		ret = -ENODEV;
++		goto error;
++	}
++
++	__ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%x",
++		card, card->usage, mode, buf, size, *paddr );
++	
++	ctrlr = card->ctrlr;
++	if ( (ret = mmc_acquire_io( ctrlr, card )) )
++		goto error;
++	
++	memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) );
++	transfer.cmd = MMC_READ;
++	transfer.mode = mode;
++	transfer.type = MMC_USER; /* FIXME: buffer cache */
++	transfer.buf = buf;
++	transfer.addr = *paddr;
++	transfer.cnt = size;
++
++/* max block size defined by CSD[read_bl_len] */
++	transfer.blksz = card->info.read_bl_len;
++	transfer.nob = size / transfer.blksz;
++	if ( (size - (transfer.nob * transfer.blksz)) > 0 )
++		transfer.nob++;
++
++/* TODO: controller may restrict maximum block size; set block size
++ * and number of blocks that their accumulated length fit to
++ * CSD[READ_BL_LEN] not to bother with block misalignment in multiple
++ * block transfers */
++	ctrlr = card->ctrlr;
++	if ( transfer.blksz > ctrlr->tmpl->block_size_max ) { 
++		ret = -EINVAL; /* FIXME */
++		goto error;
++	}
++		
++    	if ( ctrlr->stack.selected != card ) {
++		if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) )
++			goto err_mmc;		
++		ctrlr->stack.selected = card;
++	}
++	
++	switch( mode ) {
++		case MMC_TRANSFER_MODE_STREAM:
++			if ( !ctrlr->tmpl->stream_read ) {
++				ret = -ENXIO;
++				goto err_down;
++			}
++/* TODO: The max clock frequency for stream read operation is given by
++   the following formula:
++   	max speed = min ( TRAN_SPEED, 8*2^(READ_BL_LEN) - NSAC/TAAC )
++
++   If the card is not able to sustain data transfer it will set the
++   UNDERRUN error bit in the status register, abort the transmission
++   and wait in the Data state for a stop command 
++ */
++			ret = ctrlr->tmpl->stream_read( ctrlr, &transfer );
++			break;
++
++		case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++			if ( !ctrlr->tmpl->read_block ) {
++				ret = -ENXIO;
++				goto err_down;
++			}
++/* TODO: buffer size and data alignment (v3.4, p.29): 
++	if CSD[READ_BL_PARTIAL] is set, smaller blocks whose starting
++	and ending address are entirely contained within one physical
++	block (as defined by CSD[READ_BL_LEN]) may also be transmitted
++ */
++			transfer.type = MMC_KERNEL; /* FIXME */
++			ret = ctrlr->tmpl->read_block( ctrlr, &transfer );
++			break;
++			
++		case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++			if ( !ctrlr->tmpl->read_mblock ) {
++				ret = -ENXIO;
++				goto err_down;
++			}
++			
++			if ( transfer.nob > ctrlr->tmpl->nob_max ) {
++				ret = -EINVAL;
++				goto error;
++			}
++/* TODO: buffer size and data alignment (v3.4, p.29): 
++	if the host uses patrial blocks whose accumulated length is
++	not block aligned and block misalignment is not allowed, the
++	card should detect a block misalignment error condition at the
++	beginning of the first misaligned block
++ */
++			transfer.type = MMC_KERNEL; /* FIXME */
++			ret = ctrlr->tmpl->read_mblock( card->ctrlr, &transfer );
++			break;
++		
++		default:
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" );
++			ret = -EINVAL;
++	}
++err_mmc:
++	ret = __mmc_check_error( card, ret );
++	if ( ret >= 0 ) {
++		ret = size - transfer.cnt;
++		*paddr += ret;
++	}
++err_down:
++	mmc_release_io( ctrlr, card );
++error:
++	__LEAVE("ret=%d", ret);
++	return ret;
++}
++EXPORT_SYMBOL( mmc_read );
++
++ssize_t mmc_write( mmc_card_t card, mmc_transfer_mode_t mode, const char *buf, size_t size, loff_t *paddr )
++{
++	ssize_t ret = -ESPIPE;
++	mmc_controller_t ctrlr;
++	mmc_data_transfer_req_rec_t transfer; 
++		
++	if ( !paddr ) {
++		ret = -EINVAL;
++		goto error;
++	}
++	
++	if ( !card ) {
++		ret = -ENODEV;
++		goto error;
++	}
++
++	__ENTER( "card=%p usage=%d mode=%d buf=%p size=%d addr=%llx",
++		card, card->usage, mode, buf, size, *paddr );
++
++	ctrlr = card->ctrlr;	
++	if ( (ret = mmc_acquire_io( ctrlr, card )) )
++		goto error;
++	
++	memset( &transfer, 0, sizeof( mmc_data_transfer_req_rec_t ) );
++	transfer.cmd = MMC_WRITE;
++	transfer.mode = mode;
++	transfer.type = MMC_USER; /* FIXME: buffer cache */
++	transfer.buf = (char *)buf;
++	transfer.addr = *paddr;
++	transfer.cnt = size;
++
++/* max block size defined by CSD[write_bl_len] */
++	transfer.blksz = card->info.write_bl_len;
++	transfer.nob = size / transfer.blksz;
++	if ( (size - (transfer.nob * transfer.blksz)) > 0 )
++		transfer.nob++;
++
++/* TODO: controller may restrict maximum block size; set block size
++ * and number of blocks that their accumulated length fit to
++ * CSD[WRITE_BL_LEN] not to bother with block misalignment in multiple
++ * block transfers */
++	ctrlr = card->ctrlr;
++	if ( transfer.blksz > ctrlr->tmpl->block_size_max ) { 
++		ret = -EINVAL; /* FIXME */
++		goto error;
++	}
++		
++	if ( ctrlr->stack.selected != card ) {
++		if ( (ret = ctrlr->tmpl->setup_card( ctrlr, card )) )
++			goto err_mmc;		
++		ctrlr->stack.selected = card;
++	}
++	
++	transfer.cmd = MMC_WRITE;
++	transfer.mode = mode;
++	transfer.type = MMC_USER;
++	switch( mode ) {
++		case MMC_TRANSFER_MODE_STREAM:
++			if ( !ctrlr->tmpl->stream_write ) {
++				ret = -ENXIO;
++				goto err_down;
++			}
++			ret = ctrlr->tmpl->stream_write( ctrlr, &transfer );
++			break;
++
++		case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++			if ( !ctrlr->tmpl->write_block ) {
++				ret = -ENXIO;
++				goto err_down;
++			}
++			transfer.type = MMC_KERNEL; /* FIXME */
++			ret = ctrlr->tmpl->write_block( ctrlr, &transfer );
++			break;
++			
++		case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++			if ( !ctrlr->tmpl->write_mblock ) {
++				ret = -ENXIO;
++				goto err_down;
++			}
++			transfer.type = MMC_KERNEL; /* FIXME */
++			ret = ctrlr->tmpl->write_mblock( card->ctrlr, &transfer );
++			break;
++		
++		default:
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "request for unknown transfer type\n" );
++	}
++
++err_mmc:
++	ret = __mmc_check_error( card, ret ); /* FIXME */
++	if ( ret >= 0 ) {
++		ret = size - transfer.cnt;
++		*paddr += ret;
++	}
++err_down:
++	mmc_release_io( ctrlr, card );
++error:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++EXPORT_SYMBOL( mmc_write );
++
++int mmc_ioctl( mmc_card_t card, unsigned int cmd, unsigned long arg )
++{
++	int ret = -EINVAL;
++	mmc_controller_t ctrlr;
++	
++	if ( !card ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" )
++		goto error;
++	}
++		
++	ctrlr = card->ctrlr;
++	if ( mmc_acquire_io( ctrlr, card ) ) {  
++		ret = -ENXIO;
++		goto error;
++	}
++
++	switch ( cmd ) {
++		case IOCMMCGCARDESC:
++			if ( copy_to_user( (void *)arg, &card->info, sizeof( mmc_card_info_rec_t ) ) )
++				ret = -EFAULT;
++			break;
++/*	
++ * 1. TODO: erase region
++ * 2. TODO: set/unset write protection, lock/password 
++ */
++		default:
++			ret = -ENOIOCTLCMD;
++	}
++	
++	mmc_release_io( ctrlr, card );
++error:
++	return ret;
++}
++EXPORT_SYMBOL( mmc_ioctl );
++
++/* 
++ * registry stuff 
++ */
++mmc_card_t mmc_get_card( int host, int slot )
++{
++	mmc_card_t ret = NULL;
++	mmc_controller_t ctrlr = NULL;
++	int found;
++
++	__ENTER( "host=%d, card=%d", host, slot );
++	
++	if ( ((host < 0) || (host >= MMC_CONTROLLERS_MAX)) 
++	     && ((slot < 0) || (slot >= MMC_CARDS_MAX)) )
++		goto error;	
++
++ 	down_read( &mmc_controller_sem );
++	
++	if ( (ctrlr = mmc_controller[host]) ) {
++		down_write( &ctrlr->update_sem );
++		if ( ctrlr->stack.ncards > 0 ) {
++			ret = ctrlr->stack.first;
++			found = FALSE;
++			while ( ret ) {
++				if ( (ret->slot == slot) && (ret->state != 
++				     MMC_CARD_STATE_UNPLUGGED) ) {
++					found = TRUE;
++					break;
++				}
++				ret = ret->next;
++			}
++
++			if ( found ) {
++				if ( ctrlr->tmpl->owner ) {
++					++ctrlr->usage;
++					MMC_DEBUG( MMC_DEBUG_LEVEL2, 
++					    "'%s' use count increased (%d)\n", 
++					    ctrlr->tmpl->name, ctrlr->usage );
++					__MOD_INC_USE_COUNT( ctrlr->tmpl->owner );
++				}
++				++ret->usage;
++			} else
++				ret = NULL;
++		}
++		up_write( &ctrlr->update_sem );	
++	}
++	up_read( &mmc_controller_sem );
++error:
++	__LEAVE("ret=0x%p usage=%d", ret, ret ? ret->usage : -1 );
++	return ret;
++}
++EXPORT_SYMBOL( mmc_get_card );
++
++void mmc_put_card( mmc_card_t card )
++{
++	mmc_card_t tmp = NULL;
++	mmc_controller_t ctrlr;
++	int found;
++	
++	__ENTER( "card=0x%p", card );
++
++	if ( !card )
++	     	goto error;	
++
++	ctrlr = card->ctrlr;
++	
++ 	down_read( &mmc_controller_sem );
++	if ( !ctrlr || (ctrlr != mmc_controller[ctrlr->slot]) ) {
++		MMC_ERROR( "bad controller reference: ctrlr=0x%p\n", ctrlr );
++		goto err_down;
++	}
++	
++	down_write( &ctrlr->update_sem );
++	if ( ctrlr->stack.ncards > 0 ) {
++		tmp = ctrlr->stack.first;
++		found = FALSE;
++		while ( tmp ) {
++			if ( tmp == card ) {
++				found = TRUE;
++				break;
++			}
++			tmp = tmp->next;
++		}
++
++		if ( found ) {
++			if ( tmp->usage > 0 ) {
++				--tmp->usage;
++				MMC_DEBUG( MMC_DEBUG_LEVEL2, "usage=%d"
++					"owner=0x%p\n", tmp->usage, 
++					ctrlr->tmpl->owner );
++				if ( !tmp->usage && (ctrlr->usage > 0) 
++	  			     && ctrlr->tmpl->owner ) {
++					--ctrlr->usage;
++					MMC_DEBUG( MMC_DEBUG_LEVEL2, 
++						"'%s' use count "
++						"decreased (%d)\n", 
++						ctrlr->tmpl->name, 
++						ctrlr->usage );
++					__MOD_DEC_USE_COUNT( 
++							ctrlr->tmpl->owner );
++				}
++			}
++		} else
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" );
++			
++	}
++	up_write( &ctrlr->update_sem );	
++err_down:
++ 	up_read( &mmc_controller_sem );
++error:
++	__LEAVE( "found=%d", found );
++	return;
++}
++EXPORT_SYMBOL( mmc_put_card );
++
++static inline void *mmc_register_user( mmc_notifier_t notifier )
++{
++	mmc_notifier_t ret = NULL, last = mmc_notifier;
++	
++	MOD_INC_USE_COUNT;
++	if ( notifier ) {
++		down_write( &mmc_notifier_sem );
++		
++		notifier->next = NULL;
++		if ( !last ) {
++			mmc_notifier = notifier;
++			ret = notifier;	
++		} else {
++			while ( last->next ) {
++				if ( last == notifier ) {
++					MOD_DEC_USE_COUNT;
++					break;
++				}
++				last = last->next;
++			}
++			if ( last != notifier ) {
++				last->next = notifier;
++				ret = notifier;
++			}
++		}
++		up_write( &mmc_notifier_sem );
++	}
++/* notify new user about the cards present in the system */
++	if ( ret && ret->add ) {
++		int i;
++		
++		down_read( &mmc_controller_sem );
++		for ( i = 0; i < mmc_ncontrollers; i++ ) {
++			mmc_controller_t ctrlr = mmc_controller[i];
++			
++			down_read( &ctrlr->update_sem ); /* FIXME */
++			__mmc_card_stack_foreach( &ctrlr->stack, 
++					ret->add, FALSE );
++			up_read( &ctrlr->update_sem ); /* FIXME */
++		}
++		up_read( &mmc_controller_sem );
++	}
++/* error: */
++	__LEAVE( "mmc_notifier=0x%p, mmc_notifier->next=0x%p",
++			mmc_notifier, mmc_notifier ? mmc_notifier->next : NULL );
++	return ret;
++}
++
++static inline mmc_controller_t mmc_register_controller( mmc_controller_tmpl_t tmpl, size_t extra )
++{
++	mmc_controller_t ret = NULL;
++	int found;
++	int i;
++	
++	MOD_INC_USE_COUNT;
++	
++	down_write( &mmc_controller_sem );
++	
++	if ( mmc_ncontrollers >= MMC_CONTROLLERS_MAX ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're too many controllers\n" );
++		goto error;
++	}
++	
++	found = FALSE;
++	for ( i = 0; i < MMC_CONTROLLERS_MAX; i++ )
++		if ( !mmc_controller[i] ) {
++			found = TRUE;
++			break;
++		}
++	
++	if ( !found ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're no empty slots\n" );
++		goto error;
++	}
++
++	if ( !tmpl->init ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init()'\n" );
++		goto error;
++	}
++	
++	if ( !tmpl->probe ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'probe()'\n" );
++		goto error;
++	}
++	
++	if ( !tmpl->init_card_stack ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init_card_stack()'\n" );
++		goto error;
++	}
++	
++	if ( !tmpl->update_acq ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'update_acq()'\n" );
++		goto error;
++	}
++	
++	if ( !tmpl->check_card_stack ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'check_card_stack()'\n" );
++		goto error;
++	}
++	
++	if ( !tmpl->setup_card ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'setup_card()'\n" );
++		goto error;
++	}
++	
++	ret = kmalloc( sizeof( mmc_controller_rec_t ) + extra, GFP_ATOMIC ); /* FIXME: ISA + GFP_DMA */
++	if ( !ret ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "out of memory\n" );
++		goto error;
++	}
++
++	memset( ret, 0, sizeof( mmc_controller_rec_t ) + extra );
++	
++	if ( (tmpl->probe( ret ) != 1) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller probe failed\n" );
++		goto err_free;
++	}
++	
++	if ( tmpl->init( ret ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller initialization failure\n" );
++		goto err_free;
++	}
++	
++	ret->state = MMC_CONTROLLER_FOUND;
++	ret->slot = i;
++	ret->tmpl = tmpl;
++	init_MUTEX( &ret->io_sem );
++	init_rwsem( &ret->update_sem );
++#ifdef CONFIG_PROC_FS
++	if ( mmc_proc_dir ) {
++		snprintf( ret->proc_name, sizeof( ret->proc_name ),
++				"host%d", ret->slot );
++		ret->proc = proc_mkdir( ret->proc_name, mmc_proc_dir );
++	}
++#endif
++	
++/* initialize card stack */
++	if ( ret->tmpl->init_card_stack( ret ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "card stack initialization failure\n" );
++		if ( ret->tmpl->remove )
++			ret->tmpl->remove( ret ); /* FIXME */
++		goto err_free;
++	}
++	
++	mmc_controller[ret->slot] = ret;
++	++mmc_ncontrollers;
++
++/* notify users */
++	if ( ret->stack.ncards > 0 ) {
++		down_read( &mmc_notifier_sem );
++		if ( (i = __mmc_card_stack_foreach( &ret->stack, mmc_notify_add, FALSE ) ) < 0 )
++			MMC_ERROR( "device add notification failed at slot %d\n", -i );
++		up_read( &mmc_notifier_sem );
++	}
++	goto out;
++	
++err_free:
++#ifdef CONFIG_PROC_FS
++	if ( ret->proc )
++		remove_proc_entry( ret->proc_name, mmc_proc_dir );
++#endif
++	kfree( ret );
++error:
++	ret = NULL;
++	MOD_DEC_USE_COUNT;
++out:	
++	up_write( &mmc_controller_sem );
++	return ret;
++}
++
++static inline mmc_card_t mmc_register_card( mmc_card_t card )
++{
++	mmc_card_t ret = NULL;
++	mmc_controller_t ctrlr;
++	
++	if ( !card || !card->ctrlr )
++		goto error;
++	
++	ctrlr = card->ctrlr;
++#ifdef CONFIG_PROC_FS
++	if ( ctrlr->proc ) {
++		snprintf( card->proc_name, sizeof( card->proc_name ),
++					"card%d", card->slot );
++		card->proc = create_proc_read_entry( card->proc_name,
++					0444, ctrlr->proc,
++					mmc_proc_read_card_info, card );
++	}
++#endif
++	mmc_notify_add( card );
++error:
++	return ret;
++}
++
++void *mmc_register( mmc_reg_type_t reg_type, void *tmpl, size_t extra )
++{
++	void *ret = NULL;
++
++	switch ( reg_type ) {
++		case MMC_REG_TYPE_CARD:
++			ret = mmc_register_card( (mmc_card_t)tmpl );
++			break;
++
++		case MMC_REG_TYPE_USER:
++			ret = mmc_register_user( (mmc_notifier_t)tmpl );
++			break;
++
++		case MMC_REG_TYPE_HOST:
++			ret = mmc_register_controller( (mmc_controller_tmpl_t)tmpl, extra );
++			break;
++		
++		default:
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "register request for unknown type\n" );
++	}
++	
++	return ret;
++}
++EXPORT_SYMBOL( mmc_register );
++
++static inline void mmc_unregister_user( mmc_notifier_t notifier )
++{
++	mmc_notifier_t prev = mmc_notifier;
++	int found = FALSE;
++	
++	if ( notifier ) {
++		down_write( &mmc_notifier_sem );
++		
++		if ( mmc_notifier == notifier) {
++			mmc_notifier = prev->next;
++			found = TRUE;
++			
++		} else if ( mmc_notifier ) {
++			while( prev ) {
++				if ( prev->next == notifier ) {
++					found = TRUE;
++					prev->next = prev->next->next;
++					break;
++				}
++				prev = prev->next;
++			}
++		}
++		
++		if ( found ) {
++			if ( notifier->remove ) {
++				int i;
++		
++				down_read( &mmc_controller_sem );
++				for ( i = 0; i < mmc_ncontrollers; i++ ) {
++					mmc_controller_t ctrlr = 
++						mmc_controller[i];
++	
++					down_read( &ctrlr->update_sem );
++					__mmc_card_stack_foreach( &ctrlr->stack, notifier->remove, FALSE );
++					up_read( &ctrlr->update_sem );
++				}
++				up_read( &mmc_controller_sem );
++			}
++		}
++		
++		up_write( &mmc_notifier_sem );
++	}
++	
++	MOD_DEC_USE_COUNT;
++}
++
++static inline void mmc_unregister_controller( mmc_controller_t ctrlr )
++{
++	if ( !ctrlr || (mmc_controller[ctrlr->slot] != ctrlr ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad unregister request\n" );
++		goto error;
++	}
++
++	down_write( &mmc_controller_sem );
++
++/* notify users */
++	if ( ctrlr->stack.ncards > 0 ) {
++		int slot;
++		
++		down_read( &mmc_notifier_sem );
++		if ( (slot = __mmc_card_stack_foreach( &ctrlr->stack, mmc_notify_remove, FALSE ) ) )
++			MMC_ERROR( "device remove notification failed at slot %d\n", -slot );
++		up_read( &mmc_notifier_sem );
++	}
++
++#ifdef CONFIG_PROC_FS
++	if ( ctrlr->proc ) 
++		remove_proc_entry( ctrlr->proc_name, mmc_proc_dir );
++#endif
++
++	if ( ctrlr->tmpl && ctrlr->tmpl->remove )
++			ctrlr->tmpl->remove( ctrlr );
++
++	mmc_controller[ctrlr->slot] = NULL;
++	--mmc_ncontrollers;
++
++	__mmc_free_controller( ctrlr ); 
++
++	up_write( &mmc_controller_sem );
++	MOD_DEC_USE_COUNT;
++error:
++	return;
++}
++
++void mmc_unregister( mmc_reg_type_t reg_type, void *tmpl )
++{
++	switch ( reg_type ) {
++		case MMC_REG_TYPE_USER:
++			mmc_unregister_user( (mmc_notifier_t)tmpl );
++			break;
++
++		case MMC_REG_TYPE_HOST:
++			mmc_unregister_controller( (mmc_controller_t)tmpl );
++			break;
++		
++		default:
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "unregister request for unknown type\n" );
++	}
++}
++EXPORT_SYMBOL( mmc_unregister );
++
++#ifdef CONFIG_PM
++/* power management support */
++static int mmc_pm_callback( struct pm_dev *pmdev, pm_request_t pmreq, void *pmdata )
++{
++	int ret = -EINVAL;
++	mmc_controller_t ctrlr;
++	int i;
++	
++	__ENTER( "pmreq=%d", pmreq );
++	
++	down_read( &mmc_controller_sem );
++	
++	switch ( pmreq ) {
++	case PM_SUSPEND:
++		for ( ret = 0, i = 0; !ret && (i < mmc_ncontrollers); i++ ) {
++			ctrlr = mmc_controller[i];
++			if ( ctrlr->tmpl->suspend )
++				ret = ctrlr->tmpl->suspend( ctrlr );
++		}
++		if ( !ret )
++			break;
++		
++	case PM_RESUME:
++		for ( i = mmc_ncontrollers - 1; i >= 0; i-- ) {
++			ctrlr = mmc_controller[i];
++			if ( ctrlr->tmpl->resume )
++				ctrlr->tmpl->resume( ctrlr );
++		}
++		ret = 0;
++		break;
++
++	default:
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "unsupported PM request %d\n", 
++					pmreq );
++	}
++
++	up_read( &mmc_controller_sem );
++/* error: */	
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++#endif
++
++/* kernel module stuff */
++static int __init mmc_core_module_init( void )
++{
++	int ret = -ENODEV;
++	
++	memset( &mmc_controller, 0, sizeof( mmc_controller ) );
++	
++	init_rwsem( &mmc_controller_sem );
++	init_rwsem( &mmc_notifier_sem );
++#ifdef CONFIG_PM
++	if ( !(mmc_pm_dev = pm_register( PM_UNKNOWN_DEV, 0, mmc_pm_callback )) ) 		MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register PM callback\n" );
++#endif
++#ifdef CONFIG_PROC_FS
++	mmc_proc_dir = proc_mkdir( "mmc", NULL );
++#endif
++	ret = 0;
++/* error: */
++	return ret;
++}
++
++static void __exit mmc_core_module_cleanup( void )
++{
++#ifdef CONFIG_PROC_FS
++	if ( mmc_proc_dir )
++		remove_proc_entry( "mmc", NULL );
++#endif
++#ifdef CONFIG_PM
++	pm_unregister( mmc_pm_dev );
++#endif
++}
++
++module_init( mmc_core_module_init );
++module_exit( mmc_core_module_cleanup );
++
++MODULE_LICENSE( "GPL" );
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/mmc_pxa.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,1902 @@
++/*
++ *  linux/drivers/mmc/mmc_pxa.c 
++ *      driver for Cotulla MMC controller 
++ *
++ *  Authors:    Vladimir Shebordaev, Igor Oblakov   
++ *  Copyright:  MontaVista Software Inc.
++ *
++ *  $Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/dma.h>
++
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++#include <mmc/ioctl.h>
++
++#include "types.h"
++#include "mmc.h"
++#include "mmc_pxa.h"
++
++static mmc_controller_t host = NULL;
++
++/* service routines */
++static inline int pxa_mmc_check_state( mmc_controller_t ctrlr, pxa_mmc_state_t state )
++{
++    int ret = -1;
++    pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++    
++    if ( hostdata->state != state ) {
++        //MMC_DEBUG( MMC_DEBUG_LEVEL3,  "state (%s vs %s)\n",  PXA_MMC_STATE_LABEL( hostdata->state ),  PXA_MMC_STATE_LABEL( state ) );
++        goto error;
++    }
++    ret = 0;
++error:          
++    return ret;
++}
++
++static inline void pxa_mmc_set_state( mmc_controller_t ctrlr, pxa_mmc_state_t state )
++{
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++    
++	hostdata->state = state;
++}
++
++static inline int pxa_mmc_init_completion( mmc_controller_t ctrlr, u32 mask )
++{
++	int ret = -1;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++    
++	if ( xchg( &hostdata->busy, 1 ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "another interrupt "
++			"is already been expected\n" );
++		goto error;
++	}
++    
++#if CONFIG_MMC_DEBUG_IRQ 
++	hostdata->irqcnt = 1000;
++#endif
++	init_completion( &hostdata->completion );
++    
++	MMC_I_MASK = MMC_I_MASK_ALL & ~mask;
++	ret = 0;
++error:
++	return ret;
++}
++
++#if CONFIG_MMC_DEBUG_IRQ 
++static struct timer_list timer;
++static void wait_timeo( unsigned long arg ) {
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)arg;
++	hostdata->timeo = 1;
++	complete( &hostdata->completion );
++	return;
++}
++#endif
++
++static inline int pxa_mmc_wait_for_completion( mmc_controller_t ctrlr, u32 mask )
++{
++	int ret = -1;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++    
++	if ( !xchg( &hostdata->busy, 1 ) ) {
++        	MMC_DEBUG( MMC_DEBUG_LEVEL3, "there were no "
++				"interrupt awaited for\n" );
++		goto error;
++	}
++
++#if CONFIG_MMC_DEBUG_IRQ
++    	hostdata->timeo = 0;
++    	del_timer( &timer );
++	timer.function = wait_timeo;
++	timer.expires = jiffies + 1UL*HZ;
++	timer.data = (unsigned long)hostdata;
++	add_timer( &timer );
++#endif
++	wait_for_completion( &hostdata->completion );
++#if CONFIG_MMC_DEBUG_IRQ
++    	del_timer( &timer );
++	if ( hostdata->timeo ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "irq timed out: " "mask=%x stat=%x\n", mask, MMC_STAT );
++		goto error;
++	}
++#endif	
++	/*  verify interrupt */
++	if ( (mask == ~0UL) || !( hostdata->mmc_i_reg & ~mask ) ) 
++		ret = 0;
++    
++error:
++	xchg( &hostdata->busy, 0 ); 
++	return ret;
++}
++
++static inline int pxa_mmc_stop_bus_clock( mmc_controller_t ctrlr )
++{
++	int ret = -1;
++    
++	if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_CLK_OFF ) )
++		goto out;
++		
++	if ( !pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "BUFFER_IN_TRANSIT\n" );
++	        goto error;
++	}
++	
++	if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_CLK_IS_OFF ) )
++		goto error;
++    
++	MMC_STRPCL = MMC_STRPCL_STOP_CLK;
++	
++	if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_CLK_IS_OFF ) )
++		goto error;
++    
++	//MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is off\n" );
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_CLK_OFF );
++out:
++	ret = 0;
++error:
++	return ret;
++}
++
++static inline int pxa_mmc_start_bus_clock( mmc_controller_t ctrlr )
++{
++	int ret = -1;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;    
++
++	if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF)
++	     && (hostdata->state != PXA_MMC_FSM_END_IO) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n", PXA_MMC_STATE_LABEL( hostdata->state ) );
++		goto error;
++	}
++    
++	MMC_STRPCL = MMC_STRPCL_START_CLK;
++	wmb();
++	//MMC_DEBUG( MMC_DEBUG_LEVEL3, "clock is on\n" ); 
++	ret = 0;
++error:
++	return ret;
++}
++
++/* 
++int pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t response )
++
++Effects: initializes completion to wait for END_CMD_RES intr,
++         waits for intr to occur, checks controller and card status 
++Requiers: controller is in CLK_OFF state
++Modifies: moves controller to the END_CMD state
++Returns: 
++*/ 
++static mmc_error_t pxa_mmc_complete_cmd( mmc_controller_t ctrlr, mmc_response_fmt_t format, int send_abort )
++{
++	mmc_error_t ret = MMC_ERROR_GENERIC;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	int mask, nwords;
++	u32 status;
++    
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD%d(0x%04x%04x)\n", MMC_CMD & 0x3f, MMC_ARGH, MMC_ARGL);
++
++/* FIXME: check arguments */
++    
++	if ( (hostdata->state != PXA_MMC_FSM_CLK_OFF)
++	     && (hostdata->state != PXA_MMC_FSM_END_IO) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "illegal state %s\n",
++				PXA_MMC_STATE_LABEL( hostdata->state ) );
++		goto error;
++	}
++    
++	mask = MMC_I_MASK_END_CMD_RES;
++	if ( pxa_mmc_init_completion( ctrlr, mask ) )
++		goto error;
++    
++	MMC_PRTBUF = MMC_PRTBUF_BUF_FULL; 
++/* start the clock */
++	if ( pxa_mmc_start_bus_clock( ctrlr ) )
++		goto error;
++    
++/* wait for END_CMD_RES intr */
++	if ( pxa_mmc_wait_for_completion( ctrlr, MMC_I_REG_END_CMD_RES ) )
++		goto error;
++
++/* check status */
++	if ( hostdata->mmc_stat & MMC_STAT_TIME_OUT_RESPONSE ) {
++		// MMC_DEBUG(MMC_DEBUG_LEVEL3, "response timeout\n");
++		ret = MMC_ERROR_TIME_OUT_RESPONSE;
++		goto error;
++    
++	} else if ( hostdata->mmc_stat & MMC_STAT_READ_TIME_OUT ) {
++		// MMC_DEBUG(MMC_DEBUG_LEVEL3, "read timeout\n");
++		ret = MMC_ERROR_READ_TIME_OUT;
++		goto error;
++    
++	} else if ( hostdata->mmc_stat & MMC_STAT_RES_CRC_ERROR ) {
++		// MMC_DEBUG(MMC_DEBUG_LEVEL3, "response crc err\n");
++		ret = MMC_ERROR_RES_CRC_ERROR;
++		goto error;
++    
++	} else if ( hostdata->mmc_stat & MMC_STAT_CRC_READ_ERROR ) {
++		// MMC_DEBUG(MMC_DEBUG_LEVEL3, "read crc err\n");
++		ret = MMC_ERROR_CRC_READ_ERROR;
++		goto error;
++        
++	} else if ( hostdata->mmc_stat & MMC_STAT_CRC_WRITE_ERROR ) {
++		// MMC_DEBUG(MMC_DEBUG_LEVEL3, "write crc err\n");
++		ret = MMC_ERROR_CRC_WRITE_ERROR;
++		goto error;
++	}
++    
++	nwords = (format == MMC_NORESPONSE) ? 0 :
++		(format == MMC_R1) ? 3 : 
++		(format == MMC_R2) ? 8 :
++		(format == MMC_R3) ? 3 : 
++		-1;
++	ret = nwords;
++	if ( nwords > 0 ) {
++		register int i;
++
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "nwords=%d\n", nwords );
++		for ( i = nwords - 1; i >= 0 ; i-- ) {
++			u32 res = MMC_RES;
++			int ibase = i<<1;
++
++			hostdata->mmc_res[ibase] = ((u8 *)&res)[0];
++			hostdata->mmc_res[ibase + 1] = ((u8 *)&res)[1];
++			--ret;
++		}
++#ifdef CONFIG_MMC_DEBUG
++		switch ( format ) {
++		case MMC_R1:
++			MMC_DUMP_R1( ctrlr );
++			break;
++		case MMC_R2:
++			MMC_DUMP_R2( ctrlr );
++			break;
++		case MMC_R3:
++			MMC_DUMP_R3( ctrlr );
++			break;
++		default:
++			MMC_DEBUG( MMC_DEBUG_LEVEL3, 
++					"unknown response format\n" );
++			ret = MMC_ERROR_GENERIC;
++			goto error;
++		}
++#endif
++
++/* check card status for R1(b) commands */
++		if ( format == MMC_R1 ) {
++			u8 cmd;
++			
++			((u8 *)&status)[0] = hostdata->mmc_res[1];
++			((u8 *)&status)[1] = hostdata->mmc_res[2];
++			((u8 *)&status)[2] = hostdata->mmc_res[3];
++			((u8 *)&status)[3] = hostdata->mmc_res[4];
++			cmd = PXA_MMC_RESPONSE( ctrlr, 5 )&0x3f;
++			MMC_DEBUG( MMC_DEBUG_LEVEL3, 
++			//printk( KERN_INFO __FUNCTION__"(): "
++				"cmd=%u status: 0x%08x\n",
++				cmd, status );
++			switch ( cmd ) {
++			case 11:
++			case 18:
++			case 20:
++			case 25:
++				if ( !(status & 0x00000100) ) /* FIXME */
++					goto mmc_error;
++			default:
++				break;
++			}
++			if ( status & MMC_CARD_STATUS_OUT_OF_RANGE ) {
++				ret = MMC_ERROR_OUT_OF_RANGE;
++				goto mmc_error;
++		    	} else if ( status & MMC_CARD_STATUS_ADDRESS_ERROR ) {
++				ret = MMC_ERROR_ADDRESS_ERROR;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_BLOCK_LEN_ERROR ) {
++				ret = MMC_ERROR_ADDRESS_ERROR;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_ERASE_SEQ_ERROR ) {
++				ret = MMC_ERROR_ERASE_SEQ_ERROR;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_ERASE_PARAM ) {
++				ret = MMC_ERROR_ERASE_PARAM;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_WP_VIOLATION ) {
++				ret = MMC_ERROR_WP_VIOLATION;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_CARD_IS_LOCKED ) {
++				ret = MMC_ERROR_CARD_IS_LOCKED;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_LOCK_UNLOCK_FAILED ) {
++				ret = MMC_ERROR_LOCK_UNLOCK_FAILED;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_COM_CRC_ERROR ) {
++				ret = MMC_ERROR_COM_CRC_ERROR;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_ILLEGAL_COMMAND ) {
++				ret = MMC_ERROR_ILLEGAL_COMMAND;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_CARD_ECC_FAILED ) {
++				ret = MMC_ERROR_CARD_ECC_FAILED;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_CC_ERROR ) {
++				ret = MMC_ERROR_CC_ERROR;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_ERROR ) {
++				ret = MMC_ERROR_ERROR;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_UNDERRUN ) {
++				ret = MMC_ERROR_UNDERRUN;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_OVERRUN ) {
++				ret = MMC_ERROR_OVERRUN;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_CID_CSD_OVERWRITE ) {
++				ret = MMC_ERROR_CID_CSD_OVERWRITE;
++				goto mmc_error;
++			} else if ( status & MMC_CARD_STATUS_ERASE_RESET ) {
++				ret = MMC_ERROR_ERASE_RESET;
++				goto mmc_error;
++			}
++		}
++	}
++    
++	if ( ret >= 0 )
++		pxa_mmc_set_state( ctrlr,  PXA_MMC_FSM_END_CMD );
++	goto out;
++mmc_error:
++#if 1
++	if ( send_abort ) {
++		/* send CMD12 to abort failed transfer */
++            	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++                	goto error;
++    
++	        MMC_CMD = CMD(12); /* STOP_TRANSMISSION */
++        	MMC_CMDAT = MMC_CMDAT_R1;
++    		
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++		        goto error;
++    		
++		ret = -EIO;
++		goto error;
++	}
++#endif
++error:
++	/* move controller to the IDLE state */
++	pxa_mmc_stop_bus_clock( ctrlr );
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++out:
++	return ret;
++}
++
++/* 
++int pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t cmd, mmc_dir_t dir, mmc_transfer_mode_t mode )
++
++Effects: finilizes data transfer request  
++Reqires: controller is in the END_BUFFER state
++Modifies: moves controller to the IDLE state
++Returns: zero upon success or error condition code otherwise
++ */
++static mmc_error_t pxa_mmc_complete_io( mmc_controller_t ctrlr, mmc_dir_t dir, mmc_transfer_mode_t mode )
++{
++	int ret = MMC_ERROR_GENERIC; 
++
++	if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_IO ) )
++		goto error;
++    
++	switch ( mode ) {
++	case MMC_TRANSFER_MODE_STREAM: /* FIXME */
++		if ( dir == MMC_WRITE ) {
++		/* 1. wait for STOP_CMD intr */
++			if ( (ret = pxa_mmc_init_completion( ctrlr,
++					MMC_I_MASK_STOP_CMD )) )
++				goto error;
++			if ( (ret = pxa_mmc_wait_for_completion( ctrlr, 
++					MMC_I_REG_STOP_CMD )) )
++				goto error;
++		}
++		/* 2. send CMD12 */
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto error;
++    
++		MMC_CMD = CMD(12); /* STOP_TRANSMISSION */
++		MMC_CMDAT = MMC_CMDAT_R1;
++		if ( dir == MMC_WRITE ) 
++			MMC_CMDAT |= MMC_CMDAT_BUSY;
++            
++		/* 3. wait for CMD12 to complete */
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "ready for CMD12\n" );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++			goto error;
++            
++		/* 4. wait for DATA_TRAN_DONE intr */
++		if ( (ret = pxa_mmc_init_completion( ctrlr,
++				MMC_I_MASK_DATA_TRAN_DONE )) )
++			goto error;
++		if ( (ret = pxa_mmc_wait_for_completion( ctrlr, 
++				MMC_I_REG_DATA_TRAN_DONE )) )
++			goto error;
++	    
++		if ( dir == MMC_WRITE ) {
++		/* 5. wait for PRG_DONE intr */
++			if ( (ret = pxa_mmc_init_completion( ctrlr,
++					MMC_I_MASK_PRG_DONE )) )
++				goto error;
++        	        if ( (ret = pxa_mmc_wait_for_completion( ctrlr, 
++                	        	MMC_I_REG_PRG_DONE )) )
++				goto error;
++		}
++		break;
++	case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++		/* 1. wait for DATA_TRAN done intr */
++		if ( (ret = pxa_mmc_init_completion( ctrlr,
++				MMC_I_MASK_DATA_TRAN_DONE )) )
++			goto error;
++		if ( (ret = pxa_mmc_wait_for_completion( ctrlr, 
++				MMC_I_REG_DATA_TRAN_DONE )) )
++			goto error;
++            
++		/* 2. send CMD12 */
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto error;
++    
++		MMC_CMD = CMD(12); /* STOP_TRANSMISSION */
++		MMC_CMDAT = MMC_CMDAT_R1;
++		if ( dir == MMC_WRITE ) 
++			MMC_CMDAT |= MMC_CMDAT_BUSY;
++            
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD12\n" );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++			goto error;
++        
++		if ( dir == MMC_WRITE ) {
++		/* 3. wait for PRG_DONE intr */
++			if ( (ret = pxa_mmc_init_completion( ctrlr,
++					MMC_I_MASK_PRG_DONE )) )
++				goto error;
++			if ( (ret = pxa_mmc_wait_for_completion( ctrlr, 
++					MMC_I_REG_PRG_DONE )) )
++				goto error;
++		}
++		break;
++	case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++		/* 1. wait for DATA_TRAN_DONE intr */
++		if ( (ret = pxa_mmc_init_completion( ctrlr,
++				MMC_I_MASK_DATA_TRAN_DONE )) )
++			goto error;
++		if ( (ret = pxa_mmc_wait_for_completion( ctrlr, 
++				MMC_I_REG_DATA_TRAN_DONE )) )
++			goto error;
++            
++		if ( dir == MMC_WRITE ) {
++		/* 2. wait for PRG_DONE intr */
++			if ( (ret = pxa_mmc_init_completion( ctrlr,
++					MMC_I_MASK_PRG_DONE )) )
++				goto error;
++			if ( (ret = pxa_mmc_wait_for_completion( ctrlr, 
++					MMC_I_REG_PRG_DONE )) )
++				goto error;
++		}
++		break;
++	default:
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown transfer mode\n" );
++		goto error;
++	}
++/* move the controller to the IDLE state */ 
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto error;
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++
++	ret = 0;
++error:
++	return ret;
++}
++
++static inline int pxa_mmc_update_acq( mmc_controller_t ctrlr )
++{
++	int ret = -EINVAL;
++	pxa_mmc_hostdata_t hostdata = NULL;
++	mmc_card_t card = NULL;
++	mmc_card_stack_rec_t fake;
++	mmc_card_stack_t stack = &fake;
++	u16 argl = 0U, argh = 0U;
++	int ncards = 0;
++
++	if ( !ctrlr )
++		goto error;
++
++	hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	
++	__mmc_card_stack_init( stack );
++	
++	/* max open-drain mode frequency is 400kHZ */
++	MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
++	MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */
++
++	/*  discover and add cards to the stack */  
++	/* I. bus operation condition setup */
++	/*      1) send CMD1 */
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto err_free;
++    
++	argl = 0x0000;
++	argh = 0x0004;
++
++	MMC_CMD = CMD(1);
++	MMC_ARGH = argh;
++	MMC_ARGL = argl; 
++    
++	MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3; 
++    
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl );
++	ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE );
++	if ( !ret ) {
++		argh = (PXA_MMC_RESPONSE( ctrlr, 4 ) << 8) 
++			| PXA_MMC_RESPONSE( ctrlr, 3 );
++		argl = (PXA_MMC_RESPONSE( ctrlr, 2 ) << 8)
++			| PXA_MMC_RESPONSE( ctrlr, 1 );
++
++	} else if ( ret != MMC_ERROR_TIME_OUT_RESPONSE ) 
++		goto err_free;
++    
++	if ( !argh && !argl ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, 
++			"assuming full voltage range support\n" );
++		argh = 0x00ff;
++		argl = 0xff00;
++	}
++    
++	/* 2) continuously send CMD1 'till there're busy cards */
++	for(;;) {
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto err_free;
++
++		MMC_CMD = CMD(1);
++		MMC_ARGH = argh;
++		MMC_ARGL = argl;
++
++		MMC_CMDAT = MMC_CMDAT_BUSY|MMC_CMDAT_R3;
++        
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD1(0x%04x%04x)\n", argh, argl );
++		ret = pxa_mmc_complete_cmd( ctrlr, MMC_R3, FALSE );
++		if ( ret == MMC_ERROR_TIME_OUT_RESPONSE )
++			break; 
++
++		else if ( !ret ) {
++			/* busy state reported by LOW signal level 
++			 * (MMC v3.2, p.58)
++			 *
++			 * Thanks to Alexander Samoutin :)
++			 */
++			if ( !(PXA_MMC_RESPONSE( ctrlr, 4 ) & 0x80) ) {
++				MMC_DEBUG( MMC_DEBUG_LEVEL3, "busy state reported\n");
++				udelay( 20 );
++				continue;
++			} else 
++				break;
++		} else
++			goto err_free;
++	}
++
++/* II. card identification: the cards in Ready state 
++ *     are the only expected to respond 
++ */     
++	for (;;) {
++		argh = 0U;
++		argl = 0U;
++    
++		/* 1) send CMD2 */
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto err_free;
++        
++		MMC_CMD = CMD(2);
++		MMC_ARGH = 0x0003;
++		MMC_ARGL = 0xf300;
++		MMC_CMDAT = MMC_CMDAT_R2;
++        
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD2(0x%04x%04x)\n", argh, argl );
++		ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE );
++		if ( ret == MMC_ERROR_TIME_OUT_RESPONSE )
++			break;
++        
++		else if ( ret ) /* bus error */
++			goto err_free;
++        
++	        /* TODO: store CID for the card */
++        
++        	/* 2) assign RCA */
++		if ( !++ctrlr->rca_next ) /* overflow */
++			++ctrlr->rca_next;
++		argh = ctrlr->rca_next; 
++        
++        	/* 3) send it to the card last responded (CMD3) */
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto err_free;
++        
++		MMC_CMD = CMD(3);
++		MMC_ARGH = argh;
++		MMC_ARGL = argl;
++		MMC_CMDAT = MMC_CMDAT_R1;
++
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD3(0x%04x%04x)\n", argh, argl );
++		ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE );
++		if ( ret )   /* CMD3 failed */ 
++			goto err_free;
++
++		card = __mmc_card_alloc( sizeof( pxa_mmc_card_data_rec_t ) );
++		if ( !card ) {
++			MMC_ERROR( "out of memory\n" );
++			goto err_free;
++		}
++
++		card->info.rca = argh;  
++		card->slot = ctrlr->slot_next++; /* FIXME: minor encoding */
++		card->ctrlr = ctrlr;
++        
++		if ( !__mmc_card_stack_add( stack, card ) )
++			goto err_free;
++        
++		MMC_DEBUG( MMC_DEBUG_LEVEL2, "added card: "
++				"slot %d, RCA=0x%04x\n", card->slot, argh );
++		++ncards;
++	}
++   
++	if ( ncards ) {
++/* III. read CSD registers of all cards; DSR support also reported there */
++		for ( card = stack->first; card; card = card->next ) {
++			pxa_mmc_card_data_t card_data = 
++				(pxa_mmc_card_data_t)card->card_data;
++	    
++			/* 1) send CMD9 */
++			argh = card->info.rca;
++			argl = 0U;
++        
++			if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++				goto err_free;
++        
++			MMC_CMD = CMD(9);
++			MMC_ARGH = argh;
++			MMC_ARGL = argl;
++			MMC_CMDAT = MMC_CMDAT_R2;
++        
++			MMC_DEBUG( MMC_DEBUG_LEVEL3, 
++				"CMD9(0x%04x%04x)\n", argh, argl );
++			if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R2, FALSE )) )
++				goto err_free; 
++       	
++			memcpy( &card->info.csd, hostdata->mmc_res, 15 );
++			MMC_DUMP_CSD( card );
++	    
++			card->info.read_bl_len = (1<<card->info.csd.read_bl_len);
++			card->info.write_bl_len = (1<<card->info.csd.write_bl_len);
++			card->info.capacity = (card->info.csd.c_size + 1) 
++					* (1<<(card->info.csd.c_size_mult + 2)) 
++					* card->info.read_bl_len;
++			MMC_DEBUG( MMC_DEBUG_LEVEL2, "card capacity=%dMb\n", 
++					card->info.capacity>>20 );
++			card->info.tran_speed = 20*1024; /* FIXME */
++			card->info.transfer_mode = MMC_TRANSFER_MODE_BLOCK_SINGLE; 
++		/* 2) set bus operation freq */
++			card_data->clkrt = pxa_mmc_clkrt( card->info.tran_speed );
++		/* 3) register card with MMC core */
++			mmc_register( MMC_REG_TYPE_CARD, card, 0 );
++		}
++/* IV. set DSR registers of the cards */
++#if 0 /* TODO */
++		if ( card->info.csd.dsr_imp ) {
++			set_dsr = TRUE;
++			/*  calculate DSR */
++		}
++#endif
++	}
++#if 0 /* TODO */
++	if ( set_dsr ) {
++			/* send CMD4 */
++	}
++#endif
++/* merge list of the newly inserted cards into controller card stack */
++	if ( !ctrlr->stack.ncards ) {
++		ctrlr->stack.first = stack->first;
++		ctrlr->stack.last = stack->last;
++	} else	
++		ctrlr->stack.last->next = stack->first;
++	
++	ctrlr->stack.ncards += stack->ncards;
++	
++	ret = 0;
++	goto out;
++err_free:
++	__mmc_card_stack_free( stack );
++error:
++out:
++	return ret;
++}
++
++/* MMC protocol macros: v3.4, p.120 */
++static int pxa_mmc_init_card_stack( mmc_controller_t ctrlr )
++{
++	int ret = -EIO;
++	u16 argl = 0U, argh = 0U;
++    
++	if ( !ctrlr || ctrlr->stack.ncards ) {
++		ret = -EINVAL;
++		goto error;
++	}
++
++	/* initialize stack */  
++	/*     1) send CMD0 */
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto error;
++
++	/* max open-drain mode frequency is 400kHZ */
++	MMC_CLKRT = MMC_CLKRT_0_3125MHZ;
++	MMC_RESTO = MMC_RES_TO_MAX; /* set response timeout */
++	MMC_SPI = MMC_SPI_DISABLE;
++
++	MMC_CMD = CMD(0); /* CMD0 with zero argument */
++	MMC_ARGH = argh;
++	MMC_ARGL = argl; 
++	MMC_CMDAT = MMC_CMDAT_INIT;
++    
++	//MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", argh, argl );
++	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE, FALSE )) )
++		goto error;
++
++	/* update card stack */
++	if ( (ret = pxa_mmc_update_acq( ctrlr )) )
++		goto err_free;
++	
++	/* move the controller to the IDLE state */ 
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto err_free;
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++	
++	ret = 0;
++	MMC_DEBUG( MMC_DEBUG_LEVEL2, "ncards=%d\n", ctrlr->stack.ncards );
++	goto out;
++
++err_free:
++	__mmc_card_stack_free( &ctrlr->stack ); 
++error:
++out:
++	return ret;
++}
++
++static int pxa_mmc_check_card_stack( mmc_controller_t ctrlr )
++{
++	int ret = -1;
++	mmc_card_t card;
++	
++	if ( !ctrlr )
++		goto error;
++	
++	if ( ctrlr->stack.ncards > 0 )	 {
++/* for each card in the stack: */
++		for( card = ctrlr->stack.first; card; card = card->next ) {
++			u16 argh = card->info.rca;
++			u16 argl = 0UL;
++			
++/* 	1) send CMD9( card->rca ) */
++			if ( pxa_mmc_stop_bus_clock( ctrlr ) )
++				goto error;
++			
++			/* SanDisk's cards do not respond to CMD9 */	
++			MMC_CMD = CMD(13);
++			MMC_ARGH = argh;
++			MMC_ARGL = argl;
++			MMC_CMDAT = MMC_CMDAT_R1;
++			
++			MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD13(0x%04x%04x)\n", 
++					argh, argl );
++			ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE );
++/* 	2) if card responded, it is still there */
++			if ( ret ) 
++				card->state = MMC_CARD_STATE_UNPLUGGED;
++		}
++	}
++	ret = 0;	
++error:
++	return ret;
++}
++
++/* This procedure links the bus master with a single card
++ *  1)  cross checks with the internal stack management data if a card still
++ *      exists in the slot
++ *  2)  send CMD7( card->public.rca )
++ *  3)  setup data path and controller options 
++ */
++static int pxa_mmc_setup_card( mmc_controller_t ctrlr, mmc_card_t card ) 
++{
++	int ret = -ENODEV;
++	pxa_mmc_hostdata_t hostdata;
++	pxa_mmc_card_data_t card_data;
++	u16 argh = 0U;
++#ifdef CONFIG_MMC_DEBUG
++	u16 argl = 0U;
++#endif
++    
++	if ( !ctrlr || !card ) {
++		ret = -EINVAL;
++		goto error;
++	}
++    
++	if ( card->ctrlr != ctrlr ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "card is on another bus\n" );
++		goto error;
++	}
++    
++	hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	card_data = (pxa_mmc_card_data_t)card->card_data;
++
++	argh = card->info.rca;
++    
++/* select requested card */ 
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) 
++		goto error;
++        
++	MMC_CMD = CMD(7);
++	MMC_ARGH = argh;
++	MMC_CMDAT = MMC_CMDAT_R1;
++
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD7(0x%04x%04x)\n", argh, argl );
++	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++		goto error;
++
++/* set controller options */
++#ifndef CONFIG_MMC_DEBUG
++	MMC_CLKRT = card_data->clkrt; 
++#endif    
++/* move the controller to the IDLE state */ 
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto error;
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_IDLE );
++	
++	ret = 0;
++error:  
++	return ret;
++}
++
++static inline int pxa_mmc_iobuf_init( mmc_controller_t ctrlr, ssize_t cnt )
++{
++#ifdef PIO
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#endif 
++#ifndef PIO
++/* TODO */
++#else
++	hostdata->iobuf.buf.pos = hostdata->iobuf.iodata;
++	hostdata->iobuf.buf.cnt = cnt;
++#endif
++	return 0;
++}
++/* TODO: ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt )
++effects: reads at most cnt bytes from the card to the controller I/O buffer;
++       takes care of partial data transfers
++requieres: 
++modifies: ctrlr->iobuf
++returns: number of bytes actually transferred or negative error code if there were any errors
++ */
++ssize_t pxa_mmc_read_buffer( mmc_controller_t ctrlr, ssize_t cnt )
++{
++	ssize_t ret = -EIO;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++	register int ndesc;
++	int chan = hostdata->iobuf.buf.chan;
++	pxa_dma_desc *desc;
++#endif
++
++	if ( (hostdata->state != PXA_MMC_FSM_END_CMD) && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) {
++            goto error;
++	}
++	
++	if ( cnt > hostdata->iobuf.bufsz )
++		cnt = hostdata->iobuf.bufsz;
++
++	if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) )
++		goto error;
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT );
++#ifndef PIO
++	if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */
++		goto error;
++	
++	if ( (desc = hostdata->iobuf.buf.last_read_desc) ) {
++		desc->ddadr &= ~DDADR_STOP;
++		desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH);
++		desc->dcmd |= (1<<5);
++	}
++/* 1) setup descriptors for DMA transfer from the device */
++	ndesc = (cnt>>5) - 1; /* FIXME: partial read */
++	desc = &hostdata->iobuf.buf.read_desc[ndesc];
++	hostdata->iobuf.buf.last_read_desc = desc;	
++	/* TODO: partial read */
++	desc->ddadr |= DDADR_STOP;
++	desc->dcmd |= DCMD_ENDIRQEN;
++/* 2) start DMA channel */
++	DDADR( chan ) = hostdata->iobuf.buf.read_desc_phys_addr;
++	DCSR( chan ) |= DCSR_RUN;
++#else
++	if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_RXFIFO_RD_REQ ) )
++		goto error;
++#endif
++
++	if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) )
++		goto error;
++
++	if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) )
++		goto error;
++
++	if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */  
++		ret = cnt;
++error:
++	return ret;
++}
++
++ssize_t pxa_mmc_write_buffer( mmc_controller_t ctrlr, ssize_t cnt )
++{
++	ssize_t ret = -EIO;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++	register int ndesc;
++	int chan = hostdata->iobuf.buf.chan;
++	pxa_dma_desc *desc;
++#endif
++	
++	if ( (hostdata->state != PXA_MMC_FSM_END_CMD) 
++	    && (hostdata->state != PXA_MMC_FSM_END_BUFFER) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state (%s)\n",
++			PXA_MMC_STATE_LABEL( hostdata->state ) ); 
++		goto error;
++	}
++    
++	if ( cnt > hostdata->iobuf.bufsz )
++		cnt = hostdata->iobuf.bufsz;
++	
++	if ( (ret = pxa_mmc_iobuf_init( ctrlr, cnt )) )
++		goto error;
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_BUFFER_IN_TRANSIT );
++#ifndef PIO
++	if ( pxa_mmc_init_completion( ctrlr, ~MMC_I_MASK_ALL ) ) /* FIXME */
++		goto error;
++	if ( (desc = hostdata->iobuf.buf.last_write_desc) ) {
++		desc->ddadr &= ~DDADR_STOP;
++		desc->dcmd &= ~(DCMD_ENDIRQEN|DCMD_LENGTH);
++		desc->dcmd |= (1<<5);
++	}
++/* 1) setup descriptors for DMA transfer to the device */
++	ndesc = (cnt>>5) - 1; /* FIXME: partial write */
++	desc = &hostdata->iobuf.buf.write_desc[ndesc];
++	/* TODO: partial write */
++	hostdata->iobuf.buf.last_write_desc = desc;	
++	desc->ddadr |= DDADR_STOP;
++	desc->dcmd |= DCMD_ENDIRQEN;
++/* 2) start DMA channel */
++	DDADR( chan ) = hostdata->iobuf.buf.write_desc_phys_addr;
++	DCSR( chan ) |= DCSR_RUN;
++#else
++	if ( pxa_mmc_init_completion( ctrlr, MMC_I_MASK_TXFIFO_WR_REQ ) )
++		goto error;
++#endif
++	if ( pxa_mmc_wait_for_completion( ctrlr, ~0UL ) )
++		goto error;
++    
++	if ( pxa_mmc_check_state( ctrlr, PXA_MMC_FSM_END_BUFFER ) )
++		goto error;
++
++	if ( !(hostdata->mmc_stat & MMC_STAT_ERRORS) ) /* FIXME */  
++		ret = cnt;
++error:
++	return ret;
++}
++
++/* TODO: ssize_t pxa_mmc_copy_from_buffer( ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt )
++effects: copies at most cnt bytes from the controller I/O buffer to the user or kernel buffer
++         pointed by buf
++requiers:
++modifies:
++returns: number of bytes actually transferred or negative error code if there were any errors
++ */ 
++ssize_t pxa_mmc_copy_from_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt )
++{
++	ssize_t ret = -EIO;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++#ifndef PIO
++/* TODO: check that DMA channel is not running */
++#endif
++	switch ( to ) {
++	case MMC_USER:
++		if ( copy_to_user( buf, hostdata->iobuf.iodata, cnt ) ) {
++			ret = -EFAULT;
++			goto error;
++		}
++		break;
++        case MMC_KERNEL:
++		memcpy( buf, hostdata->iobuf.iodata, cnt );
++		break;
++        default:
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" );
++		goto error;
++	}
++	ret = cnt;
++error:
++	return ret;
++}
++
++ssize_t pxa_mmc_copy_to_buffer( mmc_controller_t ctrlr, mmc_buftype_t to, char *buf, ssize_t cnt )
++{
++	ssize_t ret = -EIO;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++/* check that DMA channel is not running */
++#endif
++	switch ( to ) {
++	case MMC_USER:
++		if ( copy_from_user( hostdata->iobuf.iodata, buf, cnt ) ) {
++			ret = -EFAULT;
++			goto error;
++		}
++		break;
++	case MMC_KERNEL:
++		memcpy( hostdata->iobuf.iodata, buf, cnt );
++		break;
++	default:
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "unknown buffer type\n" );
++		goto error;
++	}
++	ret = cnt;
++error:
++	return ret;
++}
++
++/* This procedure sequentally passes the data from the user buffer to the card */
++static int pxa_mmc_stream_read( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++	int ret = -EIO;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	u16 argh = 0UL, argl = 0UL;
++	ssize_t size = 0;
++
++	while ( transfer->cnt > 0 ) {
++		size = (transfer->cnt < hostdata->iobuf.blksz) ?
++			transfer->cnt : hostdata->iobuf.blksz; 
++		/* 1. send CMD11 */
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto error;
++
++		argh = transfer->addr >> 16;
++		argl = transfer->addr;
++		/* 2. setup controller registers to start stream data transfer */
++		MMC_CMD = CMD(11); /* READ_DAT_UNTIL_STOP */
++		MMC_ARGH = argh;
++		MMC_ARGL = argl;
++		MMC_NOB = 0xffff;
++		MMC_BLKLEN = size;
++		MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++		MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; 
++#endif
++		/* 3. wait for cmd to complete */
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD11(0x%04x%04x)\n", argh, argl );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) )
++			goto error;	
++    
++		/* 4. transfer the data to the caller supplied buffer */
++		if ( (ret = pxa_mmc_read_buffer( ctrlr, size )) < 0 )
++			goto error;
++
++		if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 )
++			goto error;
++        
++		pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++		if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++			goto error;
++	        
++		transfer->buf += ret;
++		transfer->addr += ret;
++		transfer->cnt -= ret;
++	}
++	ret = 0;    
++error:
++	return ret;
++}
++
++/* This procedure reads a data block from a card at a given kernel address */ 
++static int pxa_mmc_read_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++	int ret = -ENODEV;
++	u16 argh = 0UL, argl = 0UL;
++
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */  
++	if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) {
++		argh = transfer->blksz >> 16;
++		argl = transfer->blksz;
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) 
++			goto error;
++    
++		MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++		MMC_ARGH = argh;
++		MMC_ARGL = argl;
++		MMC_CMDAT = MMC_CMDAT_R1;
++        
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, 
++				"CMD16(0x%04x%04x)\n", argh, argl );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++			goto error;
++	}
++    
++/* CMD17 (READ_SINGLE_BLOCK) */
++	argh = transfer->addr >> 16;
++	argl = transfer->addr;
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto error;
++	
++	MMC_CMD = CMD(17); /* READ_SINGLE_BLOCK */
++	MMC_ARGH = argh;
++	MMC_ARGL = argl;
++	MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++	MMC_NOB = 1;
++	MMC_BLKLEN = transfer->blksz;
++#ifndef PIO
++	MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; 
++#endif
++    
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD17(0x%04x%04x)\n", argh, argl );
++	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++		goto error;
++    
++/* transfer the data to the caller supplied buffer */
++	if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->blksz )) < 0 )
++		goto error;
++
++	if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 )
++		goto error;
++        
++	transfer->buf += ret;
++	transfer->cnt -= ret;
++	transfer->nob -= 1;
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++	if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++		goto error;
++    
++	ret = 0;    
++error:
++	return ret;
++}
++
++/* This procedure sequentally reads data blocks from
++ * a card to the user buffer. Controller options and block size 
++ * are already set by setup_card(). Data alignment and partial
++ * data accessibility assumed to be checked by mmc_core */
++static int pxa_mmc_read_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++	int ret = -EIO;
++	u16 argh = 0UL, argl = 0UL;
++
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */  
++	if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) {
++		argh = transfer->blksz >> 16;
++		argl = transfer->blksz;
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto error;
++    
++		MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++		MMC_ARGH = argh;
++		MMC_ARGL = argl;
++		MMC_CMDAT = MMC_CMDAT_R1;
++        
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++			goto error;
++	}
++    
++	argh = transfer->addr >> 16;
++	argl = transfer->addr;
++/* 1. stop bus clock */
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto error;
++
++/* 2. setup controller registers to start multiple block transfer */
++	MMC_CMD = CMD(18); /* READ_MULTIPLE_BLOCK */
++	MMC_ARGH = argh;
++	MMC_ARGL = argl;
++	MMC_NOB = transfer->nob;
++	MMC_BLKLEN = transfer->blksz;
++	MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_READ|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++	MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; 
++#endif
++
++/* 3. start clock */
++	if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) )
++		goto error;
++    
++/* 4. wait for cmd to complete */
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD18(0x%04x%04x)\n", argh, argl );
++	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) )
++		goto error;
++    
++/* 6. transfer the data to the caller supplied buffer */
++	while ( transfer->cnt > 0 ) {
++		if ( (ret = pxa_mmc_read_buffer( ctrlr, transfer->cnt )) < 0 )
++			goto error;
++
++		if ( (ret = pxa_mmc_copy_from_buffer( ctrlr, transfer->type, transfer->buf, ret )) < 0 )
++			goto error;
++        
++		transfer->buf += ret;
++		transfer->cnt -= ret;
++	}
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++	if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++		goto error;
++    
++	ret = 0;
++error:
++	return ret;
++}
++
++/* Sequentally writes the data from a user buffer to the card */
++static int pxa_mmc_stream_write( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++	int ret = -EIO;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	u16 argh = 0UL, argl = 0UL;
++	ssize_t size = 0;
++    
++	__ENTER( "transfer: cmd=%d mode=%d type=%d blksz=%d "
++		 "nob=%d buf=%p cnt=%d addr=%Lx", transfer->cmd, 
++		transfer->mode, transfer->type, transfer->blksz, 
++		transfer->nob, transfer->buf, transfer->cnt, transfer->addr );
++
++	argh = transfer->addr >> 16;
++	argl = transfer->addr;
++/* 1. stop bus clock */
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) 
++		goto error;
++
++/* 2. setup controller registers to start stream data transfer */
++	MMC_CMD = CMD(20); /* WRITE_DAT_UNTIL_STOP */
++	MMC_ARGH = argh;
++	MMC_ARGL = argl;
++	MMC_NOB = 0xffff;
++	MMC_BLKLEN = hostdata->iobuf.blksz;
++	MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_STREAM|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++	MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; 
++#endif
++
++/* 3. wait for cmd to complete */
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD20(0x%04x%04x)\n", argh, argl );
++	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) )
++		goto error;
++    
++/* 4. transfer the data to the caller supplied buffer */
++	while ( transfer->cnt > 0 ) {
++		size = (transfer->cnt < hostdata->iobuf.blksz) ?
++			transfer->cnt : hostdata->iobuf.blksz; 
++		if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, 
++				transfer->type, transfer->buf, size )) < 0 )
++			goto error;
++        
++		if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )
++			goto error;
++
++		transfer->buf += ret;
++		transfer->cnt -= ret;
++	}
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++	if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++		goto error;
++    
++	ret = 0;
++error:
++	return ret;
++}
++
++/* This procedure writes a data block to a card at a given address */
++static int pxa_mmc_write_block( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++	int ret = -ENODEV;
++	u16 argh = 0UL, argl = 0UL;
++
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */  
++	if ( transfer->blksz != ctrlr->stack.selected->info.read_bl_len ) {
++		argh = transfer->blksz >> 16;
++		argl = transfer->blksz;
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) ) 
++			goto error;
++    
++		MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++		MMC_ARGH = argh;
++		MMC_ARGL = argl;
++		MMC_CMDAT = MMC_CMDAT_R1;
++        
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++			goto error;
++	}
++    
++/* CMD17 (READ_SINGLE_BLOCK) */
++	argh = transfer->addr >> 16;
++	argl = transfer->addr;
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto error;
++    
++	MMC_CMD = CMD(24); /* WRITE_BLOCK */
++	MMC_ARGH = argh;
++	MMC_ARGL = argl;
++	MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++	MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; 
++#endif
++	MMC_NOB = 1;
++	MMC_BLKLEN = transfer->blksz;
++    
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD24(0x%04x%04x)\n", argh, argl );
++	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++		goto error;
++    
++/* transfer the data to the caller supplied buffer */
++	if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type, transfer->buf, transfer->cnt )) < 0 )
++		goto error;
++        
++	if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )
++		goto error;
++
++	transfer->buf += ret;
++	transfer->cnt -= ret;
++	transfer->nob -= 1;
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++	if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++		goto error;
++    
++	ret = 0;    
++error:
++	return ret;
++}
++
++/* This procedure sequentally writes data blocks to a card at a given address */
++static ssize_t pxa_mmc_write_mblock( mmc_controller_t ctrlr, mmc_data_transfer_req_t transfer )
++{
++	int ret = -EIO;
++	u16 argh = 0UL, argl = 0UL;
++    	
++/* send CMD16 (SET_BLOCK_LEN) when requested block size is not the default
++ * for the current card */  
++	if ( transfer->blksz != ctrlr->stack.selected->info.write_bl_len ) {
++		argh = transfer->blksz >> 16;
++		argl = transfer->blksz;
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto error;
++    
++		MMC_CMD = CMD(16); /* SET_BLOCK_LEN */
++		MMC_ARGH = argh;
++		MMC_ARGL = argl;
++		MMC_CMDAT = MMC_CMDAT_R1;
++        
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD16(0x%04x%04x)\n", argh, argl );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, FALSE )) )
++			goto error;
++	}
++    
++	argh = transfer->addr >> 16;
++	argl = transfer->addr;
++/* 1. stop bus clock */
++	if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++		goto error;
++
++/* 2. setup controller registers to start multiple block transfer */
++	MMC_CMD = CMD(25); /* WRITE_MULTIPLE_BLOCK */
++	MMC_ARGH = argh;
++	MMC_ARGL = argl;
++	MMC_NOB = transfer->nob;
++	MMC_BLKLEN = transfer->blksz;
++	MMC_CMDAT = MMC_CMDAT_R1|MMC_CMDAT_WRITE|MMC_CMDAT_BLOCK|MMC_CMDAT_DATA_EN;
++#ifndef PIO
++	MMC_CMDAT |= MMC_CMDAT_MMC_DMA_EN; 
++#endif
++
++/* 3. start clock */
++	if ( (ret = pxa_mmc_start_bus_clock( ctrlr )) )
++		goto error;
++    
++/* 4. wait for cmd to complete */
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD25(0x%04x%04x)\n", argh, argl );
++	if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_R1, TRUE )) ) 
++		goto error;
++
++/* 6. transfer the data to the caller supplied buffer */
++	while ( transfer->cnt > 0 ) {
++		if ( (ret = pxa_mmc_copy_to_buffer( ctrlr, transfer->type,
++				transfer->buf, transfer->cnt )) < 0 )
++			goto error;
++        
++		if ( (ret = pxa_mmc_write_buffer( ctrlr, ret )) < 0 )
++			goto error;
++
++		transfer->buf += ret;
++		transfer->cnt -= ret;
++	}
++    
++	pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_IO );
++
++	if ( (ret = pxa_mmc_complete_io( ctrlr, transfer->cmd, transfer->mode )) )
++		goto error;
++    
++	ret = 0;    
++error:
++	return ret;
++}
++
++static void pxa_mmc_irq( int irq, void *dev_id, struct pt_regs *regs )
++{
++	mmc_controller_t ctrlr = (mmc_controller_t)dev_id;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifdef PIO
++	register int i, cnt;
++	register char *buf;
++#endif    
++
++	hostdata->mmc_i_reg = MMC_I_REG;
++	hostdata->mmc_stat = MMC_STAT;
++	hostdata->mmc_cmdat = MMC_CMDAT;
++#if 0
++	if (hostdata->mmc_i_reg != 0x0010) {
++	printk("IREG %08x", hostdata->mmc_i_reg);
++	if (hostdata->mmc_i_reg & 0x0001) printk(" DATA_TRAN_DONE");
++	if (hostdata->mmc_i_reg & 0x0002) printk(" PRG_DONE");
++	if (hostdata->mmc_i_reg & 0x0004) printk(" END_CMD");
++	if (hostdata->mmc_i_reg & 0x0008) printk(" STOP_CMD");
++	if (hostdata->mmc_i_reg & 0x0010) printk(" CLK_OFF");
++	if (hostdata->mmc_i_reg & 0x0020) printk(" RX_FIFO");
++	if (hostdata->mmc_i_reg & 0x0040) printk(" TX_FIFO");
++	printk("\nSTAT %08x", hostdata->mmc_stat);
++	if (hostdata->mmc_stat & 0x0001) printk(" READ_TO");
++	if (hostdata->mmc_stat & 0x0002) printk(" RESP_TO");
++	if (hostdata->mmc_stat & 0x0004) printk(" WR_CRC");
++	if (hostdata->mmc_stat & 0x0008) printk(" READ_CRC");
++	if (hostdata->mmc_stat & 0x0010) printk(" SPI_RD_TKN");
++	if (hostdata->mmc_stat & 0x0020) printk(" RESP_CRC");
++	if (hostdata->mmc_stat & 0x0040) printk(" TX_FIFO");
++	if (hostdata->mmc_stat & 0x0080) printk(" RX_FIFO");
++	if (hostdata->mmc_stat & 0x0100) printk(" CLK");
++	if (hostdata->mmc_stat & 0x0800) printk(" DATA_TRAN_DONE");
++	if (hostdata->mmc_stat & 0x1000) printk(" PRG_DONE");
++	if (hostdata->mmc_stat & 0x2000) printk(" END_CMD");
++	printk("\n");
++	}
++#endif
++
++#if CONFIG_MMC_DEBUG_IRQ 
++	if ( --hostdata->irqcnt <= 0 ) {
++		printk( KERN_INFO __FUNCTION__"(): irqcnt exceeded\n" );
++		goto complete;
++	}
++#endif
++	switch ( hostdata->state ) {
++	case PXA_MMC_FSM_IDLE:
++	case PXA_MMC_FSM_CLK_OFF:
++	case PXA_MMC_FSM_END_IO:
++	case PXA_MMC_FSM_END_BUFFER:
++	case PXA_MMC_FSM_END_CMD:
++		goto complete;
++#ifdef PIO   
++	case PXA_MMC_FSM_BUFFER_IN_TRANSIT:
++        	if ( hostdata->mmc_stat & MMC_STAT_ERRORS )
++         		goto complete;
++        
++		buf = hostdata->iobuf.buf.pos;
++        	cnt = (hostdata->iobuf.buf.cnt < 32) ? 
++			hostdata->iobuf.buf.cnt : 32;
++		if ( hostdata->mmc_cmdat & MMC_CMDAT_WRITE ) {
++			if ( !(hostdata->mmc_stat & MMC_STAT_XMIT_FIFO_EMPTY) )
++				break;
++			for ( i = 0; i < cnt; i++ ) 
++				MMC_TXFIFO = *buf++;
++			if ( cnt < 32 ) 
++				MMC_PRTBUF = MMC_PRTBUF_BUF_PART_FULL; 
++		} else { /* i.e. MMC_CMDAT_READ */
++			if( !(hostdata->mmc_stat & MMC_STAT_RECV_FIFO_FULL) )
++				break;
++			for( i = 0; i < cnt; i++ ) 
++				*buf++ = MMC_RXFIFO;
++		}
++        
++		hostdata->iobuf.buf.pos = buf;
++		hostdata->iobuf.buf.cnt -= i;
++		if ( hostdata->iobuf.buf.cnt <= 0 ) {
++			pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER );
++			MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" );
++			goto complete;
++		}
++		break; 
++#endif /* PIO */
++	default:
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "unexpected state %d\n", 
++				hostdata->state );
++		goto complete;
++	}   
++	return;	
++complete:   
++	MMC_I_MASK = MMC_I_MASK_ALL;
++	complete( &hostdata->completion );
++	return;
++}
++
++#ifndef PIO
++static void pxa_mmc_dma_irq( int irq, void *dev_id, struct pt_regs *regs )
++{
++	mmc_controller_t ctrlr = (mmc_controller_t)dev_id;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	u32 dcsr;
++	u32 ddadr;
++	int chan = hostdata->iobuf.buf.chan;
++	
++	ddadr = DDADR( chan );
++	dcsr = DCSR( chan );
++	DCSR( chan ) = dcsr & ~DCSR_STOPIRQEN;
++	
++	MMC_DEBUG( MMC_DEBUG_LEVEL3, 
++			"MMC DMA interrupt: chan=%d ddadr=0x%08x "
++			"dcmd=0x%08x dcsr=0x%08x\n", 
++			chan, ddadr, DCMD( chan ), dcsr );
++/* bus error */
++	if ( dcsr & DCSR_BUSERR ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "bus error on DMA channel %d\n",
++				chan );
++		pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_ERROR );
++		goto complete;
++	}
++/* data transfer completed */
++	if ( dcsr & DCSR_ENDINTR ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "buffer transferred\n" );
++		pxa_mmc_set_state( ctrlr, PXA_MMC_FSM_END_BUFFER );
++		goto complete;
++	}
++	return;
++complete:
++	complete( &hostdata->completion );
++	return;
++}
++#endif
++
++
++static int pxa_mmc_init( mmc_controller_t ctrlr )
++{
++	int ret = -ENODEV;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++#ifndef PIO
++	register int i;
++	register pxa_dma_desc *desc;
++#endif
++
++/* hardware initialization */
++/* I. prepare to transfer data */
++/* 1. allocate buffer */
++#ifndef PIO
++	hostdata->iobuf.buf.read_desc = consistent_alloc( GFP_KERNEL,
++				(PXA_MMC_IODATA_SIZE>>5)
++				* sizeof( pxa_dma_desc ),
++				&hostdata->iobuf.buf.read_desc_phys_addr, 0 );
++	if ( !hostdata->iobuf.buf.read_desc ) {
++		ret = -ENOMEM;
++		goto error;
++	}
++	hostdata->iobuf.buf.write_desc = consistent_alloc( GFP_KERNEL,
++				(PXA_MMC_IODATA_SIZE>>5)
++				* sizeof( pxa_dma_desc ),
++				&hostdata->iobuf.buf.write_desc_phys_addr, 0 );
++	if ( !hostdata->iobuf.buf.write_desc ) {
++		ret = -ENOMEM;
++		goto error;
++	}
++	hostdata->iobuf.iodata = consistent_alloc( GFP_ATOMIC, 
++					PXA_MMC_IODATA_SIZE,
++					&hostdata->iobuf.buf.phys_addr, 0 );
++#else
++	hostdata->iobuf.iodata = kmalloc( PXA_MMC_IODATA_SIZE, GFP_ATOMIC );
++#endif
++	if ( !hostdata->iobuf.iodata ) {
++		ret = -ENOMEM;
++		goto error;
++	}
++/* 2. initialize iobuf */
++	hostdata->iobuf.blksz = PXA_MMC_BLKSZ_MAX;
++	hostdata->iobuf.bufsz = PXA_MMC_IODATA_SIZE;
++	hostdata->iobuf.nob = PXA_MMC_BLOCKS_PER_BUFFER;
++#ifndef PIO
++  /* request DMA channel */
++	if ( (hostdata->iobuf.buf.chan = pxa_request_dma( "MMC", DMA_PRIO_LOW,
++					pxa_mmc_dma_irq, ctrlr )) < 0 ) {
++		MMC_ERROR( "failed to request DMA channel\n" );
++		goto error;
++	}
++	
++	DRCMRRXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD;
++	DRCMRTXMMC = hostdata->iobuf.buf.chan | DRCMR_MAPVLD;
++	
++	for ( i = 0; i < ((PXA_MMC_IODATA_SIZE>>5) - 1); i++ ) {
++		desc = &hostdata->iobuf.buf.read_desc[i];
++		desc->ddadr = hostdata->iobuf.buf.read_desc_phys_addr
++				+ ((i + 1) * sizeof( pxa_dma_desc ));
++		desc->dsadr = MMC_RXFIFO_PHYS_ADDR;
++		desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++		desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR
++				|DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++		
++		desc = &hostdata->iobuf.buf.write_desc[i];
++		desc->ddadr = hostdata->iobuf.buf.write_desc_phys_addr
++				+ ((i + 1) * sizeof( pxa_dma_desc ));
++		desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++		desc->dtadr = MMC_TXFIFO_PHYS_ADDR;
++		desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR
++				|DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++	}
++	desc = &hostdata->iobuf.buf.read_desc[i];
++	desc->ddadr = (hostdata->iobuf.buf.read_desc_phys_addr +
++				(i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP;
++	desc->dsadr = MMC_RXFIFO_PHYS_ADDR;
++	desc->dtadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++	desc->dcmd = DCMD_FLOWSRC|DCMD_INCTRGADDR
++			|DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++		
++	desc = &hostdata->iobuf.buf.write_desc[i];
++	desc->ddadr = (hostdata->iobuf.buf.write_desc_phys_addr +
++				(i + 1) * sizeof( pxa_dma_desc))|DDADR_STOP;
++	desc->dsadr = hostdata->iobuf.buf.phys_addr + (i<<5);
++	desc->dtadr = MMC_TXFIFO_PHYS_ADDR;
++	desc->dcmd = DCMD_FLOWTRG|DCMD_INCSRCADDR
++			|DCMD_WIDTH1|DCMD_BURST32|(1<<5);
++#endif
++/* II. MMC */
++/*  1) request irq */
++	if ( request_irq( IRQ_MMC, pxa_mmc_irq, 0, "MMC", ctrlr ) ) {
++		MMC_ERROR( "failed to request IRQ_MMC\n" );
++		goto error;
++	}
++    
++/*  2) initialize h/w and ctrlr */
++	set_GPIO_mode( GPIO6_MMCCLK_MD );
++	CKEN |= CKEN12_MMC; /* enable MMC unit clock */
++
++	ret = 0;
++	goto out;
++error:
++#ifndef PIO
++/* free DMA resources */
++	if ( hostdata->iobuf.buf.chan >= 0 ) {
++		DRCMRRXMMC = 0;
++		DRCMRTXMMC = 0;
++		pxa_free_dma( hostdata->iobuf.buf.chan );
++	}
++	if ( hostdata->iobuf.iodata )
++		consistent_free( hostdata->iobuf.iodata, 
++				 PXA_MMC_IODATA_SIZE,
++				 hostdata->iobuf.buf.phys_addr );
++	if ( hostdata->iobuf.buf.read_desc )	
++		consistent_free( hostdata->iobuf.buf.read_desc,
++				(PXA_MMC_IODATA_SIZE>>5)
++				* sizeof( pxa_dma_desc ),
++				hostdata->iobuf.buf.read_desc_phys_addr );
++	if ( hostdata->iobuf.buf.write_desc )	
++		consistent_free( hostdata->iobuf.buf.write_desc,
++				(PXA_MMC_IODATA_SIZE>>5)
++				* sizeof( pxa_dma_desc ),
++				hostdata->iobuf.buf.write_desc_phys_addr );
++#else
++	kfree( hostdata->iobuf.iodata );
++#endif
++out:
++	return ret; 
++}
++
++static void pxa_mmc_remove( mmc_controller_t ctrlr )
++{
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	
++/*  1) free buffer(s) */
++#ifndef PIO
++	consistent_free( hostdata->iobuf.iodata, PXA_MMC_IODATA_SIZE,
++			 hostdata->iobuf.buf.phys_addr );
++	consistent_free( hostdata->iobuf.buf.read_desc,
++	 		 (PXA_MMC_IODATA_SIZE>>5)
++			 * sizeof( pxa_dma_desc ),
++			 hostdata->iobuf.buf.read_desc_phys_addr );
++	consistent_free( hostdata->iobuf.buf.write_desc,
++			 (PXA_MMC_IODATA_SIZE>>5)
++			 * sizeof( pxa_dma_desc ),
++			 hostdata->iobuf.buf.write_desc_phys_addr );
++/*  2) release DMA channel */
++	if ( hostdata->iobuf.buf.chan >= 0 ) {
++		DRCMRRXMMC = 0;
++		DRCMRTXMMC = 0;
++		pxa_free_dma( hostdata->iobuf.buf.chan );
++	}
++#else
++	kfree( hostdata->iobuf.iodata );
++#endif
++/* II. MMC */
++/*  1) release irq */
++	free_irq( IRQ_MMC, ctrlr );
++	CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */
++}
++
++static int pxa_mmc_probe( mmc_controller_t ctrlr )
++{
++	return 1;
++}
++
++#ifdef CONFIG_PM
++static int pxa_mmc_suspend( mmc_controller_t ctrlr )
++{
++	int ret = -EBUSY;
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++	
++	MMC_DEBUG( MMC_DEBUG_LEVEL2, "state=%s\n", 
++			PXA_MMC_STATE_LABEL( hostdata->state ) );
++
++	if ( hostdata->state == PXA_MMC_FSM_IDLE ) {
++		/* save registers */
++		SAVED_MMC_CLKRT = MMC_CLKRT;
++		SAVED_MMC_RESTO = MMC_RESTO;
++		SAVED_MMC_SPI = MMC_SPI;
++		SAVED_DRCMRRXMMC = DRCMRRXMMC;
++		SAVED_DRCMRTXMMC = DRCMRTXMMC;
++
++#if 0 /* FIXME */
++		/* send CMD0 */
++		if ( (ret = pxa_mmc_stop_bus_clock( ctrlr )) )
++			goto error;
++
++		MMC_CMD = CMD(0); /* CMD0 with zero argument */
++		MMC_ARGH = 0UL;
++		MMC_ARGL = 0UL; 
++		MMC_CMDAT = 0UL;
++    
++		MMC_DEBUG( MMC_DEBUG_LEVEL3, "CMD0(0x%04x%04x)\n", 0UL, 0UL );
++		if ( (ret = pxa_mmc_complete_cmd( ctrlr, MMC_NORESPONSE, 
++						FALSE )) ) 
++		{
++			ret = -EIO;
++			goto error;
++		}
++#endif		
++	
++		set_GPIO_mode( GPIO6_MMCCLK );
++		CKEN &= ~CKEN12_MMC; /* disable MMC unit clock */
++		
++		hostdata->suspended = TRUE;
++		ret = 0;
++	}
++error:
++	return ret;
++}
++
++static void pxa_mmc_resume( mmc_controller_t ctrlr )
++{
++	pxa_mmc_hostdata_t hostdata = (pxa_mmc_hostdata_t)ctrlr->host_data;
++
++	if ( hostdata->suspended == TRUE ) {
++		set_GPIO_mode( GPIO6_MMCCLK_MD );
++		CKEN |= CKEN12_MMC; /* enable MMC unit clock */
++		
++		/* restore registers */
++		MMC_CLKRT = SAVED_MMC_CLKRT;
++		MMC_RESTO = SAVED_MMC_RESTO;
++		MMC_SPI = SAVED_MMC_SPI;
++		DRCMRRXMMC = SAVED_DRCMRRXMMC;
++		DRCMRTXMMC = SAVED_DRCMRTXMMC;
++
++		hostdata->suspended = FALSE;
++
++		mmc_update_card_stack( ctrlr->slot ); /* FIXME */
++	}
++	
++	return;
++}
++#endif
++
++static mmc_controller_tmpl_rec_t pxa_mmc_controller_tmpl_rec = {
++	owner:			THIS_MODULE,
++	name:			"PXA250",
++	block_size_max:		PXA_MMC_BLKSZ_MAX,
++	nob_max:		PXA_MMC_NOB_MAX,
++	probe:			pxa_mmc_probe,
++	init:			pxa_mmc_init,
++	remove:			__devexit_p( pxa_mmc_remove ),
++#ifdef CONFIG_PM
++	suspend:		pxa_mmc_suspend,
++	resume:			pxa_mmc_resume,
++#endif /* CONFIG_PM */
++	update_acq:		pxa_mmc_update_acq,
++//	single_card_acq:	pxa_mmc_single_card_acq,
++	init_card_stack:	pxa_mmc_init_card_stack,
++	check_card_stack:	pxa_mmc_check_card_stack,
++	setup_card:		pxa_mmc_setup_card,
++	stream_read:		pxa_mmc_stream_read,
++	read_block:		pxa_mmc_read_block,
++	read_mblock:		pxa_mmc_read_mblock,
++	stream_write:		pxa_mmc_stream_write,
++	write_block:		pxa_mmc_write_block,
++	write_mblock:		pxa_mmc_write_mblock
++	/* TODO
++	sg_io:			pxa_mmc_sg_io
++	 */
++	/* TODO: 
++	 *  erase, 
++	 *  write protection,
++	 *  lock/password management methods
++	 */
++};
++
++static int __devinit mmc_pxa_module_init( void )
++{
++    	int ret = -ENODEV;
++#ifdef CONFIG_ARCH_RAMSES
++	RAMSES_MMC_ON();
++	udelay(1000);
++#endif
++
++	host = mmc_register( MMC_REG_TYPE_HOST, &pxa_mmc_controller_tmpl_rec,
++			sizeof( pxa_mmc_hostdata_rec_t ) );
++	if ( !host ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, 
++				"failed to register with MMC core\n" );
++		goto error;
++	}
++	
++	ret = 0;
++error:
++	return ret;
++}
++
++static void __devexit mmc_pxa_module_cleanup( void )
++{
++	mmc_unregister( MMC_REG_TYPE_HOST, host );
++#ifdef CONFIG_ARCH_RAMSES
++	RAMSES_MMC_OFF();
++#endif
++}
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_LICENSE( "GPL" );
++
++module_init( mmc_pxa_module_init );
++module_exit( mmc_pxa_module_cleanup );
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/mmc_pxa.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,278 @@
++/*
++ *  linux/drivers/mmc/mmc_pxa.h 
++ *
++ *  Author: Vladimir Shebordaev, Igor Oblakov   
++ *  Copyright:  MontaVista Software Inc.
++ *
++ *  $Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#ifndef __MMC_PXA_P_H__
++#define __MMC_PXA_P_H__
++
++#include <linux/completion.h>
++
++#define PIO
++
++/* PXA-250 MMC controller registers */
++
++/* MMC_STRPCL */
++#define MMC_STRPCL_STOP_CLK     (0x0001UL)
++#define MMC_STRPCL_START_CLK        (0x0002UL)
++
++/* MMC_STAT */
++#define MMC_STAT_END_CMD_RES        (0x0001UL << 13)
++#define MMC_STAT_PRG_DONE       (0x0001UL << 12)
++#define MMC_STAT_DATA_TRAN_DONE     (0x0001UL << 11)
++#define MMC_STAT_CLK_EN         (0x0001UL << 8)
++#define MMC_STAT_RECV_FIFO_FULL     (0x0001UL << 7)
++#define MMC_STAT_XMIT_FIFO_EMPTY    (0x0001UL << 6)
++#define MMC_STAT_RES_CRC_ERROR      (0x0001UL << 5)
++#define MMC_STAT_SPI_READ_ERROR_TOKEN   (0x0001UL << 4)
++#define MMC_STAT_CRC_READ_ERROR     (0x0001UL << 3)
++#define MMC_STAT_CRC_WRITE_ERROR    (0x0001UL << 2)
++#define MMC_STAT_TIME_OUT_RESPONSE  (0x0001UL << 1)
++#define MMC_STAT_READ_TIME_OUT      (0x0001UL)
++
++#define MMC_STAT_ERRORS (MMC_STAT_RES_CRC_ERROR|MMC_STAT_SPI_READ_ERROR_TOKEN\
++        |MMC_STAT_CRC_READ_ERROR|MMC_STAT_TIME_OUT_RESPONSE\
++        |MMC_STAT_READ_TIME_OUT)
++
++/* MMC_CLKRT */
++#define MMC_CLKRT_20MHZ         (0x0000UL)
++#define MMC_CLKRT_10MHZ         (0x0001UL)
++#define MMC_CLKRT_5MHZ          (0x0002UL)
++#define MMC_CLKRT_2_5MHZ        (0x0003UL)
++#define MMC_CLKRT_1_25MHZ       (0x0004UL)
++#define MMC_CLKRT_0_625MHZ      (0x0005UL)
++#define MMC_CLKRT_0_3125MHZ     (0x0006UL)
++
++/* MMC_SPI */
++#define MMC_SPI_DISABLE         (0x00UL)
++#define MMC_SPI_EN          (0x01UL)
++#define MMC_SPI_CS_EN           (0x01UL << 2)
++#define MMC_SPI_CS_ADDRESS      (0x01UL << 3)
++#define MMC_SPI_CRC_ON          (0x01UL << 1)
++
++/* MMC_CMDAT */
++#define MMC_CMDAT_MMC_DMA_EN        (0x0001UL << 7)
++#define MMC_CMDAT_INIT          (0x0001UL << 6)
++#define MMC_CMDAT_BUSY          (0x0001UL << 5)
++#define MMC_CMDAT_STREAM        (0x0001UL << 4)
++#define MMC_CMDAT_BLOCK         (0x0000UL << 4)
++#define MMC_CMDAT_WRITE         (0x0001UL << 3)
++#define MMC_CMDAT_READ          (0x0000UL << 3)
++#define MMC_CMDAT_DATA_EN       (0x0001UL << 2)
++#define MMC_CMDAT_R1            (0x0001UL)
++#define MMC_CMDAT_R2            (0x0002UL)
++#define MMC_CMDAT_R3            (0x0003UL)
++
++/* MMC_RESTO */
++#define MMC_RES_TO_MAX          (0x007fUL) /* [6:0] */
++
++/* MMC_RDTO */
++#define MMC_READ_TO_MAX         (0x0ffffUL) /* [15:0] */
++
++/* MMC_BLKLEN */
++#define MMC_BLK_LEN_MAX         (0x03ffUL) /* [9:0] */
++
++/* MMC_PRTBUF */
++#define MMC_PRTBUF_BUF_PART_FULL       (0x01UL) 
++#define MMC_PRTBUF_BUF_FULL		(0x00UL    )
++
++/* MMC_I_MASK */
++#define MMC_I_MASK_TXFIFO_WR_REQ        (0x01UL << 6)
++#define MMC_I_MASK_RXFIFO_RD_REQ        (0x01UL << 5)
++#define MMC_I_MASK_CLK_IS_OFF           (0x01UL << 4)
++#define MMC_I_MASK_STOP_CMD         (0x01UL << 3)
++#define MMC_I_MASK_END_CMD_RES          (0x01UL << 2)
++#define MMC_I_MASK_PRG_DONE         (0x01UL << 1)
++#define MMC_I_MASK_DATA_TRAN_DONE       (0x01UL)
++#define MMC_I_MASK_ALL              (0x07fUL)
++
++
++/* MMC_I_REG */
++#define MMC_I_REG_TXFIFO_WR_REQ     (0x01UL << 6)
++#define MMC_I_REG_RXFIFO_RD_REQ     (0x01UL << 5)
++#define MMC_I_REG_CLK_IS_OFF        (0x01UL << 4)
++#define MMC_I_REG_STOP_CMD      (0x01UL << 3)
++#define MMC_I_REG_END_CMD_RES       (0x01UL << 2)
++#define MMC_I_REG_PRG_DONE      (0x01UL << 1)
++#define MMC_I_REG_DATA_TRAN_DONE    (0x01UL)
++#define MMC_I_REG_ALL           (0x007fUL)
++
++/* MMC_CMD */
++#define MMC_CMD_INDEX_MAX       (0x006fUL)  /* [5:0] */
++#define CMD(x)  (x)
++
++/* MMC_ARGH */
++/* MMC_ARGL */
++/* MMC_RES */
++/* MMC_RXFIFO */
++#define MMC_RXFIFO_PHYS_ADDR 0x41100040 //MMC_RXFIFO physical address
++/* MMC_TXFIFO */ 
++#define MMC_TXFIFO_PHYS_ADDR 0x41100044 //MMC_TXFIFO physical address
++
++/* implementation specific declarations */
++#define PXA_MMC_BLKSZ_MAX (1<<9) /* actually 1023 */
++#define PXA_MMC_NOB_MAX ((1<<16)-2)
++#define PXA_MMC_BLOCKS_PER_BUFFER (2)
++
++#define PXA_MMC_IODATA_SIZE (PXA_MMC_BLOCKS_PER_BUFFER*PXA_MMC_BLKSZ_MAX) /* 1K */
++
++typedef enum _pxa_mmc_fsm {         /* command processing FSM */
++    PXA_MMC_FSM_IDLE = 1,
++    PXA_MMC_FSM_CLK_OFF,
++    PXA_MMC_FSM_END_CMD,
++    PXA_MMC_FSM_BUFFER_IN_TRANSIT,
++    PXA_MMC_FSM_END_BUFFER, 
++    PXA_MMC_FSM_END_IO, 
++    PXA_MMC_FSM_END_PRG,
++    PXA_MMC_FSM_ERROR
++} pxa_mmc_state_t;
++
++#define PXA_MMC_STATE_LABEL( state ) (\
++    (state == PXA_MMC_FSM_IDLE) ? "IDLE" :\
++    (state == PXA_MMC_FSM_CLK_OFF) ? "CLK_OFF" :\
++    (state == PXA_MMC_FSM_END_CMD) ? "END_CMD" :\
++    (state == PXA_MMC_FSM_BUFFER_IN_TRANSIT) ? "IN_TRANSIT" :\
++    (state == PXA_MMC_FSM_END_BUFFER) ? "END_BUFFER" :\
++    (state == PXA_MMC_FSM_END_IO) ? "END_IO" :\
++    (state == PXA_MMC_FSM_END_PRG) ? "END_PRG" : "UNKNOWN" )
++
++typedef enum _pxa_mmc_result {
++    PXA_MMC_NORMAL = 0,
++    PXA_MMC_INVALID_STATE = -1,
++    PXA_MMC_TIMEOUT = -2,
++    PXA_MMC_ERROR = -3
++} pxa_mmc_result_t;
++
++typedef u32 pxa_mmc_clkrt_t;
++
++typedef char *pxa_mmc_iodata_t;
++#ifdef PIO
++typedef struct _pxa_mmc_piobuf_rec {
++    char *pos; /* current buffer position */
++    int   cnt; /* byte counter */
++} pxa_mmc_piobuf_rec_t, *pxa_mmc_piobuf_t;
++#else /* i.e. DMA */
++typedef struct _pxa_mmc_dmabuf_rec { /* TODO: buffer ring, DMA irq completion */
++	int chan; /* dma channel no */
++	dma_addr_t phys_addr; /* iodata physical address */
++	pxa_dma_desc *read_desc; /* input descriptor array virtual address */
++	pxa_dma_desc *write_desc; /* output descriptor array virtual address */
++	dma_addr_t read_desc_phys_addr; /* descriptor array physical address */
++	dma_addr_t write_desc_phys_addr; /* descriptor array physical address */
++	pxa_dma_desc *last_read_desc; /* last input descriptor 
++				       * used by the previous transfer 
++				       */
++	pxa_dma_desc *last_write_desc; /* last output descriptor
++					* used by the previous transfer 
++					*/
++} pxa_mmc_dmabuf_rec_t, *pxa_mmc_dmabuf_t;
++#endif
++
++typedef struct _pxa_mmc_iobuf_rec {
++    ssize_t blksz; /* current block size in bytes */
++    ssize_t bufsz; /* buffer size for each transfer */
++    ssize_t nob; /* number of blocks pers buffer */ 
++#ifndef PIO 
++    pxa_mmc_dmabuf_rec_t buf; /* i.e. DMA buffer ring on the iodata */
++#else /* i.e. DMA */
++    pxa_mmc_piobuf_rec_t buf; /* PIO buffer accounting */
++#endif
++    pxa_mmc_iodata_t iodata; /* I/O data buffer */
++} pxa_mmc_iobuf_rec_t, *pxa_mmc_iobuf_t;
++
++typedef struct _pxa_mmc_hostdata_rec {
++    pxa_mmc_state_t state; /* FSM */
++#ifdef CONFIG_PM
++    int suspended;
++#endif
++    pxa_mmc_iobuf_rec_t iobuf; /* data transfer state */
++    
++    int busy;   /* atomic busy flag */
++    struct completion completion; /* completion */
++#if CONFIG_MMC_DEBUG_IRQ
++    int irqcnt;
++    int timeo;
++#endif
++    
++/* cached controller state */
++    u32 mmc_i_reg;  /* interrupt last requested */
++    u32 mmc_i_mask; /* mask to be set by intr handler */
++    u32 mmc_stat;   /* status register at the last intr */
++    u32 mmc_cmdat;  /* MMC_CMDAT at the last inr */
++    u8 mmc_res[16]; /* response to the last command in host order */ 
++    u32 saved_mmc_clkrt;
++    u32 saved_mmc_resto;
++    u32 saved_mmc_spi;
++    u32 saved_drcmrrxmmc;
++    u32 saved_drcmrtxmmc;
++
++/* controller options */
++    pxa_mmc_clkrt_t clkrt; /* current bus clock rate */
++} pxa_mmc_hostdata_rec_t, *pxa_mmc_hostdata_t;
++
++#define PXA_MMC_STATUS( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_stat)
++#define PXA_MMC_RESPONSE( ctrlr, idx ) ((((pxa_mmc_hostdata_t)ctrlr->host_data)->mmc_res)[idx])
++#define PXA_MMC_CLKRT( ctrlr ) (((pxa_mmc_hostdata_t)ctrlr->host_data)->clkrt)  
++
++#define SAVED_MMC_CLKRT (hostdata->saved_mmc_clkrt)
++#define SAVED_MMC_RESTO (hostdata->saved_mmc_resto)
++#define SAVED_MMC_SPI (hostdata->saved_mmc_spi)
++#define SAVED_DRCMRRXMMC (hostdata->saved_drcmrrxmmc )
++#define SAVED_DRCMRTXMMC (hostdata->saved_drcmrtxmmc )
++
++static inline int pxa_mmc_clkrt( int speed )
++{
++    return MMC_CLKRT_20MHZ; /* TODO */
++}
++
++/* PXA MMC controller specific card data */
++typedef struct _pxa_mmc_card_data_rec { 
++    pxa_mmc_clkrt_t clkrt;   /* clock rate to be set for the card */
++} pxa_mmc_card_data_rec_t, *pxa_mmc_card_data_t;
++
++#ifdef CONFIG_MMC_DEBUG
++#undef MMC_DUMP_R1
++#undef MMC_DUMP_R2
++#undef MMC_DUMP_R3
++#define MMC_DUMP_R2( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"R2 response: %02x %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", \
++PXA_MMC_RESPONSE( ctrlr, 15 ), \
++PXA_MMC_RESPONSE( ctrlr, 14 ), \
++PXA_MMC_RESPONSE( ctrlr, 13 ), \
++PXA_MMC_RESPONSE( ctrlr, 12 ), \
++PXA_MMC_RESPONSE( ctrlr, 11 ), \
++PXA_MMC_RESPONSE( ctrlr, 10 ), \
++PXA_MMC_RESPONSE( ctrlr, 9 ), \
++PXA_MMC_RESPONSE( ctrlr, 8 ), \
++PXA_MMC_RESPONSE( ctrlr, 7 ), \
++PXA_MMC_RESPONSE( ctrlr, 6 ), \
++PXA_MMC_RESPONSE( ctrlr, 5 ), \
++PXA_MMC_RESPONSE( ctrlr, 4 ), \
++PXA_MMC_RESPONSE( ctrlr, 3 ), \
++PXA_MMC_RESPONSE( ctrlr, 2 ), \
++PXA_MMC_RESPONSE( ctrlr, 1 ), \
++PXA_MMC_RESPONSE( ctrlr, 0 ) );
++#define MMC_DUMP_R1( ctrlr ) MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"R1(b) response: %02x %02x%02x%02x%02x\n", \
++PXA_MMC_RESPONSE( ctrlr, 5 ), \
++PXA_MMC_RESPONSE( ctrlr, 4 ), \
++PXA_MMC_RESPONSE( ctrlr, 3 ), \
++PXA_MMC_RESPONSE( ctrlr, 2 ), \
++PXA_MMC_RESPONSE( ctrlr, 1 ) );
++#define MMC_DUMP_R3( ctrlr )	MMC_DEBUG( MMC_DEBUG_LEVEL3, \
++"R3 response: %02x %02x%02x%02x%02x\n", \
++PXA_MMC_RESPONSE( ctrlr, 5 ), \
++PXA_MMC_RESPONSE( ctrlr, 4 ), \
++PXA_MMC_RESPONSE( ctrlr, 3 ), \
++PXA_MMC_RESPONSE( ctrlr, 2 ), \
++PXA_MMC_RESPONSE( ctrlr, 1 ) );
++
++#endif
++#endif /* __MMC_PXA_P_H__ */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/mmc_test.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,538 @@
++/*
++ *  linux/drivers/mmc/mmc_test.c 
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *	$Id$
++ * 
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++
++#include <linux/fs.h>
++#ifdef CONFIG_DEVFS_FS
++#include <linux/devfs_fs_kernel.h>
++#endif
++
++#include <asm/uaccess.h>
++
++#include <mmc/types.h>
++#include <mmc/mmc.h>
++#include <mmc/ioctl.h>
++
++#include "types.h"
++#include "mmc.h"
++
++typedef struct _mmc_test_device_rec mmc_test_device_rec_t;
++typedef struct _mmc_test_device_rec *mmc_test_device_t;
++
++struct _mmc_test_device_rec {
++	mmc_card_t card;
++	mmc_transfer_mode_t transfer_mode;
++	int usage;
++#ifdef CONFIG_DEVFS_FS
++	devfs_handle_t devfs_handle;
++#endif
++};
++
++/* MMC device table */
++static mmc_test_device_rec_t mmc_test_device[MMC_CONTROLLERS_MAX][MMC_CARDS_MAX];
++static DECLARE_MUTEX(mmc_test_device_mutex);
++
++static inline mmc_test_device_t __mmc_test_get_device( kdev_t rdev )
++{
++	mmc_test_device_t ret = NULL;
++	u8 minor = MINOR( rdev );
++	int host_no, card_no;
++
++	host_no = minor >> MMC_MINOR_HOST_SHIFT;
++	if ( host_no >= MMC_CONTROLLERS_MAX )
++		goto error;
++	
++	card_no = minor & MMC_MINOR_CARD_MASK;
++	if ( card_no >= MMC_CARDS_MAX )
++		goto error;
++	
++	ret = &mmc_test_device[host_no][card_no];
++	if ( !ret->card ) {
++		ret->card = mmc_get_card( host_no, card_no );
++		if ( !ret->card ) {
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to get card: host=%d, card=%d\n", host_no, card_no );
++			ret = NULL;
++			goto error;
++		}
++		
++	}
++	++ret->usage;
++	
++error:
++	return ret;
++}
++
++static inline void __mmc_test_put_device( mmc_test_device_t dev )
++{
++	mmc_put_card( dev->card );
++	--dev->usage;
++}
++
++static inline mmc_test_device_t mmc_test_get_device( kdev_t kdev )
++{
++	mmc_test_device_t ret = NULL;
++	
++	down( &mmc_test_device_mutex );
++	ret = __mmc_test_get_device( kdev );
++	up( &mmc_test_device_mutex );
++
++	return ret;
++}
++
++static inline void mmc_test_put_device( mmc_test_device_t dev )
++{
++	if ( dev ) {
++		down( &mmc_test_device_mutex );
++		__mmc_test_put_device( dev );
++		if ( !dev->usage ) {
++			if ( dev->card ) {
++				if ( dev->card->usage ) {
++					MMC_DEBUG( MMC_DEBUG_LEVEL0, 
++						"broken card reference\n" );
++				}
++				memset( dev, 0, sizeof( mmc_test_device_rec_t ) );
++			}
++		}
++		up( &mmc_test_device_mutex );
++	}
++}
++
++static inline int mmc_test_set_transfer_mode( mmc_test_device_t dev, mmc_transfer_mode_t mode )
++{
++	int ret = -1;
++	
++	if ( dev ) {
++		down( &mmc_test_device_mutex );
++		dev->transfer_mode = mode;
++		ret = 0;
++		up( &mmc_test_device_mutex );
++	}
++	return ret;
++}
++
++static inline mmc_transfer_mode_t mmc_test_get_transfer_mode( mmc_test_device_t dev )
++{
++	mmc_transfer_mode_t ret = MMC_TRANSFER_MODE_UNDEFINED;
++	
++	if ( dev ) {
++		down( &mmc_test_device_mutex );
++		ret = dev->transfer_mode;
++		up( &mmc_test_device_mutex );
++	}
++	return ret;
++}
++
++static int mmc_test_open( struct inode *inode, struct file *file )
++{
++	int ret = -ENODEV;
++	mmc_test_device_t dev = NULL;
++	
++	MOD_INC_USE_COUNT;
++	
++	__ENTER0( );	
++	dev = mmc_test_get_device( inode->i_rdev );
++	if ( !dev || !dev->card ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to acquire device\n" );
++		goto error;
++	}
++	
++	if ( dev->card->usage > 1 ) {
++		ret = -EBUSY;
++		goto error;
++	}
++	
++	dev->transfer_mode = MMC_TEST_TRANSFER_MODE_DEFAULT; /* FIXME: should check card CCC */
++	file->private_data = dev;
++	
++	__LEAVE0( );
++	return 0;
++error:
++	MOD_DEC_USE_COUNT;
++	mmc_test_put_device( dev );
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static int mmc_test_release( struct inode *inode, struct file *file )
++{
++	int ret = -ENODEV;
++	mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++	
++	if ( !dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++		goto error;
++	}
++
++	__ENTER( "host=%d, card=%d", dev->card->ctrlr->slot, dev->card->slot );
++	
++	file->private_data = NULL;
++	
++	mmc_test_put_device( dev );
++	MOD_DEC_USE_COUNT;
++	
++	ret = 0;
++error:	
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static ssize_t mmc_test_read( struct file *file, char *buf, size_t size, loff_t *ppos )
++{
++	ssize_t ret = -ENODEV;
++	ssize_t retsize = 0;
++	mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++
++	__ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size );
++	
++	if ( !dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++		goto error;
++	}
++	
++	switch ( dev->transfer_mode ) {
++		char *mbuf;
++		
++		case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++			mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual read_bl_len or ctrlr->block_size_max whichever is less ), GFP_KERNEL */
++			if ( !mbuf ) { 
++				ret = -ENOMEM; 
++				goto error; 
++			}
++			
++			while( size > 0 ) {
++				int lsize = (size > 512) ? 512 : size; 
++		
++				MMC_DEBUG( MMC_DEBUG_LEVEL4, 
++						"before mmc_read mbuf=0x%x "
++						"lsize=%d ppos=0x%x *ppos=%d\n",
++						mbuf, lsize, ppos, *ppos );
++				ret = mmc_read( dev->card, 
++						MMC_TRANSFER_MODE_BLOCK_SINGLE,
++						mbuf, lsize, ppos );
++				if ( ret <= 0 )
++					break;
++				
++				/* Copy to user */
++				if ( copy_to_user( buf, mbuf, ret ) ) {
++					ret = -EFAULT;
++					break;
++				}
++				retsize += ret;
++				buf += ret;
++				size -= ret;
++			}
++			
++			if ( retsize > 0 )
++				ret = retsize;
++			kfree(mbuf);
++			break;
++			
++		case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++			mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */
++			if ( !mbuf ) { 
++				ret = -ENOMEM; 
++				goto error; 
++			}
++			
++			while( size > 0 ) {
++				int lsize = (size > 1024) ? 1024 : size; 
++		
++				MMC_DEBUG( MMC_DEBUG_LEVEL4, 
++						"before mmc_read mbuf=0x%x "
++						"lsize=%d ppos=0x%x *ppos=%d\n",
++						mbuf, lsize, ppos, *ppos );
++				ret = mmc_read( dev->card, 
++					MMC_TRANSFER_MODE_BLOCK_MULTIPLE,
++					mbuf, lsize, ppos );
++				if ( ret <= 0 )
++					break;
++				
++				/* Copy to user */
++				if ( copy_to_user( buf, mbuf, ret ) ) {
++					ret = -EFAULT;
++					break;
++				}
++				retsize += ret;
++				buf += ret;
++				size -= ret;
++			}
++			
++			if ( retsize > 0 )
++				ret = retsize;
++			kfree(mbuf);
++			break;
++			
++		case MMC_TRANSFER_MODE_STREAM:
++			ret = mmc_read( dev->card, dev->transfer_mode,
++					buf, size, ppos );
++			break;
++			
++		default:
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" );
++	}
++error:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static ssize_t mmc_test_write( struct file *file, const char *buf, size_t size, loff_t *ppos )
++{
++	ssize_t ret = -ENODEV;
++	mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++	int retsize=0;
++
++	__ENTER( "host=%d, card=%d, size=%d", dev->card->ctrlr->slot, dev->card->slot, size );
++	
++	if ( !dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++		goto error;
++	}
++	
++	switch ( dev->transfer_mode ) {
++		char *mbuf;
++		
++		case MMC_TRANSFER_MODE_BLOCK_SINGLE:
++			mbuf = kmalloc( 512, GFP_ATOMIC ); /* FIXME: actual write_bl_len or ctrlr->block_size_max whichever is less, GFP_KERNEL */
++			if ( !mbuf ) { 
++				ret = -ENOMEM; 
++				goto error; 
++			}
++	
++			while ( size > 0 ) {
++				int lsize = ( size > 512 ) ? 512 : size;
++		
++				/* Copy from user */
++				if ( copy_from_user( mbuf, buf, lsize ) ) {
++					ret = -EFAULT;
++					break;
++				}
++				
++				ret = mmc_write( dev->card,
++					MMC_TRANSFER_MODE_BLOCK_SINGLE, 
++					mbuf, lsize, ppos );
++				if( ret <= 0 )
++					break;
++	
++				retsize += ret;
++				buf += ret;
++				size -= ret;
++			}
++			
++			if ( retsize > 0 )
++				ret = retsize;
++			
++			kfree( mbuf );
++			break; 
++			
++		case MMC_TRANSFER_MODE_BLOCK_MULTIPLE:
++			mbuf = kmalloc( 1024, GFP_ATOMIC ); /* FIXME */
++			if ( !mbuf ) { 
++				ret = -ENOMEM; 
++				goto error; 
++			}
++			
++			while( size > 0 ) {
++				int lsize = (size > 1024) ? 1024 : size; 
++		
++				MMC_DEBUG( MMC_DEBUG_LEVEL4, 
++						"before mmc_read mbuf=0x%x "
++						"lsize=%d ppos=0x%x *ppos=%d\n",
++						mbuf, lsize, ppos, *ppos );
++				ret = mmc_write( dev->card, 
++					MMC_TRANSFER_MODE_BLOCK_MULTIPLE,
++					mbuf, lsize, ppos );
++				if ( ret <= 0 )
++					break;
++				
++				/* Copy to user */
++				if ( copy_to_user( (char *)buf, mbuf, ret ) ) {
++					ret = -EFAULT;
++					break;
++				}
++				retsize += ret;
++				buf += ret;
++				size -= ret;
++			}
++			
++			if ( retsize > 0 )
++				ret = retsize;
++			kfree(mbuf);
++			break;
++		case MMC_TRANSFER_MODE_STREAM:
++			ret = mmc_write( dev->card, dev->transfer_mode,
++					buf, size, ppos );
++			break;
++			
++		default:
++			MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid transfer mode\n" );
++	}
++error:
++	__LEAVE( "ret=%d", ret );
++	return ret;
++}
++
++static loff_t mmc_test_llseek( struct file *file, loff_t offset, int origin )
++{
++	loff_t ret = -ESPIPE;
++	mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++	mmc_card_t card;
++	
++	if ( !dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++		ret = -ENODEV;
++		goto error;
++	}
++	
++	__ENTER( "host=%d, card=%d, off=%ld, orig=%d", dev->card->ctrlr->slot, dev->card->slot, (long)offset, origin );
++	
++	card = dev->card;
++	
++	switch ( origin ) {
++		case SEEK_CUR:
++			file->f_pos += offset;
++			break;
++	
++		case SEEK_END:
++			file->f_pos = card->info.capacity + offset;
++			break;
++		
++		case SEEK_SET:
++			file->f_pos = offset;
++			break;
++			
++		default:
++			ret = -EINVAL;
++			goto error;
++	}
++	
++	ret = file->f_pos;
++error:	
++	__LEAVE( "ret=%ld", (long)ret );
++	return ret;
++}
++
++static int mmc_test_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg )
++{
++	int ret = -ENODEV;
++	mmc_test_device_t dev = (mmc_test_device_t)file->private_data;
++
++	if ( !dev ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "file->private_data == NULL\n" );
++		goto error;
++	}
++	
++	switch ( cmd ) {
++		case IOCMMCSTRNSMODE:
++			if ( get_user( ret, (int *)arg ) ) {
++				ret = -EFAULT;
++				goto error;
++			}
++			ret = mmc_test_set_transfer_mode( dev, ret );
++			break;
++			
++		case IOCMMCGTRNSMODE:
++			ret = mmc_test_get_transfer_mode( dev );
++			if ( put_user( ret, (int *)arg ) ) 
++				ret = -EFAULT;
++			break;
++		
++		default:
++			ret = mmc_ioctl( dev->card, cmd, arg );
++	}
++	
++error:
++	return ret;
++}
++
++struct file_operations mmc_test_fops = {
++	owner:		THIS_MODULE,
++	open:		mmc_test_open,
++	release:	mmc_test_release,
++	read:		mmc_test_read,
++	write:		mmc_test_write,
++	ioctl:		mmc_test_ioctl,
++	llseek:		mmc_test_llseek
++};
++
++#ifdef CONFIG_DEVFS_FS
++static int mmc_test_add_card( mmc_card_t card ) /* TODO */
++{
++	int ret = -1;
++	__ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot );
++/* TODO: make kdev; register with devfs */
++	__LEAVE0( );
++	return ret;
++}
++
++static int mmc_test_remove_card( mmc_card_t card ) /* TODO */
++{
++	int ret = -1;
++	__ENTER( "host=%d, card=%d", card->ctrlr->slot, card->slot );
++/* TODO: make kdev; unregister with devfs */
++	__LEAVE0( );
++	return ret;
++}
++
++static mmc_notifier_rec_t mmc_test_notifier = {
++	add:	mmc_test_add_card,
++	remove: mmc_test_remove_card
++};
++#endif /* CONFIG_DEVFS_FS */
++
++static int __init mmc_test_module_init( void )
++{
++	int ret = -ENODEV;
++
++#ifdef CONFIG_DEVFS_FS
++	if ( !mmc_register( MMC_REG_TYPE_USER, &mmc_test_notifier, 0 ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register with MMC core\n" );
++		goto error;
++	}
++#else
++	mmc_register( MMC_REG_TYPE_USER, NULL, 0 );
++	if ( register_chrdev( MMC_TEST_MAJOR, "mmc_test", &mmc_test_fops ) ) {
++		MMC_DEBUG( MMC_DEBUG_LEVEL0, 
++				"failed to request device major number\n" );
++		mmc_unregister( MMC_REG_TYPE_USER, NULL );
++		goto error;
++	}
++#endif
++	
++	memset( mmc_test_device, 0, sizeof( mmc_test_device ) );
++	
++	ret = 0;
++error:
++	return ret;
++}
++
++static void __exit mmc_test_module_cleanup( void )
++{
++#ifdef CONFIG_DEVFS_FS
++	mmc_unregister( MMC_REG_TYPE_USER, &mmc_test_notifier );
++#else
++	mmc_unregister( MMC_REG_TYPE_USER, NULL );
++	unregister_chrdev( MMC_TEST_MAJOR, "mmc_test" );
++#endif
++}
++
++EXPORT_NO_SYMBOLS;
++
++module_init( mmc_test_module_init );
++module_exit( mmc_test_module_cleanup );
++
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/pm_test.c	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,29 @@
++/* Power Managment Test Module.  RTSoft Co. 2002 */ 
++
++/* The necessary header files */
++
++/* Standard in kernel modules */
++#include <linux/kernel.h>   /* We're doing kernel work */
++#include <linux/module.h>   /* Specifically, a module */
++#define CONFIG_PM
++#include <linux/pm.h>
++
++
++static int pmdata = -1;
++
++/* Initialize the module - register the proc file  */
++
++int init_module()
++{
++  pm_send_all(PM_SUSPEND,&pmdata);    
++  return(0);
++}
++
++
++/* Cleanup - unregister our file from /proc */
++void cleanup_module()
++{
++  pm_send_all(PM_RESUME,NULL);
++}
++
++MODULE_LICENSE( "GPL" );
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mmc/types.h	2004-03-31 17:15:11.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ *  linux/drivers/mmc/types.h
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *  $Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#ifndef __MMC_TYPES_P_H__
++#define __MMC_TYPES_P_H__
++
++#ifdef __KERNEL__
++#include <linux/kdev_t.h>
++
++typedef enum _mmc_reg_type mmc_reg_type_t;
++typedef enum _mmc_response mmc_response_fmt_t;
++
++/* MMC card private description */
++typedef struct _mmc_card_rec mmc_card_rec_t;
++typedef struct _mmc_card_rec *mmc_card_t;
++typedef enum _mmc_dir mmc_dir_t;
++typedef enum _mmc_buftype mmc_buftype_t;
++
++/* notifier declarations */
++typedef struct _mmc_notifier_rec mmc_notifier_rec_t;
++typedef struct _mmc_notifier_rec *mmc_notifier_t;
++
++typedef int (*mmc_notifier_fn_t) ( mmc_card_t );
++
++/* MMC card stack */
++typedef struct _mmc_card_stack_rec mmc_card_stack_rec_t;
++typedef struct _mmc_card_stack_rec *mmc_card_stack_t;
++
++typedef struct _mmc_data_transfer_req_rec mmc_data_transfer_req_rec_t;
++typedef struct _mmc_data_transfer_req_rec *mmc_data_transfer_req_t;
++
++/* MMC controller */
++typedef struct _mmc_controller_tmpl_rec mmc_controller_tmpl_rec_t;
++typedef struct _mmc_controller_tmpl_rec *mmc_controller_tmpl_t;
++
++typedef enum _mmc_controller_state mmc_controller_state_t;
++typedef struct _mmc_controller_rec mmc_controller_rec_t;
++typedef struct _mmc_controller_rec *mmc_controller_t;
++
++/* various kernel types */
++typedef struct semaphore semaphore_t;
++typedef struct rw_semaphore rwsemaphore_t;
++typedef struct proc_dir_entry proc_dir_entry_rec_t;
++typedef struct proc_dir_entry *proc_dir_entry_t;
++typedef struct gendisk gendisk_rec_t;
++typedef struct gendisk *gendisk_t;
++#endif /* __KERNEL__ */
++
++#endif /* __MMC_TYPES_P_H__ */
++
+--- linux-2.4.25/drivers/net/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/net/Config.in	2004-03-31 17:15:11.000000000 +0200
+@@ -125,6 +125,7 @@
+       dep_tristate '    SMC Ultra support' CONFIG_ULTRA $CONFIG_ISA
+       dep_tristate '    SMC Ultra32 EISA support' CONFIG_ULTRA32 $CONFIG_EISA
+       dep_tristate '    SMC 9194 support' CONFIG_SMC9194 $CONFIG_ISA
++      tristate     '    SMC 91C9x/91C1xx support' CONFIG_SMC91X
+    fi
+    bool '  Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
+    if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
+--- linux-2.4.25/drivers/net/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/net/Makefile	2004-03-31 17:15:11.000000000 +0200
+@@ -137,6 +137,7 @@
+ obj-$(CONFIG_SK_G16) += sk_g16.o
+ obj-$(CONFIG_HP100) += hp100.o
+ obj-$(CONFIG_SMC9194) += smc9194.o
++obj-$(CONFIG_SMC91X) += smc91x.o
+ obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
+ obj-$(CONFIG_ARM_ETHERH) += 8390.o
+ obj-$(CONFIG_WD80x3) += wd.o 8390.o
+--- linux-2.4.25/drivers/net/cirrus.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/net/cirrus.c	2004-03-31 17:15:11.000000000 +0200
+@@ -67,6 +67,9 @@
+ #elif CONFIG_ARCH_CDB89712
+ #	define CIRRUS_DEFAULT_IO ETHER_BASE + 0x300
+ #	define CIRRUS_DEFAULT_IRQ IRQ_EINT3
++#elif CONFIG_ARCH_CSB226
++#	define CIRRUS_DEFAULT_IO 0xF8000000
++#	define CIRRUS_DEFAULT_IRQ IRQ_GPIO(14) 
+ #else
+ #	define CIRRUS_DEFAULT_IO	0
+ #	define CIRRUS_DEFAULT_IRQ	0
+--- linux-2.4.25/drivers/net/irda/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/net/irda/Config.in	2004-03-31 17:15:11.000000000 +0200
+@@ -42,5 +42,7 @@
+ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+    dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL
+ fi
+-
++if [ "$CONFIG_ARCH_PXA" = "y" ]; then
++   dep_tristate 'Intel PXA2xx Internal IR' CONFIG_PXA_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL        
++fi
+ endmenu
+--- linux-2.4.25/drivers/net/irda/Makefile~2.4.25-vrs2-pxa1.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/net/irda/Makefile	2004-03-31 17:15:12.000000000 +0200
+@@ -16,6 +16,7 @@
+ obj-$(CONFIG_USB_IRDA)		+= irda-usb.o
+ obj-$(CONFIG_NSC_FIR)		+= nsc-ircc.o
+ obj-$(CONFIG_WINBOND_FIR)	+= w83977af_ir.o
++obj-$(CONFIG_PXA_FIR)		+= pxa_ir.o
+ obj-$(CONFIG_SA1100_FIR)	+= sa1100_ir.o
+ obj-$(CONFIG_TOSHIBA_OLD)	+= toshoboe.o
+ obj-$(CONFIG_TOSHIBA_FIR)	+= donauboe.o
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/net/irda/pxa_ir.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,1545 @@
++/*
++ *  linux/drivers/net/irda/pxa_ir.c
++ *
++ *  Author:
++ *  Alexey Lugovskoy RTSoft. 
++ *	lugovskoy@rtsoft.msk.ru
++ *
++ *  Dmitrij Frasenyak RTSoft. 
++ *      sed@mipt.sw.ru
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Infra-red SIR and FIR driver for the PXA 210/250 embedded microprocessors
++ *  Based on linux/drivers/net/irda/sa1100_ir.c
++ *
++ */
++
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/netdevice.h>
++#include <linux/slab.h>
++#include <linux/rtnetlink.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++
++#include <linux/pm.h>
++
++#include <net/irda/irda.h>
++#include <net/irda/irmod.h>
++#include <net/irda/wrapper.h>
++#include <net/irda/irda_device.h>
++
++#include <asm/irq.h>
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/arch/lubbock.h>
++
++
++static int rx_count = 0;
++static int tx_count = 0;
++
++/*
++ * Our netdevice.  There is only ever one of these.
++ */
++ 
++static struct net_device *netdev;
++
++struct pxa250_irda {
++	
++	unsigned char		open;
++
++	int			speed;
++	int			newspeed;
++
++	struct sk_buff		*txskb;
++	struct sk_buff		*rxskb;
++	
++
++	/* => FIR */
++	unsigned int		fir_irq;
++	int			txdma_ch;
++	int			rxdma_ch;
++	dma_addr_t		txbuf_dma;
++	dma_addr_t		rxbuf_dma;
++	void* 			txbuf_dma_virt;
++	void* 			rxbuf_dma_virt;
++	/* <= FIR*/
++	struct net_device_stats	stats;
++	struct irlap_cb		*irlap;
++	struct pm_dev		*pmdev;
++	struct qos_info		qos;
++
++	/* => SIR */
++	iobuff_t		tx_buff;
++	iobuff_t		rx_buff;
++	/* <= SIR */
++};
++
++#define IS_FIR(si)		((si)->speed >= 4000000)
++
++#define HPSIR_MAX_RXLEN		2050
++#define HPSIR_MAX_TXLEN		2050
++#define TXBUFF_MAX_SIZE		HPSIR_MAX_TXLEN
++#define SET_SIR_MODE            STISR = STISR_RCVEIR | STISR_XMITIR | STISR_XMODE
++
++/*
++ * If you want to disable debug information
++ * please uncomment line bellow
++ */
++
++#define PXA_FIR_DUMP_ENABLE
++#undef PXA_FIR_DUMP_ENABLE     
++
++
++#define PXA_FIR_DEBUG_ENABLE
++#undef PXA_FIR_DEBUG_ENABLE              
++
++#define PXA_FIR_IRQ_DEBUG_ENABLE
++#undef PXA_FIR_IRQ_DEBUG_ENABLE               
++
++#ifdef PXA_FIR_DEBUG_ENABLE
++#define __ECHO_IN printk(KERN_ERR "%s: enter\n",__FUNCTION__);
++#define __ECHO_OUT printk(KERN_ERR "%s: exit\n",__FUNCTION__);
++#define DBG(args...) printk(KERN_ERR __FUNCTION__"():"args);
++#else
++#define __ECHO_IN
++#define __ECHO_OUT
++#define DBG(args...)
++#endif
++
++#ifdef PXA_FIR_IRQ_DEBUG_ENABLE
++#define DBG_IRQ(args...) printk(KERN_ERR __FUNCTION__"():"args);
++#else
++#define DBG_IRQ(args...)
++#endif
++
++
++static int pxa250_irda_set_speed(struct net_device *dev,int speed);
++static void pxa250_start_rx_dma(struct net_device *dev);
++
++
++
++/**************************************************************************
++ *			Misc FIR/SIR functions				  *
++ **************************************************************************/
++/*
++ * Allocate the receive buffer, unless it is already allocated.
++ */
++
++static int pxa250_irda_rx_alloc(struct pxa250_irda *si)
++{
++   __ECHO_IN;
++   
++   if (si->rxskb)
++      return 0;
++
++   si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
++
++   if (!si->rxskb) {
++      printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n");
++      return -ENOMEM;
++   }
++
++   /*
++    * Align any IP headers that may be contained
++    * within the frame.
++    */
++   skb_reserve(si->rxskb, 1);
++
++   __ECHO_OUT;
++
++   return 0;
++}
++
++
++
++/**************************************************************************
++ *			FIR						  *
++ **************************************************************************/
++
++
++
++
++static inline void pxa250_dma_stop(int ch)
++{
++   __ECHO_IN;
++
++   DCSR(ch) &= ~DCSR_RUN;
++
++   __ECHO_OUT;
++   
++}
++
++
++static void pxa250_ficp_rx_start(void)
++{
++   ICCR0 = 0;
++   ICCR2 =  1 << 2 | 0 << 3 ; 
++   ICCR0 = ICCR0_ITR ;
++   ICCR0 |= ICCR0_RIE |  ICCR0_RXE ; 
++}
++
++/*
++ * Change Alternative Function encoding
++ * Enable ICP unit
++ * Disabe STUART unit
++ * Enable IRQ unit clock;
++ * Configure direction of GPIO used by ICP
++ */
++
++
++static void pxa250_do_fir_GPIO_config(void)
++{
++   /*
++    * Modify GPIO 46 and 47 Alternate Function 
++    */
++
++   __ECHO_IN;
++
++   /*Switch AF*/
++   set_GPIO_mode (GPIO46_ICPRXD_MD);
++   set_GPIO_mode (GPIO47_ICPTXD_MD);
++
++   if (machine_is_lubbock())
++      LUB_MISC_WR |= 1 << 4;
++
++   /*init clock*/
++   CKEN |= CKEN13_FICP;
++
++   __ECHO_OUT;
++}
++
++/*
++ * Low level hardware configuration and startup.
++ */
++
++static int pxa250_fir_irda_startup(struct pxa250_irda *si)
++{
++
++	__ECHO_IN;
++
++	/*
++	 * Disable STUART
++	 */
++
++	STIER &= ~IER_UUE;
++
++	/*Disable STUART FIFO */
++	STFCR = 0;
++
++	/*
++	 * Do low level configuration for HW AF and clock
++	 */
++	pxa250_do_fir_GPIO_config();
++
++	__ECHO_OUT;
++	return 0;
++}
++
++
++/*
++ * Aieeeeee .. we should never get here :(
++ */
++static void pxa250_irda_rxdma_irq(int ch,void *id, struct pt_regs *regs)
++{
++   struct net_device *dev=id;
++   struct pxa250_irda *si=dev->priv;
++   u_int dcsr;
++
++
++   __ECHO_IN;
++
++   /* 
++    * Make sure that irq is our.
++    */
++
++   if ( ch != si->rxdma_ch )
++      /*just*/ return;
++
++   /*
++    * Check status 
++    */
++   dcsr = DCSR(ch);
++
++   DBG("DCSR=%x\n",dcsr);
++
++   if (dcsr &  DCSR_STOPSTATE )
++   {
++      DBG_IRQ("Chanel %d in stop state\n",ch);
++   }
++
++   if (dcsr &  DCSR_BUSERR )
++   {
++      /*
++       * BUS Error we must restart reception
++       */
++      
++      DBG("PXA IrDA: bus error interrupt on channel %d\n", ch);
++      DCSR(ch) |= DCSR_BUSERR;
++   }
++
++   if (dcsr &  DCSR_ENDINTR )
++   {
++      DBG("PXA IrDA: Normal end of dma channel %d - packet to big\n", ch);
++      DCSR(ch) |= DCSR_ENDINTR;
++   }
++
++   /* no mater what restart rx*/
++   pxa250_start_rx_dma(dev);
++   
++   return ;
++   
++}
++
++
++static void pxa250_irda_txdma_irq(int ch, void *id , struct pt_regs *regs)
++{
++   struct net_device *dev=id;
++   struct pxa250_irda *si=dev->priv;
++   struct sk_buff *skb = si->txskb;
++   u_int dcsr;
++
++
++   __ECHO_IN;
++   DBG_IRQ("transmit\n"); 
++   
++     
++   /* 
++    * Make sure that irq is our.
++    */
++
++   if ( ch != si->txdma_ch )
++      /*just*/ return;
++
++
++   /*
++    * Check status 
++    */
++   dcsr = DCSR(ch);
++
++   DBG("DCSR=%x",dcsr);
++
++   if (dcsr &  DCSR_STOPSTATE )
++   {
++      DBG("Chanel %d in stop state\n",ch);
++   }
++
++   if (dcsr &  DCSR_BUSERR )
++   {
++      DBG("PXA IrDA: bus error interrupt on channel %d\n", ch);
++      DCSR(ch) |= DCSR_BUSERR;
++      si->txskb = NULL;
++   }
++
++   if (dcsr &  DCSR_ENDINTR )
++   {
++      DBG("PXA IrDA: Normal end of dma channel %d\n", ch);
++      DCSR(ch) |= DCSR_ENDINTR;
++      si->txskb = NULL;
++   }
++
++   /*
++    * Account and free the packet.
++    */
++   if (skb)
++   {
++      si->stats.tx_packets ++;
++      si->stats.tx_bytes += skb->len;
++      dev_kfree_skb_irq(skb);
++   }
++
++	/*Disable transceiver and enable receiver*/
++
++	if (si->newspeed) {
++	   pxa250_irda_set_speed(dev, si->newspeed);
++	   si->newspeed = 0;
++	}
++
++	while (ICSR1 & ICSR1_TBY)
++	   udelay(1);
++	
++     	ICCR0 &= ~ICCR0_TXE;
++
++	
++	enable_irq(si->fir_irq);
++
++  	ICCR0 |= ICCR0_RXE; 
++
++	/*
++	 * Make sure that the TX queue is available for sending
++	 * (for retries).  TX has priority over RX at all times.
++	 */
++	netif_wake_queue(dev);
++	
++	__ECHO_OUT;
++}
++
++
++static void pxa250_start_rx_dma(struct net_device *dev)
++{
++   struct pxa250_irda *si = dev->priv;
++   int ch=si->rxdma_ch;
++
++   if (!si->rxskb) {
++      DBG("rx buffer went missing\n");
++/*        return; */
++   }
++
++   DCSR(ch)=0;
++   DCSR(ch)=DCSR_NODESC;
++   DSADR(ch) = __PREG(ICDR);
++   DTADR(ch) = si->rxbuf_dma; /* phisical address */;
++
++   /* We should never do END_IRQ.  !!!*/
++   DCMD(ch) = DCMD_ENDIRQEN| DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_BURST8 | DCMD_WIDTH1 | HPSIR_MAX_RXLEN;
++
++   /*
++    * All right information will be available as soon as we set RXE flag
++    */
++   
++   DCSR(ch) = DCSR_ENDINTR | DCSR_BUSERR;
++   DCSR(ch) = DCSR_RUN | DCSR_NODESC ;
++
++}
++
++
++
++
++static int pxa250_get_rx_len(struct pxa250_irda *si)
++{
++   /*
++    * DMA have to be stoped here
++    */
++
++   if ( ! (DCSR(si->rxdma_ch) & DCSR_STOPSTATE) )
++      printk("warning dma have to be stoped befor counting len\n");
++   
++   return ( HPSIR_MAX_RXLEN - ( DCMD(si->rxdma_ch) & DCMD_LENGTH ) );
++   
++}
++
++static void pxa250_irda_fir_error(struct net_device *dev)
++{
++   struct pxa250_irda *si = dev->priv;
++   struct sk_buff *skb = si->rxskb;
++   int len;
++   int stat,data;
++
++   __ECHO_IN;
++   
++      if (!skb)
++      {
++	 printk("pxa250 fir_error: SKB is NULL!\n");
++	 return;
++      }
++
++      /*
++       * Get the current data position.
++       */
++
++      len=pxa250_get_rx_len(si);
++      DBG("RXLEN=%d\n",len);
++      memcpy(skb->data, si->rxbuf_dma_virt, len);
++
++      do {
++	 /*
++	  * Read Status, and then Data.
++	  */
++	   stat = ICSR1;
++	   rmb();
++	   data = ICDR;
++	   if (stat & (ICSR1_CRE | ICSR1_ROR)) {
++	      si->stats.rx_errors++;
++	      if (stat & ICSR1_CRE)
++		 si->stats.rx_crc_errors++;
++	      if (stat & ICSR1_ROR)
++		 si->stats.rx_frame_errors++;
++	   } else
++	      skb->data[len++] = data;
++
++		/*
++		 * If we hit the end of frame, there's
++		 * no point in continuing.
++		 */
++	   if (stat & ICSR1_EOF)
++	      break;
++	} while (ICSR0 & ICSR0_EIF);
++
++	if (stat & ICSR1_EOF) {
++	   si->rxskb = NULL;
++
++	   skb_put(skb, len);
++	   skb->dev = dev;
++	   skb->mac.raw = skb->data;
++	   skb->protocol = htons(ETH_P_IRDA);
++	   si->stats.rx_packets++;
++	   si->stats.rx_bytes += len;
++
++	   /*
++	    * Before we pass the buffer up, allocate a new one.
++	    */
++
++	   si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
++
++	   if (!si->rxskb) {
++	      printk(KERN_ERR "pxa250_ir: out of memory for RX SKB\n");
++	      return;
++	   }
++
++	   /*
++	    * Align any IP headers that may be contained
++	    * within the frame.
++	    */
++	   skb_reserve(si->rxskb, 1);
++
++	   netif_rx(skb);
++	}
++}
++
++/*
++ * FIR format interrupt service routine.  We only have to
++ * handle RX events; transmit events go via the TX DMA irq handler.
++ *
++ * No matter what, we disable RX, process, and then restart RX.
++ */
++
++static void pxa250_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++   struct net_device *dev = dev_id;
++   struct pxa250_irda *si = dev->priv;
++   int status;
++   
++   /*
++    * Stop RX
++    */
++
++   __ECHO_IN;
++
++   pxa250_dma_stop(si->rxdma_ch);
++
++   
++   /*
++    * Framing error - we throw away the packet completely.
++    * Clearing RXE flushes the error conditions and data
++    * from the fifo.
++    */
++   status=ICSR0;
++   
++   if (status & (ICSR0_FRE | ICSR0_RAB)) {
++      DBG_IRQ("Framing error or RAB\n"); 
++      
++      si->stats.rx_errors++;
++
++      if (ICSR0 & ICSR0_FRE)
++	 si->stats.rx_frame_errors++;
++
++      /* Clear RX fifo
++       * DMA will be cleared when we restart RX
++       * Should we check RNE after that? 
++       */
++
++      ICCR0 &= ~ICCR0_RXE;
++      
++      /*
++       * Clear selected status bits now, so we
++       * don't miss them next time around.
++       */
++      ICSR0 = status & (ICSR0_FRE | ICSR0_RAB);
++   }
++
++   
++   /*
++    * Deal with any receive errors.  The any of the lowest
++    * 8 bytes in the FIFO may contain an error.  We must read
++    * them one by one.  The "error" could even be the end of
++    * packet!
++    */
++   if (ICSR0 & ICSR0_EIF)
++      pxa250_irda_fir_error(dev);
++
++   /*
++    * No matter what happens, we must restart reception.
++    */
++
++   ICCR0 = 0;
++   pxa250_start_rx_dma(dev);
++   pxa250_ficp_rx_start();
++   __ECHO_OUT;
++}
++
++
++
++
++
++/**************************************************************************
++ *			SIR 						  *
++ **************************************************************************/
++/*
++ * HP-SIR format interrupt service routines.
++ */
++static void pxa250_sir_transmit(struct net_device *dev)
++{
++   struct pxa250_irda *si = dev->priv;
++   
++   if (si->tx_buff.len) 
++   {
++	/* Disable receiver and  enable transmiter*/
++
++      
++      
++		STISR &= ~STISR_RCVEIR; 
++//	        STISR |= STISR_XMITIR;
++
++				
++		
++                disable_irq(dev->irq);
++		
++		do 
++		{
++
++		   if (STLSR & LSR_TDRQ)
++		   {
++		      STTHR = *si->tx_buff.data++;
++		      si->tx_buff.len -= 1;
++ 
++		      tx_count++;
++		   }
++		   
++				         
++		} while (si->tx_buff.len);
++
++				
++		if (si->tx_buff.len == 0) 
++		{
++		   
++		   
++			si->stats.tx_packets++;
++			si->stats.tx_bytes += si->tx_buff.data -
++					      si->tx_buff.head;
++
++			/*
++			 * We need to ensure that the transmitter has
++			 * finished.
++			 */
++			
++		        do
++			{
++			   udelay(1);
++			   
++            		}				
++			while ( ! (STLSR & LSR_TEMT) );
++                       
++						
++			/*
++
++			 * Ok, we've finished transmitting.  Now enable
++			 * the receiver.  Sometimes we get a receive IRQ
++			 * immediately after a transmit...
++			 */
++
++			if (si->newspeed)
++			{
++				pxa250_irda_set_speed(dev, si->newspeed);
++				si->newspeed = 0;
++			}
++
++			/* I'm hungry! */
++			netif_wake_queue(dev);
++		}
++		
++		enable_irq (dev->irq);
++                STIER = (IER_RAVIE | IER_UUE | IER_RTIOE);
++
++		STISR |= STISR_RCVEIR;
++//		STISR &= ~STISR_XMITIR;
++   }
++}
++
++static void pxa250_irda_hpsir_irq(struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++
++	/*
++	 * Deal with any receive errors first.  The bytes in error may be
++	 * the only bytes in the receive FIFO, so we do this first.
++	 */
++  	__ECHO_IN; 
++	
++	while (STLSR & LSR_FIFOE)
++	{
++		int stat, data;
++
++		stat = STLSR; 
++		data = STRBR;
++               
++		
++                if (stat & (LSR_FE | LSR_OE | LSR_PE)) 
++		
++		{
++		        si->stats.rx_errors++;
++			if (stat & LSR_FE) 
++				si->stats.rx_frame_errors++;
++			if (stat & LSR_OE) 
++				si->stats.rx_fifo_errors++;
++			
++		} else
++		{
++		   rx_count++;
++		   async_unwrap_char(dev, &si->stats, &si->rx_buff, data);
++                }
++		
++	}
++
++	/*
++	 * We must clear certain bits.
++	 */
++	 
++	if (STLSR & (LSR_DR)) 
++	{
++		/*
++		 * Fifo contains at least 1 character.
++		 */
++		do
++		{
++		   int data;
++		   
++		   data = STRBR;
++		   
++		   async_unwrap_char(dev, &si->stats, &si->rx_buff,
++					  data); /* was Ser2UTDR); Clo */
++		   rx_count++;
++		   
++		} while (STLSR & LSR_DR); 
++		
++		dev->last_rx = jiffies;
++	}
++
++  	__ECHO_OUT; 
++}
++
++static void pxa250_sir_irda_shutdown(struct pxa250_irda *si)
++{
++
++   STIER = 0;
++   STFCR = 0;
++   STISR = 0;
++   CKEN &= ~CKEN5_STUART; 
++}
++
++
++/************************************************************************************/
++
++/*Low level init/uninstall function PM control and IrDA protocol stack registration */
++
++/*
++ * Set the IrDA communications speed.
++ * Interrupt have to be disabled here.
++ */
++
++static int pxa250_irda_startup(struct net_device *dev)
++{
++   
++
++   __ECHO_IN;
++
++   /*
++    * Ensure that the ports for this device are setup correctly.
++    */
++
++
++   set_GPIO_mode (GPIO46_STRXD_MD);
++   set_GPIO_mode (GPIO47_STTXD_MD);
++
++   STMCR = MCR_OUT2;
++   STLCR = LCR_WLS1 | LCR_WLS0;
++
++   SET_SIR_MODE;
++   CKEN |= CKEN5_STUART;
++   /* enable irq from stuart */
++   ICMR |= ( 1 << 20 );
++	
++   /*reset FIFO*/
++		
++/*	STFCR = FCR_TRFIFOE |  FCR_RESETTF | FCR_RESETRF;// | FCR_ITL_16;
++
++	STIER = IER_UUE | IER_RAVIE | IER_RTOIE;
++*/	
++   __ECHO_OUT;
++
++   return 0;
++	
++}
++
++
++#ifdef CONFIG_PM
++/*
++ * Suspend the IrDA interface.
++ */
++
++static int pxa250_irda_shutdown(struct pxa250_irda *si)
++{
++
++   pxa250_sir_irda_shutdown(si);
++   return 0;
++   
++}
++
++
++static int pxa250_irda_suspend(struct net_device *dev, int state)
++{
++	struct pxa250_irda *si = dev->priv;
++
++	if (si && si->open) {
++	   /*
++	    * Stop the transmit queue
++	    */
++	   if (IS_FIR(si))
++	      return -1;
++
++	   netif_stop_queue(dev);
++	   disable_irq(dev->irq);
++	   disable_irq(si->fir_irq);
++	   pxa250_sir_irda_shutdown(si);
++	}
++
++	return 0;
++}
++
++/*
++ * Resume the IrDA interface.
++ */
++
++static int pxa250_irda_resume(struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++
++	__ECHO_IN;
++	
++	if (si && si->open) {
++		/*
++		 * If we missed a speed change, initialise at the new speed
++		 * directly.  It is debatable whether this is actually
++		 * required, but in the interests of continuing from where
++		 * we left off it is desireable.  The converse argument is
++		 * that we should re-negotiate at 9600 baud again.
++		 */
++		if (si->newspeed) {
++			si->speed = si->newspeed;
++			si->newspeed = 0;
++		}
++
++		pxa250_irda_startup(dev);
++		enable_irq(dev->irq);
++
++		/*
++		 * This automatically wakes up the queue
++		 */
++		netif_wake_queue(dev);
++		pxa250_irda_set_speed(dev,si->speed = 9600);
++		
++	}
++
++	__ECHO_OUT;
++	return 0;
++}
++
++static int pxa250_irda_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++	int ret;
++
++	
++	if (!dev->data)
++		return -EINVAL;
++
++
++	switch (rqst) {
++	case PM_SUSPEND:
++		ret = pxa250_irda_suspend((struct net_device *)dev->data,
++					  (int)data);
++		break;
++
++	case PM_RESUME:
++		ret = pxa250_irda_resume((struct net_device *)dev->data);
++		break;
++
++	default:
++
++	   ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++#endif
++
++
++
++
++static void pxa250_irda_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct net_device *dev = dev_id;
++	
++	pxa250_irda_hpsir_irq(dev);
++	
++}
++
++
++static int pxa250_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++	int speed = irda_get_next_speed(skb);
++	int mtt;
++	
++  	__ECHO_IN; 
++
++	/*
++	 * Does this packet contain a request to change the interface
++	 * speed?  If so, remember it until we complete the transmission
++	 * of this frame.
++	 */
++	if (speed != si->speed && speed != -1)
++		si->newspeed = speed;
++
++	/*
++	 * If this is an empty frame, we can bypass a lot.
++	 */
++	if (skb->len == 0) {
++		if (si->newspeed) {
++			si->newspeed = 0;
++			pxa250_irda_set_speed(dev, speed);
++		}
++		dev_kfree_skb(skb);
++		return 0;
++	}
++
++
++  	DBG("stop queue\n"); 
++	netif_stop_queue(dev);
++
++	if(!IS_FIR(si))
++	{
++	   
++	   si->tx_buff.data = si->tx_buff.head;
++	   si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
++						  si->tx_buff.truesize);
++
++        
++	   pxa250_sir_transmit(dev);
++
++	
++	
++	   dev_kfree_skb(skb);
++
++	   dev->trans_start = jiffies;
++
++	   return 0;
++	}
++	else /* FIR */
++	{
++	   DBG("Enter FIR transmit\n");
++	   /*
++	    * We must not be transmitting...
++	    */
++	   if (si->txskb)
++	      BUG();
++
++      	   disable_irq(si->fir_irq); 
++	   
++	   netif_stop_queue(dev);
++	   DBG("queue stoped\n");
++	   si->txskb = skb;
++
++	   /* we could not just map so we'll need some triks */
++	   /* skb->data may be not DMA capable -Sed- */
++
++
++	   if (skb->len > TXBUFF_MAX_SIZE)
++	   {
++	      printk (KERN_ERR "skb data too large\n");
++	      printk (KERN_ERR "len=%d",skb->len);
++	      BUG();
++	   }
++		
++
++	   DBG("gonna copy %d bytes to txbuf\n",skb->len);
++
++	   memcpy (si->txbuf_dma_virt, skb->data , skb->len);
++	   
++	   /* Actual sending ;must not be receiving !!! */
++	   /* Write data and source address */
++
++	   DBG("ICSR1 & RNE =%d\n",(ICSR1 & ICSR1_RNE) ? 1 : 0 );
++
++	   /*Disable receiver and enable transifer */
++  	   ICCR0 &= ~ICCR0_RXE;      
++	   
++	   if (ICSR1 & ICSR1_TBY)
++	      BUG();
++
++    	   ICCR0 |= ICCR0_TXE;  
++		
++	   DBG("FICP status %x\n",ICSR0);
++
++	   if (0){
++	      int i;
++		   
++	      DBG("sending packet\n");
++	      for (i=0;i<skb->len;i++)
++		 (i % 64) ? printk ("%2x ",skb->data[i]) : printk ("%2x \n",skb->data[i]) ;
++	      DBG(" done\n");
++   
++	   }
++	   /*
++	    * If we have a mean turn-around time, impose the specified
++	    * specified delay.  We could shorten this by timing from
++	    * the point we received the packet.
++	    */
++	   
++	   mtt = irda_get_mtt(skb); 
++	   if(mtt)    
++	      udelay(mtt);    
++	   
++	   DCSR(si->txdma_ch)=0;
++	   DCSR(si->txdma_ch)=DCSR_NODESC;
++	   DSADR(si->txdma_ch) = si->txbuf_dma; /* phisic address */
++	   DTADR(si->txdma_ch) = __PREG(ICDR);
++		
++	   DCMD(si->txdma_ch) = DCMD_ENDIRQEN| DCMD_INCSRCADDR | DCMD_FLOWTRG | DCMD_BURST8 | DCMD_WIDTH1 | skb->len;
++
++	   DCSR(si->txdma_ch) = DCSR_ENDINTR | DCSR_BUSERR;
++	   DCSR(si->txdma_ch) = DCSR_RUN | DCSR_NODESC ;
++
++	   DBG("FICP status %x\n",ICSR0);
++
++	   return 0;
++	}
++	
++}
++
++static int
++pxa250_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd)
++{
++	struct if_irda_req *rq = (struct if_irda_req *)ifreq;
++	struct pxa250_irda *si = dev->priv;
++	int ret = -EOPNOTSUPP;
++
++	__ECHO_IN;
++	
++	switch (cmd) {
++	case SIOCSBANDWIDTH:
++		if (capable(CAP_NET_ADMIN)) {
++			/*
++			 * We are unable to set the speed if the
++			 * device is not running.
++			 */
++			if (si->open) {
++				ret = pxa250_irda_set_speed(dev,
++						rq->ifr_baudrate);
++			} else {
++				printk("pxa250_irda_ioctl: SIOCSBANDWIDTH: !netif_running\n");
++				ret = 0;
++			}
++		}
++		break;
++
++	case SIOCSMEDIABUSY:
++		ret = -EPERM;
++		if (capable(CAP_NET_ADMIN)) {
++			irda_device_set_media_busy(dev, TRUE);
++			ret = 0;
++		}
++		break;
++
++	case SIOCGRECEIVING:
++		rq->ifr_receiving = IS_FIR(si) ? 0
++					: si->rx_buff.state != OUTSIDE_FRAME;
++		break;
++
++	default:
++		break;
++	}
++
++	__ECHO_OUT;
++
++	return ret;
++}
++
++static struct net_device_stats *pxa250_irda_stats(struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++	return &si->stats;
++}
++
++static int pxa250_irda_start(struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++	int err;
++	unsigned int flags;
++	
++
++	MOD_INC_USE_COUNT;
++
++	__ECHO_IN;
++	si->speed = 9600;
++
++	local_irq_save(flags);
++	
++	err = request_irq(si->fir_irq, pxa250_irda_fir_irq, 0,  dev->name, dev);
++	if (err)
++		goto err_fir_irq;
++
++	err = request_irq(dev->irq, pxa250_irda_irq, 0, dev->name, dev);
++	if (err)
++		goto err_irq;
++
++	/*
++	 * The interrupt must remain disabled for now.
++	 */
++	
++	disable_irq(dev->irq);
++  	disable_irq(si->fir_irq);
++
++	local_irq_restore(flags);
++
++
++	/* Allocate DMA channel for receiver (not used) */
++	err = pxa_request_dma("IrDA receive", DMA_PRIO_LOW, pxa250_irda_rxdma_irq, dev);
++	if (err < 0 )
++	   goto err_rx_dma;
++	si->rxdma_ch=err;
++
++	DRCMRRXICDR = DRCMR_MAPVLD | si->rxdma_ch;
++	
++
++	/* Allocate DMA channel for transmit */
++	err = pxa_request_dma("IrDA transmit", DMA_PRIO_LOW, pxa250_irda_txdma_irq , dev);
++	if (err < 0 )
++	   goto err_tx_dma;
++
++	si->txdma_ch=err;
++
++	/*
++	 * Make sure that ICP will be able 
++	 * to assert the transmit dma request bit
++	 * through the peripherals request bus (PREQ)
++	 */
++	
++	DRCMRTXICDR = DRCMR_MAPVLD | si->txdma_ch;
++
++	DBG("rx(not used) channel=%d tx channel=%d\n",si->rxdma_ch,si->txdma_ch);
++	
++	/* allocate consistent buffers for dma access
++	 * buffers have to be aligned and situated in dma capable memory region;
++	 */
++	si->rxbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA ,HPSIR_MAX_RXLEN , &si->rxbuf_dma);
++	if (! si->rxbuf_dma_virt )
++		goto err_rxbuf_dma;
++
++	si->txbuf_dma_virt = consistent_alloc(GFP_KERNEL | GFP_DMA, HPSIR_MAX_TXLEN,  &si->txbuf_dma); 
++	if (! si->txbuf_dma_virt )
++		goto err_txbuf_dma;
++
++	/* Alocate skb for receiver */
++	err=pxa250_irda_rx_alloc(si);
++	if (err)
++	   goto err_rx_alloc;
++	
++	/*
++	 * Setup the serial port for the specified config.
++	 */
++	err = pxa250_irda_startup(dev);
++	if (err)
++		goto err_startup;
++
++	pxa250_irda_set_speed(dev,si->speed = 9600);
++
++
++	/*
++	 * Open a new IrLAP layer instance.
++	 */
++	si->irlap = irlap_open(dev, &si->qos, "pxa250");
++	err = -ENOMEM;
++	if (!si->irlap)
++		goto err_irlap;
++
++	/*
++	 * Now enable the interrupt and start the queue
++	 */
++	si->open = 1;
++	enable_irq(dev->irq);
++	netif_start_queue(dev);
++	return 0;
++
++err_irlap:
++	si->open = 0;
++	pxa250_sir_irda_shutdown(si);
++err_startup:
++	dev_kfree_skb(si->rxskb);
++err_rx_alloc:	
++	consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma);
++err_txbuf_dma:
++	consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma);
++err_rxbuf_dma:
++	pxa_free_dma(si->txdma_ch);
++err_tx_dma:
++	pxa_free_dma(si->rxdma_ch);
++err_rx_dma:
++	free_irq(dev->irq, dev);
++err_irq:
++	free_irq(si->fir_irq, dev);
++err_fir_irq:	
++	MOD_DEC_USE_COUNT;
++	return err;
++}
++
++static int pxa250_irda_stop(struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++	
++	printk(KERN_ERR "Irda stop... RX = %d TX = %d\n",rx_count,tx_count);
++
++	disable_irq(dev->irq);
++  	disable_irq(si->fir_irq); 
++/*  	pxa250_irda_shutdown(si); */
++
++	/*
++	 * If we have been doing DMA receive, make sure we
++	 * tidy that up cleanly.
++	 */
++	if (si->rxskb) {
++	        dev_kfree_skb(si->rxskb);
++		si->rxskb = NULL;
++	}
++
++	/* Stop IrLAP */
++	if (si->irlap) {
++		irlap_close(si->irlap);
++		si->irlap = NULL;
++	}
++
++	consistent_free (si->txbuf_dma_virt,HPSIR_MAX_TXLEN,si->txbuf_dma);
++	consistent_free (si->rxbuf_dma_virt,HPSIR_MAX_RXLEN,si->rxbuf_dma);
++	pxa_free_dma(si->txdma_ch);
++	pxa_free_dma(si->rxdma_ch);
++
++	netif_stop_queue(dev);
++	si->open = 0;
++
++	/*
++	 * Free resources
++	 */
++	free_irq(dev->irq, dev);
++	free_irq(si->fir_irq, dev);
++
++
++	MOD_DEC_USE_COUNT;
++
++	return 0;
++}
++
++static int pxa250_irda_init_iobuf(iobuff_t *io, int size)
++{
++	io->head = kmalloc(size, GFP_KERNEL | GFP_DMA);
++	if (io->head != NULL) {
++		io->truesize = size;
++		io->in_frame = FALSE;
++		io->state    = OUTSIDE_FRAME;
++		io->data     = io->head;
++	}
++	return io->head ? 0 : -ENOMEM;
++}
++
++
++
++
++static int pxa250_stop_fir(struct net_device *dev)
++{
++   struct pxa250_irda *si = dev->priv;
++   unsigned int flag;
++
++   save_flags(flag);
++   cli();
++   
++   pxa250_dma_stop(si->txdma_ch);
++   pxa250_dma_stop(si->rxdma_ch);
++
++   if (si->txskb)
++      dev_kfree_skb_irq(si->txskb);
++
++   ICCR0 &= ~(ICCR0_RXE | ICCR0_TXE );
++   disable_irq(si->fir_irq);
++   CKEN &= ~CKEN13_FICP;
++
++   restore_flags(flag);
++
++   return 0;
++}
++
++
++
++static int pxa250_irda_set_speed(struct net_device *dev, int speed)
++{
++   struct pxa250_irda *si = dev->priv;
++   int brd, ret = -EINVAL;
++   static int last_fir_speed=0;
++
++   __ECHO_IN;
++   
++
++
++   switch (speed) {
++      case 9600:	case 19200:	case 38400:
++      case 57600:	case 115200:
++	   
++	 /* Baud rate fixed - Clo */
++
++	 /*
++	  * FIXME
++	  */
++	 if (last_fir_speed) 
++	 {
++
++	    pxa250_stop_fir(dev);
++	    set_GPIO_mode (GPIO46_STRXD_MD);
++	    set_GPIO_mode (GPIO47_STTXD_MD);
++   
++	    enable_irq(dev->irq);
++	    netif_wake_queue(dev);
++	    last_fir_speed=0;
++	 }
++	 
++
++	 LUB_MISC_WR &= ~(1 << 4);
++
++	 brd = 14745600 / (16 * speed); 
++
++	 STLCR |= LCR_DLAB;
++
++	 STDLH = brd >> 8; /* Clo: set Divisor Latch High */
++	 STDLL = brd & 0xFF; /* Clo: set Devisor Latch Low */
++		
++	 STLCR &= ~LCR_DLAB; /* Clo: clear DLAB bit */ 
++
++	 STMCR = MCR_OUT2;
++
++	 CKEN |= CKEN5_STUART;
++
++	 ICMR |= ( 1 << 20 );
++		
++	 STLCR = LCR_WLS1 | LCR_WLS0;
++
++	 SET_SIR_MODE;
++		
++	 STFCR = FCR_TRFIFOE |  FCR_RESETTF | FCR_RESETRF | FCR_ITL_1 ;// | FCR_ITL_16;
++
++	 STIER = IER_UUE | IER_RAVIE | IER_RTIOE;
++
++	 si->speed = speed;
++
++	 ret = 0;
++	 break;
++
++      case 4000000:
++
++	 if (last_fir_speed)
++	    goto speed_out;
++	 
++	 disable_irq(dev->irq);
++
++	 pxa250_sir_irda_shutdown(si);
++	 pxa250_fir_irda_startup(si);
++	 pxa250_irda_rx_alloc(si);
++	 ICCR0=0;
++	 pxa250_start_rx_dma(dev);
++	 pxa250_ficp_rx_start();
++	 
++	 enable_irq(si->fir_irq);
++	 DBG("enable FIR \n");
++	 si->speed = speed;
++
++	 netif_wake_queue(dev);
++	 last_fir_speed=1;
++speed_out:
++	 
++	 ret=0;
++	 
++	 break;
++
++      default:
++	 break;
++   }
++   __ECHO_OUT;
++
++   return ret;
++}
++
++
++static int pxa250_irda_net_init(struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++	unsigned int baudrate_mask;
++	int err = -ENOMEM;
++
++	si = kmalloc(sizeof(struct pxa250_irda), GFP_KERNEL);
++	if (!si)
++		goto out;
++
++	memset(si, 0, sizeof(*si));
++
++	/*
++	 * Initialise the HP-SIR buffers
++	 */
++
++	err = pxa250_irda_init_iobuf(&si->rx_buff, 14384);
++	if (err)
++		goto out;
++	err = pxa250_irda_init_iobuf(&si->tx_buff, 4000);
++	if (err)
++		goto out_free_rx;
++
++	si->fir_irq		= IRQ_ICP;
++	dev->priv = si;
++	dev->hard_start_xmit	= pxa250_irda_hard_xmit;
++	dev->open		= pxa250_irda_start;
++	dev->stop		= pxa250_irda_stop;
++	dev->do_ioctl		= pxa250_irda_ioctl;
++	dev->get_stats		= pxa250_irda_stats;
++
++	irda_device_setup(dev);
++	irda_init_max_qos_capabilies(&si->qos);
++
++	/*
++	 * We support original IRDA up to 115k2. (we don't currently
++	 * support 4Mbps).  Min Turn Time set to 1ms or greater.
++	 */
++	baudrate_mask = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
++  	baudrate_mask |= IR_4000000 << 8; 
++	si->qos.baud_rate.bits &= baudrate_mask;
++	si->qos.min_turn_time.bits = 7;
++
++	irda_qos_bits_to_value(&si->qos);
++
++#ifdef CONFIG_PM
++	/*
++	 * Power-Management is optional.
++	 */
++	si->pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, pxa250_irda_pmproc);
++	if (si->pmdev)
++		si->pmdev->data = dev;
++#endif
++
++	return 0;
++
++	kfree(si->tx_buff.head);
++out_free_rx:
++	kfree(si->rx_buff.head);
++out:
++	kfree(si);
++
++	return err;
++}
++
++/*
++ * Remove all traces of this driver module from the kernel, so we can't be
++ * called.  Note that the device has already been stopped, so we don't have
++ * to worry about interrupts or dma.
++ */
++static void pxa250_irda_net_uninit(struct net_device *dev)
++{
++	struct pxa250_irda *si = dev->priv;
++
++	dev->hard_start_xmit	= NULL;
++	dev->open		= NULL;
++	dev->stop		= NULL;
++	dev->do_ioctl		= NULL;
++	dev->get_stats		= NULL;
++	dev->priv		= NULL;
++
++	pm_unregister(si->pmdev);
++
++	kfree(si->tx_buff.head);
++	kfree(si->rx_buff.head);
++	kfree(si);
++}
++
++static int __init pxa250_irda_init(void)
++{
++	struct net_device *dev;
++	int err;
++
++	/* STUART */
++	err = request_mem_region(__PREG(STRBR), 0x24, "IrDA") ? 0 : -EBUSY;
++	if (err)
++		goto err_mem_1;
++
++	/* FIR */
++	err = request_mem_region(__PREG(ICCR0), 0x1c, "IrDA") ? 0 : -EBUSY;
++	if (err)
++		goto err_mem_2;
++
++
++	rtnl_lock();
++	dev = dev_alloc("irda%d", &err);
++	if (dev) {
++		dev->irq    = IRQ_STUART;
++		dev->init   = pxa250_irda_net_init;
++		dev->uninit = pxa250_irda_net_uninit;
++
++		err = register_netdevice(dev);
++
++		if (err)
++			kfree(dev);
++		else
++			netdev = dev;
++	}
++	rtnl_unlock();
++
++	if (err) {
++		release_mem_region(__PREG(ICCR0), 0x1c);
++err_mem_2:
++		release_mem_region(__PREG(STRBR), 0x24);
++	}
++err_mem_1:
++	return err;
++}
++
++static void __exit pxa250_irda_exit(void)
++{
++	struct net_device *dev = netdev;
++
++	netdev = NULL;
++	if (dev) {
++		rtnl_lock();
++		unregister_netdevice(dev);
++		rtnl_unlock();
++	}
++
++        release_mem_region(__PREG(ICCR0), 0x1c);
++
++	release_mem_region(__PREG(STRBR), 0x24);
++
++	/*
++	 * We now know that the netdevice is no longer in use, and all
++	 * references to our driver have been removed.  The only structure
++	 * which may still be present is the netdevice, which will get
++	 * cleaned up by net/core/dev.c
++	 */
++}
++
++module_init(pxa250_irda_init);
++module_exit(pxa250_irda_exit);
++
++MODULE_AUTHOR("Alexey Lugovskoy Frasenyak Dmitrij");
++MODULE_DESCRIPTION("PXA250 SIR/FIR");
++MODULE_LICENSE("GPL");
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/net/smc91x.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,2123 @@
++/*------------------------------------------------------------------------
++ . smc91x.c
++ . This is a driver for SMSC's 91C9x/91C1xx single-chip Ethernet devices.
++ .
++ . Copyright (C) 1996 by Erik Stahlman
++ . Copyright (C) 2001 Standard Microsystems Corporation
++ .	Developed by Simple Network Magic Corporation
++ . Copyright (C) 2003 Monta Vista Software, Inc.
++ .	Unified SMC91x driver by Nicolas Pitre
++ .
++ . 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
++ .
++ . Arguments:
++ . 	io	= for the base address
++ .	irq	= for the IRQ
++ .	nowait	= 0 for normal wait states, 1 eliminates additional wait states
++ .
++ . original author:
++ . 	Erik Stahlman <erik@vt.edu>
++ .
++ . hardware multicast code:
++ .    Peter Cammaert <pc@denkart.be>
++ .
++ . contributors:
++ . 	Daris A Nevil <dnevil@snmc.com>
++ .      Nicolas Pitre <nico@cam.org>
++ .
++ . History:
++ .   08/20/00  Arnaldo Melo       fix kfree(skb) in smc_hardware_send_packet
++ .   12/15/00  Christian Jullien  fix "Warning: kfree_skb on hard IRQ"
++ .   03/16/01  Daris A Nevil      modified smc9194.c for use with LAN91C111
++ .   08/22/01  Scott Anderson     merge changes from smc9194 to smc91111
++ .   08/21/01  Pramod B Bhardwaj  added support for RevB of LAN91C111
++ .   12/20/01  Jeff Sutherland    initial port to Xscale PXA with DMA support
++ .   04/07/03  Nicolas Pitre      unified SMC91x driver, killed irq races,
++ .                                more bus abstraction, big cleanup, etc.
++ ----------------------------------------------------------------------------*/
++
++static const char version[] =
++	"smc91x.c: v1.0, mar 07 2003 by Nicolas Pitre <nico@cam.org>\n";
++
++/* Debugging level */
++#ifndef SMC_DEBUG
++#define SMC_DEBUG		0
++#endif
++
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#ifdef CONFIG_PM
++#include <linux/pm.h>
++#endif
++
++#include <asm/io.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include "smc91x.h"
++
++
++#ifdef CONFIG_ISA
++/*
++ . the LAN91C111 can be at any of the following port addresses.  To change,
++ . for a slightly different card, you can add it to the array.  Keep in
++ . mind that the array must end in zero.
++*/
++static unsigned int smc_portlist[] __initdata = {
++	0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0,
++	0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0
++};
++#endif  /* CONFIG_ISA */
++
++#ifndef SMC_IOADDR
++# define SMC_IOADDR		-1
++#endif
++static int io = SMC_IOADDR;
++
++#ifndef SMC_IRQ
++# define SMC_IRQ		-1
++#endif
++static int irq = SMC_IRQ;
++
++#ifndef SMC_NOWAIT
++# define SMC_NOWAIT		0
++#endif
++static int nowait = SMC_NOWAIT;
++
++MODULE_PARM(io, "i");
++MODULE_PARM(irq, "i");
++MODULE_PARM(nowait, "i");
++MODULE_PARM_DESC(io, "I/O base address");
++MODULE_PARM_DESC(irq, "IRQ number");
++MODULE_PARM_DESC(nowait, "set to 1 for no wait state");
++
++
++/*------------------------------------------------------------------------
++ .
++ . The internal workings of the driver.  If you are changing anything
++ . here with the SMC stuff, you should have the datasheet and know
++ . what you are doing.
++ .
++ -------------------------------------------------------------------------*/
++#define CARDNAME "LAN91x"
++
++// Use power-down feature of the chip
++#define POWER_DOWN		1
++
++/*
++ . Wait time for memory to be free.  This probably shouldn't be
++ . tuned that much, as waiting for this means nothing else happens
++ . in the system
++*/
++#define MEMORY_WAIT_TIME	16
++
++/*
++ . This selects whether TX packets are sent one by one to the SMC91x internal
++ . memory ans throttled until transmission completes.  This may prevent
++ . RX overruns a litle by keeping much of the memory free for RX packets
++ . but to the expense of reduced TX throughput and increased IRQ overhead.
++ . Note this is not a cure for a too slow data bus or too high IRQ latency.
++ */
++#define THROTTLE_TX_PKTS	0
++
++
++/* store this information for the driver.. */
++struct smc_local {
++
++	// If I have to wait until memory is available to send
++	// a packet, I will store the skbuff here, until I get the
++	// desired memory.  Then, I'll send it out and free it.
++	struct sk_buff *saved_skb;
++
++ 	// these are things that the kernel wants me to keep, so users
++	// can find out semi-useless statistics of how well the card is
++	// performing
++	struct net_device_stats stats;
++
++	// version/revision of the SMC91x chip
++	int version;
++
++	// Set to true during the auto-negotiation sequence
++	int autoneg_active;
++
++	// Address of our PHY port
++	int	phyaddr;
++
++	// Type of PHY
++	int	phytype;
++
++	// Last contents of PHY Register 18
++	int	lastPhy18;
++
++	// Contains the current active transmission mode
++	int	tcr_cur_mode;
++
++	// Contains the current active receive mode
++	int	rcr_cur_mode;
++
++	// Contains the current active receive/phy mode
++	int	rpc_cur_mode;
++	int	ctl_autoneg;
++	int	ctl_rfduplx;
++	int	ctl_rspeed;
++
++#ifdef CONFIG_PM
++	struct	pm_dev* pm;
++#endif
++
++};
++
++
++#if SMC_DEBUG > 2
++#define PRINTK3(args...)  printk(args)
++#else
++#define PRINTK3(args...)  do { } while(0)
++#endif
++
++#if SMC_DEBUG > 1
++#define PRINTK2(args...)  printk(args)
++#else
++#define PRINTK2(args...)  do { } while(0)
++#endif
++
++#if SMC_DEBUG > 0
++#define PRINTK1(args...)  printk(args)
++#define PRINTK(args...)   printk(args)
++#else
++#define PRINTK1(args...)  do { } while(0)
++#define PRINTK(args...)   printk(KERN_DEBUG args)
++#endif
++
++#if SMC_DEBUG > 3
++static void PRINT_PKT(u_char *buf, int length)
++{
++	int i;
++	int remainder;
++	int lines;
++
++	lines = length / 16;
++	remainder = length % 16;
++
++	for (i = 0; i < lines ; i ++) {
++		int cur;
++		for (cur = 0; cur < 8; cur++) {
++			u_char a, b;
++			a = *buf++;
++			b = *buf++;
++			printk("%02x%02x ", a, b);
++		}
++		printk("\n");
++	}
++	for (i = 0; i < remainder/2 ; i++) {
++		u_char a, b;
++		a = *buf++;
++		b = *buf++;
++		printk("%02x%02x ", a, b );
++	}
++	printk("\n");
++}
++#else
++#define PRINT_PKT(x...)  do { } while(0)
++#endif
++
++
++/* this enables an interrupt in the interrupt mask register */
++#define SMC_ENABLE_INT(x) do {						\
++	unsigned long flags;						\
++	unsigned char mask;						\
++	local_irq_save(flags);						\
++	mask = SMC_GET_INT_MASK();					\
++	mask |= (x);							\
++	SMC_SET_INT_MASK(mask);						\
++	local_irq_restore(flags);					\
++} while (0)
++
++/* this disables an interrupt from the interrupt mask register */
++#define SMC_DISABLE_INT(x) do {						\
++	unsigned long flags;						\
++	unsigned char mask;						\
++	local_irq_save(flags);						\
++	mask = SMC_GET_INT_MASK();					\
++	mask &= ~(x);							\
++	SMC_SET_INT_MASK(mask);						\
++	local_irq_restore(flags);					\
++} while (0)
++
++/* wait while MMU is busy */
++#define SMC_WAIT_MMU_BUSY() do {					\
++	if (unlikely(SMC_GET_MMU_CMD() & MC_BUSY)) {				\
++		unsigned long timeout = jiffies + 2;			\
++		while (SMC_GET_MMU_CMD() & MC_BUSY) {			\
++			if (time_after(jiffies, timeout)) {		\
++				printk("%s: timeout %s line %d\n",	\
++					dev->name, __FILE__, __LINE__);	\
++				break;					\
++			}						\
++		}							\
++	}								\
++} while (0)
++
++
++/* this does a soft reset on the device */
++static void
++smc_reset(struct net_device *dev)
++{
++	unsigned long ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	int phyaddr = lp->phyaddr;
++	int status;
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	/* This resets the registers mostly to defaults, but doesn't
++	   affect EEPROM.  That seems unnecessary */
++	SMC_SELECT_BANK( 0 );
++	SMC_SET_RCR( RCR_SOFTRST );
++
++	/* Setup the Configuration Register */
++	/* This is necessary because the CONFIG_REG is not affected */
++	/* by a soft reset */
++	SMC_SELECT_BANK( 1 );
++	SMC_SET_CONFIG( CONFIG_DEFAULT );
++
++	/* Setup for fast accesses if requested */
++	/* If the card/system can't handle it then there will */
++	/* be no recovery except for a hard reset or power cycle */
++	if (nowait)
++		SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_NO_WAIT );
++
++#ifdef POWER_DOWN
++	/* Release from possible power-down state */
++	/* Configuration register is not affected by Soft Reset */
++	SMC_SELECT_BANK( 1 );
++	SMC_SET_CONFIG( SMC_GET_CONFIG() | CONFIG_EPH_POWER_EN );
++	status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++	status &= ~PHY_CNTL_PDN;
++	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++#endif
++
++	/* this should pause enough for the chip to be happy */
++	udelay(1);
++
++	/* Disable transmit and receive functionality */
++	SMC_SELECT_BANK( 0 );
++	SMC_SET_RCR( RCR_CLEAR );
++	SMC_SET_TCR( TCR_CLEAR );
++
++	/* set the control register to automatically
++	   release successfully transmitted packets, to make the best
++	   use out of our limited memory */
++	SMC_SELECT_BANK( 1 );
++#if ! THROTTLE_TX_PKTS
++	SMC_SET_CTL( SMC_GET_CTL() | CTL_AUTO_RELEASE );
++#else
++	SMC_SET_CTL( SMC_GET_CTL() & ~CTL_AUTO_RELEASE );
++#endif
++
++	/* Disable all interrupts */
++	SMC_SELECT_BANK( 2 );
++	SMC_SET_INT_MASK( 0 );
++
++	/* Reset the MMU */
++	SMC_SET_MMU_CMD( MC_RESET );
++	SMC_WAIT_MMU_BUSY();
++}
++
++/* Enable Interrupts, Receive, and Transmit */
++static void
++smc_enable(struct net_device *dev)
++{
++	unsigned long ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	int mask;
++
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	/* see the header file for options in TCR/RCR DEFAULT*/
++	SMC_SELECT_BANK( 0 );
++	SMC_SET_TCR( lp->tcr_cur_mode );
++	SMC_SET_RCR( lp->rcr_cur_mode );
++
++	/* now, enable interrupts */
++	mask = IM_EPH_INT|IM_RX_OVRN_INT|IM_RCV_INT;
++	if (lp->version >= 0x70)
++		mask |= IM_MDINT;
++	SMC_SELECT_BANK( 2 );
++	SMC_SET_INT_MASK( mask );
++}
++
++/* this puts the device in an inactive state */
++static void
++smc_shutdown(struct net_device *dev)
++{
++	int ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	int phyaddr = lp->phyaddr;
++	int status;
++
++	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++	/* no more interrupts for me */
++	SMC_SELECT_BANK( 2 );
++	SMC_SET_INT_MASK( 0 );
++
++	/* and tell the card to stay away from that nasty outside world */
++	SMC_SELECT_BANK( 0 );
++	SMC_SET_RCR( RCR_CLEAR );
++	SMC_SET_TCR( TCR_CLEAR );
++
++#ifdef POWER_DOWN
++	status = smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++	status |= PHY_CNTL_PDN;
++	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG);
++
++	/* finally, shut the chip down */
++	SMC_SELECT_BANK( 1 );
++	SMC_SET_CONFIG( SMC_GET_CONFIG() & ~CONFIG_EPH_POWER_EN );
++#endif
++}
++
++/* This is the procedure to handle the receipt of a packet. */
++static inline void 
++smc_rcv(struct net_device *dev)
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	unsigned long ioaddr = dev->base_addr;
++	unsigned int packet_number, status, packet_len;
++
++	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++	packet_number = SMC_GET_RXFIFO();
++	if (unlikely(packet_number & RXFIFO_REMPTY)) {
++		PRINTK("%s: smc_rcv with nothing on FIFO.\n", dev->name);
++		return;
++	}
++
++	/* read from start of packet */
++	SMC_SET_PTR( PTR_READ | PTR_RCV | PTR_AUTOINC );
++
++	/* First two words are status and packet length */
++	SMC_GET_PKT_HDR(status, packet_len);
++	packet_len &= 0x07ff;  /* mask off top bits */
++	PRINTK2("%s: RX PNR 0x%x STATUS 0x%04x LENGTH 0x%04x (%d)\n",
++		dev->name, packet_number, status,
++		packet_len, packet_len);
++
++	if (unlikely(status & RS_ERRORS)) {
++		lp->stats.rx_errors++;
++		if (status & RS_ALGNERR)
++			lp->stats.rx_frame_errors++;
++		if (status & (RS_TOOSHORT | RS_TOOLONG))
++			lp->stats.rx_length_errors++;
++		if (status & RS_BADCRC)
++			lp->stats.rx_crc_errors++;
++	} else {
++		struct sk_buff *skb;
++		unsigned char *data;
++		unsigned int data_len;
++
++		/* set multicast stats */
++		if (status & RS_MULTICAST)
++			lp->stats.multicast++;
++
++		/*
++		 * Actual payload is packet_len - 4 (or 3 if odd byte).
++		 * We want skb_reserve(2) and the final ctrl word
++		 * (2 bytes, possibly containing the payload odd byte).
++		 * Ence packet_len - 4 + 2 + 2.
++		 */
++		skb = dev_alloc_skb(packet_len);
++		if (unlikely(skb == NULL)) {
++			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
++				dev->name);
++			lp->stats.rx_dropped++;
++			goto done;
++		}
++
++		/* Align IP header to 32 bits */
++		skb_reserve(skb, 2);
++
++		/* BUG: the LAN91C111 rev A never sets this bit. Force it. */
++		if (lp->version == 0x90)
++			status |= RS_ODDFRAME;
++
++		/*
++		 * If odd length: packet_len - 3,
++		 * otherwise packet_len - 4.
++		 */
++		data_len = packet_len - ((status & RS_ODDFRAME) ? 3 : 4);
++		data = skb_put(skb, data_len);
++		SMC_PULL_DATA(data, packet_len - 2);
++
++		PRINT_PKT(data, packet_len - 2);
++
++		dev->last_rx = jiffies;
++		skb->dev = dev;
++		skb->protocol = eth_type_trans(skb, dev);
++		netif_rx(skb);
++		lp->stats.rx_packets++;
++		lp->stats.rx_bytes += data_len;
++	}
++
++done:
++	SMC_WAIT_MMU_BUSY();
++	SMC_SET_MMU_CMD( MC_RELEASE );
++}
++
++/*
++ * This is called to actually send a packet to the chip.
++ * Returns non-zero when successful.
++ */
++static void
++smc_hardware_send_packet(struct net_device *dev)
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	unsigned long ioaddr = dev->base_addr;
++	struct sk_buff *skb = lp->saved_skb;
++	unsigned int packet_no, len;
++	unsigned char *buf;
++
++	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++	if (unlikely(!skb)) {
++		printk ("%s: In XMIT with no packet to send\n", dev->name);
++		return;
++	}
++
++	packet_no = SMC_GET_AR();
++	if (unlikely(packet_no & AR_FAILED)) {
++		printk("%s: Memory allocation failed.\n", dev->name);
++		lp->saved_skb = NULL;
++		lp->stats.tx_errors++;
++		lp->stats.tx_fifo_errors++;
++		dev_kfree_skb_any(skb);
++		return;
++	}
++
++	/* point to the beginning of the packet */
++	SMC_SET_PN( packet_no );
++	SMC_SET_PTR( PTR_AUTOINC );
++
++	buf = skb->data;
++	len = skb->len;
++	PRINTK2("%s: TX PNR 0x%x lENGTH 0x%04x (%d) BUF 9x%p\n",
++		dev->name, packet_no, len, len, buf);
++	PRINT_PKT(buf, len);
++
++	/*
++	 * Send the packet length ( +6 for status words, length, and ctl.
++	 * The card will pad to 64 bytes with zeroes if packet is too small.
++	 */
++	SMC_PUT_PKT_HDR(0, len + 6);
++
++	/* send the actual data */
++	SMC_PUSH_DATA(buf, len & ~1);
++
++	/* Send final ctl word with the last byte if there is one */
++	SMC_outw( ((len & 1) ? (0x2000 | buf[len-1]) : 0), ioaddr, DATA_REG );
++
++	/* and let the chipset deal with it */
++	SMC_SET_MMU_CMD( MC_ENQUEUE );
++	SMC_ACK_INT( IM_TX_EMPTY_INT );
++
++	dev->trans_start = jiffies;
++	dev_kfree_skb_any(skb);
++	lp->saved_skb = NULL;
++	lp->stats.tx_packets++;
++	lp->stats.tx_bytes += len;
++}
++
++/*
++ . Since I am not sure if I will have enough room in the chip's ram
++ . to store the packet, I call this routine which either sends it
++ . now, or set the card to generates an interrupt when ready
++ . for the packet.
++ */
++static int
++smc_hard_start_xmit( struct sk_buff * skb, struct net_device * dev )
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	unsigned long ioaddr = dev->base_addr;
++	unsigned int numPages, poll_count, status, saved_bank;
++
++	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++	if (unlikely(lp->saved_skb != NULL)) {
++		/* THIS SHOULD NEVER HAPPEN. */
++		printk( KERN_CRIT
++			"%s: Bad Craziness - sent packet while busy.\n",
++			dev->name );
++		lp->stats.tx_errors++;
++		lp->stats.tx_aborted_errors++;
++		return 1;
++	}
++	lp->saved_skb = skb;
++
++	/*
++	** The MMU wants the number of pages to be the number of 256 bytes
++	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
++	**
++	** The 91C111 ignores the size bits, but the code is left intact
++	** for backwards and future compatibility.
++	**
++	** Pkt size for allocating is data length +6 (for additional status
++	** words, length and ctl!)
++	**
++	** If odd size then last byte is included in ctl word.
++	*/
++	numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
++	if (unlikely(numPages > 7)) {
++		printk("%s: Far too big packet error.\n", dev->name);
++		lp->saved_skb = NULL;
++		lp->stats.tx_errors++;
++		lp->stats.tx_dropped++;
++		dev_kfree_skb(skb);
++		return 0;
++	}
++
++	/* now, try to allocate the memory */
++	saved_bank = SMC_CURRENT_BANK();
++	SMC_SELECT_BANK( 2 );
++	SMC_SET_MMU_CMD( MC_ALLOC | numPages );
++
++	/*
++	 * Poll the chip for a short amount of time in case the
++	 * allocation succeeds quickly.
++	 */
++	poll_count = MEMORY_WAIT_TIME;
++	do {
++		status = SMC_GET_INT();
++		if (status & IM_ALLOC_INT) {
++			SMC_ACK_INT( IM_ALLOC_INT );
++  			break;
++		}
++   	} while (--poll_count);
++
++   	if (!poll_count) {
++		/* oh well, wait until the chip finds memory later */
++		netif_stop_queue(dev);
++		PRINTK2("%s: TX memory allocation deferred.\n", dev->name);
++		SMC_ENABLE_INT( IM_ALLOC_INT );
++   	} else {
++		/* Send current packet immediately.. */
++#if THROTTLE_TX_PKTS
++		netif_stop_queue(dev);
++#endif
++		smc_hardware_send_packet(dev);
++		SMC_ENABLE_INT( IM_TX_INT | IM_TX_EMPTY_INT );
++	}
++
++	SMC_SELECT_BANK( saved_bank );
++	return 0;
++}
++
++/*
++ . This handles a TX interrupt, which is only called when an error
++ . relating to a packet is sent or CTL_AUTO_RELEASE is not set.
++*/
++static void
++smc_tx(struct net_device *dev)
++{
++	unsigned long ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	unsigned int saved_packet, packet_no, tx_status, pkt_len;
++
++	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++	/* If the TX FIFO is empty then nothing to do */
++	packet_no = SMC_GET_TXFIFO();
++	if (unlikely(packet_no & TXFIFO_TEMPTY)) {
++		PRINTK("%s: smc_tx with nothing on FIFO.\n", dev->name);
++		return;
++	}
++
++	/* select packet to read from */
++	saved_packet = SMC_GET_PN();
++	SMC_SET_PN( packet_no );
++
++	/* read the first word (status word) from this packet */
++	SMC_SET_PTR( PTR_AUTOINC | PTR_READ );
++	SMC_GET_PKT_HDR(tx_status, pkt_len);
++	PRINTK2("%s: TX STATUS 0x%04x PNR 0x%02x\n",
++		dev->name, tx_status, packet_no);
++
++	if (!(tx_status & TS_SUCCESS))
++		lp->stats.tx_errors++;
++	if (tx_status & TS_LOSTCAR)
++		lp->stats.tx_carrier_errors++;
++	if (tx_status & TS_LATCOL) {
++		printk( KERN_DEBUG
++			"%s: Late collision occurred on last xmit.\n",
++			dev->name);
++		lp->stats.tx_window_errors++;
++	}
++
++	/* kill the packet */
++	SMC_WAIT_MMU_BUSY();
++	SMC_SET_MMU_CMD( MC_FREEPKT );
++
++	/* Don't restore Packet Number Reg until busy bit is cleared */
++	SMC_WAIT_MMU_BUSY();
++	SMC_SET_PN( saved_packet );
++
++	/* re-enable transmit */
++	SMC_SELECT_BANK( 0 );
++	SMC_SET_TCR( lp->tcr_cur_mode );
++	SMC_SELECT_BANK( 2 );
++}
++
++
++//---PHY CONTROL AND CONFIGURATION-----------------------------------------
++
++/*------------------------------------------------------------
++ . Debugging function for viewing MII Management serial bitstream
++ .-------------------------------------------------------------*/
++#if SMC_DEBUG > 3
++static void
++PRINT_MII_STREAM(u_char *bits, int size)
++{
++	int i;
++
++	printk("BIT#:");
++	for (i = 0; i < size; ++i)
++		printk("%d", i%10);
++
++	printk("\nMDOE:");
++	for (i = 0; i < size; ++i) {
++		if (bits[i] & MII_MDOE)
++			printk("1");
++		else
++			printk("0");
++	}
++
++	printk("\nMDO :");
++	for (i = 0; i < size; ++i) {
++		if (bits[i] & MII_MDO)
++			printk("1");
++		else
++			printk("0");
++	}
++
++	printk("\nMDI :");
++	for (i = 0; i < size; ++i) {
++		if (bits[i] & MII_MDI)
++			printk("1");
++		else
++			printk("0");
++	}
++
++	printk("\n");
++}
++#else
++#define PRINT_MII_STREAM(x...)
++#endif
++
++/*------------------------------------------------------------
++ . Reads a register from the MII Management serial interface
++ .-------------------------------------------------------------*/
++static int
++smc_read_phy_register(unsigned long ioaddr, int phyaddr, int phyreg)
++{
++	int oldBank;
++	int i, mask, mii_reg;
++	u_char bits[64];
++	int input_idx, phydata;
++	int clk_idx = 0;
++
++	// 32 consecutive ones on MDO to establish sync
++	for (i = 0; i < 32; ++i)
++		bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++	// Start code <01>
++	bits[clk_idx++] = MII_MDOE;
++	bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++	// Read command <10>
++	bits[clk_idx++] = MII_MDOE | MII_MDO;
++	bits[clk_idx++] = MII_MDOE;
++
++	// Output the PHY address, msb first
++	mask = 0x10;
++	for (i = 0; i < 5; ++i) {
++		if (phyaddr & mask)
++			bits[clk_idx++] = MII_MDOE | MII_MDO;
++		else
++			bits[clk_idx++] = MII_MDOE;
++
++		// Shift to next lowest bit
++		mask >>= 1;
++	}
++
++	// Output the phy register number, msb first
++	mask = 0x10;
++	for (i = 0; i < 5; ++i) {
++		if (phyreg & mask)
++			bits[clk_idx++] = MII_MDOE | MII_MDO;
++		else
++			bits[clk_idx++] = MII_MDOE;
++
++		// Shift to next lowest bit
++		mask >>= 1;
++	}
++
++	// Tristate and turnaround (2 bit times)
++	bits[clk_idx++] = 0;
++	//bits[clk_idx++] = 0;
++
++	// Input starts at this bit time
++	input_idx = clk_idx;
++
++	// Will input 16 bits
++	for (i = 0; i < 16; ++i)
++		bits[clk_idx++] = 0;
++
++	// Final clock bit
++	bits[clk_idx++] = 0;
++
++	// Save the current bank
++	oldBank = SMC_CURRENT_BANK();
++
++	// Select bank 3
++	SMC_SELECT_BANK( 3 );
++
++	// Get the current MII register value
++	mii_reg = SMC_GET_MII();
++
++	// Turn off all MII Interface bits
++	mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
++
++	// Clock all 64 cycles
++	for (i = 0; i < sizeof bits; ++i) {
++		// Clock Low - output data
++		SMC_SET_MII( mii_reg | bits[i] );
++		udelay(50);
++
++		// Clock Hi - input data
++		SMC_SET_MII( mii_reg | bits[i] | MII_MCLK );
++		udelay(50);
++		bits[i] |= SMC_GET_MII() & MII_MDI;
++	}
++
++	// Return to idle state
++	// Set clock to low, data to low, and output tristated
++	SMC_SET_MII( mii_reg );
++	udelay(50);
++
++	// Restore original bank select
++	SMC_SELECT_BANK( oldBank );
++
++	// Recover input data
++	phydata = 0;
++	for (i = 0; i < 16; ++i) {
++		phydata <<= 1;
++
++		if (bits[input_idx++] & MII_MDI)
++			phydata |= 0x0001;
++	}
++
++	PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
++		__FUNCTION__, phyaddr, phyreg, phydata);
++	PRINT_MII_STREAM(bits, sizeof(bits));
++
++	return phydata;
++}
++
++/*------------------------------------------------------------
++ . Writes a register to the MII Management serial interface
++ .-------------------------------------------------------------*/
++static void
++smc_write_phy_register( unsigned long ioaddr, int phyaddr,
++			int phyreg, int phydata )
++{
++	int oldBank;
++	int i, mask, mii_reg;
++	u_char bits[65];
++	int clk_idx = 0;
++
++	// 32 consecutive ones on MDO to establish sync
++	for (i = 0; i < 32; ++i)
++		bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++	// Start code <01>
++	bits[clk_idx++] = MII_MDOE;
++	bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++	// Write command <01>
++	bits[clk_idx++] = MII_MDOE;
++	bits[clk_idx++] = MII_MDOE | MII_MDO;
++
++	// Output the PHY address, msb first
++	mask = 0x10;
++	for (i = 0; i < 5; ++i) {
++		if (phyaddr & mask)
++			bits[clk_idx++] = MII_MDOE | MII_MDO;
++		else
++			bits[clk_idx++] = MII_MDOE;
++
++		// Shift to next lowest bit
++		mask >>= 1;
++	}
++
++	// Output the phy register number, msb first
++	mask = 0x10;
++	for (i = 0; i < 5; ++i) {
++		if (phyreg & mask)
++			bits[clk_idx++] = MII_MDOE | MII_MDO;
++		else
++			bits[clk_idx++] = MII_MDOE;
++
++		// Shift to next lowest bit
++		mask >>= 1;
++	}
++
++	// Tristate and turnaround (2 bit times)
++	bits[clk_idx++] = 0;
++	bits[clk_idx++] = 0;
++
++	// Write out 16 bits of data, msb first
++	mask = 0x8000;
++	for (i = 0; i < 16; ++i) {
++		if (phydata & mask)
++			bits[clk_idx++] = MII_MDOE | MII_MDO;
++		else
++			bits[clk_idx++] = MII_MDOE;
++
++		// Shift to next lowest bit
++		mask >>= 1;
++	}
++
++	// Final clock bit (tristate)
++	bits[clk_idx++] = 0;
++
++	// Save the current bank
++	oldBank = SMC_CURRENT_BANK();
++
++	// Select bank 3
++	SMC_SELECT_BANK( 3 );
++
++	// Get the current MII register value
++	mii_reg = SMC_GET_MII();
++
++	// Turn off all MII Interface bits
++	mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
++
++	// Clock all cycles
++	for (i = 0; i < sizeof bits; ++i) {
++		// Clock Low - output data
++		SMC_SET_MII( mii_reg | bits[i] );
++		udelay(50);
++
++		// Clock Hi - input data
++		SMC_SET_MII( mii_reg | bits[i] | MII_MCLK );
++		udelay(50);
++		bits[i] |= SMC_GET_MII() & MII_MDI;
++	}
++
++	// Return to idle state
++	// Set clock to low, data to low, and output tristated
++	SMC_SET_MII( mii_reg );
++	udelay(50);
++
++	// Restore original bank select
++	SMC_SELECT_BANK( oldBank );
++
++	PRINTK3("%s: phyaddr=0x%x, phyreg=0x%x, phydata=0x%x\n",
++		__FUNCTION__, phyaddr, phyreg, phydata);
++	PRINT_MII_STREAM(bits, sizeof(bits));
++}
++
++
++/*------------------------------------------------------------
++ . Finds and reports the PHY address
++ .-------------------------------------------------------------*/
++static int smc_detect_phy(struct net_device* dev)
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	unsigned long ioaddr = dev->base_addr;
++	int phy_id1, phy_id2;
++	int phyaddr;
++	int found = 0;
++
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	// Scan all 32 PHY addresses if necessary
++	for (phyaddr = 0; phyaddr < 32; ++phyaddr) {
++		// Read the PHY identifiers
++		phy_id1 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
++		phy_id2 = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
++
++		PRINTK3("%s: phy_id1=0x%x, phy_id2=0x%x\n",
++			dev->name, phy_id1, phy_id2);
++
++		// Make sure it is a valid identifier
++		if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
++		    (phy_id1 > 0x0000) && (phy_id1 < 0xffff)) {
++			if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000)) {
++				// Save the PHY's address
++				lp->phyaddr = phyaddr;
++				found = 1;
++				break;
++			}
++		}
++	}
++
++	if (!found) {
++		PRINTK("%s: No PHY found\n", dev->name);
++		return(0);
++	}
++
++	// Set the PHY type
++	if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) ) {
++		lp->phytype = PHY_LAN83C183;
++		PRINTK("%s: PHY=LAN83C183 (LAN91C111 Internal)\n", dev->name);
++	}
++
++	if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) ) {
++		lp->phytype = PHY_LAN83C180;
++		PRINTK("%s: PHY=LAN83C180\n", dev->name);
++	}
++
++	return 1;
++}
++
++/*------------------------------------------------------------
++ . Waits the specified number of milliseconds - kernel friendly
++ .-------------------------------------------------------------*/
++static void
++smc_wait_ms(unsigned int ms)
++{
++	if (!in_interrupt()) {
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		schedule_timeout(1 + ms * HZ / 1000);
++	} else {
++		/* if this happens it must be fixed */
++		printk( KERN_WARNING "%s: busy wait while in interrupt!\n",
++			__FUNCTION__);
++		mdelay(ms);
++	}
++}
++
++/*------------------------------------------------------------
++ . Sets the PHY to a configuration as determined by the user
++ .-------------------------------------------------------------*/
++static int
++smc_phy_fixed(struct net_device *dev)
++{
++	unsigned long ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	int phyaddr = lp->phyaddr;
++	int my_fixed_caps, cfg1;
++
++	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++	// Enter Link Disable state
++	cfg1 = smc_read_phy_register(ioaddr, phyaddr, PHY_CFG1_REG);
++	cfg1 |= PHY_CFG1_LNKDIS;
++	smc_write_phy_register(ioaddr, phyaddr, PHY_CFG1_REG, cfg1);
++
++	// Set our fixed capabilities
++	// Disable auto-negotiation
++	my_fixed_caps = 0;
++
++	if (lp->ctl_rfduplx)
++		my_fixed_caps |= PHY_CNTL_DPLX;
++
++	if (lp->ctl_rspeed == 100)
++		my_fixed_caps |= PHY_CNTL_SPEED;
++
++	// Write our capabilities to the phy control register
++	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, my_fixed_caps);
++
++	// Re-Configure the Receive/Phy Control register
++	SMC_SET_RPC( lp->rpc_cur_mode );
++
++	// Success
++	return(1);
++}
++
++/*------------------------------------------------------------
++ . Configures the specified PHY through the MII management interface
++ . using Autonegotiation.
++ . Calls smc_phy_fixed() if the user has requested a certain config.
++ .-------------------------------------------------------------*/
++static void
++smc_phy_configure(struct net_device* dev)
++{
++	unsigned long ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	int timeout;
++	int phyaddr;
++	int my_phy_caps; // My PHY capabilities
++	int my_ad_caps; // My Advertised capabilities
++	int status;
++
++	PRINTK3("%s:smc_program_phy()\n", dev->name);
++
++	// Set the blocking flag
++	lp->autoneg_active = 1;
++
++	// Find the address and type of our phy
++	if (!smc_detect_phy(dev))
++		goto smc_phy_configure_exit;
++
++	// Get the detected phy address
++	phyaddr = lp->phyaddr;
++
++	// Reset the PHY, setting all other bits to zero
++	smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
++
++	// Wait for the reset to complete, or time out
++	timeout = 6; // Wait up to 3 seconds
++	while (timeout--) {
++		if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
++		    & PHY_CNTL_RST))
++			// reset complete
++			break;
++		smc_wait_ms(500); // wait 500 millisecs
++		if (signal_pending(current)) { // Exit anyway if signaled
++			PRINTK("%s: PHY reset interrupted by signal\n",
++				dev->name);
++			timeout = 0;
++			break;
++		}
++	}
++
++	if (timeout < 1) {
++		printk("%s: PHY reset timed out\n", dev->name);
++		goto smc_phy_configure_exit;
++	}
++
++	// Read PHY Register 18, Status Output
++	lp->lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
++
++	// Enable PHY Interrupts (for register 18)
++	// Interrupts listed here are disabled
++	smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG,
++		PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
++		PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
++		PHY_INT_SPDDET | PHY_INT_DPLXDET);
++
++	/* Configure the Receive/Phy Control register */
++	SMC_SELECT_BANK( 0 );
++	SMC_SET_RPC( lp->rpc_cur_mode );
++
++	// Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
++	my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
++
++	// If the user requested no auto neg, then go set his request
++	if (!(lp->ctl_autoneg)) {
++		smc_phy_fixed(dev);
++		goto smc_phy_configure_exit;
++	}
++
++	if( !( my_phy_caps & PHY_STAT_CAP_ANEG))
++	{
++		printk(KERN_INFO "Auto negotiation NOT supported\n");
++		smc_phy_fixed(dev);
++		goto smc_phy_configure_exit;
++	}
++
++	my_ad_caps  = PHY_AD_CSMA; // I am CSMA capable
++
++	if (my_phy_caps & PHY_STAT_CAP_T4)
++		my_ad_caps |= PHY_AD_T4;
++
++	if (my_phy_caps & PHY_STAT_CAP_TXF)
++		my_ad_caps |= PHY_AD_TX_FDX;
++
++	if (my_phy_caps & PHY_STAT_CAP_TXH)
++		my_ad_caps |= PHY_AD_TX_HDX;
++
++	if (my_phy_caps & PHY_STAT_CAP_TF)
++		my_ad_caps |= PHY_AD_10_FDX;
++
++	if (my_phy_caps & PHY_STAT_CAP_TH)
++		my_ad_caps |= PHY_AD_10_HDX;
++
++	// Disable capabilities not selected by our user
++	if (lp->ctl_rspeed != 100)
++		my_ad_caps &= ~(PHY_AD_T4|PHY_AD_TX_FDX|PHY_AD_TX_HDX);
++
++	if (!lp->ctl_rfduplx)
++		my_ad_caps &= ~(PHY_AD_TX_FDX|PHY_AD_10_FDX);
++
++	// Update our Auto-Neg Advertisement Register
++	smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
++
++	// Read the register back.  Without this, it appears that when
++	// auto-negotiation is restarted, sometimes it isn't ready and
++	// the link does not come up.
++	status = smc_read_phy_register(ioaddr, phyaddr, PHY_AD_REG);
++
++	PRINTK2("%s: phy caps=%x\n", dev->name, my_phy_caps);
++	PRINTK2("%s: phy advertised caps=%x\n", dev->name, my_ad_caps);
++
++	// Restart auto-negotiation process in order to advertise my caps
++	smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
++		PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
++
++	// Wait for the auto-negotiation to complete.  This may take from
++	// 2 to 3 seconds.
++	// Wait for the reset to complete, or time out
++	timeout = 20; // Wait up to 10 seconds
++	while (timeout--) {
++		status = smc_read_phy_register(ioaddr, phyaddr, PHY_RMT_REG);
++		if (status & PHY_AD_ACK)
++			// auto-negotiate complete
++			break;
++
++		smc_wait_ms(500); // wait 500 millisecs
++		if (signal_pending(current)) { // Exit anyway if signaled
++			printk(KERN_DEBUG
++				"%s: PHY auto-negotiate interrupted by signal\n",
++				dev->name);
++			timeout = 0;
++			break;
++		}
++	}
++	status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
++
++	if (timeout < 1) {
++		PRINTK("%s: PHY auto-negotiate timed out\n", dev->name);
++	}
++
++	// Fail if we detected an auto-negotiate remote fault
++	if (status & PHY_STAT_REM_FLT) {
++		PRINTK("%s: PHY remote fault detected\n", dev->name);
++	}
++
++	// Wait for link. Once the link is up, phy18 should be up to date
++        timeout = 200;
++        do              
++        {
++                udelay(100);
++                status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
++        } while ( ((status & PHY_STAT_LINK)==0) && --timeout);
++
++        if (status & PHY_STAT_LINK)        
++        {                                      
++                PRINTK("%s: Ethernet Link Detected\n", dev->name); 
++        }       
++
++	// The smc_phy_interrupt() routine will be called to update lastPhy18
++
++	// Set our sysctl parameters to match auto-negotiation results
++	if ( lp->lastPhy18 & PHY_INT_SPDDET ) {
++		PRINTK("%s: PHY 100BaseT\n", dev->name);
++		lp->rpc_cur_mode |= RPC_SPEED;
++	} else {
++		PRINTK("%s: PHY 10BaseT\n", dev->name);
++		lp->rpc_cur_mode &= ~RPC_SPEED;
++	}
++
++	if ( lp->lastPhy18 & PHY_INT_DPLXDET ) {
++		PRINTK("%s: PHY Full Duplex\n", dev->name);
++		lp->rpc_cur_mode |= RPC_DPLX;
++		lp->tcr_cur_mode |= TCR_SWFDUP;
++	} else {
++		PRINTK("%s: PHY Half Duplex\n", dev->name);
++		lp->rpc_cur_mode &= ~RPC_DPLX;
++		lp->tcr_cur_mode &= ~TCR_SWFDUP;
++	}
++
++	// Re-Configure the Receive/Phy Control register and TCR
++	SMC_SET_RPC( lp->rpc_cur_mode );
++	SMC_SET_TCR( lp->tcr_cur_mode );
++
++smc_phy_configure_exit:
++	// Exit auto-negotiation
++	lp->autoneg_active = 0;
++}
++
++/*************************************************************************
++ . smc_phy_interrupt
++ .
++ . Purpose:  Handle interrupts relating to PHY register 18. This is
++ .  called from the "hard" interrupt handler.
++ .
++ ************************************************************************/
++static void
++smc_phy_interrupt(struct net_device* dev)
++{
++	unsigned long ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	int phyaddr = lp->phyaddr;
++	int phy18;
++
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	for(;;) {
++		// Read PHY Register 18, Status Output
++		phy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
++
++		// Exit if not more changes
++		if (phy18 == lp->lastPhy18)
++			break;
++
++#if SMC_DEBUG > 1
++		PRINTK2("%s:     phy18=0x%04x\n", dev->name, phy18);
++		PRINTK2("%s: lastPhy18=0x%04x\n", dev->name, lp->lastPhy18);
++
++		// Handle events
++		if ((phy18 & PHY_INT_LNKFAIL) !=
++				(lp->lastPhy18 & PHY_INT_LNKFAIL))
++			PRINTK2("%s: PHY Link Fail=%x\n", dev->name,
++					phy18 & PHY_INT_LNKFAIL);
++
++		if ((phy18 & PHY_INT_LOSSSYNC) !=
++				(lp->lastPhy18 & PHY_INT_LOSSSYNC))
++			PRINTK2("%s: PHY LOSS SYNC=%x\n", dev->name,
++					phy18 & PHY_INT_LOSSSYNC);
++
++		if ((phy18 & PHY_INT_CWRD) != (lp->lastPhy18 & PHY_INT_CWRD))
++			PRINTK2("%s: PHY INVALID 4B5B code=%x\n", dev->name,
++					phy18 & PHY_INT_CWRD);
++
++		if ((phy18 & PHY_INT_SSD) != (lp->lastPhy18 & PHY_INT_SSD))
++			PRINTK2("%s: PHY No Start Of Stream=%x\n", dev->name,
++					phy18 & PHY_INT_SSD);
++
++		if ((phy18 & PHY_INT_ESD) != (lp->lastPhy18 & PHY_INT_ESD))
++
++			PRINTK2("%s: PHY No End Of Stream=%x\n", dev->name,
++					phy18 & PHY_INT_ESD);
++
++		if ((phy18 & PHY_INT_RPOL) != (lp->lastPhy18 & PHY_INT_RPOL))
++			PRINTK2("%s: PHY Reverse Polarity Detected=%x\n",
++					dev->name, phy18 & PHY_INT_RPOL);
++
++		if ((phy18 & PHY_INT_JAB) != (lp->lastPhy18 & PHY_INT_JAB))
++			PRINTK2("%s: PHY Jabber Detected=%x\n", dev->name,
++					phy18 & PHY_INT_JAB);
++
++		if ((phy18 & PHY_INT_SPDDET) !=
++				(lp->lastPhy18 & PHY_INT_SPDDET))
++			PRINTK2("%s: PHY Speed Detect=%x\n", dev->name,
++					phy18 & PHY_INT_SPDDET);
++
++		if ((phy18 & PHY_INT_DPLXDET) !=
++				(lp->lastPhy18 & PHY_INT_DPLXDET))
++			PRINTK2("%s: PHY Duplex Detect=%x\n", dev->name,
++					phy18 & PHY_INT_DPLXDET);
++#endif
++		// Update the last phy 18 variable
++		lp->lastPhy18 = phy18;
++	}
++}
++
++//--- END PHY CONTROL AND CONFIGURATION-------------------------------------
++
++
++/*
++ * This is the main routine of the driver, to handle the device when
++ * it needs some attention.
++ */
++static void
++smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct net_device *dev = dev_id;
++	unsigned long ioaddr = dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	int status, mask, timeout, card_stats;
++	int saved_bank, saved_pointer;
++
++	PRINTK3("%s: %s\n", dev->name, __FUNCTION__);
++
++	saved_bank = SMC_CURRENT_BANK();
++	SMC_SELECT_BANK(2);
++	saved_pointer = SMC_GET_PTR();
++	mask = SMC_GET_INT_MASK();
++	SMC_SET_INT_MASK( 0 );
++
++	/* set a timeout value, so I don't stay here forever */
++	timeout = 8;
++
++	do {
++		status = SMC_GET_INT();
++
++		PRINTK2("%s: IRQ 0x%02x MASK 0x%02x MEM 0x%04x FIFO 0x%04x\n",
++			dev->name, status, mask,
++			({ int meminfo; SMC_SELECT_BANK(0);
++			   meminfo = SMC_GET_MIR();
++			   SMC_SELECT_BANK(2); meminfo; }),
++			SMC_GET_FIFO());
++
++		status &= mask;
++		if (!status)
++			break;
++
++		if (status & IM_RCV_INT) {
++			PRINTK3("%s: RX irq\n", dev->name);
++			smc_rcv(dev);
++		} else if (status & IM_TX_INT) {
++			PRINTK3("%s: TX int\n", dev->name);
++			smc_tx(dev);
++			SMC_ACK_INT( IM_TX_INT );
++#if THROTTLE_TX_PKTS
++			netif_wake_queue(dev);
++#endif
++		} else if (status & IM_ALLOC_INT) {
++			PRINTK3("%s: Allocation irq\n", dev->name);
++			smc_hardware_send_packet(dev);
++			mask |= (IM_TX_INT | IM_TX_EMPTY_INT);
++			mask &= ~IM_ALLOC_INT;
++#if ! THROTTLE_TX_PKTS
++			netif_wake_queue(dev);
++#endif
++		} else if (status & IM_TX_EMPTY_INT) {
++			PRINTK3("%s: TX empty\n", dev->name);
++			mask &= ~IM_TX_EMPTY_INT;
++
++			/* update stats */
++			SMC_SELECT_BANK( 0 );
++			card_stats = SMC_GET_COUNTER();
++			SMC_SELECT_BANK( 2 );
++
++			/* single collisions */
++			lp->stats.collisions += card_stats & 0xF;
++			card_stats >>= 4;
++
++			/* multiple collisions */
++			lp->stats.collisions += card_stats & 0xF;
++		} else if (status & IM_RX_OVRN_INT) {
++			PRINTK1( "%s: RX overrun\n", dev->name);
++			SMC_ACK_INT( IM_RX_OVRN_INT );
++			lp->stats.rx_errors++;
++			lp->stats.rx_fifo_errors++;
++		} else if (status & IM_EPH_INT) {
++			PRINTK("%s: UNSUPPORTED: EPH INTERRUPT\n", dev->name);
++		} else if (status & IM_MDINT) {
++			SMC_ACK_INT( IM_MDINT );
++			smc_phy_interrupt(dev);
++		} else if (status & IM_ERCV_INT ) {
++			SMC_ACK_INT( IM_ERCV_INT );
++			PRINTK("%s: UNSUPPORTED: ERCV INTERRUPT \n", dev->name);
++		}
++	} while (--timeout);
++
++	/* restore register states */
++	SMC_SET_INT_MASK( mask );
++	SMC_SET_PTR( saved_pointer );
++	SMC_SELECT_BANK( saved_bank );
++
++	PRINTK3("%s: Interrupt done\n", dev->name);
++}
++
++/* Our watchdog timed out. Called by the networking layer */
++static void
++smc_timeout(struct net_device *dev)
++{
++	struct smc_local *lp 	= (struct smc_local *)dev->priv;
++
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	smc_reset(dev);
++	smc_enable(dev);
++
++#if 0
++	/* Reconfiguring the PHY doesn't seem like a bad idea here, but
++	 * it introduced a problem.  Now that this is a timeout routine,
++	 * we are getting called from within an interrupt context.
++	 * smc_phy_configure() calls smc_wait_ms() which calls
++	 * schedule_timeout() which calls schedule().  When schedule()
++	 * is called from an interrupt context, it prints out
++	 * "Scheduling in interrupt" and then calls BUG().  This is
++	 * obviously not desirable.  This was worked around by removing
++	 * the call to smc_phy_configure() here because it didn't seem
++	 * absolutely necessary.  Ultimately, if smc_wait_ms() is
++	 * supposed to be usable from an interrupt context (which it
++	 * looks like it thinks it should handle), it should be fixed.
++	 */
++	/* Reconfigure the PHY */
++	smc_phy_configure(dev);
++#endif
++
++	/* clear anything saved */
++	if (lp->saved_skb != NULL) {
++		dev_kfree_skb (lp->saved_skb);
++		lp->saved_skb = NULL;
++		lp->stats.tx_errors++;
++		lp->stats.tx_aborted_errors++;
++	}
++	dev->trans_start = jiffies;
++	netif_wake_queue(dev);
++}
++
++/*
++ * Finds the CRC32 of a set of bytes.
++ * (from Peter Cammaert's code)
++ */
++static int
++crc32(char *s, int length)
++{
++	/* indices */
++	int perByte;
++	int perBit;
++	/* crc polynomial for Ethernet */
++	const unsigned long poly = 0xedb88320;
++	/* crc value - preinitialized to all 1's */
++	unsigned long crc_value = 0xffffffff;
++
++	for ( perByte = 0; perByte < length; perByte ++ ) {
++		unsigned char	c;
++
++		c = *(s++);
++		for ( perBit = 0; perBit < 8; perBit++ ) {
++			crc_value = (crc_value>>1)^
++				(((crc_value^c)&0x01)?poly:0);
++			c >>= 1;
++		}
++	}
++	return	crc_value;
++}
++
++/*
++ .    This sets the internal hardware table to filter out unwanted multicast
++ .    packets before they take up memory.
++ .
++ .    The SMC chip uses a hash table where the high 6 bits of the CRC of
++ .    address are the offset into the table.  If that bit is 1, then the
++ .    multicast packet is accepted.  Otherwise, it's dropped silently.
++ .
++ .    To use the 6 bits as an offset into the table, the high 3 bits are the
++ .    number of the 8 bit register, while the low 3 bits are the bit within
++ .    that register.
++ .
++ .    This routine is based very heavily on the one provided by Peter Cammaert.
++*/
++static void
++smc_setmulticast(unsigned long ioaddr, int count, struct dev_mc_list *addrs)
++{
++	int			i;
++	unsigned char		multicast_table[ 8 ];
++	struct dev_mc_list	*cur_addr;
++
++	/* table for flipping the order of 3 bits */
++	static unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
++
++	/* start with a table of all zeros: reject all */
++	memset( multicast_table, 0, sizeof( multicast_table ) );
++
++	cur_addr = addrs;
++	for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next  ) {
++		int position;
++
++		/* do we have a pointer here? */
++		if ( !cur_addr )
++			break;
++		/* make sure this is a multicast address - shouldn't this
++		   be a given if we have it here ? */
++		if ( !( *cur_addr->dmi_addr & 1 ) )
++			continue;
++
++		/* only use the low order bits */
++		position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f;
++
++		/* do some messy swapping to put the bit in the right spot */
++		multicast_table[invert3[position&7]] |=
++					(1<<invert3[(position>>3)&7]);
++
++	}
++	/* now, the table can be loaded into the chipset */
++	SMC_SELECT_BANK( 3 );
++	SMC_SET_MCAST( multicast_table );
++}
++
++/*
++ . This routine will, depending on the values passed to it,
++ . either make it accept multicast packets, go into
++ . promiscuous mode ( for TCPDUMP and cousins ) or accept
++ . a select set of multicast packets
++*/
++static void smc_set_multicast_list(struct net_device *dev)
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	unsigned long ioaddr = dev->base_addr;
++
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	SMC_SELECT_BANK(0);
++	if ( dev->flags & IFF_PROMISC ) {
++		PRINTK2("%s: RCR_PRMS\n", dev->name);
++		lp->rcr_cur_mode |= RCR_PRMS;
++		SMC_SET_RCR( lp->rcr_cur_mode );
++	}
++
++/* BUG?  I never disable promiscuous mode if multicasting was turned on.
++   Now, I turn off promiscuous mode, but I don't do anything to multicasting
++   when promiscuous mode is turned on.
++*/
++
++	/* Here, I am setting this to accept all multicast packets.
++	   I don't need to zero the multicast table, because the flag is
++	   checked before the table is
++	*/
++	else if (dev->flags & IFF_ALLMULTI) {
++		lp->rcr_cur_mode |= RCR_ALMUL;
++		SMC_SET_RCR( lp->rcr_cur_mode );
++		PRINTK2("%s: RCR_ALMUL\n", dev->name);
++	}
++
++	/* We just get all multicast packets even if we only want them
++	 . from one source.  This will be changed at some future
++	 . point. */
++	else if (dev->mc_count )  {
++		/* support hardware multicasting */
++
++		/* be sure I get rid of flags I might have set */
++		lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
++		SMC_SET_RCR( lp->rcr_cur_mode );
++		/* NOTE: this has to set the bank, so make sure it is the
++		   last thing called.  The bank is set to zero at the top */
++		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
++	} else  {
++		PRINTK2("%s: ~(RCR_PRMS|RCR_ALMUL)\n", dev->name);
++		lp->rcr_cur_mode &= ~(RCR_PRMS | RCR_ALMUL);
++		SMC_SET_RCR( lp->rcr_cur_mode );
++
++		/*
++		  since I'm disabling all multicast entirely, I need to
++		  clear the multicast list
++		*/
++		SMC_SELECT_BANK( 3 );
++		SMC_CLEAR_MCAST();
++	}
++}
++
++
++/*
++ * Open and Initialize the board
++ *
++ * Set up everything, reset the card, etc ..
++ */
++static int
++smc_open(struct net_device *dev)
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	unsigned long ioaddr = dev->base_addr;
++
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	/* clear out all the junk that was put here before... */
++	memset(dev->priv, 0, sizeof(struct smc_local));
++
++	// Setup the default Register Modes
++	lp->tcr_cur_mode = TCR_DEFAULT;
++	lp->rcr_cur_mode = RCR_DEFAULT;
++	lp->rpc_cur_mode = RPC_DEFAULT;
++
++	/* Set default parameters */
++#ifdef CONFIG_ARCH_RAMSES
++	lp->ctl_autoneg = 0;
++	lp->ctl_rfduplx = 0;
++	lp->ctl_rspeed = 10;
++#else
++	lp->ctl_autoneg = 1;
++	lp->ctl_rfduplx = 1;
++	lp->ctl_rspeed = 100;
++#endif
++
++	SMC_SELECT_BANK(3);
++	lp->version = SMC_GET_REV() & 0xff;
++
++	/* reset the hardware */
++	smc_reset(dev);
++	smc_enable(dev);
++
++	SMC_SELECT_BANK( 1 );
++	SMC_SET_MAC_ADDR(dev->dev_addr);
++
++	/* Configure the PHY */
++	if (lp->version >= 0x70)
++		smc_phy_configure(dev);
++
++	netif_start_queue(dev);
++	return 0;
++}
++
++/*----------------------------------------------------
++ . smc_close
++ .
++ . this makes the board clean up everything that it can
++ . and not talk to the outside world.   Caused by
++ . an 'ifconfig ethX down'
++ .
++ -----------------------------------------------------*/
++static int
++smc_close(struct net_device *dev)
++{
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	netif_stop_queue(dev);
++
++	/* clear everything */
++	smc_shutdown(dev);
++
++	return 0;
++}
++
++/*------------------------------------------------------------
++ . Get the current statistics.
++ . This may be called with the card open or closed.
++ .-------------------------------------------------------------*/
++static struct net_device_stats *
++smc_query_statistics(struct net_device *dev)
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++
++	PRINTK2("%s: %s\n", dev->name, __FUNCTION__);
++
++	return &lp->stats;
++}
++
++/*----------------------------------------------------------------------
++ . smc_findirq
++ .
++ . This routine has a simple purpose -- make the SMC chip generate an
++ . interrupt, so an auto-detect routine can detect it, and find the IRQ,
++ ------------------------------------------------------------------------
++*/
++int __init
++smc_findirq( unsigned long ioaddr )
++{
++	int timeout = 20;
++	unsigned long cookie;
++
++	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++	cookie = probe_irq_on();
++
++	/*
++	 * What I try to do here is trigger an ALLOC_INT. This is done
++	 * by allocating a small chunk of memory, which will give an interrupt
++	 * when done.
++	 */
++
++	/* enable ALLOCation interrupts ONLY */
++	SMC_SELECT_BANK(2);
++	SMC_SET_INT_MASK( IM_ALLOC_INT );
++
++	/*
++ 	 . Allocate 512 bytes of memory.  Note that the chip was just
++	 . reset so all the memory is available
++	*/
++	SMC_SET_MMU_CMD( MC_ALLOC | 1 );
++
++	/*
++	 . Wait until positive that the interrupt has been generated
++	*/
++	do {
++		int int_status;
++		udelay(10);
++		int_status = SMC_GET_INT();
++		if (int_status & IM_ALLOC_INT)
++			break;		/* got the interrupt */
++	} while (--timeout);
++
++	/* there is really nothing that I can do here if timeout fails,
++	   as autoirq_report will return a 0 anyway, which is what I
++	   want in this case.   Plus, the clean up is needed in both
++	   cases.  */
++
++	/* and disable all interrupts again */
++	SMC_SET_INT_MASK( 0 );
++
++	/* and return what I found */
++	return probe_irq_off(cookie);
++}
++
++/*----------------------------------------------------------------------
++ . Function: smc_probe( unsigned long ioaddr )
++ .
++ . Purpose:
++ .	Tests to see if a given ioaddr points to an SMC91x chip.
++ .	Returns a 0 on success
++ .
++ . Algorithm:
++ .	(1) see if the high byte of BANK_SELECT is 0x33
++ . 	(2) compare the ioaddr with the base register's address
++ .	(3) see if I recognize the chip ID in the appropriate register
++ .
++ .---------------------------------------------------------------------
++ */
++/*---------------------------------------------------------------
++ . Here I do typical initialization tasks.
++ .
++ . o  Initialize the structure if needed
++ . o  print out my vanity message if not done so already
++ . o  print out what type of hardware is detected
++ . o  print out the ethernet address
++ . o  find the IRQ
++ . o  set up my private data
++ . o  configure the dev structure with my subroutines
++ . o  actually GRAB the irq.
++ . o  GRAB the region
++ .-----------------------------------------------------------------
++*/
++static int __init
++smc_probe(struct net_device *dev, unsigned long ioaddr)
++{
++	struct smc_local *lp = (struct smc_local *)dev->priv;
++	static int version_printed = 0;
++	int i, retval;
++	unsigned int val, revision_register;
++	const char *version_string;
++
++	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++	/* Grab the region so that no one else tries to probe our ioports. */
++	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))
++		return -EBUSY;
++
++	/* First, see if the high byte is 0x33 */
++	val = SMC_CURRENT_BANK();
++	PRINTK2("%s: bank signature probe returned 0x%04x\n", CARDNAME, val);
++	if ( (val & 0xFF00) != 0x3300 ) {
++		if ( (val & 0xFF) == 0x33 ) {
++			printk( KERN_WARNING
++				"%s: Detected possible byte-swapped interface"
++				" at IOADDR 0x%lx\n", CARDNAME, ioaddr);
++		}
++		retval = -ENODEV;
++		goto err_out;
++	}
++
++	/* The above MIGHT indicate a device, but I need to write to further
++ 	 	test this.  */
++	SMC_SELECT_BANK(0);
++	val = SMC_CURRENT_BANK();
++	if ( (val & 0xFF00 ) != 0x3300 ) {
++		retval = -ENODEV;
++		goto err_out;
++	}
++
++	/* well, we've already written once, so hopefully another time won't
++ 	   hurt.  This time, I need to switch the bank register to bank 1,
++	   so I can access the base address register */
++	SMC_SELECT_BANK(1);
++	val = SMC_GET_BASE();
++	val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT;
++	if ( (ioaddr & ((PAGE_SIZE-1)<<SMC_IO_SHIFT)) != val ) {
++		printk( "%s: IOADDR %lx doesn't match configuration (%x).\n",
++			CARDNAME, ioaddr, val );
++	}
++
++	/*  check if the revision register is something that I recognize.
++	    These might need to be added to later, as future revisions
++	    could be added.  */
++	SMC_SELECT_BANK(3);
++	revision_register = SMC_GET_REV();
++	PRINTK2("%s: revision = 0x%04x\n", CARDNAME, revision_register);
++	version_string = chip_ids[ (revision_register >> 4) & 0xF];
++	if (!version_string || (revision_register & 0xff00) != 0x3300) {
++		/* I don't recognize this chip, so... */
++		printk( "%s: IO 0x%lx: Unrecognized revision register 0x%04x"
++			", Contact author.\n", CARDNAME,
++			ioaddr, revision_register);
++
++		retval = -ENODEV;
++		goto err_out;
++	}
++
++	/* At this point I'll assume that the chip is an SMC91x. */
++	if (version_printed++ == 0)
++		printk("%s", version);
++
++	/* set the private data to zero by default */
++	memset(lp, 0, sizeof(struct smc_local));
++
++	/* fill in some of the fields */
++	dev->base_addr = ioaddr;
++	lp->version = revision_register & 0xff;
++
++	/* Get the MAC address */
++	SMC_SELECT_BANK( 1 );
++	SMC_GET_MAC_ADDR(dev->dev_addr);
++
++	/* now, reset the chip, and put it into a known state */
++	smc_reset( dev );
++
++	/*
++	 . If dev->irq is 0, then the device has to be banged on to see
++	 . what the IRQ is.
++ 	 .
++	 . This banging doesn't always detect the IRQ, for unknown reasons.
++	 . a workaround is to reset the chip and try again.
++	 .
++	 . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
++	 . be what is requested on the command line.   I don't do that, mostly
++	 . because the card that I have uses a non-standard method of accessing
++	 . the IRQs, and because this _should_ work in most configurations.
++	 .
++	 . Specifying an IRQ is done with the assumption that the user knows
++	 . what (s)he is doing.  No checking is done!!!!
++ 	 .
++	*/
++	if ( dev->irq < 1 ) {
++		int	trials;
++
++		trials = 3;
++		while ( trials-- ) {
++			dev->irq = smc_findirq( ioaddr );
++			if ( dev->irq )
++				break;
++			/* kick the card and try again */
++			smc_reset( dev );
++		}
++	}
++	if (dev->irq == 0 ) {
++		printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
++			dev->name);
++		retval = -ENODEV;
++		goto err_out;
++	}
++	dev->irq = irq_cannonicalize(dev->irq);
++
++	/* now, print out the card info, in a short format.. */
++	printk( "%s: %s (rev %d) at %#lx IRQ %d%s%s\n",
++		dev->name, version_string, revision_register & 0x0f,
++		ioaddr, dev->irq, nowait ? " [nowait]" : "",
++		THROTTLE_TX_PKTS ? " [throttle_tx]" : "" );
++
++	/* Print the Ethernet address */
++	printk("%s: Ethernet addr: ", dev->name);
++	for (i = 0; i < 5; i++)
++		printk("%2.2x:", dev->dev_addr[i] );
++	printk("%2.2x\n", dev->dev_addr[5] );
++
++	/* Fill in the fields of the device structure with ethernet values. */
++	ether_setup(dev);
++
++	/* Grab the IRQ */
++      	retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
++      	if (retval) {
++  	  	goto err_out;
++      	}
++
++	dev->open		        = smc_open;
++	dev->stop		        = smc_close;
++	dev->hard_start_xmit    	= smc_hard_start_xmit;
++	dev->tx_timeout		    	= smc_timeout;
++	dev->watchdog_timeo		= HZ/10;
++	dev->get_stats			= smc_query_statistics;
++	dev->set_multicast_list 	= smc_set_multicast_list;
++
++	return 0;
++
++err_out:
++	release_region(ioaddr, SMC_IO_EXTENT);
++	return retval;
++}
++
++/*-------------------------------------------------------------------------
++ |
++ | smc_init( void )
++ |   Input parameters:
++ |	dev->base_addr == 0, try to find all possible locations
++ |	dev->base_addr > 0x1ff, this is the address to check
++ |	dev->base_addr == <anything else>, return failure code
++ |
++ |   Output:
++ |	0 --> there is a device
++ |	anything else, error
++ |
++ ---------------------------------------------------------------------------
++*/
++static struct net_device *global_dev = NULL;  /* needs to be fixed */
++
++#ifdef CONFIG_PM
++
++static int smc_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++	unsigned long ioaddr = global_dev->base_addr;
++	struct smc_local *lp = (struct smc_local *)global_dev->priv;
++
++	switch (rqst) {
++	case PM_SUSPEND:
++		smc_shutdown(global_dev);
++		break;
++	case PM_RESUME:
++		smc_reset(global_dev);
++		smc_enable(global_dev);
++		SMC_SELECT_BANK( 1 );
++	        SMC_SET_MAC_ADDR(global_dev->dev_addr);
++	        if (lp->version >= 0x70)
++        	        smc_phy_configure(global_dev);
++		break;
++	}
++	return 0;
++}
++
++#endif
++
++static int __init
++smc_init(void)
++{
++	int ret;
++
++	PRINTK2("%s: %s\n", CARDNAME, __FUNCTION__);
++
++#ifdef MODULE
++	if (io == -1)
++		printk( KERN_WARNING 
++			"%s: You shouldn't use auto-probing with insmod!\n",
++			CARDNAME );
++#endif
++
++	if (global_dev) {
++		printk("%s: already initialized.\n", CARDNAME);
++		return -EBUSY;
++	}
++
++	global_dev = init_etherdev(0, sizeof(struct smc_local));
++	if (!global_dev) {
++		printk("%s: could not allocate device.\n", CARDNAME);
++		return -ENOMEM;
++	}
++	SET_MODULE_OWNER(global_dev);
++
++	/* copy the parameters from insmod into the device structure */
++	if (io != -1)
++		global_dev->base_addr	= io;
++	if (irq != -1)
++		global_dev->irq	= irq;
++
++#ifdef CONFIG_ISA
++	/*  try a specific location */
++	if (global_dev->base_addr > 0x1ff)
++		ret = smc_probe(global_dev, global_dev->base_addr);
++	else if (global_dev->base_addr != 0)
++		ret = -ENXIO;
++	else {
++		int i;
++
++		/* check every ethernet address */
++		for (i = 0; smc_portlist[i]; i++) {
++			ret = smc_probe(global_dev, smc_portlist[i]);
++			if (ret == 0)
++				break;
++		}
++	}
++#elif defined(CONFIG_ARCH_LUBBOCK)
++	{
++		int ioaddr = LUBBOCK_ETH_VIRT + (0x300 << 2);
++		volatile int *attaddr = (int *)(LUBBOCK_ETH_VIRT + 0x100000);
++		unsigned long flags;
++
++		/* first reset, then enable the device. Sequence is critical */
++		local_irq_save(flags);
++		attaddr[ECOR] |= ECOR_RESET;
++		udelay(100);
++		attaddr[ECOR] &= ~ECOR_RESET;
++		attaddr[ECOR] |= ECOR_ENABLE;
++
++		/* force 16-bit mode */
++		attaddr[ECSR] &= ~ECSR_IOIS8;
++		mdelay(1);
++		local_irq_restore(flags);
++
++		global_dev->irq = LUBBOCK_ETH_IRQ;
++		ret = smc_probe(global_dev, ioaddr);
++	}
++#elif defined(CONFIG_ARCH_PXA_IDP)
++	{
++		int ioaddr = IDP_ETH_BASE + 0x300;
++		global_dev->irq = SMC_IRQ;
++		ret = smc_probe(global_dev, ioaddr);
++	}
++#elif defined(CONFIG_ARCH_RAMSES)
++	{
++		int ioaddr = RAMSES_ETH_BASE + 0x300;
++		global_dev->irq = SMC_IRQ;
++		ret = smc_probe(global_dev, ioaddr);
++	}
++#else
++	if (global_dev->base_addr == -1) {
++		printk(KERN_WARNING"%s: SMC91X_BASE_ADDR not set!\n", CARDNAME);
++		ret = -ENXIO;
++	} else {
++		void *ioaddr = ioremap(global_dev->base_addr, SMC_IO_EXTENT);
++		ret = smc_probe(global_dev, (unsigned long)ioaddr);
++		if (ret != 0)
++			iounmap(ioaddr);
++	}
++#endif
++
++#ifdef SMC_USE_PXA_DMA
++	if (ret == 0) {
++		int dma = pxa_request_dma(global_dev->name, DMA_PRIO_LOW,
++					  smc_pxa_dma_irq, NULL);
++		if (dma >= 0) {
++			global_dev->dma = dma;
++			PRINTK("%s: using DMA channel %d\n", global_dev->name, dma);
++		} else {
++			global_dev->dma = -1;
++		}
++	}
++#endif
++
++#ifdef CONFIG_PM
++	if (ret == 0) {
++		struct smc_local *lp = (struct smc_local *)global_dev->priv;
++		lp->pm = pm_register(PM_SYS_UNKNOWN, 0x73393178, smc_pm_callback);
++	}
++#endif
++
++	if (ret != 0) {
++		printk("%s: not found.\n", CARDNAME);
++		kfree(global_dev->priv);
++		unregister_netdev(global_dev);
++		kfree(global_dev);
++	}
++
++	return ret;
++}
++
++static void __exit
++smc_cleanup(void)
++{
++	unregister_netdev(global_dev);
++#ifdef CONFIG_PM
++	{
++		struct smc_local *lp = (struct smc_local *)global_dev->priv;
++		pm_unregister(lp->pm);
++	}
++#endif
++	free_irq(global_dev->irq, global_dev);
++	release_region(global_dev->base_addr, SMC_IO_EXTENT);
++
++#ifndef CONFIG_ISA
++	iounmap((void *)global_dev->base_addr);
++#endif
++
++	kfree(global_dev);
++	global_dev = NULL;
++}
++
++module_init(smc_init);
++module_exit(smc_cleanup);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/net/smc91x.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,835 @@
++/*------------------------------------------------------------------------
++ . smc91x.h - macros for SMSC's 91C9x/91C1xx single-chip Ethernet device.
++ .
++ . Copyright (C) 1996 by Erik Stahlman
++ . Copyright (C) 2001 Standard Microsystems Corporation
++ .	Developed by Simple Network Magic Corporation
++ . Copyright (C) 2003 Monta Vista Software, Inc.
++ .	Unified SMC91x driver by Nicolas Pitre
++ .
++ . 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
++ .
++ . Information contained in this file was obtained from the LAN91C111
++ . manual from SMC.  To get a copy, if you really want one, you can find
++ . information under www.smsc.com.
++ .
++ . Authors
++ .	Erik Stahlman		<erik@vt.edu>
++ .	Daris A Nevil		<dnevil@snmc.com>
++ .	Nicolas Pitre 		<nico@cam.org>
++ .
++ ---------------------------------------------------------------------------*/
++#ifndef _SMC91X_H_
++#define _SMC91X_H_
++
++
++/*
++ * Define your architecture specific configuration parameters here.
++ */
++
++#if	defined(CONFIG_SA1100_GRAPHICSCLIENT) || \
++	defined(CONFIG_SA1100_PFS168) || \
++	defined(CONFIG_SA1100_FLEXANET) || \
++	defined(CONFIG_SA1100_GRAPHICSMASTER) || \
++	defined(CONFIG_ARCH_LUBBOCK)
++
++/* We can only do 16-bit reads and writes in the static memory space. */
++#define SMC_CAN_USE_8BIT	0
++#define SMC_CAN_USE_16BIT	1
++#define SMC_CAN_USE_32BIT	0
++#define SMC_NOWAIT		1
++
++/* The first two address lines aren't connected... */
++#define SMC_IO_SHIFT		2
++
++#define SMC_inw(a, r)		readw((a) + (r))
++#define SMC_outw(v, a, r)	writew(v, (a) + (r))
++#define SMC_insw(a, r, p, l)	insw((a) + (r), p, l)
++#define SMC_outsw(a, r, p, l)	outsw((a) + (r), p, l)
++
++#ifdef CONFIG_ARCH_LUBBOCK
++#define SMC_IOADDR		LUBBOCK_ETH_PHYS
++#endif
++
++#elif	defined(CONFIG_ARCH_MAINSTONE) || defined(CONFIG_ARCH_PXA_IDP) || defined(CONFIG_ARCH_RAMSES)
++
++#ifdef CONFIG_ARCH_MAINSTONE
++#include <asm/arch/mainstone.h>
++#define SMC_IOADDR		(MST_ETH_PHYS + 0x300)
++#define SMC_IRQ			MAINSTONE_IRQ(3)
++
++#elif CONFIG_ARCH_PXA_IDP
++#include <asm/arch/idp.h>
++#define SMC_IOADDR		(IDP_ETH_PHYS + 0x300)
++#define SMC_IRQ			ETHERNET_IRQ
++	
++#elif CONFIG_ARCH_RAMSES
++#include <asm/arch/ramses.h>
++#define SMC_IOADDR		(RAMSES_ETH_PHYS + 0x300)
++#define SMC_IRQ			ETHERNET_IRQ
++#endif
++	
++#define SMC_CAN_USE_8BIT	1
++#define SMC_CAN_USE_16BIT	1
++#define SMC_CAN_USE_32BIT	1
++#define SMC_IO_SHIFT		0
++#define SMC_NOWAIT		1
++#define SMC_USE_PXA_DMA		1
++
++#define SMC_inb(a, r)		readb((a) + (r))
++#define SMC_inw(a, r)		readw((a) + (r))
++#define SMC_inl(a, r)		readl((a) + (r))
++#define SMC_outb(v, a, r)	writeb(v, (a) + (r))
++#define SMC_outl(v, a, r)	writel(v, (a) + (r))
++#define SMC_insl(a, r, p, l)	insl((a) + (r), p, l)
++#define SMC_outsl(a, r, p, l)	outsl((a) + (r), p, l)
++
++/* We actually can't write halfwords properly if not word aligned */
++static inline void
++SMC_outw(u16 val, unsigned long ioaddr, int reg)
++{
++	if (reg & 2) {
++		unsigned int v = val << 16;
++		v |= readl(ioaddr + (reg & ~2)) & 0xffff;
++		writel(v, ioaddr + (reg & ~2));
++	} else {
++		writew(val, ioaddr + reg);
++	}
++}
++
++#elif	defined(CONFIG_ISA)
++
++#define SMC_CAN_USE_8BIT	1
++#define SMC_CAN_USE_16BIT	1
++#define SMC_CAN_USE_32BIT	0
++
++#define SMC_inb(a, r)		inb((a) + (r))
++#define SMC_inw(a, r)		inw((a) + (r))
++#define SMC_outb(v, a, r)	outb(v, (a) + (r))
++#define SMC_outw(v, a, r)	outw(v, (a) + (r))
++#define SMC_insw(a, r, p, l)	insw((a) + (r), p, l)
++#define SMC_outsw(a, r, p, l)	outsw((a) + (r), p, l)
++
++#endif
++
++
++#ifdef SMC_USE_PXA_DMA
++/*
++ * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is
++ * always happening in irq context so no need to worry about races.  TX is
++ * different and probably not worth it for that reason, and not as critical
++ * as RX which can overrun memory and lose packets.
++ */
++#include <linux/pci.h>
++#include <asm/dma.h>
++
++#ifdef SMC_insl
++#undef SMC_insl
++#define SMC_insl(a, r, p, l)	smc_pxa_dma_insl(a, r, dev->dma, p, l)
++static inline void
++smc_pxa_dma_insl(u_long ioaddr, int reg, int dma, u_char *buf, int len)
++{
++	dma_addr_t dmabuf;
++
++	/* fallback if no DMA available */
++	if (dma == -1) {
++		insl(ioaddr + reg, buf, len);
++		return;
++	}
++
++	/* 64 bit alignment is required for memory to memory DMA */
++	if ((long)buf & 4) {
++		*((u32 *)buf)++ = SMC_inl(ioaddr, reg);
++		len--;
++	}
++
++	len *= 4;
++	dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
++	DCSR(dma) = DCSR_NODESC;
++	DTADR(dma) = dmabuf;
++	DSADR(dma) = SMC_IOADDR + reg;
++	DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
++		     DCMD_WIDTH4 | (DCMD_LENGTH & len));
++	DCSR(dma) = DCSR_NODESC | DCSR_RUN;
++	while (!(DCSR(dma) & DCSR_STOPSTATE));
++	DCSR(dma) = 0;
++	pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE);
++}
++#endif
++
++#ifdef SMC_insw
++#undef SMC_insw
++#define SMC_insw(a, r, p, l)	smc_pxa_dma_insw(a, r, dev->dma, p, l)
++static inline void
++smc_pxa_dma_insw(u_long ioaddr, int reg, int dma, u_char *buf, int len)
++{
++	dma_addr_t dmabuf;
++
++	/* fallback if no DMA available */
++	if (dma == -1) {
++		insw(ioaddr + reg, buf, len);
++		return;
++	}
++
++	/* 64 bit alignment is required for memory to memory DMA */
++	while ((long)buf & 6) {
++		*((u16 *)buf)++ = SMC_inw(ioaddr, reg);
++		len--;
++	}
++
++	len *= 2;
++	dmabuf = pci_map_single(NULL, buf, len, PCI_DMA_FROMDEVICE);
++	DCSR(dma) = DCSR_NODESC;
++	DTADR(dma) = dmabuf;
++	DSADR(dma) = SMC_IOADDR + reg;
++	DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
++		     DCMD_WIDTH2 | (DCMD_LENGTH & len));
++	DCSR(dma) = DCSR_NODESC | DCSR_RUN;
++	while (!(DCSR(dma) & DCSR_STOPSTATE));
++	DCSR(dma) = 0;
++	pci_unmap_single(NULL, dmabuf,len, PCI_DMA_FROMDEVICE);
++}
++#endif
++
++static void
++smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs)
++{
++	DCSR(dma) = 0;
++}
++#endif  /* SMC_USE_PXA_DMA */
++
++
++/* Because of bank switching, the LAN91xxx uses only 16 I/O ports */
++#ifndef SMC_IO_SHIFT
++#define SMC_IO_SHIFT	0
++#endif
++#define SMC_IO_EXTENT	(16 << SMC_IO_SHIFT)
++
++
++/*
++ . Bank Select Register:
++ .
++ .		yyyy yyyy 0000 00xx
++ .		xx 		= bank number
++ .		yyyy yyyy	= 0x33, for identification purposes.
++*/
++#define BANK_SELECT		(14 << SMC_IO_SHIFT)
++
++
++// Transmit Control Register
++/* BANK 0  */
++#define TCR_REG 	SMC_REG(0x0000, 0)
++#define TCR_ENABLE	0x0001	// When 1 we can transmit
++#define TCR_LOOP	0x0002	// Controls output pin LBK
++#define TCR_FORCOL	0x0004	// When 1 will force a collision
++#define TCR_PAD_EN	0x0080	// When 1 will pad tx frames < 64 bytes w/0
++#define TCR_NOCRC	0x0100	// When 1 will not append CRC to tx frames
++#define TCR_MON_CSN	0x0400	// When 1 tx monitors carrier
++#define TCR_FDUPLX    	0x0800  // When 1 enables full duplex operation
++#define TCR_STP_SQET	0x1000	// When 1 stops tx if Signal Quality Error
++#define TCR_EPH_LOOP	0x2000	// When 1 enables EPH block loopback
++#define TCR_SWFDUP	0x8000	// When 1 enables Switched Full Duplex mode
++
++#define TCR_CLEAR	0	/* do NOTHING */
++/* the default settings for the TCR register : */
++#define TCR_DEFAULT	(TCR_ENABLE | TCR_PAD_EN)
++
++
++// EPH Status Register
++/* BANK 0  */
++#define EPH_STATUS_REG	SMC_REG(0x0002, 0)
++#define ES_TX_SUC	0x0001	// Last TX was successful
++#define ES_SNGL_COL	0x0002	// Single collision detected for last tx
++#define ES_MUL_COL	0x0004	// Multiple collisions detected for last tx
++#define ES_LTX_MULT	0x0008	// Last tx was a multicast
++#define ES_16COL	0x0010	// 16 Collisions Reached
++#define ES_SQET		0x0020	// Signal Quality Error Test
++#define ES_LTXBRD	0x0040	// Last tx was a broadcast
++#define ES_TXDEFR	0x0080	// Transmit Deferred
++#define ES_LATCOL	0x0200	// Late collision detected on last tx
++#define ES_LOSTCARR	0x0400	// Lost Carrier Sense
++#define ES_EXC_DEF	0x0800	// Excessive Deferral
++#define ES_CTR_ROL	0x1000	// Counter Roll Over indication
++#define ES_LINK_OK	0x4000	// Driven by inverted value of nLNK pin
++#define ES_TXUNRN	0x8000	// Tx Underrun
++
++
++// Receive Control Register
++/* BANK 0  */
++#define RCR_REG		SMC_REG(0x0004, 0)
++#define RCR_RX_ABORT	0x0001	// Set if a rx frame was aborted
++#define RCR_PRMS	0x0002	// Enable promiscuous mode
++#define RCR_ALMUL	0x0004	// When set accepts all multicast frames
++#define RCR_RXEN	0x0100	// IFF this is set, we can receive packets
++#define RCR_STRIP_CRC	0x0200	// When set strips CRC from rx packets
++#define RCR_ABORT_ENB	0x0200	// When set will abort rx on collision
++#define RCR_FILT_CAR	0x0400	// When set filters leading 12 bit s of carrier
++#define RCR_SOFTRST	0x8000 	// resets the chip
++
++/* the normal settings for the RCR register : */
++#define RCR_DEFAULT	(RCR_STRIP_CRC | RCR_RXEN)
++#define RCR_CLEAR	0x0	// set it to a base state
++
++
++// Counter Register
++/* BANK 0  */
++#define COUNTER_REG	SMC_REG(0x0006, 0)
++
++
++// Memory Information Register
++/* BANK 0  */
++#define MIR_REG		SMC_REG(0x0008, 0)
++
++
++// Receive/Phy Control Register
++/* BANK 0  */
++#define RPC_REG		SMC_REG(0x000A, 0)
++#define RPC_SPEED	0x2000	// When 1 PHY is in 100Mbps mode.
++#define RPC_DPLX	0x1000	// When 1 PHY is in Full-Duplex Mode
++#define RPC_ANEG	0x0800	// When 1 PHY is in Auto-Negotiate Mode
++#define RPC_LSXA_SHFT	5	// Bits to shift LS2A,LS1A,LS0A to lsb
++#define RPC_LSXB_SHFT	2	// Bits to get LS2B,LS1B,LS0B to lsb
++#define RPC_LED_100_10	(0x00)	// LED = 100Mbps OR's with 10Mbps link detect
++#define RPC_LED_RES	(0x01)	// LED = Reserved
++#define RPC_LED_10	(0x02)	// LED = 10Mbps link detect
++#define RPC_LED_FD	(0x03)	// LED = Full Duplex Mode
++#define RPC_LED_TX_RX	(0x04)	// LED = TX or RX packet occurred
++#define RPC_LED_100	(0x05)	// LED = 100Mbps link dectect
++#define RPC_LED_TX	(0x06)	// LED = TX packet occurred
++#define RPC_LED_RX	(0x07)	// LED = RX packet occurred
++#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
++
++
++/* Bank 0 0x0C is reserved */
++
++// Bank Select Register
++/* All Banks */
++#define BSR_REG		0x000E
++
++
++// Configuration Reg
++/* BANK 1 */
++#define CONFIG_REG	SMC_REG(0x0000,	1)
++#define CONFIG_EXT_PHY	0x0200	// 1=external MII, 0=internal Phy
++#define CONFIG_GPCNTRL	0x0400	// Inverse value drives pin nCNTRL
++#define CONFIG_NO_WAIT	0x1000	// When 1 no extra wait states on ISA bus
++#define CONFIG_EPH_POWER_EN 0x8000 // When 0 EPH is placed into low power mode.
++
++// Default is powered-up, Internal Phy, Wait States, and pin nCNTRL=low
++#define CONFIG_DEFAULT	(CONFIG_EPH_POWER_EN)
++
++
++// Base Address Register
++/* BANK 1 */
++#define BASE_REG	SMC_REG(0x0002, 1)
++
++
++// Individual Address Registers
++/* BANK 1 */
++#define ADDR0_REG	SMC_REG(0x0004, 1)
++#define ADDR1_REG	SMC_REG(0x0006, 1)
++#define ADDR2_REG	SMC_REG(0x0008, 1)
++
++
++// General Purpose Register
++/* BANK 1 */
++#define GP_REG		SMC_REG(0x000A, 1)
++
++
++// Control Register
++/* BANK 1 */
++#define CTL_REG		SMC_REG(0x000C, 1)
++#define CTL_RCV_BAD	0x4000 // When 1 bad CRC packets are received
++#define CTL_AUTO_RELEASE 0x0800 // When 1 tx pages are released automatically
++#define CTL_LE_ENABLE	0x0080 // When 1 enables Link Error interrupt
++#define CTL_CR_ENABLE	0x0040 // When 1 enables Counter Rollover interrupt
++#define CTL_TE_ENABLE	0x0020 // When 1 enables Transmit Error interrupt
++#define CTL_EEPROM_SELECT 0x0004 // Controls EEPROM reload & store
++#define CTL_RELOAD	0x0002 // When set reads EEPROM into registers
++#define CTL_STORE	0x0001 // When set stores registers into EEPROM
++
++
++// MMU Command Register
++/* BANK 2 */
++#define MMU_CMD_REG	SMC_REG(0x0000, 2)
++#define MC_BUSY		1	// When 1 the last release has not completed
++#define MC_NOP		(0<<5)	// No Op
++#define MC_ALLOC	(1<<5) 	// OR with number of 256 byte packets
++#define MC_RESET	(2<<5)	// Reset MMU to initial state
++#define MC_REMOVE	(3<<5) 	// Remove the current rx packet
++#define MC_RELEASE  	(4<<5) 	// Remove and release the current rx packet
++#define MC_FREEPKT  	(5<<5) 	// Release packet in PNR register
++#define MC_ENQUEUE	(6<<5)	// Enqueue the packet for transmit
++#define MC_RSTTXFIFO	(7<<5)	// Reset the TX FIFOs
++
++
++// Packet Number Register
++/* BANK 2 */
++#define PN_REG		SMC_REG(0x0002, 2)
++
++
++// Allocation Result Register
++/* BANK 2 */
++#define AR_REG		SMC_REG(0x0003, 2)
++#define AR_FAILED	0x80	// Alocation Failed
++
++
++// TX FIFO Ports Register
++/* BANK 2 */
++#define TXFIFO_REG	SMC_REG(0x0004, 2)
++#define TXFIFO_TEMPTY	0x80	// TX FIFO Empty
++
++// RX FIFO Ports Register
++/* BANK 2 */
++#define RXFIFO_REG	SMC_REG(0x0005, 2)
++#define RXFIFO_REMPTY	0x80	// RX FIFO Empty
++
++#define FIFO_REG	SMC_REG(0x0004, 2)
++
++// Pointer Register
++/* BANK 2 */
++#define PTR_REG		SMC_REG(0x0006, 2)
++#define PTR_RCV		0x8000 // 1=Receive area, 0=Transmit area
++#define PTR_AUTOINC 	0x4000 // Auto increment the pointer on each access
++#define PTR_READ	0x2000 // When 1 the operation is a read
++
++
++// Data Register
++/* BANK 2 */
++#define DATA_REG	SMC_REG(0x0008, 2)
++
++
++// Interrupt Status/Acknowledge Register
++/* BANK 2 */
++#define INT_REG		SMC_REG(0x000C, 2)
++
++
++// Interrupt Mask Register
++/* BANK 2 */
++#define IM_REG		SMC_REG(0x000D, 2)
++#define IM_MDINT	0x80 // PHY MI Register 18 Interrupt
++#define IM_ERCV_INT	0x40 // Early Receive Interrupt
++#define IM_EPH_INT	0x20 // Set by Ethernet Protocol Handler section
++#define IM_RX_OVRN_INT	0x10 // Set by Receiver Overruns
++#define IM_ALLOC_INT	0x08 // Set when allocation request is completed
++#define IM_TX_EMPTY_INT	0x04 // Set if the TX FIFO goes empty
++#define IM_TX_INT	0x02 // Transmit Interrupt
++#define IM_RCV_INT	0x01 // Receive Interrupt
++
++
++// Multicast Table Registers
++/* BANK 3 */
++#define MCAST_REG1	SMC_REG(0x0000, 3)
++#define MCAST_REG2	SMC_REG(0x0002, 3)
++#define MCAST_REG3	SMC_REG(0x0004, 3)
++#define MCAST_REG4	SMC_REG(0x0006, 3)
++
++
++// Management Interface Register (MII)
++/* BANK 3 */
++#define MII_REG		SMC_REG(0x0008, 3)
++#define MII_MSK_CRS100	0x4000 // Disables CRS100 detection during tx half dup
++#define MII_MDOE	0x0008 // MII Output Enable
++#define MII_MCLK	0x0004 // MII Clock, pin MDCLK
++#define MII_MDI		0x0002 // MII Input, pin MDI
++#define MII_MDO		0x0001 // MII Output, pin MDO
++
++
++// Revision Register
++/* BANK 3 */
++/* ( hi: chip id   low: rev # ) */
++#define REV_REG		SMC_REG(0x000A, 3)
++
++
++// Early RCV Register
++/* BANK 3 */
++/* this is NOT on SMC9192 */
++#define ERCV_REG	SMC_REG(0x000C, 3)
++#define ERCV_RCV_DISCRD	0x0080 // When 1 discards a packet being received
++#define ERCV_THRESHOLD	0x001F // ERCV Threshold Mask
++
++
++// External Register
++/* BANK 7 */
++#define EXT_REG		SMC_REG(0x0000, 7)
++
++
++#define CHIP_9192	3
++#define CHIP_9194	4
++#define CHIP_9195	5
++#define CHIP_9196	6
++#define CHIP_91100	7
++#define CHIP_91100FD	8
++#define CHIP_91111FD	9
++
++static const char * chip_ids[ 16 ] =  {
++	NULL, NULL, NULL,
++	/* 3 */ "SMC91C90/91C92",
++	/* 4 */ "SMC91C94",
++	/* 5 */ "SMC91C95",
++	/* 6 */ "SMC91C96",
++	/* 7 */ "SMC91C100",
++	/* 8 */ "SMC91C100FD",
++	/* 9 */ "SMC91C11xFD",
++	NULL, NULL, NULL,
++	NULL, NULL, NULL};
++
++
++/*
++ . Transmit status bits
++*/
++#define TS_SUCCESS 0x0001
++#define TS_LOSTCAR 0x0400
++#define TS_LATCOL  0x0200
++#define TS_16COL   0x0010
++
++/*
++ . Receive status bits
++*/
++#define RS_ALGNERR	0x8000
++#define RS_BRODCAST	0x4000
++#define RS_BADCRC	0x2000
++#define RS_ODDFRAME	0x1000
++#define RS_TOOLONG	0x0800
++#define RS_TOOSHORT	0x0400
++#define RS_MULTICAST	0x0001
++#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
++
++
++// PHY Types
++enum {
++	PHY_LAN83C183 = 1,	// LAN91C111 Internal PHY
++	PHY_LAN83C180
++};
++
++
++// PHY Register Addresses (LAN91C111 Internal PHY)
++
++// PHY Control Register
++#define PHY_CNTL_REG		0x00
++#define PHY_CNTL_RST		0x8000	// 1=PHY Reset
++#define PHY_CNTL_LPBK		0x4000	// 1=PHY Loopback
++#define PHY_CNTL_SPEED		0x2000	// 1=100Mbps, 0=10Mpbs
++#define PHY_CNTL_ANEG_EN	0x1000	// 1=Enable Auto negotiation
++#define PHY_CNTL_PDN		0x0800	// 1=PHY Power Down mode
++#define PHY_CNTL_MII_DIS	0x0400	// 1=MII 4 bit interface disabled
++#define PHY_CNTL_ANEG_RST	0x0200	// 1=Reset Auto negotiate
++#define PHY_CNTL_DPLX		0x0100	// 1=Full Duplex, 0=Half Duplex
++#define PHY_CNTL_COLTST		0x0080	// 1= MII Colision Test
++
++// PHY Status Register
++#define PHY_STAT_REG		0x01
++#define PHY_STAT_CAP_T4		0x8000	// 1=100Base-T4 capable
++#define PHY_STAT_CAP_TXF	0x4000	// 1=100Base-X full duplex capable
++#define PHY_STAT_CAP_TXH	0x2000	// 1=100Base-X half duplex capable
++#define PHY_STAT_CAP_TF		0x1000	// 1=10Mbps full duplex capable
++#define PHY_STAT_CAP_TH		0x0800	// 1=10Mbps half duplex capable
++#define PHY_STAT_CAP_SUPR	0x0040	// 1=recv mgmt frames with not preamble
++#define PHY_STAT_ANEG_ACK	0x0020	// 1=ANEG has completed
++#define PHY_STAT_REM_FLT	0x0010	// 1=Remote Fault detected
++#define PHY_STAT_CAP_ANEG	0x0008	// 1=Auto negotiate capable
++#define PHY_STAT_LINK		0x0004	// 1=valid link
++#define PHY_STAT_JAB		0x0002	// 1=10Mbps jabber condition
++#define PHY_STAT_EXREG		0x0001	// 1=extended registers implemented
++
++// PHY Identifier Registers
++#define PHY_ID1_REG		0x02	// PHY Identifier 1
++#define PHY_ID2_REG		0x03	// PHY Identifier 2
++
++// PHY Auto-Negotiation Advertisement Register
++#define PHY_AD_REG		0x04
++#define PHY_AD_NP		0x8000	// 1=PHY requests exchange of Next Page
++#define PHY_AD_ACK		0x4000	// 1=got link code word from remote
++#define PHY_AD_RF		0x2000	// 1=advertise remote fault
++#define PHY_AD_T4		0x0200	// 1=PHY is capable of 100Base-T4
++#define PHY_AD_TX_FDX		0x0100	// 1=PHY is capable of 100Base-TX FDPLX
++#define PHY_AD_TX_HDX		0x0080	// 1=PHY is capable of 100Base-TX HDPLX
++#define PHY_AD_10_FDX		0x0040	// 1=PHY is capable of 10Base-T FDPLX
++#define PHY_AD_10_HDX		0x0020	// 1=PHY is capable of 10Base-T HDPLX
++#define PHY_AD_CSMA		0x0001	// 1=PHY is capable of 802.3 CMSA
++
++// PHY Auto-negotiation Remote End Capability Register
++#define PHY_RMT_REG		0x05
++// Uses same bit definitions as PHY_AD_REG
++
++// PHY Configuration Register 1
++#define PHY_CFG1_REG		0x10
++#define PHY_CFG1_LNKDIS		0x8000	// 1=Rx Link Detect Function disabled
++#define PHY_CFG1_XMTDIS		0x4000	// 1=TP Transmitter Disabled
++#define PHY_CFG1_XMTPDN		0x2000	// 1=TP Transmitter Powered Down
++#define PHY_CFG1_BYPSCR		0x0400	// 1=Bypass scrambler/descrambler
++#define PHY_CFG1_UNSCDS		0x0200	// 1=Unscramble Idle Reception Disable
++#define PHY_CFG1_EQLZR		0x0100	// 1=Rx Equalizer Disabled
++#define PHY_CFG1_CABLE		0x0080	// 1=STP(150ohm), 0=UTP(100ohm)
++#define PHY_CFG1_RLVL0		0x0040	// 1=Rx Squelch level reduced by 4.5db
++#define PHY_CFG1_TLVL_SHIFT	2	// Transmit Output Level Adjust
++#define PHY_CFG1_TLVL_MASK	0x003C
++#define PHY_CFG1_TRF_MASK	0x0003	// Transmitter Rise/Fall time
++
++
++// PHY Configuration Register 2
++#define PHY_CFG2_REG		0x11
++#define PHY_CFG2_APOLDIS	0x0020	// 1=Auto Polarity Correction disabled
++#define PHY_CFG2_JABDIS		0x0010	// 1=Jabber disabled
++#define PHY_CFG2_MREG		0x0008	// 1=Multiple register access (MII mgt)
++#define PHY_CFG2_INTMDIO	0x0004	// 1=Interrupt signaled with MDIO pulseo
++
++// PHY Status Output (and Interrupt status) Register
++#define PHY_INT_REG		0x12	// Status Output (Interrupt Status)
++#define PHY_INT_INT		0x8000	// 1=bits have changed since last read
++#define PHY_INT_LNKFAIL		0x4000	// 1=Link Not detected
++#define PHY_INT_LOSSSYNC	0x2000	// 1=Descrambler has lost sync
++#define PHY_INT_CWRD		0x1000	// 1=Invalid 4B5B code detected on rx
++#define PHY_INT_SSD		0x0800	// 1=No Start Of Stream detected on rx
++#define PHY_INT_ESD		0x0400	// 1=No End Of Stream detected on rx
++#define PHY_INT_RPOL		0x0200	// 1=Reverse Polarity detected
++#define PHY_INT_JAB		0x0100	// 1=Jabber detected
++#define PHY_INT_SPDDET		0x0080	// 1=100Base-TX mode, 0=10Base-T mode
++#define PHY_INT_DPLXDET		0x0040	// 1=Device in Full Duplex
++
++// PHY Interrupt/Status Mask Register
++#define PHY_MASK_REG		0x13	// Interrupt Mask
++// Uses the same bit definitions as PHY_INT_REG
++
++
++/*
++ * SMC91C96 ethernet config and status registers.
++ * These are in the "attribute" space.
++ */
++#define ECOR			0x8000
++#define ECOR_RESET		0x80
++#define ECOR_LEVEL_IRQ		0x40
++#define ECOR_WR_ATTRIB		0x04
++#define ECOR_ENABLE		0x01
++
++#define ECSR			0x8002
++#define ECSR_IOIS8		0x20
++#define ECSR_PWRDWN		0x04
++#define ECSR_INT		0x02
++
++
++/*
++ * Macros to abstract register access according to the data bus
++ * capabilities.  Please try to use those and not the in/out primitives.
++ * Note: the following macros do *not* select the bank -- this must
++ * be done separately as needed in the main code.  The SMC_REG() macro
++ * only uses the bank argument for debugging purposes.
++ */
++
++#if SMC_DEBUG > 0
++#define SMC_REG(reg, bank)						\
++	({								\
++		int __b = SMC_CURRENT_BANK();				\
++		if ((__b & ~0xf0) != (0x3300 | bank)) {			\
++			printk( "%s: bank reg screwed (0x%04x)\n",	\
++				CARDNAME, __b );			\
++			BUG();						\
++		}							\
++		reg<<SMC_IO_SHIFT;					\
++	})
++#else
++#define SMC_REG(reg, bank)	(reg<<SMC_IO_SHIFT)
++#endif
++
++#if SMC_CAN_USE_8BIT
++#define SMC_GET_PN()		SMC_inb( ioaddr, PN_REG )
++#define SMC_SET_PN(x)		SMC_outb( x, ioaddr, PN_REG )
++#define SMC_GET_AR()		SMC_inb( ioaddr, AR_REG )
++#define SMC_GET_TXFIFO()	SMC_inb( ioaddr, TXFIFO_REG )
++#define SMC_GET_RXFIFO()	SMC_inb( ioaddr, RXFIFO_REG )
++#define SMC_GET_INT()		SMC_inb( ioaddr, INT_REG )
++#define SMC_ACK_INT(x)		SMC_outb( x, ioaddr, INT_REG )
++#define SMC_GET_INT_MASK()	SMC_inb( ioaddr, IM_REG )
++#define SMC_SET_INT_MASK(x)	SMC_outb( x, ioaddr, IM_REG )
++#else
++#define SMC_GET_PN()		(SMC_inw( ioaddr, PN_REG ) & 0xFF)
++#define SMC_SET_PN(x)		SMC_outw( x, ioaddr, PN_REG )
++#define SMC_GET_AR()		(SMC_inw( ioaddr, PN_REG ) >> 8)
++#define SMC_GET_TXFIFO()	(SMC_inw( ioaddr, TXFIFO_REG ) & 0xFF)
++#define SMC_GET_RXFIFO()	(SMC_inw( ioaddr, TXFIFO_REG ) >> 8)
++#define SMC_GET_INT()		(SMC_inw( ioaddr, INT_REG ) & 0xFF)
++#define SMC_ACK_INT(x)							\
++	do {								\
++		unsigned long __flags;					\
++		int __mask;						\
++		local_irq_save(__flags);				\
++		__mask = SMC_inw( ioaddr, INT_REG ) & ~0xff;		\
++		SMC_outw( __mask | (x), ioaddr, INT_REG );		\
++		local_irq_restore(__flags);				\
++	} while (0)
++#define SMC_GET_INT_MASK()	(SMC_inw( ioaddr, INT_REG ) >> 8)
++#define SMC_SET_INT_MASK(x)	SMC_outw( (x) << 8, ioaddr, INT_REG )
++#endif
++
++#define SMC_CURRENT_BANK()	SMC_inw( ioaddr, BANK_SELECT )
++#define SMC_SELECT_BANK(x)	SMC_outw( x, ioaddr, BANK_SELECT )
++#define SMC_GET_BASE()		SMC_inw( ioaddr, BASE_REG )
++#define SMC_SET_BASE(x)		SMC_outw( x, ioaddr, BASE_REG )
++#define SMC_GET_CONFIG()	SMC_inw( ioaddr, CONFIG_REG )
++#define SMC_SET_CONFIG(x)	SMC_outw( x, ioaddr, CONFIG_REG )
++#define SMC_GET_COUNTER()	SMC_inw( ioaddr, COUNTER_REG )
++#define SMC_GET_CTL()		SMC_inw( ioaddr, CTL_REG )
++#define SMC_SET_CTL(x)		SMC_outw( x, ioaddr, CTL_REG )
++#define SMC_GET_MII()		SMC_inw( ioaddr, MII_REG )
++#define SMC_SET_MII(x)		SMC_outw( x, ioaddr, MII_REG )
++#define SMC_GET_MIR()		SMC_inw( ioaddr, MIR_REG )
++#define SMC_SET_MIR(x)		SMC_outw( x, ioaddr, MIR_REG )
++#define SMC_GET_MMU_CMD()	SMC_inw( ioaddr, MMU_CMD_REG )
++#define SMC_SET_MMU_CMD(x)	SMC_outw( x, ioaddr, MMU_CMD_REG )
++#define SMC_GET_FIFO()		SMC_inw( ioaddr, FIFO_REG )
++#define SMC_GET_PTR()		SMC_inw( ioaddr, PTR_REG )
++#define SMC_SET_PTR(x)		SMC_outw( x, ioaddr, PTR_REG )
++#define SMC_GET_RCR()		SMC_inw( ioaddr, RCR_REG )
++#define SMC_SET_RCR(x)		SMC_outw( x, ioaddr, RCR_REG )
++#define SMC_GET_REV()		SMC_inw( ioaddr, REV_REG )
++#define SMC_GET_RPC()		SMC_inw( ioaddr, RPC_REG )
++#define SMC_SET_RPC(x)		SMC_outw( x, ioaddr, RPC_REG )
++#define SMC_GET_TCR()		SMC_inw( ioaddr, TCR_REG )
++#define SMC_SET_TCR(x)		SMC_outw( x, ioaddr, TCR_REG )
++
++#ifndef SMC_GET_MAC_ADDR
++#define SMC_GET_MAC_ADDR(addr)						\
++	do {								\
++		unsigned int __v;					\
++		__v = SMC_inw( ioaddr, ADDR0_REG );			\
++		addr[0] = __v; addr[1] = __v >> 8;			\
++		__v = SMC_inw( ioaddr, ADDR1_REG );			\
++		addr[2] = __v; addr[3] = __v >> 8;			\
++		__v = SMC_inw( ioaddr, ADDR2_REG );			\
++		addr[4] = __v; addr[5] = __v >> 8;			\
++	} while (0)
++#endif
++
++#define SMC_SET_MAC_ADDR(addr)						\
++	do {								\
++		SMC_outw( addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG );	\
++		SMC_outw( addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG );	\
++		SMC_outw( addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG );	\
++	} while (0)
++
++#define SMC_CLEAR_MCAST()						\
++	do {								\
++		SMC_outw( 0, ioaddr, MCAST_REG1 );			\
++		SMC_outw( 0, ioaddr, MCAST_REG2 );			\
++		SMC_outw( 0, ioaddr, MCAST_REG3 );			\
++		SMC_outw( 0, ioaddr, MCAST_REG4 );			\
++	} while (0)
++#define SMC_SET_MCAST(x)						\
++	do {								\
++		unsigned char *mt = (x);				\
++		SMC_outw( mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1 );	\
++		SMC_outw( mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2 );	\
++		SMC_outw( mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3 );	\
++		SMC_outw( mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4 );	\
++	} while (0)
++
++#if SMC_CAN_USE_32BIT
++/*
++ * Some setups just can't write 8 or 16 bits reliably when not aligned
++ * to a 32 bit boundary.  I tell you that exists!
++ * We do the ones that can have their low parts written to 0 here.
++ */
++#undef SMC_SELECT_BANK
++#define SMC_SELECT_BANK(x)	SMC_outl( (x)<<16, ioaddr, 12<<SMC_IO_SHIFT )
++#undef SMC_SET_RPC
++#define SMC_SET_RPC(x)		SMC_outl( (x)<<16, ioaddr, SMC_REG(8, 0) )
++#undef SMC_SET_PN
++#define SMC_SET_PN(x)		SMC_outl( (x)<<16, ioaddr, SMC_REG(0, 2) )
++#undef SMC_SET_PTR
++#define SMC_SET_PTR(x)		SMC_outl( (x)<<16, ioaddr, SMC_REG(4, 2) )
++#endif
++
++#if SMC_CAN_USE_32BIT
++#define SMC_PUT_PKT_HDR(status, length)					\
++	SMC_outl( (status) | (length) << 16, ioaddr, DATA_REG )
++#define SMC_GET_PKT_HDR(status, length)					\
++	do {								\
++		unsigned int __val = SMC_inl( ioaddr, DATA_REG );	\
++		(status) = __val & 0xffff;				\
++		(length) = __val >> 16;					\
++	} while (0)
++#else
++#define SMC_PUT_PKT_HDR(status, length)					\
++	do {								\
++		SMC_outw( status, ioaddr, DATA_REG );			\
++		SMC_outw( length, ioaddr, DATA_REG );			\
++	} while (0)
++#define SMC_GET_PKT_HDR(status, length)					\
++	do {								\
++		(status) = SMC_inw( ioaddr, DATA_REG );			\
++		(length) = SMC_inw( ioaddr, DATA_REG );			\
++	} while (0)
++#endif
++
++#if SMC_CAN_USE_32BIT
++#define SMC_PUSH_DATA(p, l)						\
++	do {								\
++		char *__ptr = (p);					\
++		int __len = (l);					\
++		if (__len >= 2 && (long)__ptr & 2) {			\
++			__len -= 2;					\
++			SMC_outw( *((u16 *)__ptr)++, ioaddr, DATA_REG );\
++		}							\
++		SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2);	\
++		if (__len & 2) {					\
++			__ptr += (__len & ~3);				\
++			SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG );	\
++		}							\
++	} while (0)
++#define SMC_PULL_DATA(p, l)						\
++	do {								\
++		char *__ptr = (p);					\
++		int __len = (l);					\
++		if ((long)__ptr & 2) {					\
++			/*						\
++			 * We want 32bit alignment here.		\
++			 * Since some buses perform a full 32bit	\
++			 * fetch even for 16bit data we can't use	\
++			 * SMC_inw() here.  Back both source (on chip	\
++			 * and destination) pointers of 2 bytes.	\
++			 */						\
++			(long)__ptr &= ~2;				\
++			__len += 2;					\
++			SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC );	\
++		}							\
++		__len += 2;						\
++		SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2);		\
++	} while (0)
++#elif SMC_CAN_USE_16BIT
++#define SMC_PUSH_DATA(p, l)	SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 )
++#define SMC_PULL_DATA(p, l)	SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 )
++#elif SMC_CAN_USE_8BIT
++#define SMC_PUSH_DATA(p, l)	SMC_outsb( ioaddr, DATA_REG, p, l )
++#define SMC_PULL_DATA(p, l)	SMC_insb ( ioaddr, DATA_REG, p, l )
++#endif
++
++#if ! SMC_CAN_USE_16BIT
++#define SMC_outw(x, ioaddr, reg)					\
++	do {								\
++		unsigned int __val16 = (x);				\
++		SMC_outb( __val16, ioaddr, reg );			\
++		SMC_outb( __val16 >> 8, ioaddr, reg + 1 );		\
++	} while (0)
++#define SMC_inw(ioaddr, reg)						\
++	({								\
++		unsigned int __val16;					\
++		__val16 =  SMC_inb( ioaddr, reg );			\
++		__val16 |= SMC_inb( ioaddr, reg + 1 ) << 8;		\
++		__val16;						\
++	})
++#endif
++
++
++#endif  /* _SMC91X_H_ */
+--- linux-2.4.25/drivers/pcmcia/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/Config.in	2004-03-31 17:15:12.000000000 +0200
+@@ -45,6 +45,7 @@
+ if [ "$CONFIG_ARM" = "y" ]; then
+    dep_tristate '  CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA
+    dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
++   dep_tristate '  PXA250/210 support' CONFIG_PCMCIA_PXA $CONFIG_ARCH_PXA $CONFIG_PCMCIA
+ fi
+ 
+ endmenu
+--- linux-2.4.25/drivers/pcmcia/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/Makefile	2004-03-31 17:15:12.000000000 +0200
+@@ -94,6 +94,11 @@
+ 
+ obj-$(CONFIG_PCMCIA_VRC4173)	+= vrc4173_cardu.o
+ 
++subdir-$(CONFIG_PCMCIA_PXA)			+= pxa
++ifeq ($(CONFIG_PCMCIA_PXA),y)
++  obj-y 					+= pxa/pxa_cs.o
++endif
++
+ include $(TOPDIR)/Rules.make
+ 
+ pcmcia_core.o:  $(pcmcia_core-objs)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/pxa/Makefile	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,18 @@
++#
++# Makefile for the Intel PXA250/210 PCMCIA driver
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++
++O_TARGET			:= pxa_cs.o
++
++obj-y				:= pxa.o
++obj-$(CONFIG_ARCH_LUBBOCK)	+= lubbock.o
++obj-$(CONFIG_ARCH_PXA_IDP)	+= pxa_idp.o
++obj-$(CONFIG_ARCH_TRIZEPS2)	+= trizeps2.o
++obj-$(CONFIG_ARCH_PXA_CERF)	+= ../sa1100_cerf.o
++
++obj-m				:= $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/pxa/lubbock.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,329 @@
++/*
++ * linux/drivers/pcmcia/pxa/lubbock.c
++ *
++ * Author:	George Davis
++ * Created:	Jan 10, 2002
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Originally based upon linux/drivers/pcmcia/sa1100_neponset.c
++ *
++ * Lubbock PCMCIA specific routines.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++#include <pcmcia/ss.h>
++
++#include <asm/delay.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++#include <asm/hardware/sa1111.h>
++
++/*
++ * I'd really like to move the INTPOL stuff to arch/arm/mach-sa1100/sa1111.c
++ * ... and maybe even arch/arm/mach-pxa/sa1111.c now too!  : )
++ */
++#define SA1111_IRQMASK_LO(x)	(1 << (x - IRQ_SA1111_START))
++#define SA1111_IRQMASK_HI(x)	(1 << (x - IRQ_SA1111_START - 32))
++
++static int lubbock_pcmcia_init(struct pcmcia_init *init){
++  int return_val=0;
++
++  /* Set PCMCIA Socket 0 power to standby mode.
++   */
++  PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++
++  /* Set GPIO_A<3:0> to be outputs for PCMCIA (socket 0) power controller.
++   * Note that this is done only after first initializing GPIO_A<3:0>
++   * output state above to be certain that we drive signals to the same
++   * state as the pull-downs connected to these lines. The pull-downs are
++   * req'd to make sure PCMCIA power is OFF until we can get around to
++   * setting up the GPIO_A<3:0> state and direction.
++   */
++  PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++
++  /* Set CF Socket 1 power to standby mode. */
++  LUB_MISC_WR &= ~(GPIO_bit(15) | GPIO_bit(14));
++
++  INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) |
++	     SA1111_IRQMASK_HI(S1_READY_NINT) |
++	     SA1111_IRQMASK_HI(S0_CD_VALID) |
++	     SA1111_IRQMASK_HI(S1_CD_VALID) |
++	     SA1111_IRQMASK_HI(S0_BVD1_STSCHG) |
++	     SA1111_IRQMASK_HI(S1_BVD1_STSCHG);
++
++#warning what if a request_irq fails?
++  return_val+=request_irq(S0_CD_VALID, init->handler, SA_INTERRUPT,
++			  "Lubbock PCMCIA (0) CD", NULL);
++  return_val+=request_irq(S1_CD_VALID, init->handler, SA_INTERRUPT,
++			  "Lubbock CF (1) CD", NULL);
++  return_val+=request_irq(S0_BVD1_STSCHG, init->handler, SA_INTERRUPT,
++			  "Lubbock PCMCIA (0) BVD1", NULL);
++  return_val+=request_irq(S1_BVD1_STSCHG, init->handler, SA_INTERRUPT,
++			  "Lubbock CF (1) BVD1", NULL);
++
++  return (return_val<0) ? -1 : 2;
++}
++
++static int lubbock_pcmcia_shutdown(void){
++
++  free_irq(S0_CD_VALID, NULL);
++  free_irq(S1_CD_VALID, NULL);
++  free_irq(S0_BVD1_STSCHG, NULL);
++  free_irq(S1_BVD1_STSCHG, NULL);
++
++  INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) |
++	       SA1111_IRQMASK_HI(S1_CD_VALID) |
++	       SA1111_IRQMASK_HI(S0_BVD1_STSCHG) |
++	       SA1111_IRQMASK_HI(S1_BVD1_STSCHG));
++
++  return 0;
++}
++
++static int lubbock_pcmcia_socket_state(struct pcmcia_state_array
++					*state_array){
++  unsigned long status;
++  int return_val=1;
++
++  if(state_array->size<2) return -1;
++
++  memset(state_array->state, 0, 
++	 (state_array->size)*sizeof(struct pcmcia_state));
++
++  status=PCSR;
++
++  state_array->state[0].detect=((status & PCSR_S0_DETECT)==0)?1:0;
++
++  state_array->state[0].ready=((status & PCSR_S0_READY)==0)?0:1;
++
++  state_array->state[0].bvd1=((status & PCSR_S0_BVD1)==0)?0:1;
++
++  state_array->state[0].bvd2=((status & PCSR_S0_BVD2)==0)?0:1;
++
++  state_array->state[0].wrprot=((status & PCSR_S0_WP)==0)?0:1;
++
++  state_array->state[0].vs_3v=((status & PCSR_S0_VS1)==0)?1:0;
++
++  state_array->state[0].vs_Xv=((status & PCSR_S0_VS2)==0)?1:0;
++
++  state_array->state[1].detect=((status & PCSR_S1_DETECT)==0)?1:0;
++
++  state_array->state[1].ready=((status & PCSR_S1_READY)==0)?0:1;
++
++  state_array->state[1].bvd1=((status & PCSR_S1_BVD1)==0)?0:1;
++
++  state_array->state[1].bvd2=((status & PCSR_S1_BVD2)==0)?0:1;
++
++  state_array->state[1].wrprot=((status & PCSR_S1_WP)==0)?0:1;
++
++  state_array->state[1].vs_3v=((status & PCSR_S1_VS1)==0)?1:0;
++
++  state_array->state[1].vs_Xv=((status & PCSR_S1_VS2)==0)?1:0;
++
++  return return_val;
++}
++
++static int lubbock_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
++
++  switch(info->sock){
++  case 0:
++    info->irq=S0_READY_NINT;
++    break;
++
++  case 1:
++    info->irq=S1_READY_NINT;
++    break;
++
++  default:
++    return -1;
++  }
++
++  return 0;
++}
++
++static int
++lubbock_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
++{
++  unsigned long flags, pccr, gpio, misc_wr, status;
++  int ret=1;
++
++  local_irq_save(flags);
++
++  pccr=PCCR;
++  gpio=PA_DWR;
++  misc_wr = LUB_MISC_WR;
++
++  /* Lubbock uses the Maxim MAX1602, with the following connections:
++   *
++   * Socket 0 (PCMCIA):
++   *	MAX1602	Lubbock		Register
++   *	Pin	Signal
++   *	-----	-------		----------------------
++   *	A0VPP	S0_PWR0		SA-1111 GPIO A<0>
++   *	A1VPP	S0_PWR1		SA-1111 GPIO A<1>
++   *	A0VCC	S0_PWR2		SA-1111 GPIO A<2>
++   *	A1VCC	S0_PWR3		SA-1111 GPIO A<3>
++   *	VX	VCC
++   *	VY	+3.3V
++   *	12IN	+12V
++   *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
++   *
++   * Socket 1 (CF):
++   *	MAX1602	Lubbock		Register
++   *	Pin	Signal
++   *	-----	-------		----------------------
++   *	A0VPP	GND		VPP is not connected
++   *	A1VPP	GND		VPP is not connected
++   *	A0VCC	S1_PWR0		MISC_WR<14>
++   *	A1VCC	S1_PWR0		MISC_WR<15>
++   *	VX	VCC
++   *	VY	+3.3V
++   *	12IN	GND		VPP is not connected
++   *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
++   *
++   */
++
++again:
++  switch(sock){
++  case 0:
++
++    switch(state->Vcc){
++    case 0:
++      pccr = (pccr & ~PCCR_S0_FLT);
++      gpio &= ~(GPIO_bit(2) | GPIO_bit(3));
++      break;
++
++    case 33:
++      pccr = (pccr & ~PCCR_S0_PSE) | PCCR_S0_FLT | PCCR_S0_PWAITEN;
++      gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(3);
++      break;
++
++    case 50:
++      pccr = (pccr | PCCR_S0_PSE | PCCR_S0_FLT | PCCR_S0_PWAITEN);
++      gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
++      break;
++
++    default:
++      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
++      ret = -1;
++      break;
++    }
++
++    switch(state->Vpp){
++    case 0:
++      gpio &= ~(GPIO_bit(0) | GPIO_bit(1));
++      break;
++
++    case 120:
++      gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(1);
++      break;
++
++    default:
++      /* REVISIT: I'm not sure about this? Is this correct?
++         Is it always safe or do we have potential problems
++         with bogus combinations of Vcc and Vpp settings? */
++      if(state->Vpp == state->Vcc)
++        gpio = (gpio & ~(GPIO_bit(0) | GPIO_bit(1))) | GPIO_bit(0);
++      else {
++	printk(KERN_ERR "%s(): unrecognized Vpp %u\n", __FUNCTION__, state->Vpp);
++	ret = -1;
++	break;
++      }
++    }
++
++    pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S0_RST) : (pccr&~PCCR_S0_RST);
++
++    break;
++
++  case 1:
++    switch(state->Vcc){
++    case 0:
++      pccr = (pccr & ~PCCR_S1_FLT);
++      misc_wr &= ~((1 << 15) | (1 << 14));
++      break;
++
++    case 33:
++      pccr = (pccr & ~PCCR_S1_PSE) | PCCR_S1_FLT | PCCR_S1_PWAITEN;
++      misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
++      gpio = (gpio & ~(GPIO_bit(2) | GPIO_bit(3))) | GPIO_bit(2);
++      break;
++
++    case 50:
++      pccr = (pccr | PCCR_S1_PSE | PCCR_S1_FLT | PCCR_S1_PWAITEN);
++      misc_wr = (misc_wr & ~(1 << 15)) | (1 << 14);
++      break;
++
++    default:
++      printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__, state->Vcc);
++      ret = -1;
++      break;
++    }
++
++    if(state->Vpp!=state->Vcc && state->Vpp!=0){
++      printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n", __FUNCTION__, state->Vpp);
++      ret = -1;
++      break;
++    }
++
++    pccr = (state->flags&SS_RESET) ? (pccr|PCCR_S1_RST) : (pccr&~PCCR_S1_RST);
++
++    break;
++
++  default:
++    ret = -1;
++  }
++
++  if (ret >= 0) {
++    PCCR = pccr;
++    LUB_MISC_WR = misc_wr;
++    PA_DWR = gpio;
++  }
++
++  if (ret > 0) {
++    ret = 0;
++    /* 
++     * HACK ALERT: 
++     * We can't sense the voltage properly on Lubbock before actually
++     * applying some power to the socket (catch 22).
++     * Resense the socket Voltage Sense pins after applying socket power.
++     */
++    if (sock == 0)
++      status = PCSR & (PCSR_S0_VS1 | PCSR_S0_VS2);
++    else
++      status = PCSR & (PCSR_S1_VS1 | PCSR_S1_VS2);
++
++    if ((status == (PCSR_S0_VS1 | PCSR_S0_VS2)) && (state->Vcc == 33)) {
++      /* Switch to 5V,  Configure socket 0  with 5V voltage */
++      PA_DWR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++      PA_DDR &= ~(GPIO_bit(0) | GPIO_bit(1) | GPIO_bit(2) | GPIO_bit(3));
++      state->Vcc = 50;
++      state->Vpp = 50;
++      goto again;
++    }
++    if ((status == (PCSR_S1_VS1 | PCSR_S1_VS2)) && (state->Vcc == 33)) {
++      /* Switch to 5V, Configure socket 1 with 5V voltage */
++      LUB_MISC_WR &= ~((1 << 15) | (1 << 14));
++      state->Vcc = 50;
++      state->Vpp = 50;
++      goto again;
++    }
++  }
++
++  local_irq_restore(flags);
++  return ret;
++}
++
++struct pcmcia_low_level lubbock_pcmcia_ops = { 
++  lubbock_pcmcia_init,
++  lubbock_pcmcia_shutdown,
++  lubbock_pcmcia_socket_state,
++  lubbock_pcmcia_get_irq_info,
++  lubbock_pcmcia_configure_socket
++};
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/pxa/pxa.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,1247 @@
++/*
++ * linux/drivers/pcmcia/pxa/pxa.c
++ *
++ * Author:	George Davis
++ * Created:	Jan 10, 2002
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.c
++ *
++ */
++
++/*======================================================================
++
++    Device driver for the PCMCIA control functionality of Intel
++    PXA250/210 microprocessors.
++
++    The contents of this file are subject to the Mozilla Public
++    License Version 1.1 (the "License"); you may not use this file
++    except in compliance with the License. You may obtain a copy of
++    the License at http://www.mozilla.org/MPL/
++
++    Software distributed under the License is distributed on an "AS
++    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++    implied. See the License for the specific language governing
++    rights and limitations under the License.
++
++    The initial developer of the original code is John G. Dorsey
++    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
++    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
++
++    Alternatively, the contents of this file may be used under the
++    terms of the GNU Public License version 2 (the "GPL"), in which
++    case the provisions of the GPL are applicable instead of the
++    above.  If you wish to allow the use of your version of this file
++    only under the terms of the GPL and not to allow others to use
++    your version of this file under the MPL, indicate your decision
++    by deleting the provisions above and replace them with the notice
++    and other provisions required by the GPL.  If you do not delete
++    the provisions above, a recipient may use your version of this
++    file under either the MPL or the GPL.
++    
++======================================================================*/
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/config.h>
++#include <linux/cpufreq.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/kernel.h>
++#include <linux/tqueue.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/notifier.h>
++#include <linux/proc_fs.h>
++#include <linux/version.h>
++#include <linux/cpufreq.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/ss.h>
++#include <pcmcia/bus_ops.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/arch/lubbock.h>
++
++#include "pxa.h"
++
++#ifdef PCMCIA_DEBUG
++static int pc_debug;
++#endif
++
++MODULE_AUTHOR("George Davis <davis_g@mvista.com>");
++MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA250/210 Socket Controller");
++
++/* This structure maintains housekeeping state for each socket, such
++ * as the last known values of the card detect pins, or the Card Services
++ * callback value associated with the socket:
++ */
++static struct pxa_pcmcia_socket 
++pxa_pcmcia_socket[PXA_PCMCIA_MAX_SOCK];
++
++static int pxa_pcmcia_socket_count;
++
++
++/* Returned by the low-level PCMCIA interface: */
++static struct pcmcia_low_level *pcmcia_low_level;
++
++/* Event poll timer structure */
++static struct timer_list poll_timer;
++
++
++/* Prototypes for routines which are used internally: */
++
++static int  pxa_pcmcia_driver_init(void);
++static void pxa_pcmcia_driver_shutdown(void);
++static void pxa_pcmcia_task_handler(void *data);
++static void pxa_pcmcia_poll_event(unsigned long data);
++static void pxa_pcmcia_interrupt(int irq, void *dev,
++				    struct pt_regs *regs);
++static struct tq_struct pxa_pcmcia_task;
++
++#ifdef CONFIG_PROC_FS
++static int  pxa_pcmcia_proc_status(char *buf, char **start, off_t pos,
++				      int count, int *eof, void *data);
++#endif
++
++
++/* Prototypes for operations which are exported to the
++ * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core:
++ */
++
++static int pxa_pcmcia_init(unsigned int sock);
++static int pxa_pcmcia_suspend(unsigned int sock);
++static int pxa_pcmcia_register_callback(unsigned int sock,
++					   void (*handler)(void *, 
++							   unsigned int),
++					   void *info);
++static int pxa_pcmcia_inquire_socket(unsigned int sock, 
++					socket_cap_t *cap);
++static int pxa_pcmcia_get_status(unsigned int sock, u_int *value);
++static int pxa_pcmcia_get_socket(unsigned int sock, 
++				    socket_state_t *state);
++static int pxa_pcmcia_set_socket(unsigned int sock,
++				    socket_state_t *state);
++static int pxa_pcmcia_get_io_map(unsigned int sock,
++				    struct pccard_io_map *io);
++static int pxa_pcmcia_set_io_map(unsigned int sock,
++				    struct pccard_io_map *io);
++static int pxa_pcmcia_get_mem_map(unsigned int sock,
++				     struct pccard_mem_map *mem);
++static int pxa_pcmcia_set_mem_map(unsigned int sock,
++				     struct pccard_mem_map *mem);
++#ifdef CONFIG_PROC_FS
++static void pxa_pcmcia_proc_setup(unsigned int sock,
++				     struct proc_dir_entry *base);
++#endif
++
++static struct pccard_operations pxa_pcmcia_operations = {
++  pxa_pcmcia_init,
++  pxa_pcmcia_suspend,
++  pxa_pcmcia_register_callback,
++  pxa_pcmcia_inquire_socket,
++  pxa_pcmcia_get_status,
++  pxa_pcmcia_get_socket,
++  pxa_pcmcia_set_socket,
++  pxa_pcmcia_get_io_map,
++  pxa_pcmcia_set_io_map,
++  pxa_pcmcia_get_mem_map,
++  pxa_pcmcia_set_mem_map,
++#ifdef CONFIG_PROC_FS
++  pxa_pcmcia_proc_setup
++#endif
++};
++
++#ifdef CONFIG_CPU_FREQ
++/* forward declaration */
++static struct notifier_block pxa_pcmcia_notifier_block;
++#endif
++
++
++/* pxa_pcmcia_driver_init()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ *
++ * This routine performs a basic sanity check to ensure that this
++ * kernel has been built with the appropriate board-specific low-level
++ * PCMCIA support, performs low-level PCMCIA initialization, registers
++ * this socket driver with Card Services, and then spawns the daemon
++ * thread which is the real workhorse of the socket driver.
++ *
++ * Please see linux/Documentation/arm/SA1100/PCMCIA for more information
++ * on the low-level kernel interface.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int __init pxa_pcmcia_driver_init(void){
++  servinfo_t info;
++  struct pcmcia_init pcmcia_init;
++  struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
++  struct pcmcia_state_array state_array;
++  unsigned int i, clock;
++  unsigned long mecr;
++
++  printk(KERN_INFO "Intel PXA250/210 PCMCIA (CS release %s)\n", CS_RELEASE);
++
++  CardServices(GetCardServicesInfo, &info);
++
++  if(info.Revision!=CS_RELEASE_CODE){
++    printk(KERN_ERR "Card Services release codes do not match\n");
++    return -1;
++  }
++
++  /* Setup GPIOs for PCMCIA/CF alternate function mode.
++   *
++   * It would be nice if set_GPIO_mode included support
++   * for driving GPIO outputs to default high/low state
++   * before programming GPIOs as outputs. Setting GPIO
++   * outputs to default high/low state via GPSR/GPCR
++   * before defining them as outputs should reduce
++   * the possibility of glitching outputs during GPIO
++   * setup. This of course assumes external terminators
++   * are present to hold GPIOs in a defined state.
++   *
++   * In the meantime, setup default state of GPIO
++   * outputs before we enable them as outputs.
++   */
++
++  GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) |
++                      GPIO_bit(GPIO49_nPWE) |
++                      GPIO_bit(GPIO50_nPIOR) |
++                      GPIO_bit(GPIO51_nPIOW) |
++                      GPIO_bit(GPIO52_nPCE_1) |
++                      GPIO_bit(GPIO53_nPCE_2);
++
++  set_GPIO_mode(GPIO48_nPOE_MD);
++  set_GPIO_mode(GPIO49_nPWE_MD);
++  set_GPIO_mode(GPIO50_nPIOR_MD);
++  set_GPIO_mode(GPIO51_nPIOW_MD);
++  set_GPIO_mode(GPIO52_nPCE_1_MD);
++  set_GPIO_mode(GPIO53_nPCE_2_MD);
++  set_GPIO_mode(GPIO54_pSKTSEL_MD); /* REVISIT: s/b dependent on num sockets */
++  set_GPIO_mode(GPIO55_nPREG_MD);
++  set_GPIO_mode(GPIO56_nPWAIT_MD);
++  set_GPIO_mode(GPIO57_nIOIS16_MD);
++
++
++  if(machine_is_lubbock()){
++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_CSB226)
++    pcmcia_low_level=&lubbock_pcmcia_ops;
++#endif
++  } else if (machine_is_pxa_idp()) {
++    pcmcia_low_level=&pxa_idp_pcmcia_ops;
++  } else if( machine_is_pxa_cerf()){
++    pcmcia_low_level=&cerf_pcmcia_ops;
++  } else if (machine_is_trizeps2()){
++#ifdef CONFIG_ARCH_TRIZEPS2
++    pcmcia_low_level=&trizeps2_pcmcia_ops;
++#endif
++  }
++
++  if (!pcmcia_low_level) {
++    printk(KERN_ERR "This hardware is not supported by the PXA250/210 Card Service driver\n");
++    return -ENODEV;
++  }
++
++  pcmcia_init.handler=pxa_pcmcia_interrupt;
++
++  if((pxa_pcmcia_socket_count=pcmcia_low_level->init(&pcmcia_init))<0){
++    printk(KERN_ERR "Unable to initialize kernel PCMCIA service.\n");
++    return -EIO;
++  }
++
++  state_array.size=pxa_pcmcia_socket_count;
++  state_array.state=state;
++
++  /* Configure MECR based on the number of sockets present. */
++  if (pxa_pcmcia_socket_count == 2) {
++    MECR |= GPIO_bit(0);
++  } else {
++    MECR &= ~GPIO_bit(0);
++  }
++
++  if(pcmcia_low_level->socket_state(&state_array)<0){
++    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
++    return -EIO;
++  }
++
++  /* Well, it looks good to go. So we can now enable the PCMCIA
++   * controller.
++   */
++  MECR |= GPIO_bit(1);
++
++  /* We need to initialize the MCXX registers to default values
++   * here because we're not guaranteed to see a SetIOMap operation
++   * at runtime.
++   */
++
++  clock = get_lclk_frequency_10khz();
++
++  for(i=0; i<pxa_pcmcia_socket_count; ++i){
++    pxa_pcmcia_socket[i].k_state=state[i];
++
++    /* This is an interim fix. Apparently, SetSocket is no longer
++     * called to initialize each socket (prior to the first detect
++     * event). For now, we'll just manually set up the mask.
++     */
++    pxa_pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;
++
++    pxa_pcmcia_socket[i].virt_io=(i==0)?PCMCIA_IO_0_BASE:PCMCIA_IO_1_BASE;
++    pxa_pcmcia_socket[i].phys_attr=_PCMCIAAttr(i);
++    pxa_pcmcia_socket[i].phys_mem=_PCMCIAMem(i);
++
++    /* REVISIT: cleanup these macros */
++    //MCIO_SET(i, PXA_PCMCIA_IO_ACCESS, clock);
++    //MCATTR_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock);
++    //MCMEM_SET(i, PXA_PCMCIA_5V_MEM_ACCESS, clock);
++
++    pxa_pcmcia_socket[i].speed_io=PXA_PCMCIA_IO_ACCESS;
++    pxa_pcmcia_socket[i].speed_attr=PXA_PCMCIA_ATTR_MEM_ACCESS;
++    pxa_pcmcia_socket[i].speed_mem=PXA_PCMCIA_5V_MEM_ACCESS;
++  }
++
++/* REVISIT: cleanup these macros */
++MCMEM0 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++       | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++       | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCMEM1 = ((pxa_mcxx_setup(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++       | ((pxa_mcxx_asst(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++       | ((pxa_mcxx_hold(PXA_PCMCIA_5V_MEM_ACCESS, clock)
++		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++       | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++       | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++       | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++       | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCIO0 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock)
++		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++       | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock)
++		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++       | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock)
++		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++MCIO1 = ((pxa_mcxx_setup(PXA_PCMCIA_IO_ACCESS, clock)
++		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++       | ((pxa_mcxx_asst(PXA_PCMCIA_IO_ACCESS, clock)
++		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++       | ((pxa_mcxx_hold(PXA_PCMCIA_IO_ACCESS, clock)
++		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++
++#ifdef CONFIG_CPU_FREQ
++  if(cpufreq_register_notifier(&pxa_pcmcia_notifier_block) < 0){
++    printk(KERN_ERR "Unable to register CPU frequency change notifier\n");
++    return -ENXIO;
++  }
++#endif
++
++  /* Only advertise as many sockets as we can detect: */
++  if(register_ss_entry(pxa_pcmcia_socket_count, 
++		       &pxa_pcmcia_operations)<0){
++    printk(KERN_ERR "Unable to register socket service routine\n");
++    return -ENXIO;
++  }
++
++  /* Start the event poll timer.  It will reschedule by itself afterwards. */
++  pxa_pcmcia_poll_event(0);
++
++  DEBUG(1, "pxa_cs: initialization complete\n");
++
++  return 0;
++
++}  /* pxa_pcmcia_driver_init() */
++
++module_init(pxa_pcmcia_driver_init);
++
++
++/* pxa_pcmcia_driver_shutdown()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Invokes the low-level kernel service to free IRQs associated with this
++ * socket controller and reset GPIO edge detection.
++ */
++static void __exit pxa_pcmcia_driver_shutdown(void){
++
++  del_timer_sync(&poll_timer);
++  unregister_ss_entry(&pxa_pcmcia_operations);
++#ifdef CONFIG_CPU_FREQ
++  cpufreq_unregister_notifier(&pxa_pcmcia_notifier_block);
++#endif
++  pcmcia_low_level->shutdown();
++  flush_scheduled_tasks();
++
++  DEBUG(1, "pxa_cs: shutdown complete\n");
++}
++
++module_exit(pxa_pcmcia_driver_shutdown);
++
++
++/* pxa_pcmcia_init()
++ * ^^^^^^^^^^^^^^^^^^^^
++ * We perform all of the interesting initialization tasks in 
++ * pxa_pcmcia_driver_init().
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_init(unsigned int sock){
++  
++  DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock);
++
++  return 0;
++}
++
++
++/* pxa_pcmcia_suspend()
++ * ^^^^^^^^^^^^^^^^^^^^^^^
++ * We don't currently perform any actions on a suspend.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_suspend(unsigned int sock)
++{
++  socket_state_t st;
++  int ret;
++
++  DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock);
++
++  st.Vcc = 0;
++  st.Vpp = 0;
++  st.flags = SS_RESET;
++
++  ret = pcmcia_low_level->configure_socket(sock, &st);
++
++  if (ret == 0)
++    pxa_pcmcia_socket[sock].cs_state = dead_socket;
++
++  return ret;
++}
++
++
++/* pxa_pcmcia_events()
++ * ^^^^^^^^^^^^^^^^^^^^^^
++ * Helper routine to generate a Card Services event mask based on
++ * state information obtained from the kernel low-level PCMCIA layer
++ * in a recent (and previous) sampling. Updates `prev_state'.
++ *
++ * Returns: an event mask for the given socket state.
++ */
++static inline unsigned pxa_pcmcia_events(struct pcmcia_state *state,
++					    struct pcmcia_state *prev_state,
++					    unsigned int mask,
++					    unsigned int flags){
++  unsigned int events=0;
++
++  if(state->detect!=prev_state->detect){
++
++    DEBUG(2, "%s(): card detect value %u\n", __FUNCTION__, state->detect);
++
++    events|=mask&SS_DETECT;
++  }
++
++  if(state->ready!=prev_state->ready){
++
++    DEBUG(2, "%s(): card ready value %u\n", __FUNCTION__, state->ready);
++
++    events|=mask&((flags&SS_IOCARD)?0:SS_READY);
++  }
++
++  if(state->bvd1!=prev_state->bvd1){
++
++    DEBUG(2, "%s(): card BVD1 value %u\n", __FUNCTION__, state->bvd1);
++
++    events|=mask&(flags&SS_IOCARD)?SS_STSCHG:SS_BATDEAD;
++  }
++
++  if(state->bvd2!=prev_state->bvd2){
++
++    DEBUG(2, "%s(): card BVD2 value %u\n", __FUNCTION__, state->bvd2);
++
++    events|=mask&(flags&SS_IOCARD)?0:SS_BATWARN;
++  }
++
++  DEBUG(2, "events: %s%s%s%s%s%s\n",
++	(events==0)?"<NONE>":"",
++	(events&SS_DETECT)?"DETECT ":"",
++	(events&SS_READY)?"READY ":"",
++	(events&SS_BATDEAD)?"BATDEAD ":"",
++	(events&SS_BATWARN)?"BATWARN ":"",
++	(events&SS_STSCHG)?"STSCHG ":"");
++
++  *prev_state=*state;
++
++  return events;
++
++}  /* pxa_pcmcia_events() */
++
++
++/* pxa_pcmcia_task_handler()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Processes serviceable socket events using the "eventd" thread context.
++ *
++ * Event processing (specifically, the invocation of the Card Services event
++ * callback) occurs in this thread rather than in the actual interrupt
++ * handler due to the use of scheduling operations in the PCMCIA core.
++ */
++static void pxa_pcmcia_task_handler(void *data) {
++  struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
++  struct pcmcia_state_array state_array;
++  int i, events, all_events, irq_status;
++
++  DEBUG(2, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__);
++
++  state_array.size=pxa_pcmcia_socket_count;
++  state_array.state=state;
++
++  do {
++
++    DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__);
++
++    if((irq_status=pcmcia_low_level->socket_state(&state_array))<0)
++      printk(KERN_ERR "Error in kernel low-level PCMCIA service.\n");
++
++    all_events=0;
++
++    if(irq_status>0){
++
++      for(i=0; i<state_array.size; ++i, all_events|=events)
++	if((events=
++	    pxa_pcmcia_events(&state[i],
++				 &pxa_pcmcia_socket[i].k_state,
++				 pxa_pcmcia_socket[i].cs_state.csc_mask,
++				 pxa_pcmcia_socket[i].cs_state.flags)))
++	  if(pxa_pcmcia_socket[i].handler!=NULL)
++	    pxa_pcmcia_socket[i].handler(pxa_pcmcia_socket[i].handler_info,
++					    events);
++    }
++
++  } while(all_events);
++}  /* pxa_pcmcia_task_handler() */
++
++static struct tq_struct pxa_pcmcia_task = {
++	routine: pxa_pcmcia_task_handler
++};
++
++
++/* pxa_pcmcia_poll_event()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Let's poll for events in addition to IRQs since IRQ only is unreliable...
++ */
++static void pxa_pcmcia_poll_event(unsigned long dummy)
++{
++  DEBUG(3, "%s(): polling for events\n", __FUNCTION__);
++  poll_timer.function = pxa_pcmcia_poll_event;
++  poll_timer.expires = jiffies + PXA_PCMCIA_POLL_PERIOD;
++  add_timer(&poll_timer);
++  schedule_task(&pxa_pcmcia_task);
++}
++
++
++/* pxa_pcmcia_interrupt()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Service routine for socket driver interrupts (requested by the
++ * low-level PCMCIA init() operation via pxa_pcmcia_thread()).
++ * The actual interrupt-servicing work is performed by
++ * pxa_pcmcia_thread(), largely because the Card Services event-
++ * handling code performs scheduling operations which cannot be
++ * executed from within an interrupt context.
++ */
++static void pxa_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){
++  DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
++  schedule_task(&pxa_pcmcia_task);
++}
++
++
++/* pxa_pcmcia_register_callback()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the register_callback() operation for the in-kernel
++ * PCMCIA service (formerly SS_RegisterCallback in Card Services). If 
++ * the function pointer `handler' is not NULL, remember the callback 
++ * location in the state for `sock', and increment the usage counter 
++ * for the driver module. (The callback is invoked from the interrupt
++ * service routine, pxa_pcmcia_interrupt(), to notify Card Services
++ * of interesting events.) Otherwise, clear the callback pointer in the
++ * socket state and decrement the module usage count.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_register_callback(unsigned int sock,
++					   void (*handler)(void *,
++							   unsigned int),
++					   void *info){
++  if(handler==NULL){
++    pxa_pcmcia_socket[sock].handler=NULL;
++    MOD_DEC_USE_COUNT;
++  } else {
++    MOD_INC_USE_COUNT;
++    pxa_pcmcia_socket[sock].handler=handler;
++    pxa_pcmcia_socket[sock].handler_info=info;
++  }
++
++  return 0;
++}
++
++
++/* pxa_pcmcia_inquire_socket()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the inquire_socket() operation for the in-kernel PCMCIA
++ * service (formerly SS_InquireSocket in Card Services). Of note is
++ * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of
++ * `cap' to "trick" Card Services into tolerating large "I/O memory" 
++ * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory
++ * resource database check. (Mapped memory is set up within the socket
++ * driver itself.)
++ *
++ * In conjunction with the STATIC_MAP capability is a new field,
++ * `io_offset', recommended by David Hinds. Rather than go through
++ * the SetIOMap interface (which is not quite suited for communicating
++ * window locations up from the socket driver), we just pass up
++ * an offset which is applied to client-requested base I/O addresses
++ * in alloc_io_space().
++ *
++ * Returns: 0 on success, -1 if no pin has been configured for `sock'
++ */
++static int pxa_pcmcia_inquire_socket(unsigned int sock,
++					socket_cap_t *cap){
++  struct pcmcia_irq_info irq_info;
++
++  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  if(sock>=pxa_pcmcia_socket_count){
++    printk(KERN_ERR "pxa_cs: socket %u not configured\n", sock);
++    return -1;
++  }
++
++  /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the
++   *   force_low argument to validate_mem() in rsrc_mgr.c -- since in
++   *   general, the mapped * addresses of the PCMCIA memory regions
++   *   will not be within 0xffff, setting force_low would be
++   *   undesirable.
++   *
++   * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory
++   *   resource database; we instead pass up physical address ranges
++   *   and allow other parts of Card Services to deal with remapping.
++   *
++   * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but
++   *   not 32-bit CardBus devices.
++   */
++  cap->features=(SS_CAP_PAGE_REGS  | SS_CAP_STATIC_MAP | SS_CAP_PCCARD);
++
++  irq_info.sock=sock;
++  irq_info.irq=-1;
++
++  if(pcmcia_low_level->get_irq_info(&irq_info)<0){
++    printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n",
++	   sock);
++    return -1;
++  }
++
++  cap->irq_mask=0;
++  cap->map_size=PAGE_SIZE;
++  cap->pci_irq=irq_info.irq;
++  cap->io_offset=pxa_pcmcia_socket[sock].virt_io;
++
++  return 0;
++
++}  /* pxa_pcmcia_inquire_socket() */
++
++
++/* pxa_pcmcia_get_status()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_status() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetStatus in Card Services). Essentially just
++ * fills in bits in `status' according to internal driver state or
++ * the value of the voltage detect chipselect register.
++ *
++ * As a debugging note, during card startup, the PCMCIA core issues
++ * three set_socket() commands in a row the first with RESET deasserted,
++ * the second with RESET asserted, and the last with RESET deasserted
++ * again. Following the third set_socket(), a get_status() command will
++ * be issued. The kernel is looking for the SS_READY flag (see
++ * setup_socket(), reset_socket(), and unreset_socket() in cs.c).
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_get_status(unsigned int sock,
++				    unsigned int *status){
++  struct pcmcia_state state[PXA_PCMCIA_MAX_SOCK];
++  struct pcmcia_state_array state_array;
++
++  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  state_array.size=pxa_pcmcia_socket_count;
++  state_array.state=state;
++
++  if((pcmcia_low_level->socket_state(&state_array))<0){
++    printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n");
++    return -1;
++  }
++
++  pxa_pcmcia_socket[sock].k_state=state[sock];
++
++  *status=state[sock].detect?SS_DETECT:0;
++
++  *status|=state[sock].ready?SS_READY:0;
++
++  /* The power status of individual sockets is not available
++   * explicitly from the hardware, so we just remember the state
++   * and regurgitate it upon request:
++   */
++  *status|=pxa_pcmcia_socket[sock].cs_state.Vcc?SS_POWERON:0;
++
++  if(pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)
++    *status|=state[sock].bvd1?SS_STSCHG:0;
++  else {
++    if(state[sock].bvd1==0)
++      *status|=SS_BATDEAD;
++    else if(state[sock].bvd2==0)
++      *status|=SS_BATWARN;
++  }
++
++  *status|=state[sock].vs_3v?SS_3VCARD:0;
++
++  *status|=state[sock].vs_Xv?SS_XVCARD:0;
++
++  DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n",
++	(*status&SS_DETECT)?"DETECT ":"",
++	(*status&SS_READY)?"READY ":"", 
++	(*status&SS_BATDEAD)?"BATDEAD ":"",
++	(*status&SS_BATWARN)?"BATWARN ":"",
++	(*status&SS_POWERON)?"POWERON ":"",
++	(*status&SS_STSCHG)?"STSCHG ":"",
++	(*status&SS_3VCARD)?"3VCARD ":"",
++	(*status&SS_XVCARD)?"XVCARD ":"");
++
++  return 0;
++
++}  /* pxa_pcmcia_get_status() */
++
++
++/* pxa_pcmcia_get_socket()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_socket() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetSocket in Card Services). Not a very 
++ * exciting routine.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_get_socket(unsigned int sock,
++				    socket_state_t *state){
++
++  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  /* This information was given to us in an earlier call to set_socket(),
++   * so we're just regurgitating it here:
++   */
++  *state=pxa_pcmcia_socket[sock].cs_state;
++
++  return 0;
++}
++
++
++/* pxa_pcmcia_set_socket()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the set_socket() operation for the in-kernel PCMCIA
++ * service (formerly SS_SetSocket in Card Services). We more or
++ * less punt all of this work and let the kernel handle the details
++ * of power configuration, reset, &c. We also record the value of
++ * `state' in order to regurgitate it to the PCMCIA core later.
++ *
++ * Returns: 0
++ */
++static int pxa_pcmcia_set_socket(unsigned int sock,
++				    socket_state_t *state){
++
++  DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  DEBUG(3, "\tmask:  %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n"
++	"\tVcc %d  Vpp %d  irq %d\n",
++	(state->csc_mask==0)?"<NONE>":"",
++	(state->csc_mask&SS_DETECT)?"DETECT ":"",
++	(state->csc_mask&SS_READY)?"READY ":"",
++	(state->csc_mask&SS_BATDEAD)?"BATDEAD ":"",
++	(state->csc_mask&SS_BATWARN)?"BATWARN ":"",
++	(state->csc_mask&SS_STSCHG)?"STSCHG ":"",
++	(state->flags==0)?"<NONE>":"",
++	(state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"",
++	(state->flags&SS_IOCARD)?"IOCARD ":"",
++	(state->flags&SS_RESET)?"RESET ":"",
++	(state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"",
++	(state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":"",
++	state->Vcc, state->Vpp, state->io_irq);
++
++  if(pcmcia_low_level->configure_socket(sock, state)<0){
++    printk(KERN_ERR "Unable to configure socket %u\n", sock);
++    return -1;
++  }
++
++  pxa_pcmcia_socket[sock].cs_state=*state;
++  
++  return 0;
++
++}  /* pxa_pcmcia_set_socket() */
++
++
++/* pxa_pcmcia_get_io_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_io_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetIOMap in Card Services). Just returns an
++ * I/O map descriptor which was assigned earlier by a set_io_map().
++ *
++ * Returns: 0 on success, -1 if the map index was out of range
++ */
++static int pxa_pcmcia_get_io_map(unsigned int sock,
++				    struct pccard_io_map *map){
++
++  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  if(map->map>=MAX_IO_WIN){
++    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++	   map->map);
++    return -1;
++  }
++
++  *map=pxa_pcmcia_socket[sock].io_map[map->map];
++
++  return 0;
++}
++
++
++/* pxa_pcmcia_set_io_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the set_io_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_SetIOMap in Card Services). We configure
++ * the map speed as requested, but override the address ranges
++ * supplied by Card Services.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int pxa_pcmcia_set_io_map(unsigned int sock,
++				    struct pccard_io_map *map){
++  unsigned int clock, speed;
++  unsigned long mecr, start;
++
++  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  DEBUG(4, "\tmap %u  speed %u\n\tstart 0x%08lx  stop 0x%08lx\n"
++	"\tflags: %s%s%s%s%s%s%s%s\n",
++	map->map, map->speed, map->start, map->stop,
++	(map->flags==0)?"<NONE>":"",
++	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
++	(map->flags&MAP_16BIT)?"16BIT ":"",
++	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
++	(map->flags&MAP_0WS)?"0WS ":"",
++	(map->flags&MAP_WRPROT)?"WRPROT ":"",
++	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"",
++	(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
++
++  if(map->map>=MAX_IO_WIN){
++    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++	   map->map);
++    return -1;
++  }
++
++  if(map->flags&MAP_ACTIVE){
++
++    speed=(map->speed>0)?map->speed:PXA_PCMCIA_IO_ACCESS;
++
++    clock = get_lclk_frequency_10khz();
++
++    pxa_pcmcia_socket[sock].speed_io=speed;
++
++    if (sock == 0) {
++      MCIO0 = ((pxa_mcxx_setup(speed, clock)
++			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++            | ((pxa_mcxx_asst(speed, clock)
++			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++            | ((pxa_mcxx_hold(speed, clock)
++			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++    } else {
++      MCIO1 = ((pxa_mcxx_setup(speed, clock)
++			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++            | ((pxa_mcxx_asst(speed, clock)
++			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++            | ((pxa_mcxx_hold(speed, clock)
++			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++    }
++
++    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
++	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
++	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
++	  sock, MECR_BSIO_GET(mecr, sock));
++
++  }
++
++  start=map->start;
++
++  if(map->stop==1)
++    map->stop=PAGE_SIZE-1;
++
++  map->start=pxa_pcmcia_socket[sock].virt_io;
++  map->stop=map->start+(map->stop-start);
++
++  pxa_pcmcia_socket[sock].io_map[map->map]=*map;
++
++  return 0;
++
++}  /* pxa_pcmcia_set_io_map() */
++
++
++/* pxa_pcmcia_get_mem_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the get_mem_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_GetMemMap in Card Services). Just returns a
++ *  memory map descriptor which was assigned earlier by a
++ *  set_mem_map() request.
++ *
++ * Returns: 0 on success, -1 if the map index was out of range
++ */
++static int pxa_pcmcia_get_mem_map(unsigned int sock,
++				     struct pccard_mem_map *map){
++
++  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  if(map->map>=MAX_WIN){
++    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++	   map->map);
++    return -1;
++  }
++
++  *map=pxa_pcmcia_socket[sock].mem_map[map->map];
++
++  return 0;
++}
++
++
++/* pxa_pcmcia_set_mem_map()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the set_mem_map() operation for the in-kernel PCMCIA
++ * service (formerly SS_SetMemMap in Card Services). We configure
++ * the map speed as requested, but override the address ranges
++ * supplied by Card Services.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int pxa_pcmcia_set_mem_map(unsigned int sock,
++				     struct pccard_mem_map *map){
++  unsigned int clock, speed;
++  unsigned long mecr, start;
++
++  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  DEBUG(4, "\tmap %u  speed %u\n\tsys_start  %#lx\n"
++	"\tsys_stop   %#lx\n\tcard_start %#x\n"
++	"\tflags: %s%s%s%s%s%s%s%s\n",
++	map->map, map->speed, map->sys_start, map->sys_stop,
++	map->card_start, (map->flags==0)?"<NONE>":"",
++	(map->flags&MAP_ACTIVE)?"ACTIVE ":"",
++	(map->flags&MAP_16BIT)?"16BIT ":"",
++	(map->flags&MAP_AUTOSZ)?"AUTOSZ ":"",
++	(map->flags&MAP_0WS)?"0WS ":"",
++	(map->flags&MAP_WRPROT)?"WRPROT ":"",
++	(map->flags&MAP_ATTRIB)?"ATTRIB ":"",
++	(map->flags&MAP_USE_WAIT)?"USE_WAIT ":"");
++
++  if(map->map>=MAX_WIN){
++    printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
++	   map->map);
++    return -1;
++  }
++
++  if(map->flags&MAP_ACTIVE){
++    /* When clients issue RequestMap, the access speed is not always
++     * properly configured:
++     */
++    if(map->speed > 0)
++      speed = map->speed;
++    else
++      switch(pxa_pcmcia_socket[sock].cs_state.Vcc){
++      case 33:
++	speed = PXA_PCMCIA_3V_MEM_ACCESS;
++	break;
++      default:
++	speed = PXA_PCMCIA_5V_MEM_ACCESS;
++      }
++
++    clock = get_lclk_frequency_10khz();
++
++    if(map->flags&MAP_ATTRIB){
++      if (sock == 0) {
++        MCATT0 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++               | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++               | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++      } else {
++        MCATT1 = ((pxa_mcxx_setup(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++               | ((pxa_mcxx_asst(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++               | ((pxa_mcxx_hold(PXA_PCMCIA_ATTR_MEM_ACCESS, clock)
++			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++      }
++      pxa_pcmcia_socket[sock].speed_attr=speed;
++    } else {
++      if (sock == 0) {
++        MCMEM0 = ((pxa_mcxx_setup(speed, clock)
++			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++               | ((pxa_mcxx_asst(speed, clock)
++			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++               | ((pxa_mcxx_hold(speed, clock)
++			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++      } else {
++        MCMEM1 = ((pxa_mcxx_setup(speed, clock)
++			& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
++               | ((pxa_mcxx_asst(speed, clock)
++			& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
++               | ((pxa_mcxx_hold(speed, clock)
++			& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
++      }
++      pxa_pcmcia_socket[sock].speed_mem=speed;
++    }
++    DEBUG(4, "%s(): FAST%u %lx  BSM%u %lx  BSA%u %lx  BSIO%u %lx\n",
++	  __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock,
++	  MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), 
++	  sock, MECR_BSIO_GET(mecr, sock));
++  }
++
++  start=map->sys_start;
++
++  if(map->sys_stop==0)
++    map->sys_stop=PAGE_SIZE-1;
++
++  map->sys_start=(map->flags & MAP_ATTRIB)?\
++    pxa_pcmcia_socket[sock].phys_attr:\
++    pxa_pcmcia_socket[sock].phys_mem;
++
++  map->sys_stop=map->sys_start+(map->sys_stop-start);
++
++  pxa_pcmcia_socket[sock].mem_map[map->map]=*map;
++
++  return 0;
++
++}  /* pxa_pcmcia_set_mem_map() */
++
++
++#if defined(CONFIG_PROC_FS)
++
++/* pxa_pcmcia_proc_setup()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the proc_setup() operation for the in-kernel PCMCIA
++ * service (formerly SS_ProcSetup in Card Services).
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static void pxa_pcmcia_proc_setup(unsigned int sock,
++				     struct proc_dir_entry *base){
++  struct proc_dir_entry *entry;
++
++  DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock);
++
++  if((entry=create_proc_entry("status", 0, base))==NULL){
++    printk(KERN_ERR "Unable to install \"status\" procfs entry\n");
++    return;
++  }
++
++  entry->read_proc=pxa_pcmcia_proc_status;
++  entry->data=(void *)sock;
++}
++
++
++/* pxa_pcmcia_proc_status()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * Implements the /proc/bus/pccard/??/status file.
++ *
++ * Returns: the number of characters added to the buffer
++ */
++static int pxa_pcmcia_proc_status(char *buf, char **start, off_t pos,
++				     int count, int *eof, void *data){
++  char *p=buf;
++  unsigned int sock=(unsigned int)data;
++  unsigned int clock = get_lclk_frequency_10khz();
++  unsigned long mecr = MECR;
++
++  p+=sprintf(p, "k_flags  : %s%s%s%s%s%s%s\n", 
++	     pxa_pcmcia_socket[sock].k_state.detect?"detect ":"",
++	     pxa_pcmcia_socket[sock].k_state.ready?"ready ":"",
++	     pxa_pcmcia_socket[sock].k_state.bvd1?"bvd1 ":"",
++	     pxa_pcmcia_socket[sock].k_state.bvd2?"bvd2 ":"",
++	     pxa_pcmcia_socket[sock].k_state.wrprot?"wrprot ":"",
++	     pxa_pcmcia_socket[sock].k_state.vs_3v?"vs_3v ":"",
++	     pxa_pcmcia_socket[sock].k_state.vs_Xv?"vs_Xv ":"");
++
++  p+=sprintf(p, "status   : %s%s%s%s%s%s%s%s%s\n",
++	     pxa_pcmcia_socket[sock].k_state.detect?"SS_DETECT ":"",
++	     pxa_pcmcia_socket[sock].k_state.ready?"SS_READY ":"",
++	     pxa_pcmcia_socket[sock].cs_state.Vcc?"SS_POWERON ":"",
++	     pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
++	     "SS_IOCARD ":"",
++	     (pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD &&
++	      pxa_pcmcia_socket[sock].k_state.bvd1)?"SS_STSCHG ":"",
++	     ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
++	      (pxa_pcmcia_socket[sock].k_state.bvd1==0))?"SS_BATDEAD ":"",
++	     ((pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD)==0 &&
++	      (pxa_pcmcia_socket[sock].k_state.bvd2==0))?"SS_BATWARN ":"",
++	     pxa_pcmcia_socket[sock].k_state.vs_3v?"SS_3VCARD ":"",
++	     pxa_pcmcia_socket[sock].k_state.vs_Xv?"SS_XVCARD ":"");
++
++  p+=sprintf(p, "mask     : %s%s%s%s%s\n",
++	     pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_DETECT?\
++	     "SS_DETECT ":"",
++	     pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_READY?\
++	     "SS_READY ":"",
++	     pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATDEAD?\
++	     "SS_BATDEAD ":"",
++	     pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_BATWARN?\
++	     "SS_BATWARN ":"",
++	     pxa_pcmcia_socket[sock].cs_state.csc_mask&SS_STSCHG?\
++	     "SS_STSCHG ":"");
++
++  p+=sprintf(p, "cs_flags : %s%s%s%s%s\n",
++	     pxa_pcmcia_socket[sock].cs_state.flags&SS_PWR_AUTO?\
++	     "SS_PWR_AUTO ":"",
++	     pxa_pcmcia_socket[sock].cs_state.flags&SS_IOCARD?\
++	     "SS_IOCARD ":"",
++	     pxa_pcmcia_socket[sock].cs_state.flags&SS_RESET?\
++	     "SS_RESET ":"",
++	     pxa_pcmcia_socket[sock].cs_state.flags&SS_SPKR_ENA?\
++	     "SS_SPKR_ENA ":"",
++	     pxa_pcmcia_socket[sock].cs_state.flags&SS_OUTPUT_ENA?\
++	     "SS_OUTPUT_ENA ":"");
++
++  p+=sprintf(p, "Vcc      : %d\n", pxa_pcmcia_socket[sock].cs_state.Vcc);
++
++  p+=sprintf(p, "Vpp      : %d\n", pxa_pcmcia_socket[sock].cs_state.Vpp);
++
++  p+=sprintf(p, "irq      : %d\n", pxa_pcmcia_socket[sock].cs_state.io_irq);
++
++  p+=sprintf(p, "I/O      : %u (%u)\n", pxa_pcmcia_socket[sock].speed_io,
++             sock ?
++               pxa_pcmcia_cmd_time(clock,
++		((MCIO1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) :
++               pxa_pcmcia_cmd_time(clock,
++		((MCIO0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)));
++
++  p+=sprintf(p, "attribute: %u (%u)\n", pxa_pcmcia_socket[sock].speed_attr,
++             sock ?
++               pxa_pcmcia_cmd_time(clock,
++		((MCATT1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) :
++               pxa_pcmcia_cmd_time(clock,
++		((MCATT0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)));
++
++  p+=sprintf(p, "common   : %u (%u)\n", pxa_pcmcia_socket[sock].speed_mem,
++             sock ?
++               pxa_pcmcia_cmd_time(clock,
++		((MCMEM1 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)) :
++               pxa_pcmcia_cmd_time(clock,
++		((MCMEM0 >> MCXX_ASST_SHIFT) & MCXX_ASST_MASK)));
++
++  return p-buf;
++}
++
++#endif  /* defined(CONFIG_PROC_FS) */
++
++
++#ifdef CONFIG_CPU_FREQ
++
++/* pxa_pcmcia_update_mecr()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * When pxa_pcmcia_notifier() decides that a MECR adjustment (due
++ * to a core clock frequency change) is needed, this routine establishes
++ * new BS_xx values consistent with the clock speed `clock'.
++ */
++static void pxa_pcmcia_update_mecr(unsigned int clock){
++  unsigned int sock;
++
++  for(sock = 0; sock < PXA_PCMCIA_MAX_SOCK; ++sock){
++
++    // REVISIT: MCXX macros needed here
++    // MECR_BSIO_SET(mecr, sock,
++// 		  pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_io,
++// 					clock));
++    // MECR_BSA_SET(mecr, sock,
++// 		 pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_attr,
++// 				       clock));
++    // MECR_BSM_SET(mecr, sock,
++// 		 pxa_pcmcia_mecr_bs(pxa_pcmcia_socket[sock].speed_mem,
++// 				       clock));
++  }
++}
++
++/* pxa_pcmcia_notifier()
++ * ^^^^^^^^^^^^^^^^^^^^^^^^
++ * When changing the processor core clock frequency, it is necessary
++ * to adjust the MECR timings accordingly. We've recorded the timings
++ * requested by Card Services, so this is just a matter of finding
++ * out what our current speed is, and then recomputing the new MECR
++ * values.
++ *
++ * Returns: 0 on success, -1 on error
++ */
++static int pxa_pcmcia_notifier(struct notifier_block *nb,
++				  unsigned long val, void *data){
++  struct cpufreq_info *ci = data;
++
++  switch(val){
++  case CPUFREQ_MINMAX:
++
++    break;
++
++  case CPUFREQ_PRECHANGE:
++
++    if(ci->new_freq > ci->old_freq){
++      DEBUG(2, "%s(): new frequency %u.%uMHz > %u.%uMHz, pre-updating\n",
++	    __FUNCTION__,
++	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
++	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
++      pxa_pcmcia_update_mecr(ci->new_freq);
++    }
++
++    break;
++
++  case CPUFREQ_POSTCHANGE:
++
++    if(ci->new_freq < ci->old_freq){
++      DEBUG(2, "%s(): new frequency %u.%uMHz < %u.%uMHz, post-updating\n",
++	    __FUNCTION__,
++	    ci->new_freq / 1000, (ci->new_freq / 100) % 10,
++	    ci->old_freq / 1000, (ci->old_freq / 100) % 10);
++      pxa_pcmcia_update_mecr(ci->new_freq);
++    }
++
++    break;
++
++  default:
++    printk(KERN_ERR "%s(): unknown CPU frequency event %lx\n", __FUNCTION__,
++	   val);
++    return -1;
++
++  }
++
++  return 0;
++
++}
++
++static struct notifier_block pxa_pcmcia_notifier_block = {
++  notifier_call: pxa_pcmcia_notifier
++};
++
++#endif
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/pxa/pxa.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,233 @@
++/*
++ * linux/drivers/pcmcia/pxa/pxa.h
++ *
++ * Author:	George Davis
++ * Created:	Jan 10, 2002
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Originally based upon linux/drivers/pcmcia/sa1100_generic.h
++ *
++ */
++
++/*======================================================================
++
++    Device driver for the PCMCIA control functionality of Intel
++    PXA250/210 microprocessors.
++
++    The contents of this file are subject to the Mozilla Public
++    License Version 1.1 (the "License"); you may not use this file
++    except in compliance with the License. You may obtain a copy of
++    the License at http://www.mozilla.org/MPL/
++
++    Software distributed under the License is distributed on an "AS
++    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++    implied. See the License for the specific language governing
++    rights and limitations under the License.
++
++    The initial developer of the original code is John G. Dorsey
++    <john+@cs.cmu.edu>.  Portions created by John G. Dorsey are
++    Copyright (C) 1999 John G. Dorsey.  All Rights Reserved.
++
++    Alternatively, the contents of this file may be used under the
++    terms of the GNU Public License version 2 (the "GPL"), in which
++    case the provisions of the GPL are applicable instead of the
++    above.  If you wish to allow the use of your version of this file
++    only under the terms of the GPL and not to allow others to use
++    your version of this file under the MPL, indicate your decision
++    by deleting the provisions above and replace them with the notice
++    and other provisions required by the GPL.  If you do not delete
++    the provisions above, a recipient may use your version of this
++    file under either the MPL or the GPL.
++    
++======================================================================*/
++
++#if !defined(_PCMCIA_PXA_H)
++# define _PCMCIA_PXA_H
++
++#include <pcmcia/cs_types.h>
++#include <pcmcia/ss.h>
++#include <pcmcia/bulkmem.h>
++#include <pcmcia/cistpl.h>
++#include "../cs_internal.h"
++
++#include <asm/arch/pcmcia.h>
++
++
++/* MECR: Expansion Memory Configuration Register
++ * (SA-1100 Developers Manual, p.10-13; SA-1110 Developers Manual, p.10-24)
++ *
++ * MECR layout is:  
++ *
++ *   FAST1 BSM1<4:0> BSA1<4:0> BSIO1<4:0> FAST0 BSM0<4:0> BSA0<4:0> BSIO0<4:0>
++ *
++ * (This layout is actually true only for the SA-1110; the FASTn bits are
++ * reserved on the SA-1100.)
++ */
++
++#define MCXX_SETUP_MASK     (0x7f)
++#define MCXX_ASST_MASK      (0x1f)
++#define MCXX_HOLD_MASK      (0x3f)
++#define MCXX_SETUP_SHIFT    (0)
++#define MCXX_ASST_SHIFT     (7)
++#define MCXX_HOLD_SHIFT     (14)
++
++
++#define MECR_SET(mecr, sock, shift, mask, bs) \
++((mecr)=((mecr)&~(((mask)<<(shift))<<\
++                  ((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))|\
++        (((bs)<<(shift))<<((sock)==0?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT)))
++
++#define MECR_GET(mecr, sock, shift, mask) \
++((((mecr)>>(((sock)==0)?MECR_SOCKET_0_SHIFT:MECR_SOCKET_1_SHIFT))>>\
++ (shift))&(mask))
++
++#define MECR_BSIO_SET(mecr, sock, bs) \
++MECR_SET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK, (bs))
++
++#define MECR_BSIO_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_BSIO_SHIFT, MECR_BS_MASK)
++
++#define MECR_BSA_SET(mecr, sock, bs) \
++MECR_SET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK, (bs))
++
++#define MECR_BSA_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_BSA_SHIFT, MECR_BS_MASK)
++
++#define MECR_BSM_SET(mecr, sock, bs) \
++MECR_SET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK, (bs))
++
++#define MECR_BSM_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_BSM_SHIFT, MECR_BS_MASK)
++
++#define MECR_FAST_SET(mecr, sock, fast) \
++MECR_SET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK, (fast))
++
++#define MECR_FAST_GET(mecr, sock) \
++MECR_GET((mecr), (sock), MECR_FAST_SHIFT, MECR_FAST_MODE_MASK)
++
++
++/* This function implements the BS value calculation for setting the MECR
++ * using integer arithmetic:
++ */
++static inline unsigned int pxa_pcmcia_mecr_bs(unsigned int pcmcia_cycle_ns,
++						 unsigned int cpu_clock_khz){
++  unsigned int t = ((pcmcia_cycle_ns * cpu_clock_khz) / 6) - 1000000;
++  return (t / 1000000) + (((t % 1000000) == 0) ? 0 : 1);
++}
++
++static inline u_int pxa_mcxx_hold(u_int pcmcia_cycle_ns,
++					    u_int mem_clk_10khz){
++  u_int code = pcmcia_cycle_ns * mem_clk_10khz;
++  return (code / 300000) + ((code % 300000) ? 1 : 0);
++}
++
++static inline u_int pxa_mcxx_asst(u_int pcmcia_cycle_ns,
++					    u_int mem_clk_10khz){
++  u_int code = pcmcia_cycle_ns * mem_clk_10khz;
++  return (code / 300000) + ((code % 300000) ? 1 : 0);
++}
++
++static inline u_int pxa_mcxx_setup(u_int pcmcia_cycle_ns,
++					    u_int mem_clk_10khz){
++  u_int code = pcmcia_cycle_ns * mem_clk_10khz;
++  return (code / 100000) + ((code % 100000) ? 1 : 0) + 1;
++}
++
++/* This function returns the (approxmiate) command assertion period, in
++ * nanoseconds, for a given CPU clock frequency and MCXX_ASST value:
++ */
++
++static inline u_int pxa_pcmcia_cmd_time(u_int mem_clk_10khz,
++					   u_int pcmcia_mcxx_asst){
++  return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz);
++}
++
++
++/* SA-1100 PCMCIA Memory and I/O timing
++ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
++ * The SA-1110 Developer's Manual, section 10.2.5, says the following:
++ *
++ *  "To calculate the recommended BS_xx value for each address space:
++ *   divide the command width time (the greater of twIOWR and twIORD,
++ *   or the greater of twWE and twOE) by processor cycle time; divide
++ *   by 2; divide again by 3 (number of BCLK's per command assertion);
++ *   round up to the next whole number; and subtract 1."
++ *
++ * The PC Card Standard, Release 7, section 4.13.4, says that twIORD
++ * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has
++ * a minimum value of 165ns, as well. Section 4.7.2 (describing
++ * common and attribute memory write timing) says that twWE has a
++ * minimum value of 150ns for a 250ns cycle time (for 5V operation;
++ * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V
++ * operation, also section 4.7.4). Section 4.7.3 says that taOE
++ * has a maximum value of 150ns for a 300ns cycle time (for 5V
++ * operation), or 300ns for a 600ns cycle time (for 3.3V operation).
++ *
++ * When configuring memory maps, Card Services appears to adopt the policy
++ * that a memory access time of "0" means "use the default." The default
++ * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute
++ * and memory command width time is 150ns; the PCMCIA 3.3V attribute and
++ * memory command width time is 300ns.
++ */
++ 
++/* The PXA 250 and PXA 210 Application Processors Developer's Manual
++ * was used to determine correct PXA_PCMCIA_IO_ACCES time
++ */
++  
++#define PXA_PCMCIA_IO_ACCESS      (165) 
++
++/* Default PC Card Common Memory timings*/
++                                         
++#define PXA_PCMCIA_5V_MEM_ACCESS  (250)
++#define PXA_PCMCIA_3V_MEM_ACCESS  (250)
++
++/* Atrribute Memory timing - must be constant via PC Card standart*/
++ 
++#define PXA_PCMCIA_ATTR_MEM_ACCESS (300)
++
++
++/* The socket driver actually works nicely in interrupt-driven form,
++ * so the (relatively infrequent) polling is "just to be sure."
++ */
++#define PXA_PCMCIA_POLL_PERIOD    (2*HZ)
++
++
++/* This structure encapsulates per-socket state which we might need to
++ * use when responding to a Card Services query of some kind.
++ */
++struct pxa_pcmcia_socket {
++  socket_state_t        cs_state;
++  struct pcmcia_state   k_state;
++  unsigned int          irq;
++  void                  (*handler)(void *, unsigned int);
++  void                  *handler_info;
++  pccard_io_map         io_map[MAX_IO_WIN];
++  pccard_mem_map        mem_map[MAX_WIN];
++  ioaddr_t              virt_io, phys_attr, phys_mem;
++  unsigned short        speed_io, speed_attr, speed_mem;
++};
++
++
++/* I/O pins replacing memory pins
++ * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75)
++ *
++ * These signals change meaning when going from memory-only to 
++ * memory-or-I/O interface:
++ */
++#define iostschg bvd1
++#define iospkr   bvd2
++
++
++/*
++ * Declaration for all implementation specific low_level operations.
++ */
++extern struct pcmcia_low_level lubbock_pcmcia_ops;
++extern struct pcmcia_low_level pxa_idp_pcmcia_ops;
++extern struct pcmcia_low_level cerf_pcmcia_ops;
++extern struct pcmcia_low_level trizeps2_pcmcia_ops;
++
++#endif  /* !defined(_PCMCIA_PXA_H) */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/pxa/pxa_idp.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,297 @@
++/*
++ * linux/drivers/pcmcia/pxa/pxa_idp.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved
++ * 
++ * Platform specific routines for the Accelent PXA250 IDP, based on those
++ * first done for the Lubbock.
++ *
++ * Version 1.0 2002-05-02  Jeff Sutherland <jeffs@accelent.com>
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++#include <pcmcia/ss.h>
++
++#include <asm/delay.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++
++static int 
++pxa_idp_pcmcia_init(struct pcmcia_init *init)
++{
++	int return_val = 0;
++
++  	/* Set PCMCIA Socket 0 power to standby mode.
++	*  PXA IDP has dedicated CPLD pins for all this stuff :-)
++   	*/
++	
++	/* both slots disabled, reset NOT active */
++	IDP_CPLD_PCCARD_EN = PCC0_ENABLE | PCC1_ENABLE;
++
++	IDP_CPLD_PCCARD_PWR = 0; //all power to both slots off
++
++	GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID)) &=
++	    ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID));
++	GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID)) &=
++	    ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID));
++
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_CD_VALID),
++			  GPIO_BOTH_EDGES);
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_CD_VALID),
++			  GPIO_BOTH_EDGES);
++
++	/* irq's for slots: */
++	GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT)) &=
++	    ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT));
++	GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT)) &=
++	    ~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT));
++
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S0_RDYINT),
++			  GPIO_FALLING_EDGE);
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S1_RDYINT),
++			  GPIO_FALLING_EDGE);
++
++	return_val =
++	    request_irq(PCMCIA_S0_CD_VALID, init->handler, SA_INTERRUPT,
++			"PXA PCMCIA CD0", NULL);
++
++	if (return_val < 0)
++		return -1;
++	
++	return_val +=
++	    request_irq(PCMCIA_S1_CD_VALID, init->handler, SA_INTERRUPT,
++			"PXA PCMCIA CD1", NULL);
++	
++	if (return_val < 0) {
++		free_irq(PCMCIA_S0_CD_VALID, NULL);
++		return -1;
++	}
++
++	return 2;
++}
++
++static int
++pxa_idp_pcmcia_shutdown(void)
++{
++
++	free_irq(PCMCIA_S0_CD_VALID, NULL);
++	free_irq(PCMCIA_S1_CD_VALID, NULL);
++  
++	IDP_CPLD_PCCARD_EN = 0x03;	//disable slots
++	udelay(200);
++	IDP_CPLD_PCCARD_PWR = 0; //shut off all power
++
++	return 0;
++}
++
++static int
++pxa_idp_pcmcia_socket_state(struct pcmcia_state_array *state_array)
++{
++	unsigned long status;
++	int return_val = 1;
++	int i;
++	volatile unsigned long *stat_regs[2] = { &IDP_CPLD_PCCARD0_STATUS,
++		&IDP_CPLD_PCCARD1_STATUS
++	};
++
++	if (state_array->size < 2)
++		return -1;
++
++	memset(state_array->state, 0,
++	       (state_array->size) * sizeof (struct pcmcia_state));
++	
++	for (i = 0; i < 2; i++) {
++
++		status = *stat_regs[i];
++
++	      	/* this one is a gpio */
++		state_array->state[i].detect = (PCC_DETECT(i)) ? 0 : 1;
++		
++		state_array->state[i].ready =
++		    ((status & _PCC_IRQ) == 0) ? 0 : 1;
++		state_array->state[i].bvd1   = (status & PCC_BVD1) ? 0 : 1;
++		state_array->state[i].bvd2   = (status & PCC_BVD2) ? 0 : 1;
++		state_array->state[i].wrprot =
++		    (status & _PCC_WRPROT) ? 1 : 0;
++		state_array->state[i].vs_3v  = (status & PCC_VS1) ? 0 : 1;
++		state_array->state[i].vs_Xv  = (status & PCC_VS2) ? 0 : 1;
++	}
++
++	return return_val;
++}
++
++static int
++pxa_idp_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
++{
++	switch (info->sock) {
++	    case 0:
++		info->irq = PCMCIA_S0_RDYINT;
++		break;
++
++	    case 1:
++		info->irq = PCMCIA_S1_RDYINT;
++		break;
++
++	    default:
++		return -1;
++	}
++
++	return 0;
++}
++
++static int
++pxa_idp_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
++{
++  /* The PXA Idp uses the Maxim MAX1602, with the following connections:
++   *
++   * Socket 0 (PCMCIA):
++   *	MAX1602	PXA_IDP		Register
++   *	Pin	Signal  	IDP_CPLD_PCCARD_PWR:
++   *	-----	-------		----------------------
++   *	A0VPP	PCC0_PWR0	bit0
++   *	A1VPP	PCC0_PWR1	bit1	
++   *	A0VCC	PCC0_PWR2	bit2
++   *	A1VCC	PCC0_PWR3	bit3
++   *	VX	VCC
++   *	VY	+3.3V
++   *	12IN	+12V
++   *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
++   *
++   * Socket 1 (PCMCIA):
++   *	MAX1602	PXA_IDP		Register
++   *	Pin	Signal		IDP_CPLD_PCCARD_PWR:
++   *	-----	-------		----------------------
++   *	A0VPP	PCC1_PWR0	bit4
++   *	A1VPP	PCC1_PWR1	bit5
++   *	A0VCC	PCC1_PWR2	bit6
++   *	A1VCC	PCC1_PWR3	bit7
++   *	VX	VCC
++   *	VY	+3.3V
++   *	12IN	+12V		
++   *	CODE	+3.3V		Cirrus  Code, CODE = High (VY)
++   *
++   */
++
++	switch (sock) {
++	    case 0:
++		switch (state->Vcc) {
++		    case 0:
++			IDP_CPLD_PCCARD_EN |= PCC0_ENABLE; // disable socket
++			udelay(200);
++			IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3);
++			break;
++
++		    case 33:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3);
++			IDP_CPLD_PCCARD_PWR |= PCC0_PWR3;
++			IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE; //turn it on
++			break;
++
++		    case 50:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR2 | PCC0_PWR3);
++			IDP_CPLD_PCCARD_PWR |= PCC0_PWR2;
++			IDP_CPLD_PCCARD_EN &= ~PCC0_ENABLE;
++			break;
++
++		    default:
++			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
++			       __FUNCTION__, state->Vcc);
++			return -1;
++		}
++
++		switch (state->Vpp) {
++		    case 0:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1);
++			break;
++
++		    case 120:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC0_PWR0 | PCC0_PWR1);
++			IDP_CPLD_PCCARD_PWR |= PCC0_PWR1;
++			break;
++
++		    default:
++			if (state->Vpp == state->Vcc)
++				IDP_CPLD_PCCARD_PWR =
++				    (IDP_CPLD_PCCARD_PWR &
++				     ~(PCC0_PWR0 | PCC0_PWR1)) | PCC0_PWR0;
++			else {
++				printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
++				       __FUNCTION__, state->Vpp);
++			return -1;
++		}
++	    }
++
++		IDP_CPLD_PCCARD_EN =
++		    (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC0_RESET)
++		    : (IDP_CPLD_PCCARD_EN & ~PCC0_RESET);
++	    break;
++
++	case 1:
++		switch (state->Vcc) {
++		    case 0:
++			IDP_CPLD_PCCARD_EN |= PCC1_ENABLE; // disable socket
++			udelay(200);
++			IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++			break;
++
++		    case 33:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++			IDP_CPLD_PCCARD_PWR |= PCC1_PWR3;
++			IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE; //turn it on
++			break;
++
++		    case 50:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR2 | PCC1_PWR3);
++			IDP_CPLD_PCCARD_PWR |= PCC1_PWR2;
++			IDP_CPLD_PCCARD_EN &= ~PCC1_ENABLE;
++			break;
++
++		    default:
++			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
++			       __FUNCTION__, state->Vcc);
++			return -1;
++		}
++
++		switch (state->Vpp) {
++		    case 0:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
++			break;
++
++		    case 120:
++			IDP_CPLD_PCCARD_PWR &= ~(PCC1_PWR0 | PCC1_PWR1);
++			IDP_CPLD_PCCARD_PWR |= PCC1_PWR1;
++			break;
++
++		    default:
++			if (state->Vpp == state->Vcc)
++				IDP_CPLD_PCCARD_PWR =
++				    (IDP_CPLD_PCCARD_PWR &
++				     ~(PCC1_PWR0 | PCC1_PWR1)) | PCC1_PWR0;
++			else {
++				printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
++				       __FUNCTION__, state->Vpp);
++				return -1;
++			}
++		}
++		IDP_CPLD_PCCARD_EN = (state->flags & SS_RESET) ? (IDP_CPLD_PCCARD_EN | PCC1_RESET)
++		    : (IDP_CPLD_PCCARD_EN & ~PCC1_RESET);
++	    break;
++	}
++	return 0;
++}
++
++struct pcmcia_low_level pxa_idp_pcmcia_ops = { 
++  pxa_idp_pcmcia_init,
++  pxa_idp_pcmcia_shutdown,
++  pxa_idp_pcmcia_socket_state,
++  pxa_idp_pcmcia_get_irq_info,
++  pxa_idp_pcmcia_configure_socket
++};
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/pxa/trizeps2.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,187 @@
++/*
++ * linux/drivers/pcmcia/pxa/trizeps2.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2002 Accelent Systems, Inc. All Rights Reserved
++ * 
++ * Platform specific routines for the Keith-n-Koep Trizeps-II, based on IDP
++ *
++ * Copyright (c) 2003 Teradyne DS, Ltd.
++ * Port to Trizeps-2 MT6N board by Luc De Cock
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++
++#include <pcmcia/ss.h>
++
++#include <asm/delay.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++
++static int trizeps2_pcmcia_init(struct pcmcia_init *init)
++{
++	int return_val = 0;
++	unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++	unsigned short val;
++
++	/* reset the PCMCIA controller */
++	val = trizeps2_bcr_shadow | BCR_PCMCIA_RESET;
++	*bcr = val;
++	udelay(500);
++	/* un-reset it again */
++	trizeps2_bcr_shadow &= ~BCR_PCMCIA_RESET;
++	/* enable the PCMCIA buffer */
++	trizeps2_bcr_shadow &= ~(1 << 5);
++	*bcr = trizeps2_bcr_shadow;
++
++	GPDR(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID)) &=
++	       	~GPIO_bit(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID));
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(PCMCIA_S_CD_VALID),
++				PCMCIA_S_CD_VALID_EDGE);
++	GPDR(IRQ_TO_GPIO(PCMCIA_S_RDYINT)) &=
++	       	~GPIO_bit(IRQ_TO_GPIO(PCMCIA_S_RDYINT));
++	set_GPIO_IRQ_edge(IRQ_TO_GPIO(PCMCIA_S_RDYINT),
++				PCMCIA_S_RDYINT_EDGE);
++
++	return_val = request_irq(PCMCIA_S_CD_VALID, init->handler, SA_INTERRUPT,
++			"PXA PCMCIA CD", NULL);
++	if (return_val < 0) {
++		return -1;
++	}
++	/* only 1 slot */
++	return 1;
++}
++
++static int trizeps2_pcmcia_shutdown(void)
++{
++	free_irq(PCMCIA_S_CD_VALID, NULL);
++
++	unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++	trizeps2_bcr_shadow |= (1 << 5); /* pcmcia buffer off */
++	*bcr = trizeps2_bcr_shadow;
++	trizeps2_bcr_shadow &= 0xFFF0; /* pcmcia control logic grounded */
++	*bcr = trizeps2_bcr_shadow;
++
++	return 0;
++}
++
++static int trizeps2_pcmcia_socket_state(struct pcmcia_state_array *state_array)
++{
++	unsigned long status;
++	int return_val = 1;
++	volatile unsigned short *stat_regs[1] = {
++	       	&TRIZEPS2_PCCARD_STATUS
++	};
++
++	if (state_array->size < 1)
++		return -1;
++
++	memset(state_array->state, 0,
++	       (state_array->size) * sizeof (struct pcmcia_state));
++	
++	status = *stat_regs[0];
++
++      	/* this one is a gpio */
++	state_array->state[0].detect = (PCC_DETECT) ? 0 : 1;
++	state_array->state[0].ready =  (PCC_READY) ? 1 : 0;
++	state_array->state[0].bvd1   = (status & PCC_BVD1) ? 1 : 0;
++	state_array->state[0].bvd2   = (status & PCC_BVD2) ? 1 : 0;
++	state_array->state[0].wrprot = 0; /* r/w all the time */
++	state_array->state[0].vs_3v  = (status & PCC_VS1) ? 0 : 1;
++	state_array->state[0].vs_Xv  = (status & PCC_VS2) ? 0 : 1;
++
++	return return_val;
++}
++
++static int trizeps2_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
++{
++	switch (info->sock) {
++	    case 0:
++		info->irq = PCMCIA_S_RDYINT;
++		break;
++
++	    default:
++		return -1;
++	}
++
++	return 0;
++}
++
++static int trizeps2_pcmcia_configure_socket(unsigned int sock, socket_state_t *state)
++{
++	unsigned short cntr_logic = trizeps2_bcr_shadow & 0xF;
++	unsigned short *bcr = (unsigned short *) TRIZEPS2_BCR_BASE;
++
++	/* configure Vcc and Vpp */
++	switch (sock) {
++	    case 0:
++		switch (state->Vcc) {
++		    case 0:
++			cntr_logic &= ~(PCC_3V | PCC_5V);
++			break;
++
++		    case 33:
++			cntr_logic &= ~(PCC_3V | PCC_5V);
++			cntr_logic |= PCC_3V;
++			break;
++
++		    case 50:
++			cntr_logic &= ~(PCC_3V | PCC_5V);
++			cntr_logic |= PCC_5V;
++			break;
++
++		    default:
++			printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
++			       __FUNCTION__, state->Vcc);
++			return -1;
++		}
++
++		switch (state->Vpp) {
++		    case 0:
++			cntr_logic &= ~(PCC_EN0 | PCC_EN1);
++			break;
++
++		    case 120:
++			cntr_logic &= ~(PCC_EN0 | PCC_EN1);
++			cntr_logic |= PCC_EN1;
++			break;
++
++		    default:
++			if (state->Vpp == state->Vcc) {
++				cntr_logic &= ~(PCC_EN0 | PCC_EN1);
++				cntr_logic |= PCC_EN0;
++			}
++			else {
++				printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
++				       __FUNCTION__, state->Vpp);
++				return -1;
++			}
++	    }
++	    trizeps2_bcr_shadow &= ~(PCC_EN0 | PCC_EN1 | PCC_3V | PCC_5V |
++			    		BCR_PCMCIA_RESET);
++	    trizeps2_bcr_shadow |= cntr_logic;
++	    *bcr = trizeps2_bcr_shadow;
++	    /* reset PCMCIA controller if requested */
++	    trizeps2_bcr_shadow |=
++	    	    (state->flags & SS_RESET) ? BCR_PCMCIA_RESET : 0;
++	    *bcr = trizeps2_bcr_shadow;
++	    udelay(500);
++	    break;
++	}
++	return 0;
++}
++
++struct pcmcia_low_level trizeps2_pcmcia_ops = { 
++  trizeps2_pcmcia_init,
++  trizeps2_pcmcia_shutdown,
++  trizeps2_pcmcia_socket_state,
++  trizeps2_pcmcia_get_irq_info,
++  trizeps2_pcmcia_configure_socket
++};
++
+--- linux-2.4.25/drivers/pcmcia/sa1100_cerf.c~2.4.25-vrs2-pxa1.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_cerf.c	2004-03-31 17:15:12.000000000 +0200
+@@ -7,15 +7,25 @@
+  */
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
++#include <linux/delay.h>
+ 
+ #include <asm/hardware.h>
+ #include <asm/irq.h>
+-#include "sa1100_generic.h"
+ 
+-#ifdef CONFIG_SA1100_CERF_CPLD
+-#define CERF_SOCKET	0
++#include <pcmcia/ss.h>
++#include <asm/arch/pcmcia.h>
++#include "sa1100_cerf.h"
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination
++ */
++//#define DEBUGGING       1
++
++#if DEBUGGING
++static unsigned int pcmcia_debug = DEBUGGING;
+ #else
+-#define CERF_SOCKET	1
++#define pcmcia_debug 0     /* gcc will remove all the debug code for us */
+ #endif
+ 
+ static struct irqs {
+@@ -23,122 +33,178 @@
+ 	unsigned int gpio;
+ 	const char *str;
+ } irqs[] = {
+-	{ IRQ_GPIO_CF_CD,   GPIO_CF_CD,   "CF_CD"   },
+-	{ IRQ_GPIO_CF_BVD2, GPIO_CF_BVD2, "CF_BVD2" },
+-	{ IRQ_GPIO_CF_BVD1, GPIO_CF_BVD1, "CF_BVD1" }
++	{ PCMCIA_IRQ_CF_CD,   PCMCIA_GPIO_CF_CD_EDGE,   "CF_CD"   },
++	{ PCMCIA_IRQ_CF_BVD2, PCMCIA_GPIO_CF_BVD2_EDGE, "CF_BVD2" },
++	{ PCMCIA_IRQ_CF_BVD1, PCMCIA_GPIO_CF_BVD1_EDGE, "CF_BVD1" }
+ };
+ 
++static void cerf_pcmcia_reset( void)
++{
++	int i;
++
++	// Make sure SKTSEL is 0 (single slot)
++	set_GPIO_mode(54 | GPIO_OUT);
++	GPCR1 = GPIO_bit(54);
++	set_GPIO_mode(GPIO54_pSKTSEL_MD);
++
++	PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK;
++	mdelay(300);
++
++	PCMCIA_GPSR = PCMCIA_GPIO_CF_RESET_MASK;
++	udelay(20);
++
++	PCMCIA_GPCR = PCMCIA_GPIO_CF_RESET_MASK;
++	mdelay(50);
++
++	for( i=0; i<10; i++)
++	{
++		if( cerf_pcmcia_level_ready()) break;
++		mdelay(100);
++	}
++}
++
+ static int cerf_pcmcia_init(struct pcmcia_init *init)
+ {
+-  int i, res;
++	int i, res;
+ 
+-  set_GPIO_IRQ_edge( GPIO_CF_IRQ, GPIO_FALLING_EDGE );
++	if( pcmcia_debug)
++		printk( KERN_INFO "cerf_pcmcia_init: enter\n");
+ 
+-  for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+-    set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+-    res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
+-		      irqs[i].str, NULL);
+-    if (res)
+-      goto irq_err;
+-  }
++	cerf_pcmcia_set_gpio_direction();
+ 
+-  return 2;
++	set_GPIO_IRQ_edge( PCMCIA_GPIO_CF_IRQ_EDGE, GPIO_FALLING_EDGE );
+ 
+- irq_err:
+-  printk(KERN_ERR "%s: Request for IRQ%d failed\n", __FUNCTION__, irqs[i].irq);
++	for (i = 0; i < ARRAY_SIZE(irqs); i++) {
+ 
+-  while (i--)
+-    free_irq(irqs[i].irq, NULL);
++		set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES);
+ 
+-  return -1;
++		res = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
++				irqs[i].str, NULL);
++		if (res)
++			goto irq_err;
++	}
++
++	printk( KERN_INFO "PCMCIA for Cerf: OK\n");
++
++	return CERF_SOCKET+1; /* last socket used +1 */
++
++irq_err:
++	printk(KERN_ERR "%s: Request for IRQ%d failed\n", 
++		__FUNCTION__, irqs[i].irq);
++
++	while (i--)
++		free_irq(irqs[i].irq, NULL);
++
++	return -1;
+ }
+ 
+ static int cerf_pcmcia_shutdown(void)
+ {
+-  int i;
++	int i;
++	if( pcmcia_debug)
++		printk( KERN_INFO "cerf_pcmcia_shutdown: enter\n");
+ 
+-  for (i = 0; i < ARRAY_SIZE(irqs); i++)
+-    free_irq(irqs[i].irq, NULL);
++	for (i = 0; i < ARRAY_SIZE(irqs); i++)
++		free_irq(irqs[i].irq, NULL);
+ 
+-  return 0;
++	return 0;
+ }
+ 
+-static int cerf_pcmcia_socket_state(struct pcmcia_state_array
+-				       *state_array){
+-  unsigned long levels;
+-  int i = CERF_SOCKET;
++static int cerf_pcmcia_socket_state(struct pcmcia_state_array *state_array)
++{
++	int i = CERF_SOCKET;
+ 
+-  if(state_array->size<2) return -1;
++	if( pcmcia_debug > 3)
++		printk( KERN_INFO "cerf_pcmcia_socket_state: i=%d, size=%d\n",
++				i, state_array->size);
+ 
+-  levels=GPLR;
++        memset(state_array->state, 0,
++                        (state_array->size)*sizeof(struct pcmcia_state));
+ 
+-  state_array->state[i].detect=((levels & GPIO_CF_CD)==0)?1:0;
+-  state_array->state[i].ready=(levels & GPIO_CF_IRQ)?1:0;
+-  state_array->state[i].bvd1=(levels & GPIO_CF_BVD1)?1:0;
+-  state_array->state[i].bvd2=(levels & GPIO_CF_BVD2)?1:0;
+-  state_array->state[i].wrprot=0;
+-  state_array->state[i].vs_3v=1;
+-  state_array->state[i].vs_Xv=0;
++	state_array->state[i].detect = cerf_pcmcia_level_detect();
++	state_array->state[i].ready  = cerf_pcmcia_level_ready();
++	state_array->state[i].bvd1   = cerf_pcmcia_level_bvd1();
++	state_array->state[i].bvd2   = cerf_pcmcia_level_bvd2();
++	state_array->state[i].wrprot=0;
++	state_array->state[i].vs_3v=1;
++	state_array->state[i].vs_Xv=0;
+ 
+-  return 1;
++	if( pcmcia_debug > 3)
++		printk( KERN_INFO "cerf_pcmcia_socket_state: "
++			"detect=%d ready=%d bvd1=%d bvd2=%d\n", 
++			state_array->state[i].detect,
++			state_array->state[i].ready,
++			state_array->state[i].bvd1,
++			state_array->state[i].bvd2);
++
++	return 1;
+ }
+ 
+ static int cerf_pcmcia_get_irq_info(struct pcmcia_irq_info *info){
+ 
+-  if(info->sock>1) return -1;
++	if( pcmcia_debug)
++		printk( KERN_INFO "cerf_pcmcia_get_irq_info: "
++				"sock=%d\n", info->sock);
+ 
+-  if (info->sock == CERF_SOCKET)
+-    info->irq=IRQ_GPIO_CF_IRQ;
++	if(info->sock>1) return -1;
+ 
+-  return 0;
++	if (info->sock == CERF_SOCKET)
++		info->irq=PCMCIA_IRQ_CF_IRQ;
++
++	if( pcmcia_debug)
++		printk( KERN_INFO "cerf_pcmcia_get_irq_info: irq=%d\n",info->irq);
++
++	return 0;
+ }
+ 
+-static int cerf_pcmcia_configure_socket(const struct pcmcia_configure
+-					   *configure)
++static int cerf_pcmcia_configure_socket( unsigned int sock, socket_state_t *state)
+ {
+-  if(configure->sock>1)
+-    return -1;
++	if( pcmcia_debug)
++		printk( KERN_INFO "cerf_pcmcia_configure_socket:"
++			"sock=%d vcc=%d flags=%x\n",
++			sock, state->Vcc, state->flags);
+ 
+-  if (configure->sock != CERF_SOCKET)
+-    return 0;
++	if(sock>1)
++		return -1;
+ 
+-  switch(configure->vcc){
+-  case 0:
+-    break;
++	if (sock != CERF_SOCKET)
++		return 0;
+ 
+-  case 50:
+-  case 33:
+-#ifdef CONFIG_SA1100_CERF_CPLD
+-     GPCR = GPIO_PWR_SHUTDOWN;
++	switch(state->Vcc){
++		case 0:
++			break;
++
++		case 50:
++		case 33:
++#if defined(CONFIG_SA1100_CERF_CPLD)
++                        PCMCIA_GPDR |= PCMCIA_PWR_SHUTDOWN;
++                        PCMCIA_GPCR |= PCMCIA_PWR_SHUTDOWN;
+ #endif
+-     break;
++                        /* voltage selected automatically */
++			break;
+ 
+-  default:
+-    printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+-	   configure->vcc);
+-    return -1;
+-  }
++		default:
++			printk(KERN_ERR "%s(): unrecognized Vcc %u\n", 
++				__FUNCTION__, state->Vcc);
++			return -1;
++	}
+ 
+-  if(configure->reset)
+-  {
+-#ifdef CONFIG_SA1100_CERF_CPLD
+-    GPSR = GPIO_CF_RESET;
+-#endif
+-  }
+-  else
+-  {
+-#ifdef CONFIG_SA1100_CERF_CPLD
+-    GPCR = GPIO_CF_RESET;
+-#endif
+-  }
++	if(state->flags&SS_RESET)
++	{
++		cerf_pcmcia_reset();
++	}
+ 
+-  return 0;
++	return 0;
+ }
+ 
++#ifdef CONFIG_SA1100_CERF
+ static int cerf_pcmcia_socket_init(int sock)
+ {
+   int i;
+ 
++  if( pcmcia_debug)
++      printk( KERN_INFO "cerf_pcmcia_socket_init: sock=%d\n",sock);
++
+   if (sock == CERF_SOCKET)
+     for (i = 0; i < ARRAY_SIZE(irqs); i++)
+       set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_BOTH_EDGES);
+@@ -150,21 +216,26 @@
+ {
+   int i;
+ 
++  if( pcmcia_debug)
++      printk( KERN_INFO "cerf_pcmcia_socket_suspend: sock=%d\n",sock);
++
+   if (sock == CERF_SOCKET)
+     for (i = 0; i < ARRAY_SIZE(irqs); i++)
+       set_GPIO_IRQ_edge(irqs[i].gpio, GPIO_NO_EDGES);
+ 
+   return 0;
+ }
++#endif
+ 
+ struct pcmcia_low_level cerf_pcmcia_ops = { 
+-  init:			cerf_pcmcia_init,
+-  shutdown:		cerf_pcmcia_shutdown,
+-  socket_state:		cerf_pcmcia_socket_state,
+-  get_irq_info:		cerf_pcmcia_get_irq_info,
+-  configure_socket:	cerf_pcmcia_configure_socket,
++init:			cerf_pcmcia_init,
++shutdown:		cerf_pcmcia_shutdown,
++socket_state:		cerf_pcmcia_socket_state,
++get_irq_info:		cerf_pcmcia_get_irq_info,
++configure_socket:	cerf_pcmcia_configure_socket,
+ 
+-  socket_init:		cerf_pcmcia_socket_init,
+-  socket_suspend:	cerf_pcmcia_socket_suspend,
++#ifdef CONFIG_SA1100_CERF
++socket_init:		cerf_pcmcia_socket_init,
++socket_suspend:		cerf_pcmcia_socket_suspend,
++#endif
+ };
+-
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_cerf.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,138 @@
++/*
++ * drivers/pcmcia/cerf.h
++ *
++ * PCMCIA implementation routines for CerfBoard
++ * Based off the Assabet.
++ *
++ */
++#ifndef _LINUX_PCMCIA_CERF_H
++#define _LINUX_PCMCIA_CERF_H
++
++#include <linux/config.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/arch/pcmcia.h>
++
++#ifdef CONFIG_PXA_CERF /* PXA */
++
++#define PCMCIA_GPCR GPCR0
++#define PCMCIA_GPSR GPSR0
++
++#define PCMCIA_GPIO_CF_CD    14
++#define PCMCIA_GPIO_CF_IRQ   13
++#define PCMCIA_GPIO_CF_RESET 12
++#ifdef CONFIG_PXA_CERF_PDA
++# define PCMCIA_GPIO_CF_BVD1  11
++# define PCMCIA_GPIO_CF_BVD2  10
++#elif defined( CONFIG_PXA_CERF_BOARD)
++# define PCMCIA_GPIO_CF_BVD1  32
++# define PCMCIA_GPIO_CF_BVD2  10
++#endif
++
++#define PCMCIA_GPIO_CF_CD_MASK    (GPIO_bit(PCMCIA_GPIO_CF_CD))
++#define PCMCIA_GPIO_CF_IRQ_MASK   (GPIO_bit(PCMCIA_GPIO_CF_IRQ))
++#define PCMCIA_GPIO_CF_RESET_MASK (GPIO_bit(PCMCIA_GPIO_CF_RESET))
++#define PCMCIA_GPIO_CF_BVD1_MASK  (GPIO_bit(PCMCIA_GPIO_CF_BVD1))
++#define PCMCIA_GPIO_CF_BVD2_MASK  (GPIO_bit(PCMCIA_GPIO_CF_BVD2))
++
++#define PCMCIA_GPIO_CF_CD_EDGE    PCMCIA_GPIO_CF_CD
++#define PCMCIA_GPIO_CF_IRQ_EDGE   PCMCIA_GPIO_CF_IRQ
++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET
++#define PCMCIA_GPIO_CF_BVD1_EDGE  PCMCIA_GPIO_CF_BVD1
++#define PCMCIA_GPIO_CF_BVD2_EDGE  PCMCIA_GPIO_CF_BVD2
++
++#define PCMCIA_IRQ_CF_CD   IRQ_GPIO(PCMCIA_GPIO_CF_CD)
++#define PCMCIA_IRQ_CF_IRQ  IRQ_GPIO(PCMCIA_GPIO_CF_IRQ)
++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO(PCMCIA_GPIO_CF_BVD1)
++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO(PCMCIA_GPIO_CF_BVD2)
++
++#define PCMCIA_PWR_SHUTDOWN 0 /* not needed */
++#define CERF_SOCKET 0
++
++inline void cerf_pcmcia_set_gpio_direction(void)
++{
++	GPDR(PCMCIA_GPIO_CF_CD)   &= ~(PCMCIA_GPIO_CF_CD_MASK);
++	GPDR(PCMCIA_GPIO_CF_BVD1) &= ~(PCMCIA_GPIO_CF_BVD1_MASK);
++	GPDR(PCMCIA_GPIO_CF_BVD2) &= ~(PCMCIA_GPIO_CF_BVD2_MASK);
++	GPDR(PCMCIA_GPIO_CF_IRQ)  &= ~(PCMCIA_GPIO_CF_IRQ_MASK);
++	GPDR(PCMCIA_GPIO_CF_RESET)|=  (PCMCIA_GPIO_CF_RESET_MASK);
++}
++
++inline int cerf_pcmcia_level_detect( void)
++{
++	return ((GPLR(PCMCIA_GPIO_CF_CD)&PCMCIA_GPIO_CF_CD_MASK)==0)?1:0;
++}
++inline int cerf_pcmcia_level_ready( void)
++{
++	return (GPLR(PCMCIA_GPIO_CF_IRQ)&PCMCIA_GPIO_CF_IRQ_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd1( void)
++{
++	return (GPLR(PCMCIA_GPIO_CF_BVD1)&PCMCIA_GPIO_CF_BVD1_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd2( void)
++{
++	return (GPLR(PCMCIA_GPIO_CF_BVD2)&PCMCIA_GPIO_CF_BVD2_MASK)?1:0;
++}
++
++#elif defined(CONFIG_SA1100_CERF) /* SA1100 */
++
++#define PCMCIA_GPDR GPDR
++#define PCMCIA_GPCR GPCR
++#define PCMCIA_GPSR GPSR
++#define PCMCIA_GPLR GPLR
++
++#define PCMCIA_GPIO_CF_CD_MASK    GPIO_CF_CD
++#define PCMCIA_GPIO_CF_IRQ_MASK   GPIO_CF_IRQ
++#define PCMCIA_GPIO_CF_RESET_MASK GPIO_CF_RESET
++#define PCMCIA_GPIO_CF_BVD1_MASK  GPIO_CF_BVD1
++#define PCMCIA_GPIO_CF_BVD2_MASK  GPIO_CF_BVD2
++
++#define PCMCIA_GPIO_CF_CD_EDGE    PCMCIA_GPIO_CF_CD_MASK
++#define PCMCIA_GPIO_CF_IRQ_EDGE   PCMCIA_GPIO_CF_IRQ_MASK
++#define PCMCIA_GPIO_CF_RESET_EDGE PCMCIA_GPIO_CF_RESET_MASK
++#define PCMCIA_GPIO_CF_BVD1_EDGE  PCMCIA_GPIO_CF_BVD1_MASK
++#define PCMCIA_GPIO_CF_BVD2_EDGE  PCMCIA_GPIO_CF_BVD2_MASK
++
++#define PCMCIA_IRQ_CF_CD   IRQ_GPIO_CF_CD
++#define PCMCIA_IRQ_CF_IRQ  IRQ_GPIO_CF_IRQ
++#define PCMCIA_IRQ_CF_BVD1 IRQ_GPIO_CF_BVD1
++#define PCMCIA_IRQ_CF_BVD2 IRQ_GPIO_CF_BVD2
++
++#define PCMCIA_PWR_SHUTDOWN GPIO_PWR_SHUTDOWN
++
++#ifdef CONFIG_SA1100_CERF_CPLD
++#define CERF_SOCKET 0
++#else
++#define CERF_SOCKET 1
++#endif
++
++inline void cerf_pcmcia_set_gpio_direction(void)
++{
++	PCMCIA_GPDR &= ~(PCMCIA_GPIO_CF_CD_MASK |
++			 PCMCIA_GPIO_CF_BVD1_MASK |
++			 PCMCIA_GPIO_CF_BVD2_MASK |
++			 PCMCIA_GPIO_CF_IRQ_MASK);
++	PCMCIA_GPDR |=   PCMCIA_GPIO_CF_RESET_MASK;
++}
++
++inline int cerf_pcmcia_level_detect( void)
++{
++	return ((PCMCIA_GPLR & PCMCIA_GPIO_CF_CD_MASK)==0)?1:0;
++}
++inline int cerf_pcmcia_level_ready( void)
++{
++	return (PCMCIA_GPLR & PCMCIA_GPIO_CF_IRQ_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd1( void)
++{
++	return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD1_MASK)?1:0;
++}
++inline int cerf_pcmcia_level_bvd2( void)
++{
++	return (PCMCIA_GPLR & PCMCIA_GPIO_CF_BVD2_MASK)?1:0;
++}
++
++#endif
++
++#endif
+--- linux-2.4.25/drivers/sound/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/sound/Config.in	2004-03-31 17:15:12.000000000 +0200
+@@ -239,6 +239,7 @@
+       dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
+    fi
+    dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER
++   dep_tristate '  Intel PXA250/210 AC97 audio' CONFIG_SOUND_PXA_AC97 $CONFIG_ARCH_PXA $CONFIG_SOUND
+ fi
+ 
+ dep_tristate '  TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C
+--- linux-2.4.25/drivers/sound/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/sound/Makefile	2004-03-31 17:15:12.000000000 +0200
+@@ -11,7 +11,7 @@
+ 		    msnd.o opl3.o sb_common.o sequencer_syms.o \
+ 		    sound_core.o sound_syms.o uart401.o	\
+ 		    nm256_audio.o ac97.o ac97_codec.o aci.o \
+-		    sa1100-audio.o
++		    sa1100-audio.o pxa-audio.o pxa-ac97.o
+ 
+ # Each configuration option enables a list of files.
+ 
+@@ -85,6 +85,7 @@
+ obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o
+ obj-$(CONFIG_SOUND_SA1111_AC97)	+= sa1111-ac97.o ac97_codec.o
+ obj-$(CONFIG_SOUND_SA1100SSP)	+= sa1100ssp.o
++obj-$(CONFIG_SOUND_PXA_AC97)+= pxa-ac97.o pxa-audio.o ac97_codec.o
+ obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
+ obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
+ obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
+--- linux-2.4.25/drivers/sound/ac97_codec.c~2.4.25-vrs2-pxa1.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/sound/ac97_codec.c	2004-03-31 17:15:12.000000000 +0200
+@@ -155,6 +155,7 @@
+ 	{0x45838308, "ESS Allegro ES1988",	&null_ops},
+ 	{0x49434511, "ICE1232",			&null_ops}, /* I hope --jk */
+ 	{0x4e534331, "National Semiconductor LM4549", &null_ops},
++	{0x50534304, "Philips UCB1400",		&default_ops},
+ 	{0x53494c22, "Silicon Laboratory Si3036", &null_ops},
+ 	{0x53494c23, "Silicon Laboratory Si3038", &null_ops},
+ 	{0x545200FF, "TriTech TR?????",		&tritech_m_ops},
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/pxa-ac97.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,370 @@
++/*
++ *  linux/drivers/sound/pxa-ac97.c -- AC97 interface for the Cotula chip
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Aug 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  AC97 GPIO Changes:-
++ *   In order to read/write codec GPIO bits using AC97 link slot 12,
++ *   all IO to AC97_GPIO_STATUS must be via the Xscale modem codec
++ *   address space. 
++ *     Liam Girdwood <liam.girdwood@wolfsonmicro.com>
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/poll.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/ac97_codec.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++#include <asm/dma.h>
++
++#include "pxa-audio.h"
++
++static struct completion CAR_completion;
++static int waitingForMask;
++static DECLARE_MUTEX(CAR_mutex);
++
++static u16 pxa_ac97_read(struct ac97_codec *codec, u8 reg)
++{
++	u16 val = -1;
++
++	down(&CAR_mutex);
++	if (!(CAR & CAR_CAIP)) {
++		volatile u32 *reg_addr;
++		
++		// if we are reading the GPIO status then this is cached 
++		// in hardware so we don't need to read over the link.		
++		if (reg == AC97_GPIO_STATUS) {
++			reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1);
++			val = *reg_addr;
++			return val;
++		} 
++		
++		reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1);
++
++		waitingForMask=GSR_SDONE;
++
++		init_completion(&CAR_completion);
++		(void)*reg_addr;			//start read access across the ac97 link
++		wait_for_completion(&CAR_completion);
++
++		if (GSR & GSR_RDCS) {
++			GSR |= GSR_RDCS;		//write a 1 to clear
++			printk(KERN_CRIT __FUNCTION__": read codec register timeout.\n");
++		}
++
++		init_completion(&CAR_completion);
++		val = *reg_addr;			//valid data now but we've just started another cycle...
++		wait_for_completion(&CAR_completion);
++
++	} else {
++		printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n");
++	}
++	up(&CAR_mutex);
++	//printk("%s(0x%02x) = 0x%04x\n", __FUNCTION__, reg, val);
++	return val;
++}
++
++static void pxa_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
++{
++	down(&CAR_mutex);
++	if (!(CAR & CAR_CAIP)) {
++		volatile u32 *reg_addr;
++		
++		// if we are writing to the codec GPIO using slot 12 
++		// then we have to write to the modem register space		
++		if (reg == AC97_GPIO_STATUS) {
++			reg_addr = (u32 *)&PMC_REG_BASE + (reg >> 1);
++			*reg_addr = val;
++			return;
++		} 
++		
++		reg_addr = (u32 *)&PAC_REG_BASE + (reg >> 1);
++
++		waitingForMask=GSR_CDONE;
++		init_completion(&CAR_completion);
++		*reg_addr = val;
++		wait_for_completion(&CAR_completion);
++	} else {
++		printk(KERN_CRIT __FUNCTION__": CAR_CAIP already set\n");
++	}
++	up(&CAR_mutex);
++	//printk("%s(0x%02x, 0x%04x)\n", __FUNCTION__, reg, val);
++}
++
++static void pxa_ac97_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++	int gsr = GSR;
++	GSR = gsr & (GSR_SDONE|GSR_CDONE);		//write a 1 to clear
++	if (gsr & waitingForMask)
++	{
++		complete(&CAR_completion);
++	}
++}
++
++static struct ac97_codec pxa_ac97_codec = {
++	codec_read:	pxa_ac97_read,
++	codec_write:	pxa_ac97_write,
++};
++
++static DECLARE_MUTEX(pxa_ac97_mutex);
++static int pxa_ac97_refcount;
++
++int pxa_ac97_get(struct ac97_codec **codec)
++{
++	int ret;
++
++	*codec = NULL;
++	down(&pxa_ac97_mutex);
++
++	if (!pxa_ac97_refcount) {
++		ret = request_irq(IRQ_AC97, pxa_ac97_irq, 0, "AC97", NULL);
++		if (ret)
++			return ret;
++
++		CKEN |= CKEN2_AC97; 
++		set_GPIO_mode(GPIO31_SYNC_AC97_MD);
++		set_GPIO_mode(GPIO30_SDATA_OUT_AC97_MD);
++		set_GPIO_mode(GPIO28_BITCLK_AC97_MD);
++		set_GPIO_mode(GPIO29_SDATA_IN_AC97_MD);
++
++		GCR = 0;
++		udelay(10);
++		GCR = GCR_COLD_RST|GCR_CDONE_IE|GCR_SDONE_IE;
++		while (!(GSR & GSR_PCR)) {
++			schedule();
++		}
++
++		ret = ac97_probe_codec(&pxa_ac97_codec);
++		if (ret != 1) {
++			free_irq(IRQ_AC97, NULL);
++			GCR = GCR_ACLINK_OFF;
++			CKEN &= ~CKEN2_AC97; 
++			return ret;
++		}
++
++		// need little hack for UCB1400 (should be moved elsewhere)
++		pxa_ac97_write(&pxa_ac97_codec,AC97_EXTENDED_STATUS,1);
++		//pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x1ff7);
++		pxa_ac97_write(&pxa_ac97_codec, 0x6a, 0x0050);
++		pxa_ac97_write(&pxa_ac97_codec, 0x6c, 0x0030);
++	}
++
++	pxa_ac97_refcount++;
++	up(&pxa_ac97_mutex);
++	*codec = &pxa_ac97_codec;
++	return 0;
++}
++
++void pxa_ac97_put(void)
++{
++	down(&pxa_ac97_mutex);
++	pxa_ac97_refcount--;
++	if (!pxa_ac97_refcount) {
++		GCR = GCR_ACLINK_OFF;
++		CKEN &= ~CKEN2_AC97; 
++		free_irq(IRQ_AC97, NULL);
++	}
++	up(&pxa_ac97_mutex);
++}
++
++EXPORT_SYMBOL(pxa_ac97_get);
++EXPORT_SYMBOL(pxa_ac97_put);
++
++
++/*
++ * Audio Mixer stuff
++ */
++
++static audio_state_t ac97_audio_state;
++static audio_stream_t ac97_audio_in;
++
++static int mixer_ioctl( struct inode *inode, struct file *file,
++			unsigned int cmd, unsigned long arg)
++{
++	int ret, val;
++
++	ret = pxa_ac97_codec.mixer_ioctl(&pxa_ac97_codec, cmd, arg);
++	if (ret)
++		return ret;
++
++	/* We must snoop for some commands to provide our own extra processing */
++	switch (cmd) {
++	case SOUND_MIXER_WRITE_RECSRC:
++		/*
++		 * According to the PXA250 spec, mic-in should use different
++		 * DRCMR and different AC97 FIFO.
++		 * Unfortunately current UCB1400 versions (up to ver 2A) don't
++		 * produce slot 6 for the audio input frame, therefore the PXA
++		 * AC97 mic-in FIFO is always starved.
++		 */
++#if 0
++		ret = get_user(val, (int *)arg);
++		if (ret)
++			return ret;
++		pxa_audio_clear_buf(&ac97_audio_in);
++		*ac97_audio_in.drcmr = 0;
++		if (val & (1 << SOUND_MIXER_MIC)) {
++			ac97_audio_in.dcmd = DCMD_RXMCDR;
++			ac97_audio_in.drcmr = &DRCMRRXMCDR;
++			ac97_audio_in.dev_addr = __PREG(MCDR);
++		} else {
++			ac97_audio_in.dcmd = DCMD_RXPCDR;
++			ac97_audio_in.drcmr = &DRCMRRXPCDR;
++			ac97_audio_in.dev_addr = __PREG(PCDR);
++		}
++		if (ac97_audio_state.rd_ref)
++			*ac97_audio_in.drcmr =
++				ac97_audio_in.dma_ch | DRCMR_MAPVLD;
++#endif
++		break;
++	}
++	return 0;
++}
++
++static struct file_operations mixer_fops = {
++	ioctl:		mixer_ioctl,
++	llseek:		no_llseek,
++	owner:		THIS_MODULE
++};
++
++/*
++ * AC97 codec ioctls
++ */
++
++static int codec_adc_rate = 48000;
++static int codec_dac_rate = 48000;
++
++static int ac97_ioctl(struct inode *inode, struct file *file,
++		      unsigned int cmd, unsigned long arg)
++{
++	int ret;
++	long val;
++
++	switch(cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *) arg);
++		if (ret)
++			return ret;
++		/* FIXME: do we support mono? */
++		ret = (val == 0) ? -EINVAL : 1;
++		return put_user(ret, (int *) arg);
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		/* FIXME: do we support mono? */
++		return put_user(2, (long *) arg);
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (long *) arg);
++		if (ret)
++			return ret;
++		if (file->f_mode & FMODE_READ)
++			codec_adc_rate = ac97_set_adc_rate(&pxa_ac97_codec, val);
++		if (file->f_mode & FMODE_WRITE)
++			codec_dac_rate = ac97_set_dac_rate(&pxa_ac97_codec, val);
++		/* fall through */
++
++	case SOUND_PCM_READ_RATE:
++		if (file->f_mode & FMODE_READ)
++			val = codec_adc_rate;
++		if (file->f_mode & FMODE_WRITE)
++			val = codec_dac_rate;
++		return put_user(val, (long *) arg);
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		/* FIXME: can we do other fmts? */
++		return put_user(AFMT_S16_LE, (long *) arg);
++
++	default:
++		/* Maybe this is meant for the mixer (As per OSS Docs) */
++		return mixer_ioctl(inode, file, cmd, arg);
++	}
++	return 0;
++}
++
++
++/*
++ * Audio stuff
++ */
++
++static audio_stream_t ac97_audio_out = {
++	name:			"AC97 audio out",
++	dcmd:			DCMD_TXPCDR,
++	drcmr:			&DRCMRTXPCDR,
++	dev_addr:		__PREG(PCDR),
++};
++
++static audio_stream_t ac97_audio_in = {
++	name:			"AC97 audio in",
++	dcmd:			DCMD_RXPCDR,
++	drcmr:			&DRCMRRXPCDR,
++	dev_addr:		__PREG(PCDR),
++};
++
++static audio_state_t ac97_audio_state = {
++	output_stream:		&ac97_audio_out,
++	input_stream:		&ac97_audio_in,
++	client_ioctl:		ac97_ioctl,
++	sem:			__MUTEX_INITIALIZER(ac97_audio_state.sem),
++};
++
++static int ac97_audio_open(struct inode *inode, struct file *file)
++{
++	return pxa_audio_attach(inode, file, &ac97_audio_state);
++}
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to pxa_audio_attach().
++ */
++
++static struct file_operations ac97_audio_fops = {
++	open:		ac97_audio_open,
++	owner:		THIS_MODULE
++};
++
++
++static int __init pxa_ac97_init(void)
++{
++	int ret;
++	struct ac97_codec *dummy;
++
++	ret = pxa_ac97_get(&dummy);
++	if (ret)
++		return ret;
++
++	ac97_audio_state.dev_dsp = register_sound_dsp(&ac97_audio_fops, -1);
++	pxa_ac97_codec.dev_mixer = register_sound_mixer(&mixer_fops, -1);
++
++	return 0;
++}
++
++static void __exit pxa_ac97_exit(void)
++{
++	unregister_sound_dsp(ac97_audio_state.dev_dsp);
++	unregister_sound_mixer(pxa_ac97_codec.dev_mixer);
++	pxa_ac97_put();
++}
++
++
++module_init(pxa_ac97_init);
++module_exit(pxa_ac97_exit);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/pxa-audio.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,853 @@
++/*
++ *  linux/drivers/sound/pxa-audio.c -- audio interface for the Cotula chip
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Aug 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/poll.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/semaphore.h>
++#include <asm/dma.h>
++
++#include "pxa-audio.h"
++
++
++#define AUDIO_NBFRAGS_DEFAULT	8
++#define AUDIO_FRAGSIZE_DEFAULT	8192
++
++#define MAX_DMA_SIZE		4096
++#define DMA_DESC_SIZE		sizeof(pxa_dma_desc)
++
++
++/*
++ * This function frees all buffers
++ */
++#define audio_clear_buf pxa_audio_clear_buf
++
++void pxa_audio_clear_buf(audio_stream_t * s)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	int frag;
++
++	if (!s->buffers)
++		return;
++
++	/* Ensure DMA isn't running */
++	set_current_state(TASK_UNINTERRUPTIBLE);
++	add_wait_queue(&s->stop_wq, &wait);
++	DCSR(s->dma_ch) = DCSR_STOPIRQEN;
++	schedule();
++	remove_wait_queue(&s->stop_wq, &wait);
++
++	/* free DMA buffers */
++	for (frag = 0; frag < s->nbfrags; frag++) {
++		audio_buf_t *b = &s->buffers[frag];
++		if (!b->master)
++			continue;
++		consistent_free(b->data, b->master, b->dma_desc->dsadr);
++	}
++
++	/* free descriptor ring */
++	if (s->buffers->dma_desc)
++		consistent_free(s->buffers->dma_desc, 
++				s->nbfrags * s->descs_per_frag * DMA_DESC_SIZE,
++				s->dma_desc_phys);
++
++	/* free buffer structure array */
++	kfree(s->buffers);
++	s->buffers = NULL;
++}
++
++/*
++ * This function allocates the DMA descriptor array and buffer data space
++ * according to the current number of fragments and fragment size.
++ */
++static int audio_setup_buf(audio_stream_t * s)
++{
++	pxa_dma_desc *dma_desc;
++	dma_addr_t dma_desc_phys;
++	int nb_desc, frag, i, buf_size = 0;
++	char *dma_buf = NULL;
++	dma_addr_t dma_buf_phys = 0;
++
++	if (s->buffers)
++		return -EBUSY;
++
++	/* Our buffer structure array */
++	s->buffers = kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
++	if (!s->buffers)
++		goto err;
++	memzero(s->buffers, sizeof(audio_buf_t) * s->nbfrags);
++
++	/* 
++	 * Our DMA descriptor array:
++	 * for Each fragment we have one checkpoint descriptor plus one 
++	 * descriptor per MAX_DMA_SIZE byte data blocks.
++	 */
++	nb_desc = (1 + (s->fragsize + MAX_DMA_SIZE - 1)/MAX_DMA_SIZE) * s->nbfrags;
++	dma_desc = consistent_alloc(GFP_KERNEL,
++				    nb_desc * DMA_DESC_SIZE,
++				    &dma_desc_phys,
++				    0);
++	if (!dma_desc)
++		goto err;
++	s->descs_per_frag = nb_desc / s->nbfrags;
++	s->buffers->dma_desc = dma_desc;
++	s->dma_desc_phys = dma_desc_phys;
++	for (i = 0; i < nb_desc - 1; i++)
++		dma_desc[i].ddadr = dma_desc_phys + (i + 1) * DMA_DESC_SIZE;
++	dma_desc[i].ddadr = dma_desc_phys;
++
++	/* Our actual DMA buffers */
++	for (frag = 0; frag < s->nbfrags; frag++) {
++		audio_buf_t *b = &s->buffers[frag];
++
++		/*
++		 * Let's allocate non-cached memory for DMA buffers.
++		 * We try to allocate all memory at once.
++		 * If this fails (a common reason is memory fragmentation),
++		 * then we'll try allocating smaller buffers.
++		 */
++		if (!buf_size) {
++			buf_size = (s->nbfrags - frag) * s->fragsize;
++			do {
++				dma_buf = consistent_alloc(GFP_KERNEL,
++							   buf_size, 
++							   &dma_buf_phys,
++							   0);
++				if (!dma_buf)
++					buf_size -= s->fragsize;
++			} while (!dma_buf && buf_size);
++			if (!dma_buf)
++				goto err;
++			b->master = buf_size;
++			memzero(dma_buf, buf_size);
++		}
++
++		/* 
++		 * Set up our checkpoint descriptor.  Since the count 
++		 * is always zero, we'll abuse the dsadr and dtadr fields
++		 * just in case this one is picked up by the hardware
++		 * while processing SOUND_DSP_GETPTR.
++		 */
++		dma_desc->dsadr = dma_buf_phys;
++		dma_desc->dtadr = dma_buf_phys;
++		dma_desc->dcmd = DCMD_ENDIRQEN;
++		if (s->output && !s->mapped)
++			dma_desc->ddadr |= DDADR_STOP;
++		b->dma_desc = dma_desc++;
++
++		/* set up the actual data descriptors */
++		for (i = 0; (i * MAX_DMA_SIZE) < s->fragsize; i++) {
++			dma_desc[i].dsadr = (s->output) ?
++				(dma_buf_phys + i*MAX_DMA_SIZE) : s->dev_addr;
++			dma_desc[i].dtadr = (s->output) ?
++				s->dev_addr : (dma_buf_phys + i*MAX_DMA_SIZE);
++			dma_desc[i].dcmd = s->dcmd |
++				((s->fragsize < MAX_DMA_SIZE) ?
++					s->fragsize : MAX_DMA_SIZE);
++		}
++		dma_desc += i;
++
++		/* handle buffer pointers */
++		b->data = dma_buf;
++		dma_buf += s->fragsize;
++		dma_buf_phys += s->fragsize;
++		buf_size -= s->fragsize;
++	}
++
++	s->usr_frag = s->dma_frag = 0;
++	s->bytecount = 0;
++	s->fragcount = 0;
++	sema_init(&s->sem, (s->output) ? s->nbfrags : 0);
++	return 0;
++
++err:
++	printk("pxa-audio: unable to allocate audio memory\n ");
++	audio_clear_buf(s);
++	return -ENOMEM;
++}
++
++/*
++ * Our DMA interrupt handler
++ */
++static void audio_dma_irq(int ch, void *dev_id, struct pt_regs *regs)
++{
++	audio_stream_t *s = dev_id;
++	u_int dcsr;
++
++	dcsr = DCSR(ch);
++	DCSR(ch) = dcsr & ~DCSR_STOPIRQEN;
++
++	if (!s->buffers) {
++		printk("AC97 DMA: wow... received IRQ for channel %d but no buffer exists\n", ch);
++		return;
++	}
++
++	if (dcsr & DCSR_BUSERR)
++		printk("AC97 DMA: bus error interrupt on channel %d\n", ch);
++
++	if (dcsr & DCSR_ENDINTR) {
++		u_long cur_dma_desc;
++		u_int cur_dma_frag;
++
++		/* 
++		 * Find out which DMA desc is current.  Note that DDADR
++		 * points to the next desc, not the current one.
++		 */
++		cur_dma_desc = DDADR(ch) - s->dma_desc_phys - DMA_DESC_SIZE;
++
++		/*
++		 * Let the compiler nicely optimize constant divisors into
++		 * multiplications for the common cases which is much faster.
++		 * Common cases: x = 1 + (1 << y) for y = [0..3]
++		 */
++		switch (s->descs_per_frag) {
++		case 2:  cur_dma_frag = cur_dma_desc / (2*DMA_DESC_SIZE); break;
++		case 3:  cur_dma_frag = cur_dma_desc / (3*DMA_DESC_SIZE); break;
++		case 5:  cur_dma_frag = cur_dma_desc / (5*DMA_DESC_SIZE); break;
++		case 9:  cur_dma_frag = cur_dma_desc / (9*DMA_DESC_SIZE); break;
++		default: cur_dma_frag =
++			    cur_dma_desc / (s->descs_per_frag * DMA_DESC_SIZE);
++		}
++
++		/* Account for possible wrap back of cur_dma_desc above */
++		if (cur_dma_frag >= s->nbfrags)
++			cur_dma_frag = s->nbfrags - 1;
++
++		while (s->dma_frag != cur_dma_frag) {
++			if (!s->mapped) {
++				/* 
++				 * This fragment is done - set the checkpoint
++				 * descriptor to STOP until it is gets
++				 * processed by the read or write function.
++				 */
++				s->buffers[s->dma_frag].dma_desc->ddadr |= DDADR_STOP;
++				up(&s->sem);
++			}
++			if (++s->dma_frag >= s->nbfrags)
++				s->dma_frag = 0;
++
++			/* Accounting */
++			s->bytecount += s->fragsize;
++			s->fragcount++;
++		}
++
++		/* ... and for polling processes */
++		wake_up(&s->frag_wq);
++	}
++
++	if ((dcsr & DCSR_STOPIRQEN) && (dcsr & DCSR_STOPSTATE))
++		wake_up(&s->stop_wq);
++}
++
++/*
++ * Validate and sets up buffer fragments, etc.
++ */
++static int audio_set_fragments(audio_stream_t *s, int val)
++{
++	if (s->mapped || DCSR(s->dma_ch) & DCSR_RUN)
++		return -EBUSY;
++	if (s->buffers)
++		audio_clear_buf(s);
++	s->nbfrags = (val >> 16) & 0x7FFF;
++	val &= 0xffff;
++	if (val < 5)
++		val = 5;
++	if (val > 15)
++		val = 15;
++	s->fragsize = 1 << val;
++	if (s->nbfrags < 2)
++		s->nbfrags = 2;
++	if (s->nbfrags * s->fragsize > 256 * 1024)
++		s->nbfrags = 256 * 1024 / s->fragsize;
++	if (audio_setup_buf(s))
++		return -ENOMEM;
++	return val|(s->nbfrags << 16);
++}
++
++
++/*
++ * The fops functions
++ */
++
++static int audio_write(struct file *file, const char *buffer,
++		       size_t count, loff_t * ppos)
++{
++	const char *buffer0 = buffer;
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	audio_stream_t *s = state->output_stream;
++	int chunksize, ret = 0;
++
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++	if (s->mapped)
++		return -ENXIO;
++	if (!s->buffers && audio_setup_buf(s))
++		return -ENOMEM;
++
++	while (count > 0) {
++		audio_buf_t *b = &s->buffers[s->usr_frag];
++
++		/* Grab a fragment */
++		if (file->f_flags & O_NONBLOCK) {
++			ret = -EAGAIN;
++			if (down_trylock(&s->sem))
++				break;
++		} else {
++			ret = -ERESTARTSYS;
++			if (down_interruptible(&s->sem))
++				break;
++		}
++
++		/* Feed the current buffer */
++		chunksize = s->fragsize - b->offset;
++		if (chunksize > count)
++			chunksize = count;
++		if (copy_from_user(b->data + b->offset, buffer, chunksize)) {
++			up(&s->sem);
++			return -EFAULT;
++		}
++		b->offset += chunksize;
++		buffer += chunksize;
++		count -= chunksize;
++		if (b->offset < s->fragsize) {
++			up(&s->sem);
++			break;
++		}
++
++		/* 
++		 * Activate DMA on current buffer.
++		 * We unlock this fragment's checkpoint descriptor and
++		 * kick DMA if it is idle.  Using checkpoint descriptors
++		 * allows for control operations without the need for 
++		 * stopping the DMA channel if it is already running.
++		 */
++		b->offset = 0;
++		b->dma_desc->ddadr &= ~DDADR_STOP;
++		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
++			DDADR(s->dma_ch) = b->dma_desc->ddadr;
++			DCSR(s->dma_ch) = DCSR_RUN;
++		}
++
++		/* move the index to the next fragment */
++		if (++s->usr_frag >= s->nbfrags)
++			s->usr_frag = 0;
++	}
++
++	if ((buffer - buffer0))
++		ret = buffer - buffer0;
++	return ret;
++}
++
++
++static int audio_read(struct file *file, char *buffer,
++		      size_t count, loff_t * ppos)
++{
++	char *buffer0 = buffer;
++	audio_state_t *state = file->private_data;
++	audio_stream_t *s = state->input_stream;
++	int chunksize, ret = 0;
++
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++	if (s->mapped)
++		return -ENXIO;
++	if (!s->buffers && audio_setup_buf(s))
++		return -ENOMEM;
++
++	while (count > 0) {
++		audio_buf_t *b = &s->buffers[s->usr_frag];
++
++		/* prime DMA */
++		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
++			DDADR(s->dma_ch) = 
++				s->buffers[s->dma_frag].dma_desc->ddadr;
++			DCSR(s->dma_ch) = DCSR_RUN;
++		}
++
++		/* Wait for a buffer to become full */
++		if (file->f_flags & O_NONBLOCK) {
++			ret = -EAGAIN;
++			if (down_trylock(&s->sem))
++				break;
++		} else {
++			ret = -ERESTARTSYS;
++			if (down_interruptible(&s->sem))
++				break;
++		}
++
++		/* Grab data from current buffer */
++		chunksize = s->fragsize - b->offset;
++		if (chunksize > count)
++			chunksize = count;
++		if (copy_to_user(buffer, b->data + b->offset, chunksize)) {
++			up(&s->sem);
++			return -EFAULT;
++		}
++		b->offset += chunksize;
++		buffer += chunksize;
++		count -= chunksize;
++		if (b->offset < s->fragsize) {
++			up(&s->sem);
++			break;
++		}
++
++		/* 
++		 * Make this buffer available for DMA again.
++		 * We unlock this fragment's checkpoint descriptor and
++		 * kick DMA if it is idle.  Using checkpoint descriptors
++		 * allows for control operations without the need for 
++		 * stopping the DMA channel if it is already running.
++		 */
++		b->offset = 0;
++		b->dma_desc->ddadr &= ~DDADR_STOP;
++
++		/* move the index to the next fragment */
++		if (++s->usr_frag >= s->nbfrags)
++			s->usr_frag = 0;
++	}
++
++	if ((buffer - buffer0))
++		ret = buffer - buffer0;
++	return ret;
++}
++
++
++static int audio_sync(struct file *file)
++{
++	audio_state_t *state = file->private_data;
++	audio_stream_t *s = state->output_stream;
++	audio_buf_t *b;
++	pxa_dma_desc *final_desc;
++	u_long dcmd_save = 0;
++	DECLARE_WAITQUEUE(wait, current);
++
++	if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped)
++		return 0;
++
++	/*
++	 * Send current buffer if it contains data.  Be sure to send
++	 * a full sample count.
++	 */
++	final_desc = NULL;
++	b = &s->buffers[s->usr_frag];
++	if (b->offset &= ~3) {
++		final_desc = &b->dma_desc[1 + b->offset/MAX_DMA_SIZE];
++		b->offset &= (MAX_DMA_SIZE-1);
++		dcmd_save = final_desc->dcmd;
++		final_desc->dcmd = b->offset | s->dcmd | DCMD_ENDIRQEN; 
++		final_desc->ddadr |= DDADR_STOP;
++		b->offset = 0;
++		b->dma_desc->ddadr &= ~DDADR_STOP;
++		if (DCSR(s->dma_ch) & DCSR_STOPSTATE) {
++			DDADR(s->dma_ch) = b->dma_desc->ddadr;
++			DCSR(s->dma_ch) = DCSR_RUN;
++		}
++	}
++
++	/* Wait for DMA to complete. */
++	set_current_state(TASK_INTERRUPTIBLE);
++#if 0
++	/* 
++	 * The STOPSTATE IRQ never seem to occur if DCSR_STOPIRQEN is set
++	 * along wotj DCSR_RUN.  Silicon bug?
++	 */
++	add_wait_queue(&s->stop_wq, &wait);
++	DCSR(s->dma_ch) |= DCSR_STOPIRQEN;
++	schedule();
++#else 
++	add_wait_queue(&s->frag_wq, &wait);
++	while ((DCSR(s->dma_ch) & DCSR_RUN) && !signal_pending(current)) {
++		schedule();
++		set_current_state(TASK_INTERRUPTIBLE);
++	}
++#endif
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&s->frag_wq, &wait);
++
++	/* Restore the descriptor chain. */
++	if (final_desc) {
++		final_desc->dcmd = dcmd_save;
++		final_desc->ddadr &= ~DDADR_STOP;
++		b->dma_desc->ddadr |= DDADR_STOP;
++	}
++	return 0;
++}
++
++
++static unsigned int audio_poll(struct file *file,
++			       struct poll_table_struct *wait)
++{
++	audio_state_t *state = file->private_data;
++	audio_stream_t *is = state->input_stream;
++	audio_stream_t *os = state->output_stream;
++	unsigned int mask = 0;
++
++	if (file->f_mode & FMODE_READ) {
++		/* Start audio input if not already active */
++		if (!is->buffers && audio_setup_buf(is))
++			return -ENOMEM;
++		if (DCSR(is->dma_ch) & DCSR_STOPSTATE) {
++			DDADR(is->dma_ch) = 
++				is->buffers[is->dma_frag].dma_desc->ddadr;
++			DCSR(is->dma_ch) = DCSR_RUN;
++		}
++		poll_wait(file, &is->frag_wq, wait);
++	}
++
++	if (file->f_mode & FMODE_WRITE) {
++		if (!os->buffers && audio_setup_buf(os))
++			return -ENOMEM;
++		poll_wait(file, &os->frag_wq, wait);
++	}
++
++	if (file->f_mode & FMODE_READ)
++		if (( is->mapped && is->bytecount > 0) ||
++		    (!is->mapped && atomic_read(&is->sem.count) > 0))
++			mask |= POLLIN | POLLRDNORM;
++
++	if (file->f_mode & FMODE_WRITE)
++		if (( os->mapped && os->bytecount > 0) ||
++		    (!os->mapped && atomic_read(&os->sem.count) > 0))
++			mask |= POLLOUT | POLLWRNORM;
++
++	return mask;
++}
++
++
++static int audio_ioctl( struct inode *inode, struct file *file,
++			uint cmd, ulong arg)
++{
++	audio_state_t *state = file->private_data;
++	audio_stream_t *os = state->output_stream;
++	audio_stream_t *is = state->input_stream;
++	long val;
++
++	switch (cmd) {
++	case OSS_GETVERSION:
++		return put_user(SOUND_VERSION, (int *)arg);
++
++	case SNDCTL_DSP_GETBLKSIZE:
++		if (file->f_mode & FMODE_WRITE)
++			return put_user(os->fragsize, (int *)arg);
++		else
++			return put_user(is->fragsize, (int *)arg);
++
++	case SNDCTL_DSP_GETCAPS:
++		val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;
++		if (is && os)
++			val |= DSP_CAP_DUPLEX;
++		return put_user(val, (int *)arg);
++
++	case SNDCTL_DSP_SETFRAGMENT:
++		if (get_user(val, (long *) arg))
++			return -EFAULT;
++		if (file->f_mode & FMODE_READ) {
++			int ret = audio_set_fragments(is, val);
++			if (ret < 0)
++				return ret;
++			ret = put_user(ret, (int *)arg);
++			if (ret)
++				return ret;
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			int ret = audio_set_fragments(os, val);
++			if (ret < 0)
++				return ret;
++			ret = put_user(ret, (int *)arg);
++			if (ret)
++				return ret;
++		}
++		return 0;
++
++	case SNDCTL_DSP_SYNC:
++		return audio_sync(file);
++
++	case SNDCTL_DSP_SETDUPLEX:
++		return 0;
++
++	case SNDCTL_DSP_POST:
++		return 0;
++
++	case SNDCTL_DSP_GETTRIGGER:
++		val = 0;
++		if (file->f_mode & FMODE_READ && DCSR(is->dma_ch) & DCSR_RUN)
++			val |= PCM_ENABLE_INPUT;
++		if (file->f_mode & FMODE_WRITE && DCSR(os->dma_ch) & DCSR_RUN)
++			val |= PCM_ENABLE_OUTPUT;
++		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) {
++				if (!is->buffers && audio_setup_buf(is))
++					return -ENOMEM;
++				if (!(DCSR(is->dma_ch) & DCSR_RUN)) {
++					audio_buf_t *b = &is->buffers[is->dma_frag];
++					DDADR(is->dma_ch) = b->dma_desc->ddadr;
++					DCSR(is->dma_ch) = DCSR_RUN;
++				}
++			} else {
++				DCSR(is->dma_ch) = 0;
++			}
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			if (val & PCM_ENABLE_OUTPUT) {
++				if (!os->buffers && audio_setup_buf(os))
++					return -ENOMEM;
++				if (!(DCSR(os->dma_ch) & DCSR_RUN)) {
++					audio_buf_t *b = &os->buffers[os->dma_frag];
++					DDADR(os->dma_ch) = b->dma_desc->ddadr;
++					DCSR(os->dma_ch) = DCSR_RUN;
++				}
++			} else {
++				DCSR(os->dma_ch) = 0;
++			}
++		}
++		return 0;
++
++	case SNDCTL_DSP_GETOSPACE:
++	case SNDCTL_DSP_GETISPACE:
++	    {
++		audio_buf_info inf = { 0, };
++		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;
++
++		if ((s == is && !(file->f_mode & FMODE_READ)) ||
++		    (s == os && !(file->f_mode & FMODE_WRITE)))
++			return -EINVAL;
++		if (!s->buffers && audio_setup_buf(s))
++			return -ENOMEM;
++		inf.bytes = atomic_read(&s->sem.count) * s->fragsize;
++		inf.bytes -= s->buffers[s->usr_frag].offset;
++		inf.fragments = inf.bytes / s->fragsize;
++		inf.fragsize = s->fragsize;
++		inf.fragstotal = s->nbfrags;
++		return copy_to_user((void *)arg, &inf, sizeof(inf));
++	    }
++
++	case SNDCTL_DSP_GETOPTR:
++	case SNDCTL_DSP_GETIPTR:
++	    {
++		count_info inf = { 0, };
++		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
++		dma_addr_t ptr;
++		int bytecount, offset, flags;
++
++		if ((s == is && !(file->f_mode & FMODE_READ)) ||
++		    (s == os && !(file->f_mode & FMODE_WRITE)))
++			return -EINVAL;
++		if (DCSR(s->dma_ch) & DCSR_RUN) {
++			audio_buf_t *b;
++			save_flags_cli(flags);
++			ptr = (s->output) ? DSADR(s->dma_ch) : DTADR(s->dma_ch);
++			b = &s->buffers[s->dma_frag];
++			offset = ptr - b->dma_desc->dsadr;
++			if (offset >= s->fragsize)
++				offset = s->fragsize - 4;
++		} else {
++			save_flags(flags);
++			offset = 0;
++		}
++		inf.ptr = s->dma_frag * s->fragsize + offset;
++		bytecount = s->bytecount + offset;
++		s->bytecount = -offset;
++		inf.blocks = s->fragcount;
++		s->fragcount = 0;
++		restore_flags(flags);
++		if (bytecount < 0)
++			bytecount = 0;
++		inf.bytes = bytecount;
++		return copy_to_user((void *)arg, &inf, sizeof(inf));
++	    }
++
++	case SNDCTL_DSP_NONBLOCK:
++		file->f_flags |= O_NONBLOCK;
++		return 0;
++
++	case SNDCTL_DSP_RESET:
++		if (file->f_mode & FMODE_WRITE) 
++			audio_clear_buf(os);
++		if (file->f_mode & FMODE_READ)
++			audio_clear_buf(is);
++		return 0;
++
++	default:
++		return state->client_ioctl(inode, file, cmd, arg);
++	}
++
++	return 0;
++}
++
++
++static int audio_mmap(struct file *file, struct vm_area_struct *vma)
++{
++	audio_state_t *state = file->private_data;
++	audio_stream_t *s;
++	unsigned long size, vma_addr;
++	int i, ret;
++
++	if (vma->vm_pgoff != 0)
++		return -EINVAL;
++
++	if (vma->vm_flags & VM_WRITE) {
++		if (!state->wr_ref)
++			return -EINVAL;;
++		s = state->output_stream;
++	} else if (vma->vm_flags & VM_READ) {
++		if (!state->rd_ref)
++			return -EINVAL;
++		s = state->input_stream;
++	} else return -EINVAL;
++
++	if (s->mapped)
++		return -EINVAL;
++	size = vma->vm_end - vma->vm_start;
++	if (size != s->fragsize * s->nbfrags)
++		return -EINVAL;
++	if (!s->buffers && audio_setup_buf(s))
++		return -ENOMEM;
++	vma_addr = vma->vm_start;
++	for (i = 0; i < s->nbfrags; i++) {
++		audio_buf_t *buf = &s->buffers[i];
++		if (!buf->master)
++			continue;
++		ret = remap_page_range(vma_addr, buf->dma_desc->dsadr,
++				       buf->master, vma->vm_page_prot);
++		if (ret)
++			return ret;
++		vma_addr += buf->master;
++	}
++	for (i = 0; i < s->nbfrags; i++)
++		s->buffers[i].dma_desc->ddadr &= ~DDADR_STOP;
++	s->mapped = 1;
++	return 0;
++}
++
++
++static int audio_release(struct inode *inode, struct file *file)
++{
++	audio_state_t *state = file->private_data;
++
++	down(&state->sem);
++
++	if (file->f_mode & FMODE_READ) {
++		audio_clear_buf(state->input_stream);
++		*state->input_stream->drcmr = 0;
++		pxa_free_dma(state->input_stream->dma_ch);
++		state->rd_ref = 0;
++	}
++
++	if (file->f_mode & FMODE_WRITE) {
++		audio_sync(file);
++		audio_clear_buf(state->output_stream);
++		*state->output_stream->drcmr = 0;
++		pxa_free_dma(state->output_stream->dma_ch);
++		state->wr_ref = 0;
++	}
++
++	up(&state->sem);
++	return 0;
++}
++
++
++int pxa_audio_attach(struct inode *inode, struct file *file,
++			 audio_state_t *state)
++{
++	audio_stream_t *is = state->input_stream;
++	audio_stream_t *os = state->output_stream;
++	int err;
++
++	down(&state->sem);
++
++	/* access control */
++	err = -ENODEV;
++	if ((file->f_mode & FMODE_WRITE) && !os)
++		goto out;
++	if ((file->f_mode & FMODE_READ) && !is)
++		goto out;
++	err = -EBUSY;
++	if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
++		goto out;
++	if ((file->f_mode & FMODE_READ) && state->rd_ref)
++		goto out;
++
++	/* request DMA channels */
++	if (file->f_mode & FMODE_WRITE) {
++		err = pxa_request_dma(os->name, DMA_PRIO_LOW, 
++					  audio_dma_irq, os);
++		if (err < 0)
++			goto out;
++		os->dma_ch = err;
++	}
++	if (file->f_mode & FMODE_READ) {
++		err = pxa_request_dma(is->name, DMA_PRIO_LOW,
++					  audio_dma_irq, is);
++		if (err < 0) {
++			if (file->f_mode & FMODE_WRITE) {
++				*os->drcmr = 0;
++				pxa_free_dma(os->dma_ch);
++			}
++			goto out;
++		}
++		is->dma_ch = err;
++	}
++
++	file->private_data	= state;
++	file->f_op->release	= audio_release;
++	file->f_op->write	= audio_write;
++	file->f_op->read	= audio_read;
++	file->f_op->mmap	= audio_mmap;
++	file->f_op->poll	= audio_poll;
++	file->f_op->ioctl	= audio_ioctl;
++	file->f_op->llseek	= no_llseek;
++
++	if ((file->f_mode & FMODE_WRITE)) {
++		state->wr_ref = 1;
++		os->fragsize = AUDIO_FRAGSIZE_DEFAULT;
++		os->nbfrags = AUDIO_NBFRAGS_DEFAULT;
++		os->output = 1;
++		os->mapped = 0;
++		init_waitqueue_head(&os->frag_wq);
++		init_waitqueue_head(&os->stop_wq);
++		*os->drcmr = os->dma_ch | DRCMR_MAPVLD;
++	}
++	if (file->f_mode & FMODE_READ) {
++		state->rd_ref = 1;
++		is->fragsize = AUDIO_FRAGSIZE_DEFAULT;
++		is->nbfrags = AUDIO_NBFRAGS_DEFAULT;
++		is->output = 0;
++		is->mapped = 0;
++		init_waitqueue_head(&is->frag_wq);
++		init_waitqueue_head(&is->stop_wq);
++		*is->drcmr = is->dma_ch | DRCMR_MAPVLD;
++	}
++
++	err = 0;
++
++out:
++	up(&state->sem);
++	return err;
++}
++
++EXPORT_SYMBOL(pxa_audio_attach);
++EXPORT_SYMBOL(pxa_audio_clear_buf);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/pxa-audio.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,55 @@
++/*
++ *  linux/drivers/sound/pxa-audio.h -- audio interface for the Cotula chip
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Aug 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++typedef struct {
++	int offset;			/* current buffer position */
++	char *data; 	           	/* actual buffer */
++	pxa_dma_desc *dma_desc;	/* pointer to the starting desc */
++	int master;             	/* owner for buffer allocation, contain size whn true */
++} audio_buf_t;
++
++typedef struct {
++	char *name;			/* stream identifier */
++	audio_buf_t *buffers;   	/* pointer to audio buffer array */
++	u_int usr_frag;			/* user fragment index */
++	u_int dma_frag;			/* DMA fragment index */
++	u_int fragsize;			/* fragment size */
++	u_int nbfrags;			/* number of fragments */
++	u_int dma_ch;			/* DMA channel number */
++	dma_addr_t dma_desc_phys;	/* phys addr of descriptor ring */
++	u_int descs_per_frag;		/* nbr descriptors per fragment */
++	int bytecount;			/* nbr of processed bytes */
++	int fragcount;			/* nbr of fragment transitions */
++	struct semaphore sem;		/* account for fragment usage */
++	wait_queue_head_t frag_wq;	/* for poll(), etc. */
++	wait_queue_head_t stop_wq;	/* for users of DCSR_STOPIRQEN */
++	u_long dcmd;			/* DMA descriptor dcmd field */
++	volatile u32 *drcmr;		/* the DMA request channel to use */
++	u_long dev_addr;		/* device physical address for DMA */
++	int mapped:1;			/* mmap()'ed buffers */
++	int output:1;			/* 0 for input, 1 for output */
++} audio_stream_t;
++	
++typedef struct {
++	audio_stream_t *output_stream;
++	audio_stream_t *input_stream;
++	int dev_dsp;			/* audio device handle */
++	int rd_ref:1;           /* open reference for recording */
++	int wr_ref:1;           /* open reference for playback */
++	int (*client_ioctl)(struct inode *, struct file *, uint, ulong);
++	struct semaphore sem;		/* prevent races in attach/release */
++} audio_state_t;
++
++extern int pxa_audio_attach(struct inode *inode, struct file *file,
++				audio_state_t *state);
++extern void pxa_audio_clear_buf(audio_stream_t *s);
++
+--- linux-2.4.25/drivers/sound/sa1100-audio.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/sound/sa1100-audio.c	2004-03-31 17:15:12.000000000 +0200
+@@ -148,7 +148,8 @@
+ 			do {
+ 			  	dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA,
+ 							  dmasize,
+-							  &dmaphys);
++							  &dmaphys,
++							  0);
+ 				if (!dmabuf)
+ 					dmasize -= s->fragsize;
+ 			} while (!dmabuf && dmasize);
+--- linux-2.4.25/drivers/video/Config.in~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/video/Config.in	2004-03-31 17:15:12.000000000 +0200
+@@ -50,6 +50,15 @@
+      if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF_CPLD" = "y" ]; then
+        bool 'Cerfboard Backlight (CerfPDA)' CONFIG_SA1100_CERF_LCD_BACKLIGHT
+      fi
++     tristate '  PXA LCD support' CONFIG_FB_PXA $CONFIG_ARCH_PXA
++     if [ "$CONFIG_FB_PXA" != "n" ]; then
++        choice 'LCD Bit Depth' \
++               "8-Bpp          CONFIG_FB_PXA_8BPP \
++                16-Bpp         CONFIG_FB_PXA_16BPP" Bit-Depth
++     fi
++     if [ "$CONFIG_FB_PXA" != "n" -a "$CONFIG_ARCH_LUBBOCK" = "y" ]; then
++	bool '  Lubbock QVGA LCD support instead of DSTN' CONFIG_FB_PXA_QVGA
++     fi
+    fi
+    dep_tristate '  CyberPro 2000/2010/5000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI
+    if [ "$CONFIG_APOLLO" = "y" ]; then
+@@ -295,7 +304,7 @@
+       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+ 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ 	   "$CONFIG_FB_TX3912" = "y"  -o "$CONFIG_FB_CLPS711X" = "y" -o \
+-           "$CONFIG_FB_DBMX1" = "y" ]; then
++           "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then
+ 	 define_tristate CONFIG_FBCON_CFB2 y
+ 	 define_tristate CONFIG_FBCON_CFB4 y
+       else
+@@ -329,7 +338,7 @@
+ 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+ 	   "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \
+ 	   "$CONFIG_FB_INTEL" = "y" -o \
+-           "$CONFIG_FB_DBMX1" = "y" ]; then
++           "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PXA" = "y" ]; then
+ 	 define_tristate CONFIG_FBCON_CFB8 y
+       else
+ 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
+@@ -372,7 +381,7 @@
+ 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
+ 	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+ 	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \
+-	   "$CONFIG_FB_ANAKIN" = "y" -o \
++	   "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_PXA" = "y" -o \
+            "$CONFIG_FB_DBMX1" = "y" ]; then
+ 	 define_tristate CONFIG_FBCON_CFB16 y
+       else
+--- linux-2.4.25/drivers/video/Makefile~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/video/Makefile	2004-03-31 17:15:12.000000000 +0200
+@@ -14,7 +14,7 @@
+ 		  fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
+ 		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
+ 		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
+-		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
++		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o pxafb.o \
+ 		  cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o
+ 
+ # Each configuration option enables a list of files.
+@@ -129,6 +129,10 @@
+ obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
+ obj-$(CONFIG_FB_HGA)              += hgafb.o
+ obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
++obj-$(CONFIG_FB_PXA)              += pxafb.o
++ifeq ($(CONFIG_PXA_CERF_PDA),y)
++   obj-$(CONFIG_FB_PXA)           += lcdctrl.o lcdctrl_cerf.o
++endif
+ obj-$(CONFIG_FB_DBMX1)            += dbmx1fb.o
+ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
+ obj-$(CONFIG_FB_HIT)              += hitfb.o fbgen.o
+--- linux-2.4.25/drivers/video/fbmem.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/video/fbmem.c	2004-03-31 17:15:12.000000000 +0200
+@@ -109,6 +109,7 @@
+ extern int chips_init(void);
+ extern int g364fb_init(void);
+ extern int sa1100fb_init(void);
++extern int pxafb_init(void);
+ extern int fm2fb_init(void);
+ extern int fm2fb_setup(char*);
+ extern int q40fb_init(void);
+@@ -305,6 +306,9 @@
+ #ifdef CONFIG_FB_SA1100
+ 	{ "sa1100", sa1100fb_init, NULL },
+ #endif
++#ifdef CONFIG_FB_PXA
++	{ "pxa", pxafb_init, NULL },
++#endif
+ #ifdef CONFIG_FB_SUN3
+ 	{ "sun3", sun3fb_init, sun3fb_setup },
+ #endif
+@@ -675,13 +679,13 @@
+ #elif defined(__i386__) || defined(__x86_64__)
+ 	if (boot_cpu_data.x86 > 3)
+ 		pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+-#elif defined(__arm__) || defined(__mips__)
++#elif defined(__mips__)
+ 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ #elif defined(__sh__)
+ 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
+ #elif defined(__hppa__)
+ 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+-#elif defined(__ia64__)
++#elif defined(__ia64__) || defined(__arm__)
+ 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ #elif defined(__hppa__)
+ 	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/lcdctrl.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,223 @@
++/*
++ *  lcdctrl.c
++ *
++ *  Generic LCD control for brightness, contrast, etc.
++ *  Device specific drivers implement a lcdctrl_device and
++ *  provides access to it via lcdctrl_device_get_ops().
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Mar 2002: Initial version [FB]
++ * 
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++
++#include <video/lcdctrl.h>
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING       0
++
++#if DEBUGGING
++static unsigned int lcd_debug = DEBUGGING;
++#else
++#define lcd_debug 	0
++#endif
++
++/* -- prototypes -- */
++
++static int lcdctrl_ioctl(struct inode * inode, struct file *filp,
++			 unsigned int cmd , unsigned long arg);
++static int lcdctrl_open(struct inode *inode, struct file *filp);
++static int lcdctrl_close(struct inode *inode, struct file *filp);
++
++/* -- variables -- */
++
++struct lcdctrl_device *lcd_device;
++
++static int intensity;
++static int brightness;
++static int contrast;
++
++static int enabled;
++static int sync_needed;
++static int chrdev_major;
++
++static struct file_operations lcdctrl_fops = {
++	ioctl:		lcdctrl_ioctl,
++	open:		lcdctrl_open,
++	release:	lcdctrl_close
++};
++
++/* -- ioctl -- */
++
++static int lcdctrl_ioctl(struct inode * inode, struct file *filp,
++                         unsigned int cmd , unsigned long arg)
++{
++	int ret;
++	ret = -EINVAL;
++
++	if( lcd_debug)
++	    printk(KERN_INFO "lcdctrl_ioctl: cmd=%d, arg=%ld\n", cmd, arg);
++
++	switch(cmd)
++	{
++		case _LCDCTRL_IOCTL_ON:
++			ret = lcdctrl_enable();
++			break;
++		case _LCDCTRL_IOCTL_OFF:
++			ret = lcdctrl_disable();  
++			break;
++		case _LCDCTRL_IOCTL_INTENSITY:
++			if ((arg >=0) && (arg <= 100))
++				ret = lcdctrl_set_intensity(arg);
++			break;
++		case _LCDCTRL_IOCTL_BRIGHTNESS:
++			if ((arg >=0) && (arg <= 100))
++				ret = lcdctrl_set_brightness(arg);
++			break;
++		case _LCDCTRL_IOCTL_CONTRAST:
++			if ((arg >=0) && (arg <= 100))
++				ret = lcdctrl_set_contrast(arg, LCD_NO_SYNC);
++			break;  
++		case _LCDCTRL_IOCTL_GET_BRIGHTNESS:
++			ret = brightness;
++			break;
++		case _LCDCTRL_IOCTL_GET_CONTRAST:
++			ret = contrast;
++			break;
++		case _LCDCTRL_IOCTL_GET_INTENSITY:
++			ret = intensity;
++			break;
++
++		default:
++			printk(KERN_ERR "lcdctrl_ioctl: invalid ioctl\n");
++			break;
++	}
++
++	return ret;
++}
++
++static int lcdctrl_open(struct inode *inode, struct file *filp)
++{
++//	MOD_INC_USE_COUNT;
++	return 0;
++}
++
++static int lcdctrl_close(struct inode *inode, struct file *filp)
++{
++//	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++/* -- -- */
++
++int lcdctrl_enable( void)
++{
++	int result;
++
++	if( enabled) return 0;
++
++	result = lcd_device->enable();
++
++	lcdctrl_set_intensity( intensity);
++	lcdctrl_set_brightness( brightness);
++	lcdctrl_set_contrast( contrast, sync_needed);
++        sync_needed = LCD_NO_SYNC;
++
++	enabled = 1;
++	return result;
++}
++
++int lcdctrl_disable( void)
++{
++	enabled = 0;
++	return lcd_device->disable();
++}
++
++int lcdctrl_set_intensity( int i)
++{
++	intensity = i;
++	return lcd_device->set_intensity( i);
++}
++
++int lcdctrl_set_brightness( int b)
++{
++	brightness = b;
++	return lcd_device->set_brightness( b);
++}
++
++int lcdctrl_set_contrast( int c, int sync)
++{
++	contrast = c;
++	return lcd_device->set_contrast( c, sync);
++}
++
++int lcdctrl_get_intensity( void)
++{
++	return intensity;
++}
++
++int lcdctrl_get_brightness( void)
++{
++	return brightness;
++}
++
++int lcdctrl_get_contrast( void)
++{
++	return contrast;
++}
++
++/* -- -- */
++
++/* the device specific driver should implement this */
++struct lcdctrl_device *lcdctrl_device_get_ops(void);
++
++int lcdctrl_init( void)
++{
++	int ret;
++
++	lcd_device = lcdctrl_device_get_ops();
++
++	if( !lcd_device)
++	{
++		printk(KERN_ERR "lcdctrl_init: No lcd_device registered.\n");
++		return -EINVAL;
++	}
++
++	ret = lcd_device->init( &intensity, &brightness, &contrast);
++
++        sync_needed = LCD_SYNC_NEEDED;
++
++	if( ret == 0)
++	{
++		chrdev_major = 
++			register_chrdev( 0,_LCD_CONTROL_NAME,&lcdctrl_fops);
++		if( lcd_debug)
++			printk(KERN_INFO "lcdctrl_init: OK\n");
++	}
++	return ret;
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/lcdctrl_cerf.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,175 @@
++/*
++ *  lcdctrl_cerf.c
++ *
++ *  Cerf LCD control for brightness and contrast.
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Mar 2002: Initial version [FB]
++ * 
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/arch/cerf_ucb1400gpio.h>
++
++#include <video/lcdctrl.h>
++
++/*
++ * Set this to zero to remove all the debug statements via
++ * dead code elimination.
++ */
++#define DEBUGGING       0
++
++#if DEBUGGING
++static unsigned int lcd_debug = DEBUGGING;
++#else
++#define lcd_debug       0
++#endif
++
++#define LCD_MAX_INTENSITY	 0
++#define LCD_MAX_BRIGHTNESS	15
++#define LCD_MAX_CONTRAST	100
++
++#define LCD_DEFAULT_INTENSITY	 0
++#define LCD_DEFAULT_BRIGHTNESS	14*100/(LCD_MAX_BRIGHTNESS)
++#define LCD_DEFAULT_CONTRAST	90*100/(LCD_MAX_CONTRAST)
++
++#define UP	1
++#define DOWN	0
++
++/* -- prototypes -- */
++
++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast);
++static int cerf_lcdctrl_enable(void);
++static int cerf_lcdctrl_disable(void);
++static int cerf_lcdctrl_set_intensity( int i);
++static int cerf_lcdctrl_set_brightness( int b);
++static int cerf_lcdctrl_set_contrast( int c, int sync);
++
++static void cerf_lcdctrl_contrast_step( int direction);
++
++/* -- variables -- */
++
++static int dev_contrast;
++
++/* -- -- */
++
++static struct lcdctrl_device cerf_dev = {
++	init: 		cerf_lcdctrl_init,
++	enable:		cerf_lcdctrl_enable,
++	disable:	cerf_lcdctrl_disable,
++	set_intensity:	cerf_lcdctrl_set_intensity,
++	set_brightness:	cerf_lcdctrl_set_brightness,
++	set_contrast:	cerf_lcdctrl_set_contrast
++}; 
++
++static int cerf_lcdctrl_enable( void)
++{
++	cerf_ucb1400gpio_lcd_enable();
++
++	return 0;
++}
++
++static int cerf_lcdctrl_disable( void)
++{
++	cerf_ucb1400gpio_lcd_disable();
++
++	return 0;
++}
++
++static int cerf_lcdctrl_set_intensity( int i)
++{
++	int dev_intensity = LCD_MAX_INTENSITY*i/100;
++	if( lcd_debug)
++		printk(KERN_INFO "cerf_lcdctrl_set_intensity: "
++			"dev_intensity = %d\n", dev_intensity);
++	return 0;
++}
++
++static int cerf_lcdctrl_set_brightness( int b)
++{
++	int dev_brightness = LCD_MAX_BRIGHTNESS*b/100;
++	outw( dev_brightness, CERF_PDA_CPLD+CERF_PDA_CPLD_BRIGHTNESS);
++	if( lcd_debug)
++		printk(KERN_INFO "cerf_lcdctrl_set_brightness: "
++			"dev_brightness = %d\n", dev_brightness);
++	return 0;
++}
++
++static int cerf_lcdctrl_set_contrast( int c, int sync)
++{
++	int new_dev_contrast = LCD_MAX_CONTRAST*c/100;
++	int i;
++	int count;
++	int direction = UP;
++	if( sync == LCD_SYNC_NEEDED)
++	{
++		/* In order to sync we step down to the lowest contrast level */
++		for( i=0; i<LCD_MAX_CONTRAST; i++)
++			cerf_lcdctrl_contrast_step(DOWN);
++		dev_contrast = 0;
++	}
++
++	count = new_dev_contrast - dev_contrast;
++	if( count < 0)
++	{
++		/* new contrast is lower then current setting */
++		direction = DOWN;
++		count = -count;
++	}
++
++	for( i=0; i<count; i++)
++		cerf_lcdctrl_contrast_step(direction);
++
++	if( lcd_debug)
++		printk(KERN_INFO "cerf_lcdctrl_set_contrast: "
++			"dev_contrast = %d\n", new_dev_contrast);
++	dev_contrast = new_dev_contrast;
++
++	return 0;
++}
++
++/* -- -- */
++
++static void cerf_lcdctrl_contrast_step( int direction)
++{
++	cerf_ucb1400gpio_lcd_contrast_step( direction);
++}
++
++/* -- -- */
++
++static int cerf_lcdctrl_init( int *intensity, int *brightness, int *contrast)
++{
++	*intensity = LCD_DEFAULT_INTENSITY;
++	*brightness = LCD_DEFAULT_BRIGHTNESS;
++	*contrast = LCD_DEFAULT_CONTRAST;
++
++	if( lcd_debug)
++		printk(KERN_INFO "cerf_lcdctrl_init: OK\n");
++	return 0;
++}
++
++/* this is the hook for lcdctrl to access to the device specifics */
++struct lcdctrl_device *lcdctrl_device_get_ops(void)
++{
++	return &cerf_dev;
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/pxafb.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,1410 @@
++/*
++ *  linux/drivers/video/pxafb.c
++ *
++ *  Copyright (C) 1999 Eric A. Thomas
++ *   Based on acornfb.c Copyright (C) Russell King.
++ *
++ * 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.
++ *
++ *	        Intel PXA250/210 LCD Controller Frame Buffer Driver
++ *
++ * Please direct your questions and comments on this driver to the following
++ * email address:
++ *
++ *	linux-arm-kernel@lists.arm.linux.org.uk
++ *
++ *
++ * Code Status:
++ *
++ * 2001/08/03: <cbrake@accelent.com>
++ *      - Ported from SA1100 to PXA250
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/fb.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/init.h>
++#include <linux/notifier.h>
++#include <linux/cpufreq.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/uaccess.h>
++
++#include <video/fbcon.h>
++#include <video/fbcon-mfb.h>
++#include <video/fbcon-cfb4.h>
++#include <video/fbcon-cfb8.h>
++#include <video/fbcon-cfb16.h>
++#include <video/lcdctrl.h> /* brightness, contrast, etc. control */
++
++/*
++ * debugging?
++ */
++#define DEBUG 0
++/*
++ * Complain if VAR is out of range.
++ */
++#define DEBUG_VAR 1
++
++#undef ASSABET_PAL_VIDEO
++
++#include "pxafb.h"
++
++void (*pxafb_blank_helper)(int blank);
++EXPORT_SYMBOL(pxafb_blank_helper);
++
++/*
++ * IMHO this looks wrong.  In 8BPP, length should be 8.
++ */
++static struct pxafb_rgb rgb_8 = {
++	red:	{ offset: 0,  length: 4, },
++	green:	{ offset: 0,  length: 4, },
++	blue:	{ offset: 0,  length: 4, },
++	transp:	{ offset: 0,  length: 0, },
++};
++
++static struct pxafb_rgb def_rgb_16 = {
++	red:	{ offset: 11, length: 5, },
++	green:	{ offset: 5,  length: 6, },
++	blue:	{ offset: 0,  length: 5, },
++	transp:	{ offset: 0,  length: 0, },
++};
++
++static struct pxafb_mach_info pxa_fb_info __initdata = {
++	pixclock:	LCD_PIXCLOCK,	/* clock period in ps */
++	bpp:		LCD_BPP,
++	xres:		LCD_XRES,
++	yres:		LCD_YRES,
++	hsync_len:	LCD_HORIZONTAL_SYNC_PULSE_WIDTH,
++	vsync_len:	LCD_VERTICAL_SYNC_PULSE_WIDTH,
++	left_margin:	LCD_BEGIN_OF_LINE_WAIT_COUNT,
++	upper_margin:	LCD_BEGIN_FRAME_WAIT_COUNT,
++	right_margin:	LCD_END_OF_LINE_WAIT_COUNT,
++	lower_margin:	LCD_END_OF_FRAME_WAIT_COUNT,
++	sync:		LCD_SYNC,
++	lccr0:		LCD_LCCR0,
++	lccr3:		LCD_LCCR3
++};
++
++static struct pxafb_mach_info * __init
++pxafb_get_machine_info(struct pxafb_info *fbi)
++{
++	return &pxa_fb_info;
++}
++
++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
++
++static inline void pxafb_schedule_task(struct pxafb_info *fbi, u_int state)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++	/*
++	 * We need to handle two requests being made at the same time.
++	 * There are two important cases:
++	 *  1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
++	 *     We must perform the unblanking, which will do our REENABLE for us.
++	 *  2. When we are blanking, but immediately unblank before we have
++	 *     blanked.  We do the "REENABLE" thing here as well, just to be sure.
++	 */
++	if (fbi->task_state == C_ENABLE && state == C_REENABLE)
++		state = (u_int) -1;
++	if (fbi->task_state == C_DISABLE && state == C_ENABLE)
++		state = C_REENABLE;
++
++	if (state != (u_int)-1) {
++		fbi->task_state = state;
++		schedule_task(&fbi->task);
++	}
++	local_irq_restore(flags);
++}
++
++/*
++ * Get the VAR structure pointer for the specified console
++ */
++static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var;
++}
++
++/*
++ * Get the DISPLAY structure pointer for the specified console
++ */
++static inline struct display *get_con_display(struct fb_info *info, int con)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	return (con < 0) ? fbi->fb.disp : &fb_display[con];
++}
++
++/*
++ * Get the CMAP pointer for the specified console
++ */
++static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap;
++}
++
++static inline u_int
++chan_to_field(u_int chan, struct fb_bitfield *bf)
++{
++	chan &= 0xffff;
++	chan >>= 16 - bf->length;
++	return chan << bf->offset;
++}
++
++static int
++pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
++		       u_int trans, struct fb_info *info)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	u_int val, ret = 1;
++
++	if (regno < fbi->palette_size) {
++		val = ((red >> 0) & 0xf800);
++		val |= ((green >> 5) & 0x07e0);
++		val |= ((blue >> 11) & 0x001f);
++
++		fbi->palette_cpu[regno] = val;
++		ret = 0;
++	}
++	return ret;
++}
++
++static int
++pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++		   u_int trans, struct fb_info *info)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	u_int val;
++	int ret = 1;
++
++	/*
++	 * If greyscale is true, then we convert the RGB value
++	 * to greyscale no mater what visual we are using.
++	 */
++	if (fbi->fb.var.grayscale)
++		red = green = blue = (19595 * red + 38470 * green +
++					7471 * blue) >> 16;
++
++	switch (fbi->fb.disp->visual) {
++	case FB_VISUAL_TRUECOLOR:
++	case FB_VISUAL_DIRECTCOLOR:
++		/*
++		 * 12 or 16-bit True Colour.  We encode the RGB value
++		 * according to the RGB bitfield information.
++		 */
++		if (regno <= 16) {
++			u16 *pal = fbi->fb.pseudo_palette;
++
++			val  = chan_to_field(red, &fbi->fb.var.red);
++			val |= chan_to_field(green, &fbi->fb.var.green);
++			val |= chan_to_field(blue, &fbi->fb.var.blue);
++
++			pal[regno] = val;
++			ret = 0;
++		}
++		break;
++
++	case FB_VISUAL_PSEUDOCOLOR:
++		ret = pxafb_setpalettereg(regno, red, green, blue, trans, info);
++		break;
++	}
++
++	return ret;
++}
++
++/*
++ *  pxafb_decode_var():
++ *    Get the video params out of 'var'. If a value doesn't fit, round it up,
++ *    if it's too big, return -EINVAL.
++ *
++ *    Suggestion: Round up in the following order: bits_per_pixel, xres,
++ *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
++ *    bitfields, horizontal timing, vertical timing.
++ */
++static int pxafb_validate_var(struct fb_var_screeninfo *var,
++				 struct pxafb_info *fbi)
++{
++	int ret = -EINVAL;
++
++	if (var->xres < MIN_XRES)
++		var->xres = MIN_XRES;
++	if (var->yres < MIN_YRES)
++		var->yres = MIN_YRES;
++	if (var->xres > fbi->max_xres)
++		var->xres = fbi->max_xres;
++	if (var->yres > fbi->max_yres)
++		var->yres = fbi->max_yres;
++	var->xres_virtual =
++	    var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
++	var->yres_virtual =
++	    var->yres_virtual < var->yres ? var->yres : var->yres_virtual;
++
++	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
++	switch (var->bits_per_pixel) {
++#ifdef FBCON_HAS_CFB4
++	case 4:  ret = 0; break;
++#endif
++#ifdef FBCON_HAS_CFB8
++	case 8:  ret = 0; break;
++#endif
++#ifdef FBCON_HAS_CFB16
++	case 12:
++		/* make sure we are in passive mode */
++		if (!(fbi->lccr0 & LCCR0_PAS))
++			ret = 0;
++		break;
++
++	case 16:
++		/* 
++		 * 16 bits works apparemtly fine in passive mode for those,
++		 * so don't complain
++		 */
++		if (machine_is_lubbock() ||
++		    machine_is_pxa_cerf()) {
++			ret = 0;
++		} else
++			/* make sure we are in active mode */
++			if ((fbi->lccr0 & LCCR0_PAS))
++				ret = 0;
++		break;
++#endif
++	default:
++		break;
++	}
++
++	return ret;
++}
++
++static inline void pxafb_set_truecolor(u_int is_true_color)
++{
++	DPRINTK("true_color = %d\n", is_true_color);
++}
++
++static void
++pxafb_hw_set_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
++{
++
++	fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, &fbi->fb);
++
++	/* Set board control register to handle new color depth */
++	pxafb_set_truecolor(var->bits_per_pixel >= 16);
++
++	pxafb_activate_var(var, fbi);
++
++}
++
++/*
++ * pxafb_set_var():
++ *	Set the user defined part of the display for the specified console
++ */
++static int
++pxafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
++	struct display *display = get_con_display(&fbi->fb, con);
++	int err, chgvar = 0, rgbidx;
++
++	DPRINTK("set_var\n");
++
++	/*
++	 * Decode var contents into a par structure, adjusting any
++	 * out of range values.
++	 */
++	err = pxafb_validate_var(var, fbi);
++	if (err)
++		return err;
++
++	if (var->activate & FB_ACTIVATE_TEST)
++		return 0;
++
++	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
++		return -EINVAL;
++
++	if (dvar->xres != var->xres)
++		chgvar = 1;
++	if (dvar->yres != var->yres)
++		chgvar = 1;
++	if (dvar->xres_virtual != var->xres_virtual)
++		chgvar = 1;
++	if (dvar->yres_virtual != var->yres_virtual)
++		chgvar = 1;
++	if (dvar->bits_per_pixel != var->bits_per_pixel)
++		chgvar = 1;
++	if (con < 0)
++		chgvar = 0;
++
++	switch (var->bits_per_pixel) {
++#ifdef FBCON_HAS_CFB4
++	case 4:
++		if (fbi->cmap_static)
++			display->visual	= FB_VISUAL_STATIC_PSEUDOCOLOR;
++		else
++			display->visual	= FB_VISUAL_PSEUDOCOLOR;
++		display->line_length	= var->xres / 2;
++		display->dispsw		= &fbcon_cfb4;
++		rgbidx			= RGB_8;
++		break;
++#endif
++#ifdef FBCON_HAS_CFB8
++	case 8:
++		if (fbi->cmap_static)
++			display->visual	= FB_VISUAL_STATIC_PSEUDOCOLOR;
++		else
++			display->visual	= FB_VISUAL_PSEUDOCOLOR;
++		display->line_length	= var->xres;
++		display->dispsw		= &fbcon_cfb8;
++		rgbidx			= RGB_8;
++		break;
++#endif
++#ifdef FBCON_HAS_CFB16
++	case 12:
++	case 16:
++		display->visual		= FB_VISUAL_TRUECOLOR;
++		display->line_length	= var->xres * 2;
++		display->dispsw		= &fbcon_cfb16;
++		display->dispsw_data	= fbi->fb.pseudo_palette;
++		rgbidx			= RGB_16;
++		break;
++#endif
++	default:
++		rgbidx = 0;
++		display->dispsw = &fbcon_dummy;
++		break;
++	}
++
++	display->screen_base	= fbi->screen_cpu;
++	display->next_line	= display->line_length;
++	display->type		= fbi->fb.fix.type;
++	display->type_aux	= fbi->fb.fix.type_aux;
++	display->ypanstep	= fbi->fb.fix.ypanstep;
++	display->ywrapstep	= fbi->fb.fix.ywrapstep;
++	display->can_soft_blank	= 1;
++	display->inverse	= 0;
++
++	*dvar			= *var;
++	dvar->activate		&= ~FB_ACTIVATE_ALL;
++
++	/*
++	 * Copy the RGB parameters for this display
++	 * from the machine specific parameters.
++	 */
++	dvar->red		= fbi->rgb[rgbidx]->red;
++	dvar->green		= fbi->rgb[rgbidx]->green;
++	dvar->blue		= fbi->rgb[rgbidx]->blue;
++	dvar->transp		= fbi->rgb[rgbidx]->transp;
++
++	DPRINTK("RGBT length = %d:%d:%d:%d\n",
++		dvar->red.length, dvar->green.length, dvar->blue.length,
++		dvar->transp.length);
++
++	DPRINTK("RGBT offset = %d:%d:%d:%d\n",
++		dvar->red.offset, dvar->green.offset, dvar->blue.offset,
++		dvar->transp.offset);
++
++	/*
++	 * Update the old var.  The fbcon drivers still use this.
++	 * Once they are using fbi->fb.var, this can be dropped.
++	 */
++	display->var = *dvar;
++
++	/*
++	 * If we are setting all the virtual consoles, also set the
++	 * defaults used to create new consoles.
++	 */
++	if (var->activate & FB_ACTIVATE_ALL)
++		fbi->fb.disp->var = *dvar;
++
++	/*
++	 * If the console has changed and the console has defined
++	 * a changevar function, call that function.
++	 */
++	if (chgvar && info && fbi->fb.changevar)
++		fbi->fb.changevar(con);
++
++	/* If the current console is selected, activate the new var. */
++	if (con != fbi->currcon)
++		return 0;
++
++	pxafb_hw_set_var(dvar, fbi);
++
++	return 0;
++}
++
++static int
++__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
++	      struct fb_info *info)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	struct fb_cmap *dcmap = get_con_cmap(info, con);
++	int err = 0;
++
++	if (con == -1)
++		con = fbi->currcon;
++
++	/* no colormap allocated? (we always have "this" colour map allocated) */
++	if (con >= 0)
++		err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
++
++	if (!err && con == fbi->currcon)
++		err = fb_set_cmap(cmap, kspc, pxafb_setcolreg, info);
++
++	if (!err)
++		fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
++
++	return err;
++}
++
++static int
++pxafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
++		  struct fb_info *info)
++{
++	struct display *disp = get_con_display(info, con);
++
++	if (disp->visual == FB_VISUAL_TRUECOLOR)
++		return -EINVAL;
++
++	return __do_set_cmap(cmap, kspc, con, info);
++}
++
++static int
++pxafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
++{
++	struct display *display = get_con_display(info, con);
++
++	*fix = info->fix;
++
++	fix->line_length = display->line_length;
++	fix->visual	 = display->visual;
++	return 0;
++}
++
++static int
++pxafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++	*var = *get_con_var(info, con);
++	return 0;
++}
++
++static int
++pxafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
++{
++	struct fb_cmap *dcmap = get_con_cmap(info, con);
++	fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
++	return 0;
++}
++
++static struct fb_ops pxafb_ops = {
++	owner:		THIS_MODULE,
++	fb_get_fix:	pxafb_get_fix,
++	fb_get_var:	pxafb_get_var,
++	fb_set_var:	pxafb_set_var,
++	fb_get_cmap:	pxafb_get_cmap,
++	fb_set_cmap:	pxafb_set_cmap,
++};
++
++/*
++ *  pxafb_switch():       
++ *	Change to the specified console.  Palette and video mode
++ *      are changed to the console's stored parameters.
++ *
++ *	Uh oh, this can be called from a tasklet (IRQ)
++ */
++static int pxafb_switch(int con, struct fb_info *info)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	struct display *disp;
++	struct fb_cmap *cmap;
++
++	DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
++
++	if (con == fbi->currcon)
++		return 0;
++
++	if (fbi->currcon >= 0) {
++		disp = fb_display + fbi->currcon;
++
++		/*
++		 * Save the old colormap and video mode.
++		 */
++		disp->var = fbi->fb.var;
++
++		if (disp->cmap.len)
++			fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
++	}
++
++	fbi->currcon = con;
++	disp = fb_display + con;
++
++	/*
++	 * Make sure that our colourmap contains 256 entries.
++	 */
++	fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
++
++	if (disp->cmap.len)
++		cmap = &disp->cmap;
++	else
++		cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
++
++	fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
++
++	fbi->fb.var = disp->var;
++	fbi->fb.var.activate = FB_ACTIVATE_NOW;
++
++	pxafb_set_var(&fbi->fb.var, con, info);
++	return 0;
++}
++
++/*
++ * Formal definition of the VESA spec:
++ *  On
++ *  	This refers to the state of the display when it is in full operation
++ *  Stand-By
++ *  	This defines an optional operating state of minimal power reduction with
++ *  	the shortest recovery time
++ *  Suspend
++ *  	This refers to a level of power management in which substantial power
++ *  	reduction is achieved by the display.  The display can have a longer 
++ *  	recovery time from this state than from the Stand-by state
++ *  Off
++ *  	This indicates that the display is consuming the lowest level of power
++ *  	and is non-operational. Recovery from this state may optionally require
++ *  	the user to manually power on the monitor
++ *
++ *  Now, the fbdev driver adds an additional state, (blank), where they
++ *  turn off the video (maybe by colormap tricks), but don't mess with the
++ *  video itself: think of it semantically between on and Stand-By.
++ *
++ *  So here's what we should do in our fbdev blank routine:
++ *
++ *  	VESA_NO_BLANKING (mode 0)	Video on,  front/back light on
++ *  	VESA_VSYNC_SUSPEND (mode 1)  	Video on,  front/back light off
++ *  	VESA_HSYNC_SUSPEND (mode 2)  	Video on,  front/back light off
++ *  	VESA_POWERDOWN (mode 3)		Video off, front/back light off
++ *
++ *  This will match the matrox implementation.
++ */
++/*
++ * pxafb_blank():
++ *	Blank the display by setting all palette values to zero.  Note, the 
++ * 	12 and 16 bpp modes don't really use the palette, so this will not
++ *      blank the display in all modes.  
++ */
++static void pxafb_blank(int blank, struct fb_info *info)
++{
++	struct pxafb_info *fbi = (struct pxafb_info *)info;
++	int i;
++
++	DPRINTK("pxafb_blank: blank=%d info->modename=%s\n", blank,
++		fbi->fb.modename);
++
++	switch (blank) {
++	case VESA_POWERDOWN:
++	case VESA_VSYNC_SUSPEND:
++	case VESA_HSYNC_SUSPEND:
++		if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
++		    fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
++			for (i = 0; i < fbi->palette_size; i++)
++				pxafb_setpalettereg(i, 0, 0, 0, 0, info);
++		pxafb_schedule_task(fbi, C_DISABLE);
++		if (pxafb_blank_helper)
++			pxafb_blank_helper(blank);
++		break;
++
++	case VESA_NO_BLANKING:
++		if (pxafb_blank_helper)
++			pxafb_blank_helper(blank);
++		if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
++		    fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
++			fb_set_cmap(&fbi->fb.cmap, 1, pxafb_setcolreg, info);
++		pxafb_schedule_task(fbi, C_ENABLE);
++	}
++}
++
++static int pxafb_updatevar(int con, struct fb_info *info)
++{
++	DPRINTK("entered\n");
++	return 0;
++}
++
++/*
++ * Calculate the PCD value from the clock rate (in picoseconds).
++ * We take account of the PPCR clock setting.
++ */
++static inline int get_pcd(unsigned int pixclock)
++{
++	unsigned int pcd;
++
++	if (pixclock) {
++		pcd = get_lclk_frequency_10khz() * pixclock;
++		pcd /= 100000000;
++		pcd += 1;	/* make up for integer math truncations */
++	} else {
++		printk(KERN_WARNING "Please convert me to use the PCD calculations\n");
++		pcd = 0;
++	}
++	return pcd;
++}
++
++/*
++ * pxafb_activate_var():
++ *	Configures LCD Controller based on entries in var parameter.  Settings are      
++ *      only written to the controller if changes were made.  
++ */
++static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
++{
++	struct pxafb_lcd_reg new_regs;
++//	u_int pcd = get_pcd(var->pixclock);
++	u_long flags;
++
++	DPRINTK("Configuring PXA LCD\n");
++
++	DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
++		var->xres, var->hsync_len,
++		var->left_margin, var->right_margin);
++	DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
++		var->yres, var->vsync_len,
++		var->upper_margin, var->lower_margin);
++
++#if DEBUG_VAR
++	if (var->xres < 16        || var->xres > 1024)
++		printk(KERN_ERR "%s: invalid xres %d\n",
++			fbi->fb.fix.id, var->xres);
++	if (var->hsync_len < 1    || var->hsync_len > 64)
++		printk(KERN_ERR "%s: invalid hsync_len %d\n",
++			fbi->fb.fix.id, var->hsync_len);
++	if (var->left_margin < 1  || var->left_margin > 255)
++		printk(KERN_ERR "%s: invalid left_margin %d\n",
++			fbi->fb.fix.id, var->left_margin);
++	if (var->right_margin < 1 || var->right_margin > 255)
++		printk(KERN_ERR "%s: invalid right_margin %d\n",
++			fbi->fb.fix.id, var->right_margin);
++	if (var->yres < 1         || var->yres > 1024)
++		printk(KERN_ERR "%s: invalid yres %d\n",
++			fbi->fb.fix.id, var->yres);
++	if (var->vsync_len < 1    || var->vsync_len > 64)
++		printk(KERN_ERR "%s: invalid vsync_len %d\n",
++			fbi->fb.fix.id, var->vsync_len);
++	if (var->upper_margin < 0 || var->upper_margin > 255)
++		printk(KERN_ERR "%s: invalid upper_margin %d\n",
++			fbi->fb.fix.id, var->upper_margin);
++	if (var->lower_margin < 0 || var->lower_margin > 255)
++		printk(KERN_ERR "%s: invalid lower_margin %d\n",
++			fbi->fb.fix.id, var->lower_margin);
++#endif
++
++#if defined (CONFIG_PXA_CERF_PDA)
++	new_regs.lccr0 = fbi->lccr0;
++	new_regs.lccr1 =
++		LCCR1_DisWdth(var->xres) +
++		LCCR1_HorSnchWdth(var->hsync_len) +
++		LCCR1_BegLnDel(var->left_margin) +
++		LCCR1_EndLnDel(var->right_margin);
++		
++	new_regs.lccr2 =
++		LCCR2_DisHght(var->yres) +
++		LCCR2_VrtSnchWdth(var->vsync_len) +
++		LCCR2_BegFrmDel(var->upper_margin) +
++		LCCR2_EndFrmDel(var->lower_margin);
++
++	new_regs.lccr3 = fbi->lccr3
++		|
++		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
++		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
++#elif defined (CONFIG_FB_PXA_QVGA)
++	new_regs.lccr0 = fbi->lccr0;
++	new_regs.lccr1 =
++		LCCR1_DisWdth(var->xres) +
++		LCCR1_HorSnchWdth(var->hsync_len) +
++		LCCR1_BegLnDel(var->left_margin) +
++		LCCR1_EndLnDel(var->right_margin);
++	new_regs.lccr2 =
++		LCCR2_DisHght(var->yres) +
++		LCCR2_VrtSnchWdth(var->vsync_len) +
++		LCCR2_BegFrmDel(var->upper_margin) +
++		LCCR2_EndFrmDel(var->lower_margin);
++	new_regs.lccr3 = fbi->lccr3;
++#else
++	// FIXME using hardcoded values for now
++	new_regs.lccr0 = fbi->lccr0;
++//		|
++//		LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
++//		LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
++
++	new_regs.lccr1 = 0x3030A7F;
++//		LCCR1_DisWdth(var->xres) +
++//		LCCR1_HorSnchWdth(var->hsync_len) +
++//		LCCR1_BegLnDel(var->left_margin) +
++//		LCCR1_EndLnDel(var->right_margin);
++
++	new_regs.lccr2 = 0x4EF;
++//		LCCR2_DisHght(var->yres) +
++//		LCCR2_VrtSnchWdth(var->vsync_len) +
++//		LCCR2_BegFrmDel(var->upper_margin) +
++//		LCCR2_EndFrmDel(var->lower_margin);
++
++	new_regs.lccr3 = fbi->lccr3;
++//	|
++//		(var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
++//		(var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
++//		LCCR3_ACBsCntOff;
++#endif
++
++//	if (pcd)
++//		new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
++
++	DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
++	DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
++	DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
++	DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
++
++	/* Update shadow copy atomically */
++	local_irq_save(flags);
++
++	/* setup dma descriptors */
++	fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16);
++	fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16);
++	fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16);
++
++	fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16;
++	fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
++	fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
++
++	#define BYTES_PER_PANEL	((fbi->lccr0 & LCCR0_SDS) ? (var->xres * var->yres * var->bits_per_pixel / 8 / 2) : \
++			                                    (var->xres * var->yres * var->bits_per_pixel / 8))
++	
++	/* populate descriptors */
++	fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
++	fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
++	fbi->dmadesc_fblow_cpu->fidr  = 0;
++	fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL;
++
++	fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */
++		
++	fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
++	fbi->dmadesc_fbhigh_cpu->fidr = 0;
++	fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
++
++	fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
++	fbi->dmadesc_palette_cpu->fidr  = 0;
++	fbi->dmadesc_palette_cpu->ldcmd = (fbi->palette_size * 2) | LDCMD_PAL;
++
++	if( var->bits_per_pixel < 12)
++	{
++		/* assume any mode with <12 bpp is palette driven */
++		fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
++		fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
++		fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
++	}
++	else
++	{
++		/* palette shouldn't be loaded in true-color mode */
++		fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
++		fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
++	}
++
++	DPRINTK("fbi->dmadesc_fblow_cpu = 0x%x\n", fbi->dmadesc_fblow_cpu);
++	DPRINTK("fbi->dmadesc_fbhigh_cpu = 0x%x\n", fbi->dmadesc_fbhigh_cpu);
++	DPRINTK("fbi->dmadesc_palette_cpu = 0x%x\n", fbi->dmadesc_palette_cpu);
++	DPRINTK("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
++	DPRINTK("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
++	DPRINTK("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
++
++	DPRINTK("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
++	DPRINTK("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
++	DPRINTK("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
++
++	DPRINTK("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
++	DPRINTK("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
++	DPRINTK("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
++
++	DPRINTK("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
++	DPRINTK("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
++	DPRINTK("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
++	
++	fbi->reg_lccr0 = new_regs.lccr0;
++	fbi->reg_lccr1 = new_regs.lccr1;
++	fbi->reg_lccr2 = new_regs.lccr2;
++	fbi->reg_lccr3 = new_regs.lccr3;
++	local_irq_restore(flags);
++
++	/*
++	 * Only update the registers if the controller is enabled
++	 * and something has changed.
++	 */
++	if ((LCCR0 != fbi->reg_lccr0)       || (LCCR1 != fbi->reg_lccr1) ||
++	    (LCCR2 != fbi->reg_lccr2)       || (LCCR3 != fbi->reg_lccr3) ||
++	    (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1))
++		pxafb_schedule_task(fbi, C_REENABLE);
++
++	return 0;
++}
++
++/*
++ * NOTE!  The following functions are purely helpers for set_ctrlr_state.
++ * Do not call them directly; set_ctrlr_state does the correct serialisation
++ * to ensure that things happen in the right way 100% of time time.
++ *	-- rmk
++ */
++
++/*
++ * FIXME: move LCD power stuff into pxafb_power_up_lcd()
++ * Also, I'm expecting that the backlight stuff should
++ * be handled differently.
++ */
++static void pxafb_backlight_on(struct pxafb_info *fbi)
++{
++	DPRINTK("backlight on\n");
++
++#ifdef CONFIG_ARCH_PXA_IDP
++	if(machine_is_pxa_idp()) {	
++		FB_BACKLIGHT_ON();
++	}
++#endif
++}
++
++/*
++ * FIXME: move LCD power stuf into pxafb_power_down_lcd()
++ * Also, I'm expecting that the backlight stuff should
++ * be handled differently.
++ */
++static void pxafb_backlight_off(struct pxafb_info *fbi)
++{
++	DPRINTK("backlight off\n");
++
++#ifdef CONFIG_ARCH_PXA_IDP
++	if(machine_is_pxa_idp()) {
++		FB_BACKLIGHT_OFF();
++	}
++#endif
++	
++}
++
++static void pxafb_power_up_lcd(struct pxafb_info *fbi)
++{
++	DPRINTK("LCD power on\n");
++	CKEN |= CKEN16_LCD;
++
++	if(machine_is_pxa_cerf()) {
++		lcdctrl_enable();
++	}
++
++#if CONFIG_ARCH_PXA_IDP
++	/* set GPIOs, etc */
++	if(machine_is_pxa_idp()) {
++		// FIXME need to add proper delays
++		FB_PWR_ON();
++		FB_VLCD_ON();	// FIXME this should be after scanning starts
++	}
++#endif
++}
++
++static void pxafb_power_down_lcd(struct pxafb_info *fbi)
++{
++	DPRINTK("LCD power off\n");
++	CKEN &= ~CKEN16_LCD;
++
++	if(machine_is_pxa_cerf()) {
++		lcdctrl_disable();
++	}
++
++	/* set GPIOs, etc */
++#if CONFIG_ARCH_PXA_IDP
++	if(machine_is_pxa_idp()) {
++		// FIXME need to add proper delays
++		FB_PWR_OFF();
++		FB_VLCD_OFF();	// FIXME this should be before scanning stops
++	}
++#endif
++
++}
++
++static void pxafb_setup_gpio(struct pxafb_info *fbi)
++{
++	unsigned int lccr0;
++
++	/*
++	 * setup is based on type of panel supported
++	 */
++
++	lccr0 = fbi->lccr0;
++
++	/* 4 bit interface */
++	if ((lccr0 & LCCR0_CMS) && (lccr0 & LCCR0_SDS) && !(lccr0 & LCCR0_DPD))
++	{
++		// bits 58-61
++		GPDR1 |= (0xf << 26);
++		GAFR1_U = (GAFR1_U & ~(0xff << 20)) | (0xaa << 20);
++
++		// bits 74-77
++		GPDR2 |= (0xf << 10);
++                GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
++	}
++
++        /* 8 bit interface */
++        else if (((lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_DPD))) ||
++                 (!(lccr0 & LCCR0_CMS) && !(lccr0 & LCCR0_PAS) && !(lccr0 & LCCR0_SDS)))
++        {
++		// bits 58-65
++                GPDR1 |= (0x3f << 26);
++                GPDR2 |= (0x3);
++
++                GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
++                GAFR2_L = (GAFR2_L & ~0xf) | (0xa);
++
++                // bits 74-77
++                GPDR2 |= (0xf << 10);
++                GAFR2_L = (GAFR2_L & ~(0xff << 20)) | (0xaa << 20);
++        }
++
++        /* 16 bit interface */
++        else if (!(lccr0 & LCCR0_CMS) && ((lccr0 & LCCR0_SDS) || (lccr0 & LCCR0_PAS)))
++        {
++		// bits 58-77
++                GPDR1 |= (0x3f << 26);
++                GPDR2 |= 0x00003fff;
++
++                GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
++                GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
++        }
++	else
++	{
++		printk( KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
++	}
++}
++
++static void pxafb_enable_controller(struct pxafb_info *fbi)
++{
++	DPRINTK("Enabling LCD controller\n");
++
++	/* Sequence from 11.7.10 */
++	LCCR3 = fbi->reg_lccr3;
++	LCCR2 = fbi->reg_lccr2;
++	LCCR1 = fbi->reg_lccr1;
++	LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
++
++	/* FIXME we used to have LCD power control here */
++
++	FDADR0 = fbi->fdadr0;
++	FDADR1 = fbi->fdadr1;
++	LCCR0 |= LCCR0_ENB;
++
++	DPRINTK("FDADR0 = 0x%08x\n", (unsigned int)FDADR0);
++	DPRINTK("FDADR1 = 0x%08x\n", (unsigned int)FDADR1);
++	DPRINTK("LCCR0 = 0x%08x\n", (unsigned int)LCCR0);
++	DPRINTK("LCCR1 = 0x%08x\n", (unsigned int)LCCR1);
++	DPRINTK("LCCR2 = 0x%08x\n", (unsigned int)LCCR2);
++	DPRINTK("LCCR3 = 0x%08x\n", (unsigned int)LCCR3);
++}
++
++static void pxafb_disable_controller(struct pxafb_info *fbi)
++{
++	DECLARE_WAITQUEUE(wait, current);
++
++	DPRINTK("Disabling LCD controller\n");
++
++	/* FIXME add power down GPIO stuff here */
++
++	add_wait_queue(&fbi->ctrlr_wait, &wait);
++	set_current_state(TASK_UNINTERRUPTIBLE);
++
++	LCSR = 0xffffffff;	/* Clear LCD Status Register */
++	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
++	LCCR0 &= ~LCCR0_ENB;	/* Disable LCD Controller */
++
++	schedule_timeout(20 * HZ / 1000);
++	current->state = TASK_RUNNING;
++	remove_wait_queue(&fbi->ctrlr_wait, &wait);
++}
++
++/*
++ *  pxafb_handle_irq: Handle 'LCD DONE' interrupts.
++ */
++static void pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct pxafb_info *fbi = dev_id;
++	unsigned int lcsr = LCSR;
++
++	if (lcsr & LCSR_LDD) {
++		LCCR0 |= LCCR0_LDM;
++		wake_up(&fbi->ctrlr_wait);
++	}
++
++	LCSR = lcsr;
++}
++
++/*
++ * This function must be called from task context only, since it will
++ * sleep when disabling the LCD controller, or if we get two contending
++ * processes trying to alter state.
++ */
++static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
++{
++	u_int old_state;
++
++	down(&fbi->ctrlr_sem);
++
++	old_state = fbi->state;
++
++	switch (state) {
++	case C_DISABLE_CLKCHANGE:
++		/*
++		 * Disable controller for clock change.  If the
++		 * controller is already disabled, then do nothing.
++		 */
++		if (old_state != C_DISABLE) {
++			fbi->state = state;
++			pxafb_disable_controller(fbi);
++		}
++		break;
++
++	case C_DISABLE:
++		/*
++		 * Disable controller
++		 */
++		if (old_state != C_DISABLE) {
++			fbi->state = state;
++
++			pxafb_backlight_off(fbi);
++			if (old_state != C_DISABLE_CLKCHANGE)
++				pxafb_disable_controller(fbi);
++			pxafb_power_down_lcd(fbi);
++		}
++		break;
++
++	case C_ENABLE_CLKCHANGE:
++		/*
++		 * Enable the controller after clock change.  Only
++		 * do this if we were disabled for the clock change.
++		 */
++		if (old_state == C_DISABLE_CLKCHANGE) {
++			fbi->state = C_ENABLE;
++			pxafb_enable_controller(fbi);
++		}
++		break;
++
++	case C_REENABLE:
++		/*
++		 * Re-enable the controller only if it was already
++		 * enabled.  This is so we reprogram the control
++		 * registers.
++		 */
++		if (old_state == C_ENABLE) {
++			pxafb_disable_controller(fbi);
++			pxafb_setup_gpio(fbi);
++			pxafb_enable_controller(fbi);
++		}
++		break;
++
++	case C_ENABLE:
++		/*
++		 * Power up the LCD screen, enable controller, and
++		 * turn on the backlight.
++		 */
++		if (old_state != C_ENABLE) {
++			fbi->state = C_ENABLE;
++			pxafb_setup_gpio(fbi);
++			pxafb_power_up_lcd(fbi);
++			pxafb_enable_controller(fbi);
++			pxafb_backlight_on(fbi);
++		}
++		break;
++	}
++	up(&fbi->ctrlr_sem);
++}
++
++/*
++ * Our LCD controller task (which is called when we blank or unblank)
++ * via keventd.
++ */
++static void pxafb_task(void *dummy)
++{
++	struct pxafb_info *fbi = dummy;
++	u_int state = xchg(&fbi->task_state, -1);
++
++	set_ctrlr_state(fbi, state);
++}
++
++#ifdef CONFIG_CPU_FREQ
++/*
++ * CPU clock speed change handler.  We need to adjust the LCD timing
++ * parameters when the CPU clock is adjusted by the power management
++ * subsystem.
++ */
++static int
++pxafb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
++			 void *data)
++{
++	struct pxafb_info *fbi = TO_INF(nb, clockchg);
++	u_int pcd;
++
++	switch (val) {
++	case CPUFREQ_MINMAX:
++		/* todo: fill in min/max values */
++		break;
++
++	case CPUFREQ_PRECHANGE:
++		set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
++		break;
++
++	case CPUFREQ_POSTCHANGE:
++		pcd = get_pcd(fbi->fb.var.pixclock);
++		fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
++		set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
++		break;
++	}
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_PM
++/*
++ * Power management hook.  Note that we won't be called from IRQ context,
++ * unlike the blank functions above, so we may sleep.
++ */
++static int
++pxafb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
++{
++	struct pxafb_info *fbi = pm_dev->data;
++
++	DPRINTK("pm_callback: %d\n", req);
++
++	if (req == PM_SUSPEND || req == PM_RESUME) {
++		int state = (int)data;
++
++		if (state == 0) {
++			/* Enter D0. */
++			set_ctrlr_state(fbi, C_ENABLE);
++		} else {
++			/* Enter D1-D3.  Disable the LCD controller.  */
++			set_ctrlr_state(fbi, C_DISABLE);
++		}
++	}
++	DPRINTK("done\n");
++	return 0;
++}
++#endif
++
++/*
++ * pxafb_map_video_memory():
++ *      Allocates the DRAM memory for the frame buffer.  This buffer is  
++ *	remapped into a non-cached, non-buffered, memory region to  
++ *      allow palette and pixel writes to occur without flushing the 
++ *      cache.  Once this area is remapped, all virtual memory
++ *      access to the video memory should occur at the new region.
++ */
++static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
++{
++	u_long palette_mem_size;
++
++	/*
++	 * We reserve one page for the palette, plus the size
++	 * of the framebuffer.
++	 *
++	 * layout of stuff in memory
++	 *
++	 *                fblow descriptor
++	 *                fbhigh descriptor
++	 *                palette descriptor
++	 *                palette
++	 *   page boundary->
++	 *                frame buffer
++	 */
++	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
++	fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
++					&fbi->map_dma, PTE_BUFFERABLE);
++
++	if (fbi->map_cpu) {
++		fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
++		fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
++		fbi->fb.fix.smem_start = fbi->screen_dma;
++
++		fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
++
++		palette_mem_size = fbi->palette_size * sizeof(u16);
++
++		DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
++
++		fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
++		fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
++
++	}
++
++	return fbi->map_cpu ? 0 : -ENOMEM;
++}
++
++/* Fake monspecs to fill in fbinfo structure */
++static struct fb_monspecs monspecs __initdata = {
++	30000, 70000, 50, 65, 0	/* Generic */
++};
++
++
++static struct pxafb_info * __init pxafb_init_fbinfo(void)
++{
++	struct pxafb_mach_info *inf;
++	struct pxafb_info *fbi;
++
++	fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(struct display) +
++		      sizeof(u16) * 16, GFP_KERNEL);
++	if (!fbi)
++		return NULL;
++
++	memset(fbi, 0, sizeof(struct pxafb_info) + sizeof(struct display));
++
++	fbi->currcon		= -1;
++
++	strcpy(fbi->fb.fix.id, PXA_NAME);
++
++	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
++	fbi->fb.fix.type_aux	= 0;
++	fbi->fb.fix.xpanstep	= 0;
++	fbi->fb.fix.ypanstep	= 0;
++	fbi->fb.fix.ywrapstep	= 0;
++	fbi->fb.fix.accel	= FB_ACCEL_NONE;
++
++	fbi->fb.var.nonstd	= 0;
++	fbi->fb.var.activate	= FB_ACTIVATE_NOW;
++	fbi->fb.var.height	= -1;
++	fbi->fb.var.width	= -1;
++	fbi->fb.var.accel_flags	= 0;
++	fbi->fb.var.vmode	= FB_VMODE_NONINTERLACED;
++
++	strcpy(fbi->fb.modename, PXA_NAME);
++	strcpy(fbi->fb.fontname, "Acorn8x8");
++
++	fbi->fb.fbops		= &pxafb_ops;
++	fbi->fb.changevar	= NULL;
++	fbi->fb.switch_con	= pxafb_switch;
++	fbi->fb.updatevar	= pxafb_updatevar;
++	fbi->fb.blank		= pxafb_blank;
++	fbi->fb.flags		= FBINFO_FLAG_DEFAULT;
++	fbi->fb.node		= -1;
++	fbi->fb.monspecs	= monspecs;
++	fbi->fb.disp		= (struct display *)(fbi + 1);
++	fbi->fb.pseudo_palette	= (void *)(fbi->fb.disp + 1);
++
++	fbi->rgb[RGB_8]		= &rgb_8;
++	fbi->rgb[RGB_16]	= &def_rgb_16;
++
++	inf = pxafb_get_machine_info(fbi);
++
++	fbi->max_xres			= inf->xres;
++	fbi->fb.var.xres		= inf->xres;
++	fbi->fb.var.xres_virtual	= inf->xres;
++	fbi->max_yres			= inf->yres;
++	fbi->fb.var.yres		= inf->yres;
++	fbi->fb.var.yres_virtual	= inf->yres;
++	fbi->max_bpp			= inf->bpp;
++	fbi->fb.var.bits_per_pixel	= inf->bpp;
++	fbi->fb.var.pixclock		= inf->pixclock;
++	fbi->fb.var.hsync_len		= inf->hsync_len;
++	fbi->fb.var.left_margin		= inf->left_margin;
++	fbi->fb.var.right_margin	= inf->right_margin;
++	fbi->fb.var.vsync_len		= inf->vsync_len;
++	fbi->fb.var.upper_margin	= inf->upper_margin;
++	fbi->fb.var.lower_margin	= inf->lower_margin;
++	fbi->fb.var.sync		= inf->sync;
++	fbi->fb.var.grayscale		= inf->cmap_greyscale;
++	fbi->cmap_inverse		= inf->cmap_inverse;
++	fbi->cmap_static		= inf->cmap_static;
++	fbi->lccr0			= inf->lccr0;
++	fbi->lccr3			= inf->lccr3;
++	fbi->state			= C_DISABLE;
++	fbi->task_state			= (u_char)-1;
++	fbi->fb.fix.smem_len		= fbi->max_xres * fbi->max_yres *
++					  fbi->max_bpp / 8;
++
++	init_waitqueue_head(&fbi->ctrlr_wait);
++	INIT_TQUEUE(&fbi->task, pxafb_task, fbi);
++	init_MUTEX(&fbi->ctrlr_sem);
++
++	return fbi;
++}
++
++int __init pxafb_init(void)
++{
++	struct pxafb_info *fbi;
++	int ret;
++
++	fbi = pxafb_init_fbinfo();
++	ret = -ENOMEM;
++	if (!fbi)
++		goto failed;
++
++	if(machine_is_pxa_cerf()) {
++		// brightness&contrast is handled via lcdctrl.
++		lcdctrl_init();
++	}
++
++	/* Initialize video memory */
++	ret = pxafb_map_video_memory(fbi);
++	if (ret)
++		goto failed;
++
++	ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT,
++			  "LCD", fbi);
++	if (ret) {
++		printk(KERN_ERR "pxafb: failed in request_irq: %d\n", ret);
++		goto failed;
++	}
++
++	pxafb_set_var(&fbi->fb.var, -1, &fbi->fb);
++
++	ret = register_framebuffer(&fbi->fb);
++	if (ret < 0)
++		goto failed;
++
++#ifdef CONFIG_PM
++	/*
++	 * Note that the console registers this as well, but we want to
++	 * power down the display prior to sleeping.
++	 */
++	fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, pxafb_pm_callback);
++	if (fbi->pm)
++		fbi->pm->data = fbi;
++#endif
++#ifdef CONFIG_CPU_FREQ
++	fbi->clockchg.notifier_call = pxafb_clkchg_notifier;
++	cpufreq_register_notifier(&fbi->clockchg);
++#endif
++
++	/*
++	 * Ok, now enable the LCD controller
++	 */
++	set_ctrlr_state(fbi, C_ENABLE);
++
++	/* This driver cannot be unloaded at the moment */
++	MOD_INC_USE_COUNT;
++
++	return 0;
++
++failed:
++	if (fbi)
++		kfree(fbi);
++	return ret;
++}
++
++
++#ifdef MODULE
++module_init(pxafb_init);
++#endif
++
++MODULE_DESCRIPTION("loadable framebuffer driver for PXA");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/pxafb.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,238 @@
++/*
++ * linux/drivers/video/pxafb.h
++ *    -- Intel PXA250/210 LCD Controller Frame Buffer Device
++ *
++ *  Copyright (C) 1999 Eric A. Thomas
++ *   Based on acornfb.c Copyright (C) Russell King.
++ *
++ *  2001-08-03: Cliff Brake <cbrake@acclent.com>
++ *	 - ported SA1100 code to PXA
++ *  
++ * 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.
++ */
++
++/*
++ * These are the bitfields for each
++ * display depth that we support.
++ */
++struct pxafb_rgb {
++	struct fb_bitfield	red;
++	struct fb_bitfield	green;
++	struct fb_bitfield	blue;
++	struct fb_bitfield	transp;
++};
++
++/*
++ * This structure describes the machine which we are running on.
++ */
++struct pxafb_mach_info {
++	u_long		pixclock;
++
++	u_short		xres;
++	u_short		yres;
++
++	u_char		bpp;
++	u_char		hsync_len;
++	u_char		left_margin;
++	u_char		right_margin;
++
++	u_char		vsync_len;
++	u_char		upper_margin;
++	u_char		lower_margin;
++	u_char		sync;
++
++	u_int		cmap_greyscale:1,
++			cmap_inverse:1,
++			cmap_static:1,
++			unused:29;
++
++	u_int		lccr0;
++	u_int		lccr3;
++};
++
++/* Shadows for LCD controller registers */
++struct pxafb_lcd_reg {
++	unsigned int lccr0;
++	unsigned int lccr1;
++	unsigned int lccr2;
++	unsigned int lccr3;
++};
++
++/* PXA LCD DMA descriptor */
++struct pxafb_dma_descriptor {
++	unsigned int fdadr;
++	unsigned int fsadr;
++	unsigned int fidr;
++	unsigned int ldcmd;
++};
++
++#define RGB_8	(0)
++#define RGB_16	(1)
++#define NR_RGB	2
++
++struct pxafb_info {
++	struct fb_info		fb;
++	signed int		currcon;
++
++	struct pxafb_rgb	*rgb[NR_RGB];
++
++	u_int			max_bpp;
++	u_int			max_xres;
++	u_int			max_yres;
++
++	/*
++	 * These are the addresses we mapped
++	 * the framebuffer memory region to.
++	 */
++
++	/* raw memory addresses */
++	dma_addr_t		map_dma;	/* physical */
++	u_char *		map_cpu;	/* virtual */
++	u_int			map_size;
++
++	/* addresses of pieces placed in raw buffer */
++	u_char *		screen_cpu;	/* virtual address of frame buffer */
++	dma_addr_t		screen_dma;	/* physical address of frame buffer */
++	u16 *			palette_cpu;	/* virtual address of palette memory */
++	dma_addr_t		palette_dma;	/* physical address of palette memory */
++	u_int			palette_size;
++
++	/* DMA descriptors */
++	struct pxafb_dma_descriptor * 	dmadesc_fblow_cpu;
++	dma_addr_t				dmadesc_fblow_dma;
++	struct pxafb_dma_descriptor * 	dmadesc_fbhigh_cpu;
++	dma_addr_t				dmadesc_fbhigh_dma;
++	struct pxafb_dma_descriptor *	dmadesc_palette_cpu;
++	dma_addr_t				dmadesc_palette_dma;
++
++	dma_addr_t		fdadr0;
++	dma_addr_t		fdadr1;
++
++	u_int			lccr0;
++	u_int			lccr3;
++	u_int			cmap_inverse:1,
++				cmap_static:1,
++				unused:30;
++
++	u_int			reg_lccr0;
++	u_int			reg_lccr1;
++	u_int			reg_lccr2;
++	u_int			reg_lccr3;
++
++	volatile u_char		state;
++	volatile u_char		task_state;
++	struct semaphore	ctrlr_sem;
++	wait_queue_head_t	ctrlr_wait;
++	struct tq_struct	task;
++
++#ifdef CONFIG_PM
++	struct pm_dev		*pm;
++#endif
++#ifdef CONFIG_CPU_FREQ
++	struct notifier_block	clockchg;
++#endif
++};
++
++#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
++
++#define TO_INF(ptr,member)	__type_entry(ptr,struct pxafb_info,member)
++
++/*
++ * These are the actions for set_ctrlr_state
++ */
++#define C_DISABLE		(0)
++#define C_ENABLE		(1)
++#define C_DISABLE_CLKCHANGE	(2)
++#define C_ENABLE_CLKCHANGE	(3)
++#define C_REENABLE		(4)
++
++#define PXA_NAME	"PXA"
++
++/*
++ *  Debug macros 
++ */
++#if DEBUG
++#  define DPRINTK(fmt, args...)	printk("%s: " fmt, __FUNCTION__ , ## args)
++#else
++#  define DPRINTK(fmt, args...)
++#endif
++
++/*
++ * Minimum X and Y resolutions
++ */
++#define MIN_XRES	64
++#define MIN_YRES	64
++
++/*
++ * Are we configured for 8 or 16 bits per pixel?
++ */
++#ifdef CONFIG_FB_PXA_8BPP
++#  define PXAFB_BPP		8
++#  define PXAFB_BPP_BITS	0x03
++#elif CONFIG_FB_PXA_16BPP
++#  define PXAFB_BPP		16
++#  define PXAFB_BPP_BITS	0x04
++#endif
++
++#if defined(CONFIG_ARCH_LUBBOCK)
++#define LCD_PIXCLOCK			150000
++#define LCD_BPP				PXAFB_BPP
++#ifdef CONFIG_FB_PXA_QVGA
++#define LCD_XRES			320
++#define LCD_YRES			240
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH	51
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH	1
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT	1
++#define LCD_BEGIN_FRAME_WAIT_COUNT 	8
++#define LCD_END_OF_LINE_WAIT_COUNT	1
++#define LCD_END_OF_FRAME_WAIT_COUNT	1
++#define LCD_SYNC			(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0			0x003008F8
++#define LCD_LCCR3 			(0x0040FF0C | (PXAFB_BPP_BITS << 24))
++#else
++#define LCD_XRES			640
++#define LCD_YRES			480
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH	1
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH	1
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT	3
++#define LCD_BEGIN_FRAME_WAIT_COUNT 	0
++#define LCD_END_OF_LINE_WAIT_COUNT	3
++#define LCD_END_OF_FRAME_WAIT_COUNT	0
++#define LCD_SYNC			(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0			0x0030087C
++#define LCD_LCCR3 			(0x0040FF0C | (PXAFB_BPP_BITS << 24))
++#endif
++
++#elif defined (CONFIG_ARCH_PXA_IDP)
++#define LCD_PIXCLOCK			150000
++#define LCD_BPP				PXAFB_BPP
++#define LCD_XRES			640
++#define LCD_YRES			480
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH	1
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH	1
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT	3
++#define LCD_BEGIN_FRAME_WAIT_COUNT 	0
++#define LCD_END_OF_LINE_WAIT_COUNT	3
++#define LCD_END_OF_FRAME_WAIT_COUNT	0
++#define LCD_SYNC			(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0			0x0030087C
++#define LCD_LCCR3 			(0x0040FF0C | (PXAFB_BPP_BITS << 24))
++
++#elif defined CONFIG_PXA_CERF_PDA
++#define LCD_PIXCLOCK			171521
++#define LCD_BPP				PXAFB_BPP
++#define LCD_XRES			240
++#define LCD_YRES			320
++#define LCD_HORIZONTAL_SYNC_PULSE_WIDTH	7
++#define LCD_VERTICAL_SYNC_PULSE_WIDTH	2
++#define LCD_BEGIN_OF_LINE_WAIT_COUNT	17
++#define LCD_BEGIN_FRAME_WAIT_COUNT 	0
++#define LCD_END_OF_LINE_WAIT_COUNT	17
++#define LCD_END_OF_FRAME_WAIT_COUNT	0
++#define LCD_SYNC			(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT)
++#define LCD_LCCR0			(LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_QDM | LCCR0_BM  | LCCR0_OUM)
++#define LCD_LCCR3 			(LCCR3_PCP | LCCR3_PixClkDiv(0x12) | LCCR3_Bpp(PXAFB_BPP_BITS) | LCCR3_Acb(0x18))
++
++#endif
+--- linux-2.4.25/drivers/video/sa1100fb.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/drivers/video/sa1100fb.c	2004-03-31 17:15:12.000000000 +0200
+@@ -2175,7 +2175,7 @@
+ 	 */
+ 	fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+ 	fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
+-					&fbi->map_dma);
++					&fbi->map_dma, PTE_BUFFERABLE);
+ 
+ 	if (fbi->map_cpu) {
+ 		fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
+--- linux-2.4.25/fs/Config.in~2.4.25-vrs2-pxa1.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/fs/Config.in	2004-03-31 17:15:12.000000000 +0200
+@@ -51,6 +51,9 @@
+    int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0
+ fi
+ tristate 'Compressed ROM file system support' CONFIG_CRAMFS
++dep_mbool '  Use linear addressing for cramfs' CONFIG_CRAMFS_LINEAR $CONFIG_CRAMFS
++dep_bool '    Support XIP on linear cramfs' CONFIG_CRAMFS_LINEAR_XIP $CONFIG_CRAMFS_LINEAR
++dep_bool '    Root file system on linear cramfs' CONFIG_ROOT_CRAMFS_LINEAR $CONFIG_CRAMFS_LINEAR
+ bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS
+ define_bool CONFIG_RAMFS y
+ 
+--- linux-2.4.25/fs/cramfs/inode.c~2.4.25-vrs2-pxa1.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/fs/cramfs/inode.c	2004-03-31 17:15:12.000000000 +0200
+@@ -4,11 +4,29 @@
+  * Copyright (C) 1999 Linus Torvalds.
+  *
+  * This file is released under the GPL.
+- */
+-
+-/*
++ *
+  * These are the VFS interfaces to the compressed rom filesystem.
+  * The actual compression is based on zlib, see the other files.
++ *
++ * Linear Addressing code
++ * Copyright (C) 2000 Shane Nay.
++ *
++ *   Allows you to have a linearly addressed cramfs filesystem.
++ *   Saves the need for buffer, and the munging of the buffer.
++ *   Savings a bit over 32k with default PAGE_SIZE, BUFFER_SIZE
++ *   etc.  Usefull on embedded platform with ROM :-).
++ *
++ *   Downsides- Currently linear addressed cramfs partitions
++ *   don't co-exist with block cramfs partitions.
++ *
++ * 28-Dec-2000: XIP mode for linear cramfs
++ * Copyright (C) 2000 Robert Leslie <rob@mars.org>
++ *
++ * Dynamic allocation of linear cramfs space by Nicolas Pitre
++ * Copyright (C) 2003 Monta Vista Software, Inc.
++ *
++ *   Linear cramfs now requires that you pass the physaddr= parameter to
++ *   the mount process.  Allows for multiple linear cramfs partitions.
+  */
+ 
+ #include <linux/module.h>
+@@ -16,10 +34,12 @@
+ #include <linux/pagemap.h>
+ #include <linux/init.h>
+ #include <linux/string.h>
++#include <linux/kernel.h>
+ #include <linux/locks.h>
+ #include <linux/blkdev.h>
+ #include <linux/cramfs_fs.h>
+ #include <asm/semaphore.h>
++#include <asm/io.h>
+ 
+ #include <asm/uaccess.h>
+ 
+@@ -28,6 +48,8 @@
+ #define CRAMFS_SB_BLOCKS u.cramfs_sb.blocks
+ #define CRAMFS_SB_FILES u.cramfs_sb.files
+ #define CRAMFS_SB_FLAGS u.cramfs_sb.flags
++#define CRAMFS_SB_LINEAR_PHYS_ADDR u.cramfs_sb.linear_phys_addr
++#define CRAMFS_SB_LINEAR_VIRT_ADDR u.cramfs_sb.linear_virt_addr
+ 
+ static struct super_operations cramfs_ops;
+ static struct inode_operations cramfs_dir_inode_operations;
+@@ -42,6 +64,74 @@
+ #define CRAMINO(x)	((x)->offset?(x)->offset<<2:1)
+ #define OFFSET(x)	((x)->i_ino)
+ 
++
++#ifdef CONFIG_CRAMFS_LINEAR_XIP
++
++static int cramfs_mmap(struct file *file, struct vm_area_struct *vma)
++{
++	unsigned long address, length;
++	struct inode *inode = file->f_dentry->d_inode;
++	struct super_block *sb = inode->i_sb;
++
++	/* this is only used in the case of read-only maps for XIP */
++
++	if (vma->vm_flags & VM_WRITE)
++		return generic_file_mmap(file, vma);
++
++	if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE))
++		return -EINVAL;
++
++	address  = PAGE_ALIGN(sb->CRAMFS_SB_LINEAR_PHYS_ADDR + OFFSET(inode));
++	address += vma->vm_pgoff << PAGE_SHIFT;
++
++	length = vma->vm_end - vma->vm_start;
++
++	if (length > inode->i_size)
++		length = inode->i_size;
++
++	length = PAGE_ALIGN(length);
++
++
++#if 0
++	/* Doing the following makes it slower and more broken.  bdl */
++	/*
++	 * Accessing memory above the top the kernel knows about or
++	 * through a file pointer that was marked O_SYNC will be
++	 * done non-cached.
++	 */
++	vma->vm_page_prot =
++		__pgprot((pgprot_val(vma->vm_page_prot) & ~_CACHE_MASK)
++			| _CACHE_UNCACHED);
++#endif
++
++	/*
++	 * Don't dump addresses that are not real memory to a core file.
++	 */
++	vma->vm_flags |= VM_IO;
++	flush_tlb_page(vma, address);
++	if (remap_page_range(vma->vm_start, address, length,
++			     vma->vm_page_prot))
++		return -EAGAIN;
++
++#ifdef DEBUG_CRAMFS_XIP
++	printk("cramfs_mmap: mapped %s at 0x%08lx, length %lu to vma 0x%08lx"
++		", page_prot 0x%08lx\n",
++		file->f_dentry->d_name.name, address, length,
++		vma->vm_start, pgprot_val(vma->vm_page_prot));
++#endif
++
++	return 0;
++}
++
++static struct file_operations cramfs_linear_xip_fops = {
++	read:	generic_file_read,
++	mmap:	cramfs_mmap,
++};
++
++#define CRAMFS_INODE_IS_XIP(x) ((x)->i_mode & S_ISVTX)
++
++#endif
++
+ static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode)
+ {
+ 	struct inode * inode = new_inode(sb);
+@@ -60,7 +150,11 @@
+ 		   without -noleaf option. */
+ 		insert_inode_hash(inode);
+ 		if (S_ISREG(inode->i_mode)) {
++#ifdef CONFIG_CRAMFS_LINEAR_XIP
++			inode->i_fop = CRAMFS_INODE_IS_XIP(inode) ? &cramfs_linear_xip_fops : &generic_ro_fops;
++#else
+ 			inode->i_fop = &generic_ro_fops;
++#endif
+ 			inode->i_data.a_ops = &cramfs_aops;
+ 		} else if (S_ISDIR(inode->i_mode)) {
+ 			inode->i_op = &cramfs_dir_inode_operations;
+@@ -76,6 +170,18 @@
+ 	return inode;
+ }
+ 
++#ifdef CONFIG_CRAMFS_LINEAR
++/*
++ * Return a pointer to the block in the linearly addressed cramfs image.
++ */
++static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)
++{
++	if (!len)
++		return NULL;
++	return (void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + offset);
++}
++
++#else /* Not linear addressing - aka regular block mode. */
+ /*
+  * We have our own block cache: don't fill up the buffer cache
+  * with the rom-image, because the way the filesystem is set
+@@ -186,23 +292,65 @@
+ 	}
+ 	return read_buffers[buffer] + offset;
+ }
+-
++#endif /* !CONFIG_CRAMFS_LINEAR */
+ 
+ static struct super_block * cramfs_read_super(struct super_block *sb, void *data, int silent)
+ {
++#ifndef CONFIG_CRAMFS_LINEAR
+ 	int i;
++#else
++	char *p;
++#endif
+ 	struct cramfs_super super;
+ 	unsigned long root_offset;
+ 	struct super_block * retval = NULL;
+ 
+-	set_blocksize(sb->s_dev, PAGE_CACHE_SIZE);
+ 	sb->s_blocksize = PAGE_CACHE_SIZE;
+ 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ 
++#ifndef CONFIG_CRAMFS_LINEAR
++
++	set_blocksize(sb->s_dev, PAGE_CACHE_SIZE);
++
+ 	/* Invalidate the read buffers on mount: think disk change.. */
+ 	for (i = 0; i < READ_BUFFERS; i++)
+ 		buffer_blocknr[i] = -1;
+ 
++#else
++
++	/*
++	 * The physical location of the cramfs image is specified as
++	 * a mount parameter.  This parameter is mandatory for obvious
++	 * reasons.  Some validation is made on the phys address but this
++	 * is not exhaustive and we count on the fact that someone using
++	 * this feature is supposed to know what he/she's doing.
++	 */
++	if (!data || !(p = strstr((char *)data, "physaddr="))) {
++		printk(KERN_ERR "cramfs: unknown physical address for linear cramfs image\n");
++		goto out;
++	}
++	sb->CRAMFS_SB_LINEAR_PHYS_ADDR = simple_strtoul(p + 9, NULL, 0);
++	if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR & (PAGE_SIZE-1)) {
++		printk(KERN_ERR "cramfs: physical address 0x%lx for linear cramfs isn't aligned to a page boundary\n",
++		       sb->CRAMFS_SB_LINEAR_PHYS_ADDR);
++		goto out;
++	}
++	if (sb->CRAMFS_SB_LINEAR_PHYS_ADDR == 0) {
++		printk(KERN_ERR "cramfs: physical address for linear cramfs image can't be 0\n");
++		goto out;
++	}
++	printk(KERN_INFO "cramfs: checking physical address 0x%lx for linear cramfs image\n",
++	       sb->CRAMFS_SB_LINEAR_PHYS_ADDR);
++
++	/* Map only one page for now.  Will remap it when fs size is known. */
++	sb->CRAMFS_SB_LINEAR_VIRT_ADDR =
++		ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, PAGE_SIZE);
++	if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) {
++		printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n");
++		goto out;
++	}
++#endif
++
+ 	down(&read_mutex);
+ 	/* Read the first block and get the superblock from it */
+ 	memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));
+@@ -254,8 +402,26 @@
+ 	/* Set it all up.. */
+ 	sb->s_op = &cramfs_ops;
+ 	sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root));
++
++#ifdef CONFIG_CRAMFS_LINEAR
++	/* Remap the whole filesystem now */
++	iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR);
++	printk(KERN_INFO "cramfs: linear cramfs image appears to be %lu KB in size\n",
++	       sb->CRAMFS_SB_SIZE/1024);
++	sb->CRAMFS_SB_LINEAR_VIRT_ADDR =
++		ioremap(sb->CRAMFS_SB_LINEAR_PHYS_ADDR, sb->CRAMFS_SB_SIZE);
++	if (!sb->CRAMFS_SB_LINEAR_VIRT_ADDR) {
++		printk(KERN_ERR "cramfs: ioremap of the linear cramfs image failed\n");
++		goto out;
++	}
++#endif
++
+ 	retval = sb;
+ out:
++#ifdef CONFIG_CRAMFS_LINEAR
++	if (!retval && sb->CRAMFS_SB_LINEAR_VIRT_ADDR)
++		iounmap(sb->CRAMFS_SB_LINEAR_VIRT_ADDR);
++#endif
+ 	return retval;
+ }
+ 
+@@ -388,6 +554,18 @@
+ 
+ 	maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ 	bytes_filled = 0;
++#ifdef CONFIG_CRAMFS_LINEAR_XIP
++	if (page->index < maxblock && CRAMFS_INODE_IS_XIP(inode)) {
++		struct super_block *sb = inode->i_sb;
++		u32 blkptr_offset = PAGE_ALIGN(OFFSET(inode)) +
++				    page->index * PAGE_CACHE_SIZE;
++		memcpy( page_address(page),
++			(void*)(sb->CRAMFS_SB_LINEAR_VIRT_ADDR + blkptr_offset),
++			PAGE_CACHE_SIZE );
++		bytes_filled = PAGE_CACHE_SIZE;
++		pgdata = kmap(page);
++	} else
++#endif
+ 	if (page->index < maxblock) {
+ 		struct super_block *sb = inode->i_sb;
+ 		u32 blkptr_offset = OFFSET(inode) + page->index*4;
+@@ -444,7 +622,11 @@
+ 	statfs:		cramfs_statfs,
+ };
+ 
++#ifndef CONFIG_CRAMFS_LINEAR
+ static DECLARE_FSTYPE_DEV(cramfs_fs_type, "cramfs", cramfs_read_super);
++#else
++static DECLARE_FSTYPE(cramfs_fs_type, "cramfs", cramfs_read_super, 0);
++#endif
+ 
+ static int __init init_cramfs_fs(void)
+ {
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/fs/cramfs/mkcramfs.c	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,821 @@
++/*
++ * mkcramfs - make a cramfs file system, optionally with XIP files.
++ *
++ * Copyright (C) 1999-2001 Transmeta 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
++ */
++
++#include <sys/types.h>
++#include <stdio.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <sys/mman.h>
++#include <sys/fcntl.h>
++#include <dirent.h>
++#include <stdlib.h>
++#include <errno.h>
++#include <string.h>
++#include <assert.h>
++#include <getopt.h>
++#include <linux/cramfs_fs.h>
++#include <zlib.h>
++
++#define PAD_SIZE 512		/* only 0 and 512 supported by kernel */
++
++static const char *progname = "mkcramfs";
++
++/* N.B. If you change the disk format of cramfs, please update fs/cramfs/README. */
++
++/* Input status of 0 to print help and exit without an error. */
++static void usage(int status)
++{
++	FILE *stream = status ? stderr : stdout;
++
++	fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n"
++		" -h         print this help\n"
++		" -E         make all warnings errors (non-zero exit status)\n"
++		" -e edition set edition number (part of fsid)\n"
++		" -i file    insert a file image into the filesystem (requires >= 2.4.0)\n"
++		" -n name    set name of cramfs filesystem\n"
++		" -p         pad by %d bytes for boot code\n"
++		" -s         sort directory entries (old option, ignored)\n"
++		" -x         make marked files eXecute In Place\n"
++		" -z         make explicit holes (requires >= 2.3.39)\n"
++		" dirname    root of the filesystem to be compressed\n"
++		" outfile    output file\n", progname, PAD_SIZE);
++
++	exit(status);
++}
++
++#define PAGE_SIZE (4096)
++#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
++#define ROM_OFFSET 0
++#define ROM_ALIGN(x) (PAGE_ALIGN((x) + ROM_OFFSET) - ROM_OFFSET)
++#define PAGE_CACHE_SIZE (4096)
++/* The kernel assumes PAGE_CACHE_SIZE as block size. */
++static unsigned int blksize = PAGE_CACHE_SIZE;
++static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
++static int image_length = 0;
++
++/*
++ * If opt_holes is set, then mkcramfs can create explicit holes in the
++ * data, which saves 26 bytes per hole (which is a lot smaller a
++ * saving than most most filesystems).
++ *
++ * Note that kernels up to at least 2.3.39 don't support cramfs holes,
++ * which is why this is turned off by default.
++ */
++static int opt_edition = 0;
++static int opt_errors = 0;
++static int opt_holes = 0;
++static int opt_xip = 0;
++static int opt_pad = 0;
++static char *opt_image = NULL;
++static char *opt_name = NULL;
++
++static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
++
++#ifndef MIN
++# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
++#endif
++
++/* In-core version of inode / directory entry. */
++struct entry {
++	/* stats */
++	char *name;
++	unsigned int mode, size, uid, gid;
++
++	/* FS data */
++	void *uncompressed;
++        /* points to other identical file */
++        struct entry *same;
++        unsigned int offset;            /* pointer to compressed data in archive */
++	unsigned int dir_offset;	/* Where in the archive is the directory entry? */
++
++	/* organization */
++	struct entry *child; /* null for non-directories and empty directories */
++	struct entry *next;
++};
++
++/*
++ * The longest file name component to allow for in the input directory tree.
++ * Ext2fs (and many others) allow up to 255 bytes.  A couple of filesystems
++ * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
++ * >255-byte names in the input directory tree given that such names get
++ * truncated to 255 bytes when written to cramfs.
++ */
++#define MAX_INPUT_NAMELEN 255
++
++static int find_identical_file(struct entry *orig,struct entry *newfile)
++{
++        if(orig==newfile) return 1;
++        if(!orig) return 0;
++        if(orig->size==newfile->size && orig->uncompressed && !memcmp(orig->uncompressed,newfile->uncompressed,orig->size)) {
++                newfile->same=orig;
++                return 1;
++        }
++        return find_identical_file(orig->child,newfile) ||
++                   find_identical_file(orig->next,newfile);
++}
++
++static void eliminate_doubles(struct entry *root,struct entry *orig) {
++        if(orig) {
++                if(orig->size && orig->uncompressed)
++			find_identical_file(root,orig);
++                eliminate_doubles(root,orig->child);
++                eliminate_doubles(root,orig->next);
++        }
++}
++
++/*
++ * We define our own sorting function instead of using alphasort which
++ * uses strcoll and changes ordering based on locale information.
++ */
++static int cramsort (const void *a, const void *b)
++{
++	return strcmp ((*(const struct dirent **) a)->d_name,
++		       (*(const struct dirent **) b)->d_name);
++}
++
++static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub)
++{
++	struct dirent **dirlist;
++	int totalsize = 0, dircount, dirindex;
++	char *path, *endpath;
++	size_t len = strlen(name);
++
++	/* Set up the path. */
++	/* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
++	path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);
++	if (!path) {
++		perror(NULL);
++		exit(8);
++	}
++	memcpy(path, name, len);
++	endpath = path + len;
++	*endpath = '/';
++	endpath++;
++
++        /* read in the directory and sort */
++        dircount = scandir(name, &dirlist, 0, cramsort);
++
++	if (dircount < 0) {
++		perror(name);
++		exit(8);
++	}
++
++	/* process directory */
++	for (dirindex = 0; dirindex < dircount; dirindex++) {
++		struct dirent *dirent;
++		struct entry *entry;
++		struct stat st;
++		int size;
++		size_t namelen;
++
++		dirent = dirlist[dirindex];
++
++		/* Ignore "." and ".." - we won't be adding them to the archive */
++		if (dirent->d_name[0] == '.') {
++			if (dirent->d_name[1] == '\0')
++				continue;
++			if (dirent->d_name[1] == '.') {
++				if (dirent->d_name[2] == '\0')
++					continue;
++			}
++		}
++		namelen = strlen(dirent->d_name);
++		if (namelen > MAX_INPUT_NAMELEN) {
++			fprintf(stderr,
++				"Very long (%u bytes) filename `%s' found.\n"
++				" Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
++				namelen, dirent->d_name);
++			exit(8);
++		}
++		memcpy(endpath, dirent->d_name, namelen + 1);
++
++		if (lstat(path, &st) < 0) {
++			perror(endpath);
++			warn_skip = 1;
++			continue;
++		}
++		entry = calloc(1, sizeof(struct entry));
++		if (!entry) {
++			perror(NULL);
++			exit(8);
++		}
++		entry->name = strdup(dirent->d_name);
++		if (!entry->name) {
++			perror(NULL);
++			exit(8);
++		}
++		if (namelen > 255) {
++			/* Can't happen when reading from ext2fs. */
++
++			/* TODO: we ought to avoid chopping in half
++			   multi-byte UTF8 characters. */
++			entry->name[namelen = 255] = '\0';
++			warn_namelen = 1;
++		}
++		entry->mode = st.st_mode;
++		entry->size = st.st_size;
++		entry->uid = st.st_uid;
++		if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
++			warn_uid = 1;
++		entry->gid = st.st_gid;
++		if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
++			/* TODO: We ought to replace with a default
++                           gid instead of truncating; otherwise there
++                           are security problems.  Maybe mode should
++                           be &= ~070.  Same goes for uid once Linux
++                           supports >16-bit uids. */
++			warn_gid = 1;
++		size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
++		*fslen_ub += size;
++		if (S_ISDIR(st.st_mode)) {
++			entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
++		} else if (S_ISREG(st.st_mode)) {
++			/* TODO: We ought to open files in do_compress, one
++			   at a time, instead of amassing all these memory
++			   maps during parse_directory (which don't get used
++			   until do_compress anyway).  As it is, we tend to
++			   get EMFILE errors (especially if mkcramfs is run
++			   by non-root).
++
++			   While we're at it, do analagously for symlinks
++			   (which would just save a little memory). */
++			int fd = open(path, O_RDONLY);
++			if (fd < 0) {
++				perror(path);
++				warn_skip = 1;
++				continue;
++			}
++			if (entry->size) {
++				if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) {
++					warn_size = 1;
++					entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
++				}
++
++				entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, fd, 0);
++				if (-1 == (int) (long) entry->uncompressed) {
++					perror("mmap");
++					exit(8);
++				}
++			}
++			close(fd);
++		} else if (S_ISLNK(st.st_mode)) {
++			entry->uncompressed = malloc(entry->size);
++			if (!entry->uncompressed) {
++				perror(NULL);
++				exit(8);
++			}
++			if (readlink(path, entry->uncompressed, entry->size) < 0) {
++				perror(path);
++				warn_skip = 1;
++				continue;
++			}
++		} else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
++			/* maybe we should skip sockets */
++			entry->size = 0;
++		} else {
++			entry->size = st.st_rdev;
++			if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
++				warn_dev = 1;
++		}
++
++		if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
++			int blocks = ((entry->size - 1) / blksize + 1);
++
++			/* block pointers & data expansion allowance + data */
++			if(entry->size)
++				*fslen_ub += (4+26)*blocks + entry->size + 3;
++                }
++
++		if (opt_xip && entry->mode & S_ISVTX) {
++			/* worse case, depending on where the offsets falls,
++			 * a single XIP entry could expand the sizeof the
++			 * file system by 8k, since we're aligning the start
++			 * and end on page boundary.
++			 */
++			*fslen_ub += 2*PAGE_CACHE_SIZE;
++		}
++
++		/* Link it into the list */
++		*prev = entry;
++		prev = &entry->next;
++		totalsize += size;
++	}
++	free(path);
++	free(dirlist);		/* allocated by scandir() with malloc() */
++	return totalsize;
++}
++
++/* Returns sizeof(struct cramfs_super), which includes the root inode. */
++static unsigned int write_superblock(struct entry *root, char *base, int size)
++{
++	struct cramfs_super *super = (struct cramfs_super *) base;
++	unsigned int offset = sizeof(struct cramfs_super) + image_length;
++
++	if (opt_pad) {
++		offset += opt_pad;
++	}
++
++	super->magic = CRAMFS_MAGIC;
++	super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
++	if (opt_holes)
++		super->flags |= CRAMFS_FLAG_HOLES;
++	if (image_length > 0)
++		super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET;
++	super->size = size;
++	memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
++
++	super->fsid.crc = crc32(0L, Z_NULL, 0);
++	super->fsid.edition = opt_edition;
++	super->fsid.blocks = total_blocks;
++	super->fsid.files = total_nodes;
++
++	memset(super->name, 0x00, sizeof(super->name));
++	if (opt_name)
++		strncpy(super->name, opt_name, sizeof(super->name));
++	else
++		strncpy(super->name, "Compressed", sizeof(super->name));
++
++	super->root.mode = root->mode;
++	super->root.uid = root->uid;
++	super->root.gid = root->gid;
++	super->root.size = root->size;
++	super->root.offset = offset >> 2;
++
++	return offset;
++}
++
++static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
++{
++	struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
++#ifdef DEBUG
++	assert ((offset & 3) == 0);
++#endif /* DEBUG */
++	if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
++		fprintf(stderr, "filesystem too big.  Exiting.\n");
++		exit(8);
++	}
++	inode->offset = (offset >> 2);
++}
++
++
++/*
++ * We do a width-first printout of the directory
++ * entries, using a stack to remember the directories
++ * we've seen.
++ */
++#define MAXENTRIES (100)
++static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
++{
++	int stack_entries = 0;
++	struct entry *entry_stack[MAXENTRIES];
++
++	for (;;) {
++		int dir_start = stack_entries;
++		while (entry) {
++			struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset);
++			size_t len = strlen(entry->name);
++
++			entry->dir_offset = offset;
++
++			inode->mode = entry->mode;
++			inode->uid = entry->uid;
++			inode->gid = entry->gid;
++			inode->size = entry->size;
++			inode->offset = 0;
++			/* Non-empty directories, regfiles and symlinks will
++			   write over inode->offset later. */
++
++			offset += sizeof(struct cramfs_inode);
++			total_nodes++;	/* another node */
++			memcpy(base + offset, entry->name, len);
++			/* Pad up the name to a 4-byte boundary */
++			while (len & 3) {
++				*(base + offset + len) = '\0';
++				len++;
++			}
++			inode->namelen = len >> 2;
++			offset += len;
++
++			/* TODO: this may get it wrong for chars >= 0x80.
++			   Most filesystems use UTF8 encoding for filenames,
++			   whereas the console is a single-byte character
++			   set like iso-latin-1. */
++			printf("  %s\n", entry->name);
++			if (entry->child) {
++				if (stack_entries >= MAXENTRIES) {
++					fprintf(stderr, "Exceeded MAXENTRIES.  Raise this value in mkcramfs.c and recompile.  Exiting.\n");
++					exit(8);
++				}
++				entry_stack[stack_entries] = entry;
++				stack_entries++;
++			}
++			entry = entry->next;
++		}
++
++		/*
++		 * Reverse the order the stack entries pushed during
++                 * this directory, for a small optimization of disk
++                 * access in the created fs.  This change makes things
++                 * `ls -UR' order.
++		 */
++		{
++			struct entry **lo = entry_stack + dir_start;
++			struct entry **hi = entry_stack + stack_entries;
++			struct entry *tmp;
++
++			while (lo < --hi) {
++				tmp = *lo;
++				*lo++ = *hi;
++				*hi = tmp;
++			}
++		}
++
++		/* Pop a subdirectory entry from the stack, and recurse. */
++		if (!stack_entries)
++			break;
++		stack_entries--;
++		entry = entry_stack[stack_entries];
++
++		set_data_offset(entry, base, offset);
++		printf("'%s':\n", entry->name);
++		entry = entry->child;
++	}
++	return offset;
++}
++
++static int is_zero(char const *begin, unsigned len)
++{
++	if (opt_holes)
++		/* Returns non-zero iff the first LEN bytes from BEGIN are
++		   all NULs. */
++		return (len-- == 0 ||
++			(begin[0] == '\0' &&
++			 (len-- == 0 ||
++			  (begin[1] == '\0' &&
++			   (len-- == 0 ||
++			    (begin[2] == '\0' &&
++			     (len-- == 0 ||
++			      (begin[3] == '\0' &&
++			       memcmp(begin, begin + 4, len) == 0))))))));
++	else
++		/* Never create holes. */
++		return 0;
++}
++
++static unsigned int do_xip(char *base, unsigned int offset,
++			   char const *name, char *uncompressed,
++			   unsigned int size)
++{
++	unsigned int start, end;
++
++	/* align to page boundary */
++
++	start = ROM_ALIGN(offset);
++	memset(base + offset, 0, start - offset);
++
++	memcpy(base + start, uncompressed, size);
++
++	/* pad to page boundary */
++
++	end = ROM_ALIGN(start + size);
++	memset(base + start + size, 0, end - (start + size));
++
++	printf("XIP (%u+%u bytes)\toffset %u\t%s\n",
++	       size, (end - offset) - size, offset, name);
++
++	return end;
++}
++
++/*
++ * One 4-byte pointer per block and then the actual blocked
++ * output. The first block does not need an offset pointer,
++ * as it will start immediately after the pointer block;
++ * so the i'th pointer points to the end of the i'th block
++ * (i.e. the start of the (i+1)'th block or past EOF).
++ *
++ * Note that size > 0, as a zero-sized file wouldn't ever
++ * have gotten here in the first place.
++ */
++static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
++{
++	unsigned long original_size = size;
++	unsigned long original_offset = offset;
++	unsigned long new_size;
++	unsigned long blocks = (size - 1) / blksize + 1;
++	unsigned long curr = offset + 4 * blocks;
++	int change;
++
++	total_blocks += blocks;
++
++	do {
++		unsigned long len = 2 * blksize;
++		unsigned int input = size;
++		if (input > blksize)
++			input = blksize;
++		size -= input;
++		if (!is_zero (uncompressed, input)) {
++			compress(base + curr, &len, uncompressed, input);
++			curr += len;
++		}
++		uncompressed += input;
++
++		if (len > blksize*2) {
++			/* (I don't think this can happen with zlib.) */
++			printf("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
++			exit(8);
++		}
++
++		*(u32 *) (base + offset) = curr;
++		offset += 4;
++	} while (size);
++
++	curr = (curr + 3) & ~3;
++	new_size = curr - original_offset;
++	/* TODO: Arguably, original_size in these 2 lines should be
++	   st_blocks * 512.  But if you say that then perhaps
++	   administrative data should also be included in both. */
++	change = new_size - original_size;
++	printf("%6.2f%% (%+d bytes)\toffset %lu\t%s\n",
++	       (change * 100) / (double) original_size, change, original_offset, name);
++
++	return curr;
++}
++
++
++/*
++ * Traverse the entry tree, writing data for every item that has
++ * non-null entry->compressed (i.e. every symlink and non-empty
++ * regfile).
++ */
++static unsigned int write_data(struct entry *entry, char *base, unsigned int offset)
++{
++	do {
++		if (entry->uncompressed) {
++                        if(entry->same) {
++                                set_data_offset(entry, base, entry->same->offset);
++                                entry->offset=entry->same->offset;
++                        } else {
++                                set_data_offset(entry, base, offset);
++                                entry->offset=offset;
++				if (opt_xip && entry->mode & S_ISVTX)
++					offset = do_xip(base, offset, entry->name, entry->uncompressed, entry->size);
++				else
++                                offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);
++                        }
++		}
++		else if (entry->child)
++			offset = write_data(entry->child, base, offset);
++                entry=entry->next;
++	} while (entry);
++	return offset;
++}
++
++static unsigned int write_file(char *file, char *base, unsigned int offset)
++{
++	int fd;
++	char *buf;
++
++	fd = open(file, O_RDONLY);
++	if (fd < 0) {
++		perror(file);
++		exit(8);
++	}
++	buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
++	memcpy(base + offset, buf, image_length);
++	munmap(buf, image_length);
++	close (fd);
++	/* Pad up the image_length to a 4-byte boundary */
++	while (image_length & 3) {
++		*(base + offset + image_length) = '\0';
++		image_length++;
++	}
++	return (offset + image_length);
++}
++
++/*
++ * Maximum size fs you can create is roughly 256MB.  (The last file's
++ * data must begin within 256MB boundary but can extend beyond that.)
++ *
++ * Note that if you want it to fit in a ROM then you're limited to what the
++ * hardware and kernel can support (64MB?).
++ */
++#define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \
++		  + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \
++		  + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ )
++
++
++/*
++ * Usage:
++ *
++ *      mkcramfs directory-name outfile
++ *
++ * where "directory-name" is simply the root of the directory
++ * tree that we want to generate a compressed filesystem out
++ * of.
++ */
++int main(int argc, char **argv)
++{
++	struct stat st;		/* used twice... */
++	struct entry *root_entry;
++	char *rom_image;
++	ssize_t offset, written;
++	int fd;
++	/* initial guess (upper-bound) of required filesystem size */
++	loff_t fslen_ub = sizeof(struct cramfs_super);
++	char const *dirname, *outfile;
++	u32 crc = crc32(0L, Z_NULL, 0);
++	int c;			/* for getopt */
++
++	total_blocks = 0;
++
++	if (argc)
++		progname = argv[0];
++
++	/* command line options */
++	while ((c = getopt(argc, argv, "hEe:i:n:psxz")) != EOF) {
++		switch (c) {
++		case 'h':
++			usage(0);
++		case 'E':
++			opt_errors = 1;
++			break;
++		case 'e':
++			opt_edition = atoi(optarg);
++			break;
++		case 'i':
++			opt_image = optarg;
++			if (lstat(opt_image, &st) < 0) {
++				perror(opt_image);
++				exit(16);
++			}
++			image_length = st.st_size; /* may be padded later */
++			fslen_ub += (image_length + 3); /* 3 is for padding */
++			break;
++		case 'n':
++			opt_name = optarg;
++			break;
++		case 'p':
++			opt_pad = PAD_SIZE;
++			fslen_ub += PAD_SIZE;
++			break;
++		case 's':
++			/* old option, ignored */
++			break;
++		case 'x':
++			opt_xip = 1;
++			break;
++		case 'z':
++			opt_holes = 1;
++			break;
++		}
++	}
++
++	if ((argc - optind) != 2)
++		usage(16);
++	dirname = argv[optind];
++	outfile = argv[optind + 1];
++
++	if (stat(dirname, &st) < 0) {
++		perror(dirname);
++		exit(16);
++	}
++	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
++
++	root_entry = calloc(1, sizeof(struct entry));
++	if (!root_entry) {
++		perror(NULL);
++		exit(8);
++	}
++	root_entry->mode = st.st_mode;
++	root_entry->uid = st.st_uid;
++	root_entry->gid = st.st_gid;
++
++	root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
++
++	/* always allocate a multiple of blksize bytes because that's
++           what we're going to write later on */
++	fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
++
++	if (fslen_ub > MAXFSLEN) {
++		fprintf(stderr,
++			"warning: guestimate of required size (upper bound) is %LdMB, but maximum image size is %uMB.  We might die prematurely.\n",
++			fslen_ub >> 20,
++			MAXFSLEN >> 20);
++		fslen_ub = MAXFSLEN;
++	}
++
++        /* find duplicate files. TODO: uses the most inefficient algorithm
++           possible. */
++        eliminate_doubles(root_entry,root_entry);
++
++	/* TODO: Why do we use a private/anonymous mapping here
++           followed by a write below, instead of just a shared mapping
++           and a couple of ftruncate calls?  Is it just to save us
++           having to deal with removing the file afterwards?  If we
++           really need this huge anonymous mapping, we ought to mmap
++           in smaller chunks, so that the user doesn't need nn MB of
++           RAM free.  If the reason is to be able to write to
++           un-mmappable block devices, then we could try shared mmap
++           and revert to anonymous mmap if the shared mmap fails. */
++	rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
++
++	if (-1 == (int) (long) rom_image) {
++		perror("ROM image map");
++		exit(8);
++	}
++
++	/* Skip the first opt_pad bytes for boot loader code */
++	offset = opt_pad;
++	memset(rom_image, 0x00, opt_pad);
++
++	/* Skip the superblock and come back to write it later. */
++	offset += sizeof(struct cramfs_super);
++
++	/* Insert a file image. */
++	if (opt_image) {
++		printf("Including: %s\n", opt_image);
++		offset = write_file(opt_image, rom_image, offset);
++	}
++
++	offset = write_directory_structure(root_entry->child, rom_image, offset);
++	printf("Directory data: %d bytes\n", offset);
++
++	offset = write_data(root_entry, rom_image, offset);
++
++	/* We always write a multiple of blksize bytes, so that
++           losetup works. */
++	offset = ((offset - 1) | (blksize - 1)) + 1;
++	printf("Everything: %d kilobytes\n", offset >> 10);
++
++	/* Write the superblock now that we can fill in all of the fields. */
++	write_superblock(root_entry, rom_image+opt_pad, offset);
++	printf("Super block: %d bytes\n", sizeof(struct cramfs_super));
++
++	/* Put the checksum in. */
++	crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
++	((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
++	printf("CRC: %x\n", crc);
++
++	/* Check to make sure we allocated enough space. */
++	if (fslen_ub < offset) {
++		fprintf(stderr, "not enough space allocated for ROM image (%Ld allocated, %d used)\n",
++			fslen_ub, offset);
++		exit(8);
++	}
++
++	written = write(fd, rom_image, offset);
++	if (written < 0) {
++		perror("ROM image");
++		exit(8);
++	}
++	if (offset != written) {
++		fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset);
++		exit(8);
++	}
++
++	/* (These warnings used to come at the start, but they scroll off the
++           screen too quickly.) */
++	if (warn_namelen) /* (can't happen when reading from ext2fs) */
++		fprintf(stderr, /* bytes, not chars: think UTF8. */
++			"warning: filenames truncated to 255 bytes.\n");
++	if (warn_skip)
++		fprintf(stderr, "warning: files were skipped due to errors.\n");
++	if (warn_size)
++		fprintf(stderr,
++			"warning: file sizes truncated to %luMB (minus 1 byte).\n",
++			1L << (CRAMFS_SIZE_WIDTH - 20));
++	if (warn_uid) /* (not possible with current Linux versions) */
++		fprintf(stderr,
++			"warning: uids truncated to %u bits.  (This may be a security concern.)\n",
++			CRAMFS_UID_WIDTH);
++	if (warn_gid)
++		fprintf(stderr,
++			"warning: gids truncated to %u bits.  (This may be a security concern.)\n",
++			CRAMFS_GID_WIDTH);
++	if (warn_dev)
++		fprintf(stderr,
++			"WARNING: device numbers truncated to %u bits.  This almost certainly means\n"
++			"that some device files will be wrong.\n",
++			CRAMFS_OFFSET_WIDTH);
++	if (opt_errors &&
++	    (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev))
++		exit(8);
++	return 0;
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/bitfield.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,113 @@
++/*
++ *	FILE    	bitfield.h
++ *
++ *	Version 	1.1
++ *	Author  	Copyright (c) Marc A. Viredaz, 1998
++ *	        	DEC Western Research Laboratory, Palo Alto, CA
++ *	Date    	April 1998 (April 1997)
++ *	System  	Advanced RISC Machine (ARM)
++ *	Language	C or ARM Assembly
++ *	Purpose 	Definition of macros to operate on bit fields.
++ */
++
++
++
++#ifndef __BITFIELD_H
++#define __BITFIELD_H
++
++#ifndef __ASSEMBLY__
++#define UData(Data)	((unsigned long) (Data))
++#else
++#define UData(Data)	(Data)
++#endif
++
++
++/*
++ * MACRO: Fld
++ *
++ * Purpose
++ *    The macro "Fld" encodes a bit field, given its size and its shift value
++ *    with respect to bit 0.
++ *
++ * Note
++ *    A more intuitive way to encode bit fields would have been to use their
++ *    mask. However, extracting size and shift value information from a bit
++ *    field's mask is cumbersome and might break the assembler (255-character
++ *    line-size limit).
++ *
++ * Input
++ *    Size      	Size of the bit field, in number of bits.
++ *    Shft      	Shift value of the bit field with respect to bit 0.
++ *
++ * Output
++ *    Fld       	Encoded bit field.
++ */
++
++#define Fld(Size, Shft)	(((Size) << 16) + (Shft))
++
++
++/*
++ * MACROS: FSize, FShft, FMsk, FAlnMsk, F1stBit
++ *
++ * Purpose
++ *    The macros "FSize", "FShft", "FMsk", "FAlnMsk", and "F1stBit" return
++ *    the size, shift value, mask, aligned mask, and first bit of a
++ *    bit field.
++ *
++ * Input
++ *    Field     	Encoded bit field (using the macro "Fld").
++ *
++ * Output
++ *    FSize     	Size of the bit field, in number of bits.
++ *    FShft     	Shift value of the bit field with respect to bit 0.
++ *    FMsk      	Mask for the bit field.
++ *    FAlnMsk   	Mask for the bit field, aligned on bit 0.
++ *    F1stBit   	First bit of the bit field.
++ */
++
++#define FSize(Field)	((Field) >> 16)
++#define FShft(Field)	((Field) & 0x0000FFFF)
++#define FMsk(Field)	(((UData (1) << FSize (Field)) - 1) << FShft (Field))
++#define FAlnMsk(Field)	((UData (1) << FSize (Field)) - 1)
++#define F1stBit(Field)	(UData (1) << FShft (Field))
++
++
++/*
++ * MACRO: FInsrt
++ *
++ * Purpose
++ *    The macro "FInsrt" inserts a value into a bit field by shifting the
++ *    former appropriately.
++ *
++ * Input
++ *    Value     	Bit-field value.
++ *    Field     	Encoded bit field (using the macro "Fld").
++ *
++ * Output
++ *    FInsrt    	Bit-field value positioned appropriately.
++ */
++
++#define FInsrt(Value, Field) \
++                	(UData (Value) << FShft (Field))
++
++
++/*
++ * MACRO: FExtr
++ *
++ * Purpose
++ *    The macro "FExtr" extracts the value of a bit field by masking and
++ *    shifting it appropriately.
++ *
++ * Input
++ *    Data      	Data containing the bit-field to be extracted.
++ *    Field     	Encoded bit field (using the macro "Fld").
++ *
++ * Output
++ *    FExtr     	Bit-field value.
++ */
++
++#define FExtr(Data, Field) \
++                	((UData (Data) >> FShft (Field)) & FAlnMsk (Field))
++
++
++#endif /* __BITFIELD_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/cerf.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,177 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/cerf.h
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++/*
++ * Add CerfBoard Specifics here...
++ */
++
++/*
++ * Memory sizes
++ */
++
++#define CERF_RAM_BASE			0xa0000000
++
++#ifdef CONFIG_PXA_CERF_RAM_128MB
++#define CERF_RAM_SIZE			128*1024*1024
++
++#elif defined (CONFIG_PXA_CERF_RAM_64MB)
++#define CERF_RAM_SIZE			64*1024*1024
++
++#elif defined (CONFIG_PXA_CERF_RAM_32MB)
++#define CERF_RAM_SIZE			32*1024*1024
++
++#elif defined (CONFIG_PXA_CERF_RAM_16MB)
++#define CERF_RAM_SIZE			16*1024*1024
++#endif
++
++/*
++ * CS memory timing via Static Memory Control Register (MSC0-2)
++ */
++
++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4))
++
++#define MSC_RBUFF_SHIFT 15 
++#define MSC_RBUFF_SLOW (0)
++#define MSC_RBUFF_FAST (1)
++#define MSC_RBUFF(x) ((x)<<MSC_RBUFF_SHIFT)
++
++#define MSC_RRR_SHIFT 12
++#define MSC_RRR(x) ((x)<<MSC_RRR_SHIFT)
++
++#define MSC_RDN_SHIFT 8
++#define MSC_RDN(x) ((x)<<MSC_RDN_SHIFT)
++
++#define MSC_RDF_SHIFT 4
++#define MSC_RDF(x) ((x)<<MSC_RDF_SHIFT)
++
++#define MSC_RBW_SHIFT 3
++#define MSC_RBW(x) ((x)<<MSC_RBW_SHIFT)
++
++#define MSC_RT_SHIFT  0
++#define MSC_RT(x) ((x)<<MSC_RT_SHIFT)
++
++/*
++ * IO Pins for devices
++ */
++
++#define CERF_FLASH_BASE			0xe8000000
++#define CERF_FLASH_SIZE			0x02000000
++#define CERF_FLASH_PHYS			PXA_CS0_PHYS
++
++#define CERF_ETH_BASE			0xf0000000
++#define CERF_ETH_SIZE			0x00100000
++#define CERF_ETH_PHYS			PXA_CS1_PHYS
++
++#define CERF_BT_BASE			0xf2000000
++#define CERF_BT_SIZE			0x00100000
++#define CERF_BT_PHYS			PXA_CS2_PHYS
++
++#define CERF_SERIAL_BASE		0xf3000000
++#define CERF_SERIAL_SIZE		0x00100000
++#define CERF_SERIAL_PHYS		PXA_CS3_PHYS
++
++#define CERF_CPLD_BASE			0xf1000000
++#define CERF_CPLD_SIZE			0x00100000
++#define CERF_CPLD_PHYS			PXA_CS4_PHYS
++
++#define CERF_PDA_CPLD_WRCLRINT		(0x0)
++#define CERF_PDA_CPLD_BRIGHTNESS	(0x2)
++#define CERF_PDA_CPLD_KEYPAD_A		(0x6)
++#define CERF_PDA_CPLD_BATTFAULT		(0x8)
++#define CERF_PDA_CPLD_KEYPAD_B		(0xa)
++#define CERF_PDA_CPLD_SOUND_ENA		(0xc)
++
++#define CERF_PDA_SOUND_ENABLE		0x1
++#define CERF_PDA_DEFAULT_BRIGHTNESS	0x9
++
++/*
++ * Access functions (registers are 4-bit wide)
++ */
++
++#define CERF_PDA_CPLD CERF_CPLD_BASE
++
++#define CERF_PDA_CPLD_Get(x, y)      (*((char*)(CERF_PDA_CPLD + (x))) & (y))
++#define CERF_PDA_CPLD_Set(x, y, z)   (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) | (y))
++#define CERF_PDA_CPLD_UnSet(x, y, z) (*((char*)(CERF_PDA_CPLD + (x))) = (*((char*)(CERF_PDA_CPLD + (x))) & ~(z)) & ~(y))
++
++/* 
++ * IO and IRQ settings for cs8900 ethernet chip
++ */
++#define CERF_ETH_IO		CERF_ETH_BASE
++#define CERF_ETH_IRQ 		GPIO_2_80_TO_IRQ(21)
++
++/*
++ * We only have one LED on the XScale CerfPDA so only the
++ * time or idle should ever be selected.
++ */
++#define CERF_HEARTBEAT_LED 0x1
++#define CERF_SYS_BUSY_LED  0x2
++
++#define CERF_HEARTBEAT_LED_GPIO	16 // GPIO 4
++#define CERF_SYS_BUSY_LED_GPIO	16 // GPIO 4
++
++#define CERF_HEARTBEAT_LED_ON  (GPSR0 = CERF_HEARTBEAT_LED_GPIO)
++#define CERF_HEARTBEAT_LED_OFF (GPCR0 = CERF_HEARTBEAT_LED_GPIO)
++#define CERF_SYS_BUSY_LED_ON  (GPSR0 = CERF_SYS_BUSY_LED_GPIO)
++#define CERF_SYS_BUSY_LED_OFF (GPCR0 = CERF_SYS_BUSY_LED_GPIO)
++
++/*
++ * UCB 1400 gpio
++ */
++
++#define CERF_GPIO_UCB1400_IRQ 32
++
++#define UCB_IO_0                (1 << 0)
++#define UCB_IO_1                (1 << 1)
++#define UCB_IO_2                (1 << 2)
++#define UCB_IO_3                (1 << 3)
++#define UCB_IO_4                (1 << 4)
++#define UCB_IO_5                (1 << 5)
++#define UCB_IO_6                (1 << 6)
++#define UCB_IO_7                (1 << 7)
++#define UCB_IO_8                (1 << 8)
++#define UCB_IO_9                (1 << 9)
++
++#define UCB1400_GPIO_CONT_CS      UCB_IO_0
++#define UCB1400_GPIO_CONT_DOWN    UCB_IO_1
++#define UCB1400_GPIO_CONT_INC     UCB_IO_2
++#define UCB1400_GPIO_CONT_ENA     UCB_IO_3
++#define UCB1400_GPIO_LCD_RESET    UCB_IO_4
++#define UCB1400_GPIO_IRDA_ENABLE  UCB_IO_5
++#define UCB1400_GPIO_BT_ENABLE    UCB_IO_6
++#define UCB1400_GPIO_TEST_P1      UCB_IO_7
++#define UCB1400_GPIO_TEST_P2      UCB_IO_8
++#define UCB1400_GPIO_TEST_P3      UCB_IO_9
++
++/*
++ * IRQ for devices
++ */
++#define UCB1400_IRQ(x)          (NR_IRQS + 1 + (x))
++
++#define IRQ_UCB1400_IO0         UCB1400_IRQ(0)
++#define IRQ_UCB1400_IO1         UCB1400_IRQ(1)
++#define IRQ_UCB1400_IO2         UCB1400_IRQ(2)
++#define IRQ_UCB1400_IO3         UCB1400_IRQ(3)
++#define IRQ_UCB1400_IO4         UCB1400_IRQ(4)
++#define IRQ_UCB1400_IO5         UCB1400_IRQ(5)
++#define IRQ_UCB1400_IO6         UCB1400_IRQ(6)
++#define IRQ_UCB1400_IO7         UCB1400_IRQ(7)
++#define IRQ_UCB1400_IO8         UCB1400_IRQ(8)
++#define IRQ_UCB1400_IO9         UCB1400_IRQ(9)
++
++#define IRQ_UCB1400_CONT_CS     IRQ_UCB1400_IO0
++#define IRQ_UCB1400_CONT_DOWN   IRQ_UCB1400_IO1
++#define IRQ_UCB1400_CONT_INC    IRQ_UCB1400_IO2
++#define IRQ_UCB1400_CONT_ENA    IRQ_UCB1400_IO3
++#define IRQ_UCB1400_LCD_RESET   IRQ_UCB1400_IO4
++#define IRQ_UCB1400_IRDA_ENABLE IRQ_UCB1400_IO5
++#define IRQ_UCB1400_BT_ENABLE   IRQ_UCB1400_IO6
++#define IRQ_UCB1400_TEST_P1     IRQ_UCB1400_IO7
++#define IRQ_UCB1400_TEST_P2     IRQ_UCB1400_IO8
++#define IRQ_UCB1400_TEST_P3     IRQ_UCB1400_IO9
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/cerf_ucb1400gpio.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,30 @@
++/*
++ *  cerf_ucb1400gpio.h
++ *
++ *  UCB1400 GPIO control stuff for the cerf.
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Mar 2002: Initial version [FB]
++ * 
++ */
++/* -- lcd -- */
++extern void cerf_ucb1400gpio_lcd_enable( void);
++extern void cerf_ucb1400gpio_lcd_disable( void);
++extern void cerf_ucb1400gpio_lcd_contrast_step( int direction);
++
++/* -- irda -- */
++extern void cerf_ucb1400gpio_irda_enable( void);
++extern void cerf_ucb1400gpio_irda_disable( void);
++
++/* -- bt -- */
++extern void cerf_ucb1400gpio_bt_enable( void);
++extern void cerf_ucb1400gpio_bt_disable( void);
++
++/* -- init -- */
++extern int cerf_ucb1400gpio_init(void);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/csb226.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,99 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/csb226.h
++ *
++ *  Author:	Robert Schwebel (stolen from lubbock.h)
++ *  Created:	Oct 30, 2002
++ *  Copyright:	Pengutronix
++ *  
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define CSB226_FPGA_PHYS	PXA_CS2_PHYS    
++
++#define CSB226_FPGA_VIRT	(0xf0000000)	/* phys 0x08000000 */
++#define CSB226_ETH_BASE		(0xf1000000)	/* phys 0x0c000000 */
++
++#define CSB226_P2V(x)		((x) - CSB226_FPGA_PHYS + CSB226_FPGA_VIRT)
++#define CSB226_V2P(x)		((x) - CSB226_FPGA_VIRT + CSB226_FPGA_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __CSB226_REG(x)	(*((volatile unsigned long *)CSB226_P2V(x)))
++#else
++#  define __CSB226_REG(x)	CSB226_P2V(x)
++#endif
++
++
++/* register physical addresses */
++#define _CSB226_MISC_WR		(CSB226_FPGA_PHYS + 0x080)
++#define _CSB226_MISC_RD		(CSB226_FPGA_PHYS + 0x090)
++#define _CSB226_IRQ_MASK_EN	(CSB226_FPGA_PHYS + 0x0C0)
++#define _CSB226_IRQ_SET_CLR	(CSB226_FPGA_PHYS + 0x0D0)
++#define _CSB226_GP		(CSB226_FPGA_PHYS + 0x100)
++
++
++
++/* register virtual addresses */
++
++#define CSB226_MISC_WR             __CSB226_REG(_CSB226_MISC_WR) 
++#define CSB226_MISC_RD             __CSB226_REG(_CSB226_MISC_RD)         
++#define CSB226_IRQ_MASK_EN         __CSB226_REG(_CSB226_IRQ_MASK_EN)
++#define CSB226_IRQ_SET_CLR         __CSB226_REG(_CSB226_IRQ_SET_CLR)             
++#define CSB226_GP                  __CSB226_REG(_CSB226_GP)      
++
++
++/* GPIOs */
++
++#define GPIO_CSB226_IRQ		0
++#define IRQ_GPIO_CSB226_IRQ	IRQ_GPIO0
++
++
++/*
++ * LED macros
++ */
++
++// #define LEDS_BASE LUB_DISC_BLNK_LED
++
++// 8 discrete leds available for general use:
++
++/*
++#define D28	0x1
++#define D27	0x2
++#define D26	0x4
++#define D25	0x8
++#define D24	0x10
++#define D23	0x20
++#define D22	0x40
++#define D21	0x80
++*/
++
++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so
++*  be sure to not monkey with them here.
++*/
++
++/*
++#define HEARTBEAT_LED	D28
++#define SYS_BUSY_LED    D27
++#define HEXLEDS_BASE LUB_HEXLED
++
++#define HEARTBEAT_LED_ON  (LEDS_BASE &= ~HEARTBEAT_LED)
++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED)
++#define SYS_BUSY_LED_OFF  (LEDS_BASE |= SYS_BUSY_LED)
++#define SYS_BUSY_LED_ON   (LEDS_BASE &= ~SYS_BUSY_LED)
++
++// use x = D26-D21 for these, please...
++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x))
++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x))
++*/
++
++#ifndef __ASSEMBLY__
++
++//extern int hexled_val = 0;
++
++#endif
++
++/*
++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++)
++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--)
++*/
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/dma.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,49 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/dma.h
++ *  
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __ASM_ARCH_DMA_H
++#define __ASM_ARCH_DMA_H
++
++#define MAX_DMA_ADDRESS		0xffffffff
++
++/* No DMA as the rest of the world see it */
++#define MAX_DMA_CHANNELS	0
++
++/*
++ * Descriptor structure for PXA's DMA engine
++ * Note: this structure must always be aligned to a 16-byte boundary.
++ */
++
++typedef struct {
++	volatile u32 ddadr;	/* Points to the next descriptor + flags */
++	volatile u32 dsadr;	/* DSADR value for the current transfer */
++	volatile u32 dtadr;	/* DTADR value for the current transfer */
++	volatile u32 dcmd;	/* DCMD value for the current transfer */
++} pxa_dma_desc;
++
++/*
++ * DMA registration
++ */
++
++typedef enum {
++	DMA_PRIO_HIGH = 0,
++	DMA_PRIO_MEDIUM = 4,
++	DMA_PRIO_LOW = 8
++} pxa_dma_prio;
++
++int pxa_request_dma (char *name,
++			 pxa_dma_prio prio,
++			 void (*irq_handler)(int, void *, struct pt_regs *),
++			 void *data);
++
++void pxa_free_dma (int dma_ch);
++
++#endif /* _ASM_ARCH_DMA_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/hardware.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,142 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/hardware.h
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H
++#define __ASM_ARCH_HARDWARE_H
++
++#include <linux/config.h>
++#include <asm/mach-types.h>
++
++
++/*
++ * These are statically mapped PCMCIA IO space for designs using it as a
++ * generic IO bus, typically with ISA parts, hardwired IDE interfaces, etc.
++ * The actual PCMCIA code is mapping required IO region at run time.
++ */
++#define PCMCIA_IO_0_BASE	0xf6000000
++#define PCMCIA_IO_1_BASE	0xf7000000
++
++
++/*
++ * XIP kernel text mapping.
++ * Note: the exact virtual address is also specified in arch/arm/Makefile.
++ */
++#ifdef CONFIG_XIP_KERNEL
++#define KERNEL_XIP_BASE_PHYS	(CONFIG_XIP_PHYS_ADDR & 0xffe00000)
++#define KERNEL_XIP_BASE_VIRT	0xe8000000
++#endif
++
++
++/*
++ * We requires absolute addresses.
++ */
++#define PCIO_BASE		0
++
++/*
++ * Workarounds for at least 2 errata so far require this.
++ * The mapping is set in mach-pxa/generic.c.
++ */
++#define UNCACHED_PHYS_0		0xff000000
++#define UNCACHED_ADDR		UNCACHED_PHYS_0
++
++/*
++ * Intel PXA internal I/O mappings:
++ *
++ * 0x40000000 - 0x41ffffff <--> 0xf8000000 - 0xf9ffffff
++ * 0x44000000 - 0x45ffffff <--> 0xfa000000 - 0xfbffffff
++ * 0x48000000 - 0x49ffffff <--> 0xfc000000 - 0xfdffffff
++ */
++
++#define io_p2v(x)	( ((x) | 0xbe000000) ^ (~((x) >> 1) & 0x06000000) )
++#define io_v2p( x )	( ((x) & 0x41ffffff) ^ ( ((x) & 0x06000000) << 1) )
++
++#ifndef __ASSEMBLY__
++
++#if 0
++# define __REG(x)	(*((volatile u32 *)io_p2v(x)))
++#else
++/*
++ * This __REG() version gives the same results as the one above,  except
++ * that we are fooling gcc somehow so it generates far better and smaller
++ * assembly code for access to contigous registers.  It's a shame that gcc
++ * doesn't guess this by itself.
++ */
++#include <asm/types.h>
++typedef struct { volatile u32 offset[4096]; } __regbase;
++# define __REGP(x)	((__regbase *)((x)&~4095))->offset[((x)&4095)>>2]
++# define __REG(x)	__REGP(io_p2v(x))
++#endif
++
++/* Let's kick gcc's ass again... */
++# define __REG2(x,y)	\
++	( __builtin_constant_p(y) ? (__REG((x) + (y))) \
++				  : (*(volatile u32 *)((u32)&__REG(x) + (y))) )
++
++# define __PREG(x)	(io_v2p((u32)&(x)))
++
++#else
++
++# define __REG(x)	io_p2v(x)
++# define __PREG(x)	io_v2p(x)
++
++#endif
++
++#include "pxa-regs.h"
++
++#ifndef __ASSEMBLY__
++
++/*
++ * GPIO edge detection for IRQs:
++ * IRQs are generated on Falling-Edge, Rising-Edge, or both.
++ * This must be called *before* the corresponding IRQ is registered.
++ * Use this instead of directly setting GRER/GFER.
++ */
++#define GPIO_FALLING_EDGE       1
++#define GPIO_RISING_EDGE        2
++#define GPIO_BOTH_EDGES         3
++extern void set_GPIO_IRQ_edge( int gpio_nr, int edge_mask );
++
++/*
++ * Handy routine to set GPIO alternate functions
++ */
++extern void set_GPIO_mode( int gpio_mode );
++
++/*
++ * return current lclk frequency in units of 10kHz
++ */
++extern unsigned int get_lclk_frequency_10khz(void);
++
++/*
++ * return current clk frequency in units of 1kHz
++ */
++extern unsigned int get_clk_frequency_khz( int info);
++
++#endif
++
++
++/*
++ * Implementation specifics
++ */
++
++//#ifdef CONFIG_ARCH_LUBBOCK
++#include "lubbock.h"
++//#endif
++
++//#ifdef CONFIG_ARCH_PXA_IDP
++#include "idp.h"
++//#endif
++
++//#ifdef CONFIG_ARCH_PXA_CERF
++#include "cerf.h"
++//#endif
++
++#endif  /* _ASM_ARCH_HARDWARE_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/ide.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,59 @@
++/*
++ * linux/include/asm-arm/arch-pxa/ide.h
++ *
++ * Author:	George Davis
++ * Created:	Jan 10, 2002
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *
++ * Originally based upon linux/include/asm-arm/arch-sa1100/ide.h
++ *
++ */
++
++#include <linux/config.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++
++
++/*
++ * Set up a hw structure for a specified data port, control port and IRQ.
++ * This should follow whatever the default interface uses.
++ */
++static __inline__ void
++ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
++{
++	ide_ioreg_t reg;
++
++	memset(hw, 0, sizeof(*hw));
++
++	reg = (ide_ioreg_t)data_port;
++
++	hw->io_ports[IDE_DATA_OFFSET] =  reg + 0;
++	hw->io_ports[IDE_ERROR_OFFSET] = reg + 1;
++	hw->io_ports[IDE_NSECTOR_OFFSET] = reg + 2;
++	hw->io_ports[IDE_SECTOR_OFFSET] = reg + 3;
++	hw->io_ports[IDE_LCYL_OFFSET] = reg + 4;
++	hw->io_ports[IDE_HCYL_OFFSET] = reg + 5;
++	hw->io_ports[IDE_SELECT_OFFSET] = reg + 6;
++	hw->io_ports[IDE_STATUS_OFFSET] = reg + 7;
++
++	hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port;
++
++	if (irq)
++		*irq = 0;
++}
++
++
++/*
++ * Register the standard ports for this architecture with the IDE driver.
++ */
++static __inline__ void
++ide_init_default_hwifs(void)
++{
++	/* Nothing to declare... */
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/idp.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,468 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/idp.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2001 Cliff Brake, Accelent Systems Inc.
++ *
++ * 2001-09-13: Cliff Brake <cbrake@accelent.com>
++ *             Initial code
++ * 
++ */
++
++
++/*
++ * Note: this file must be safe to include in assembly files
++ */
++
++/* comment out following if you have a rev01 board */
++#define PXA_IDP_REV02	1
++//#undef PXA_IDP_REV02
++
++#ifdef PXA_IDP_REV02
++
++//Use this as well for 0017-x004 and greater pcb's:
++#define PXA_IDP_REV04 1
++
++#define IDP_FLASH_PHYS		(PXA_CS0_PHYS)
++#define IDP_ALT_FLASH_PHYS	(PXA_CS1_PHYS)
++#define IDP_MEDIAQ_PHYS		(PXA_CS3_PHYS)
++#define IDP_IDE_PHYS		(PXA_CS5_PHYS + 0x03000000)
++#define IDP_ETH_PHYS		(PXA_CS5_PHYS + 0x03400000)
++#define IDP_COREVOLT_PHYS	(PXA_CS5_PHYS + 0x03800000)
++#define IDP_CPLD_PHYS		(PXA_CS5_PHYS + 0x03C00000)
++
++
++/*
++ * virtual memory map
++ */
++
++#define IDP_IDE_BASE		(0xf0000000)
++#define IDP_IDE_SIZE		(1*1024*1024)
++
++#define IDP_ETH_BASE		(IDP_IDE_BASE + IDP_IDE_SIZE)
++#define IDP_ETH_SIZE		(1*1024*1024)
++#define ETH_BASE		IDP_ETH_BASE //smc9194 driver compatibility issue
++
++#define IDP_COREVOLT_BASE	(IDP_ETH_BASE + IDP_ETH_SIZE)
++#define IDP_COREVOLT_SIZE	(1*1024*1024)
++
++#define IDP_CPLD_BASE		(IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE)
++#define IDP_CPLD_SIZE		(1*1024*1024)
++
++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000
++#error Your custom IO space is getting a bit large !!
++#endif
++
++#define CPLD_P2V(x)		((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE)
++#define CPLD_V2P(x)		((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __CPLD_REG(x)		(*((volatile unsigned long *)CPLD_P2V(x)))
++#else
++#  define __CPLD_REG(x)		CPLD_P2V(x)
++#endif
++
++/* board level registers in the CPLD: (offsets from CPLD_BASE) */
++
++#define _IDP_CPLD_REV			(IDP_CPLD_PHYS + 0x00)
++#define _IDP_CPLD_PERIPH_PWR		(IDP_CPLD_PHYS + 0x04)
++#define _IDP_CPLD_LED_CONTROL		(IDP_CPLD_PHYS + 0x08)
++#define _IDP_CPLD_KB_COL_HIGH		(IDP_CPLD_PHYS + 0x0C)
++#define _IDP_CPLD_KB_COL_LOW		(IDP_CPLD_PHYS + 0x10)
++#define _IDP_CPLD_PCCARD_EN		(IDP_CPLD_PHYS + 0x14)
++#define _IDP_CPLD_GPIOH_DIR		(IDP_CPLD_PHYS + 0x18)
++#define _IDP_CPLD_GPIOH_VALUE		(IDP_CPLD_PHYS + 0x1C)
++#define _IDP_CPLD_GPIOL_DIR		(IDP_CPLD_PHYS + 0x20)
++#define _IDP_CPLD_GPIOL_VALUE		(IDP_CPLD_PHYS + 0x24)
++#define _IDP_CPLD_PCCARD_PWR		(IDP_CPLD_PHYS + 0x28)
++#define _IDP_CPLD_MISC_CTRL		(IDP_CPLD_PHYS + 0x2C)
++#define _IDP_CPLD_LCD			(IDP_CPLD_PHYS + 0x30)
++#define _IDP_CPLD_FLASH_WE		(IDP_CPLD_PHYS + 0x34)
++
++#define _IDP_CPLD_KB_ROW		(IDP_CPLD_PHYS + 0x50)
++#define _IDP_CPLD_PCCARD0_STATUS	(IDP_CPLD_PHYS + 0x54)
++#define _IDP_CPLD_PCCARD1_STATUS	(IDP_CPLD_PHYS + 0x58)
++#define _IDP_CPLD_MISC_STATUS		(IDP_CPLD_PHYS + 0x5C)
++
++/* FPGA register virtual addresses */
++
++#define IDP_CPLD_REV			__CPLD_REG(_IDP_CPLD_REV)
++#define IDP_CPLD_PERIPH_PWR		__CPLD_REG(_IDP_CPLD_PERIPH_PWR)
++#define IDP_CPLD_LED_CONTROL		__CPLD_REG(_IDP_CPLD_LED_CONTROL)		
++#define IDP_CPLD_KB_COL_HIGH		__CPLD_REG(_IDP_CPLD_KB_COL_HIGH)	
++#define IDP_CPLD_KB_COL_LOW		__CPLD_REG(_IDP_CPLD_KB_COL_LOW)	
++#define IDP_CPLD_PCCARD_EN		__CPLD_REG(_IDP_CPLD_PCCARD_EN)		
++#define IDP_CPLD_GPIOH_DIR		__CPLD_REG(_IDP_CPLD_GPIOH_DIR)		
++#define IDP_CPLD_GPIOH_VALUE		__CPLD_REG(_IDP_CPLD_GPIOH_VALUE)
++#define IDP_CPLD_GPIOL_DIR		__CPLD_REG(_IDP_CPLD_GPIOL_DIR)	
++#define IDP_CPLD_GPIOL_VALUE		__CPLD_REG(_IDP_CPLD_GPIOL_VALUE)
++#define IDP_CPLD_PCCARD_PWR		__CPLD_REG(_IDP_CPLD_PCCARD_PWR)	
++#define IDP_CPLD_MISC_CTRL		__CPLD_REG(_IDP_CPLD_MISC_CTRL)		
++#define IDP_CPLD_LCD			__CPLD_REG(_IDP_CPLD_LCD)		
++#define IDP_CPLD_FLASH_WE		__CPLD_REG(_IDP_CPLD_FLASH_WE)
++                                                                         
++#define IDP_CPLD_KB_ROW		        __CPLD_REG(_IDP_CPLD_KB_ROW)		
++#define IDP_CPLD_PCCARD0_STATUS	        __CPLD_REG(_IDP_CPLD_PCCARD0_STATUS)
++#define IDP_CPLD_PCCARD1_STATUS	        __CPLD_REG(_IDP_CPLD_PCCARD1_STATUS)	
++#define IDP_CPLD_MISC_STATUS		__CPLD_REG(_IDP_CPLD_MISC_STATUS)	
++
++
++/*
++ * Bit masks for various registers
++ */
++// IDP_CPLD_PCCARD_PWR
++#define PCC0_PWR0	(1 << 0)
++#define PCC0_PWR1	(1 << 1)
++#define PCC0_PWR2	(1 << 2)
++#define PCC0_PWR3	(1 << 3)
++#define PCC1_PWR0	(1 << 4)
++#define PCC1_PWR1	(1 << 5)
++#define PCC1_PWR2	(1 << 6)
++#define PCC1_PWR3	(1 << 7)
++
++// IDP_CPLD_PCCARD_EN
++#define PCC0_RESET	(1 << 6)
++#define PCC1_RESET	(1 << 7)
++#define PCC0_ENABLE	(1 << 0)
++#define PCC1_ENABLE	(1 << 1)
++
++// IDP_CPLD_PCCARDx_STATUS
++#define _PCC_WRPROT	(1 << 7) // 7-4 read as low true
++#define _PCC_RESET	(1 << 6)
++#define _PCC_IRQ	(1 << 5)
++#define _PCC_INPACK	(1 << 4)
++#define PCC_BVD2	(1 << 3)
++#define PCC_BVD1	(1 << 2)
++#define PCC_VS2		(1 << 1)
++#define PCC_VS1		(1 << 0)
++
++#define PCC_DETECT(x)	(GPLR(7 + (x)) & GPIO_bit(7 + (x)))
++
++/*
++ * Macros for LCD Driver
++ */
++
++#ifdef CONFIG_FB_PXA
++
++#define FB_BACKLIGHT_ON()	(IDP_CPLD_LCD |= (1<<1)) 
++#define FB_BACKLIGHT_OFF() 	(IDP_CPLD_LCD &= ~(1<<1))
++
++#define FB_PWR_ON() 		(IDP_CPLD_LCD |= (1<< 0))
++#define FB_PWR_OFF() 		(IDP_CPLD_LCD &= ~(1<<0))
++
++#define FB_VLCD_ON()		(IDP_CPLD_LCD |= (1<<2)) 
++#define FB_VLCD_OFF() 		(IDP_CPLD_LCD &= ~(1<<2))
++
++#endif
++
++/* A listing of interrupts used by external hardware devices */
++
++#ifdef PXA_IDP_REV04
++#define TOUCH_PANEL_IRQ			IRQ_GPIO(5)
++#define IDE_IRQ				IRQ_GPIO(21) 
++#else
++#define TOUCH_PANEL_IRQ			IRQ_GPIO(21)
++#define IDE_IRQ				IRQ_GPIO(5)
++#endif
++
++#define TOUCH_PANEL_IRQ_EDGE		GPIO_FALLING_EDGE
++
++#define IDE_IRQ_EDGE			GPIO_RISING_EDGE
++
++#define ETHERNET_IRQ			IRQ_GPIO(4)
++#define ETHERNET_IRQ_EDGE		GPIO_RISING_EDGE
++
++#define IDE_IRQ_EDGE			GPIO_RISING_EDGE
++
++#define PCMCIA_S0_CD_VALID		IRQ_GPIO(7)
++#define PCMCIA_S0_CD_VALID_EDGE		GPIO_BOTH_EDGES
++
++#define PCMCIA_S1_CD_VALID		IRQ_GPIO(8)
++#define PCMCIA_S1_CD_VALID_EDGE		GPIO_BOTH_EDGES
++
++#define PCMCIA_S0_RDYINT		IRQ_GPIO(19)
++#define PCMCIA_S1_RDYINT		IRQ_GPIO(22)
++
++/*
++ * Macros for LED Driver
++ */
++
++/* leds 0 = ON */
++#define IDP_HB_LED	(1<<5)	
++#define IDP_BUSY_LED	(1<<6)
++
++#define IDP_LEDS_MASK	(IDP_HB_LED | IDP_BUSY_LED)
++
++#define IDP_WRITE_LEDS(value)	(IDP_CPLD_LED_CONTROL = (IDP_CPLD_LED_CONTROL & (~(IDP_LEDS_MASK)) | value))
++
++/*
++ * macros for MTD driver
++ */
++
++#define FLASH_WRITE_PROTECT_DISABLE()	((IDP_CPLD_FLASH_WE) &= ~(0x1))
++#define FLASH_WRITE_PROTECT_ENABLE()	((IDP_CPLD_FLASH_WE) |= (0x1))
++
++/*
++ * macros for matrix keyboard driver
++ */
++
++#define KEYBD_MATRIX_NUMBER_INPUTS	7
++#define KEYBD_MATRIX_NUMBER_OUTPUTS	14
++
++#define KEYBD_MATRIX_INVERT_OUTPUT_LOGIC	FALSE
++#define KEYBD_MATRIX_INVERT_INPUT_LOGIC		FALSE
++
++#define KEYBD_MATRIX_SETTLING_TIME_US			100
++#define KEYBD_MATRIX_KEYSTATE_DEBOUNCE_CONSTANT		2
++
++#define KEYBD_MATRIX_SET_OUTPUTS(outputs) \
++{\
++	IDP_CPLD_KB_COL_LOW = outputs;\
++	IDP_CPLD_KB_COL_HIGH = outputs >> 7;\
++}
++
++#define KEYBD_MATRIX_GET_INPUTS(inputs) \
++{\
++	inputs = (IDP_CPLD_KB_ROW & 0x7f);\
++}
++
++//------------------------------------------------------------------------------
++
++#else  // must be rev 01
++
++/* -----------------------------------------------------------------------------
++ * following is for rev01 boards only
++ */
++
++#define IDP_FLASH_PHYS		(PXA_CS0_PHYS)
++#define IDP_ALT_FLASH_PHYS	(PXA_CS1_PHYS)
++#define IDP_MEDIAQ_PHYS		(PXA_CS3_PHYS)
++#define IDP_CTRL_PORT_PHYS	(PXA_CS5_PHYS + 0x02C00000)
++#define IDP_IDE_PHYS		(PXA_CS5_PHYS + 0x03000000)
++#define IDP_ETH_PHYS		(PXA_CS5_PHYS + 0x03400000)
++#define IDP_COREVOLT_PHYS	(PXA_CS5_PHYS + 0x03800000)
++#define IDP_CPLD_PHYS		(PXA_CS5_PHYS + 0x03C00000)
++
++
++/*
++ * virtual memory map
++ */
++
++#define IDP_CTRL_PORT_BASE	(0xf0000000)
++#define IDP_CTRL_PORT_SIZE	(1*1024*1024)
++
++#define IDP_IDE_BASE		(IDP_CTRL_PORT_BASE + IDP_CTRL_PORT_SIZE)
++#define IDP_IDE_SIZE		(1*1024*1024)
++
++#define IDP_ETH_BASE		(IDP_IDE_BASE + IDP_IDE_SIZE)
++#define IDP_ETH_SIZE		(1*1024*1024)
++
++#define IDP_COREVOLT_BASE	(IDP_ETH_BASE + IDP_ETH_SIZE)
++#define IDP_COREVOLT_SIZE	(1*1024*1024)
++
++#define IDP_CPLD_BASE		(IDP_COREVOLT_BASE + IDP_COREVOLT_SIZE)
++#define IDP_CPLD_SIZE		(1*1024*1024)
++
++#if (IDP_CPLD_BASE + IDP_CPLD_SIZE) > 0xfc000000
++#error Your custom IO space is getting a bit large !!
++#endif
++
++#define CPLD_P2V(x)		((x) - IDP_CPLD_PHYS + IDP_CPLD_BASE)
++#define CPLD_V2P(x)		((x) - IDP_CPLD_BASE + IDP_CPLD_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __CPLD_REG(x)		(*((volatile unsigned long *)CPLD_P2V(x)))
++#else
++#  define __CPLD_REG(x)		CPLD_P2V(x)
++#endif
++
++/* board level registers in the CPLD: (offsets from CPLD_BASE) */
++
++#define _IDP_CPLD_LED_CONTROL		(IDP_CPLD_PHYS + 0x00)
++#define _IDP_CPLD_PERIPH_PWR		(IDP_CPLD_PHYS + 0x04)
++#define _IDP_CPLD_CIR			(IDP_CPLD_PHYS + 0x08)
++#define _IDP_CPLD_KB_COL_HIGH		(IDP_CPLD_PHYS + 0x0C)
++#define _IDP_CPLD_KB_COL_LOW		(IDP_CPLD_PHYS + 0x10)
++#define _IDP_CPLD_PCCARD_EN		(IDP_CPLD_PHYS + 0x14)
++#define _IDP_CPLD_GPIOH_DIR		(IDP_CPLD_PHYS + 0x18)
++#define _IDP_CPLD_GPIOH_VALUE		(IDP_CPLD_PHYS + 0x1C)
++#define _IDP_CPLD_GPIOL_DIR		(IDP_CPLD_PHYS + 0x20)
++#define _IDP_CPLD_GPIOL_VALUE		(IDP_CPLD_PHYS + 0x24)
++#define _IDP_CPLD_MISC			(IDP_CPLD_PHYS + 0x28)
++#define _IDP_CPLD_PCCARD0_STATUS	(IDP_CPLD_PHYS + 0x2C)
++#define _IDP_CPLD_PCCARD1_STATUS	(IDP_CPLD_PHYS + 0x30)
++
++/* FPGA register virtual addresses */
++#define IDP_CPLD_LED_CONTROL		__CPLD_REG(_IDP_CPLD_LED_CONTROL)	/* write only */
++#define IDP_CPLD_PERIPH_PWR		__CPLD_REG(_IDP_CPLD_PERIPH_PWR)	/* write only */
++#define IDP_CPLD_CIR			__CPLD_REG(_IDP_CPLD_CIR)		/* write only */
++#define IDP_CPLD_KB_COL_HIGH		__CPLD_REG(_IDP_CPLD_KB_COL_HIGH)	/* write only */
++#define IDP_CPLD_KB_COL_LOW		__CPLD_REG(_IDP_CPLD_KB_COL_LOW)	/* write only */
++#define IDP_CPLD_PCCARD_EN		__CPLD_REG(_IDP_CPLD_PCCARD_EN)		/* write only */
++#define IDP_CPLD_GPIOH_DIR		__CPLD_REG(_IDP_CPLD_GPIOH_DIR)		/* write only */
++#define IDP_CPLD_GPIOH_VALUE		__CPLD_REG(_IDP_CPLD_GPIOH_VALUE)	/* write only */
++#define IDP_CPLD_GPIOL_DIR		__CPLD_REG(_IDP_CPLD_GPIOL_DIR)		/* write only */
++#define IDP_CPLD_GPIOL_VALUE		__CPLD_REG(_IDP_CPLD_GPIOL_VALUE)	/* write only */
++#define IDP_CPLD_MISC			__CPLD_REG(_IDP_CPLD_MISC)		/* read only */
++#define IDP_CPLD_PCCARD0_STATUS		__CPLD_REG(_IDP_CPLD_PCCARD0_STATUS)	/* read only */
++#define IDP_CPLD_PCCARD1_STATUS		__CPLD_REG(_IDP_CPLD_PCCARD1_STATUS)	/* read only */
++
++
++#ifndef __ASSEMBLY__
++
++/* shadow registers for write only registers */
++extern unsigned int idp_cpld_led_control_shadow;
++extern unsigned int idp_cpld_periph_pwr_shadow;
++extern unsigned int idp_cpld_cir_shadow;
++extern unsigned int idp_cpld_kb_col_high_shadow;
++extern unsigned int idp_cpld_kb_col_low_shadow;
++extern unsigned int idp_cpld_pccard_en_shadow;
++extern unsigned int idp_cpld_gpioh_dir_shadow;
++extern unsigned int idp_cpld_gpioh_value_shadow;
++extern unsigned int idp_cpld_gpiol_dir_shadow;
++extern unsigned int idp_cpld_gpiol_value_shadow;
++
++extern unsigned int idp_control_port_shadow;
++
++/* 
++ * macros to write to write only register
++ *
++ * none of these macros are protected from 
++ * multiple drivers using them in interrupt context.
++ */
++
++#define WRITE_IDP_CPLD_LED_CONTROL(value, mask) \
++{\
++	idp_cpld_led_control_shadow = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\
++	IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\
++}
++#define WRITE_IDP_CPLD_PERIPH_PWR(value, mask) \
++{\
++	idp_cpld_periph_pwr_shadow = ((value & mask) | (idp_cpld_periph_pwr_shadow & ~mask));\
++	IDP_CPLD_PERIPH_PWR = idp_cpld_periph_pwr_shadow;\
++}
++#define WRITE_IDP_CPLD_CIR(value, mask) \
++{\
++	idp_cpld_cir_shadow = ((value & mask) | (idp_cpld_cir_shadow & ~mask));\
++	IDP_CPLD_CIR = idp_cpld_cir_shadow;\
++}
++#define WRITE_IDP_CPLD_KB_COL_HIGH(value, mask) \
++{\
++	idp_cpld_kb_col_high_shadow = ((value & mask) | (idp_cpld_kb_col_high_shadow & ~mask));\
++	IDP_CPLD_KB_COL_HIGH = idp_cpld_kb_col_high_shadow;\
++}
++#define WRITE_IDP_CPLD_KB_COL_LOW(value, mask) \
++{\
++	idp_cpld_kb_col_low_shadow = ((value & mask) | (idp_cpld_kb_col_low_shadow & ~mask));\
++	IDP_CPLD_KB_COL_LOW = idp_cpld_kb_col_low_shadow;\
++}
++#define WRITE_IDP_CPLD_PCCARD_EN(value, mask) \
++{\
++	idp_cpld_ = ((value & mask) | (idp_cpld_led_control_shadow & ~mask));\
++	IDP_CPLD_LED_CONTROL = idp_cpld_led_control_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOH_DIR(value, mask) \
++{\
++	idp_cpld_gpioh_dir_shadow = ((value & mask) | (idp_cpld_gpioh_dir_shadow & ~mask));\
++	IDP_CPLD_GPIOH_DIR = idp_cpld_gpioh_dir_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOH_VALUE(value, mask) \
++{\
++	idp_cpld_gpioh_value_shadow = ((value & mask) | (idp_cpld_gpioh_value_shadow & ~mask));\
++	IDP_CPLD_GPIOH_VALUE = idp_cpld_gpioh_value_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOL_DIR(value, mask) \
++{\
++	idp_cpld_gpiol_dir_shadow = ((value & mask) | (idp_cpld_gpiol_dir_shadow & ~mask));\
++	IDP_CPLD_GPIOL_DIR = idp_cpld_gpiol_dir_shadow;\
++}
++#define WRITE_IDP_CPLD_GPIOL_VALUE(value, mask) \
++{\
++	idp_cpld_gpiol_value_shadow = ((value & mask) | (idp_cpld_gpiol_value_shadow & ~mask));\
++	IDP_CPLD_GPIOL_VALUE = idp_cpld_gpiol_value_shadow;\
++}
++
++#define WRITE_IDP_CONTROL_PORT(value, mask) \
++{\
++	idp_control_port_shadow = ((value & mask) | (idp_control_port_shadow & ~mask));\
++	(*((volatile unsigned long *)IDP_CTRL_PORT_BASE)) = idp_control_port_shadow;\
++}
++
++#endif
++
++/* A listing of interrupts used by external hardware devices */
++
++#define TOUCH_PANEL_IRQ			IRQ_GPIO(21)
++#define TOUCH_PANEL_IRQ_EGDE		GPIO_FALLING_EDGE
++
++#define ETHERNET_IRQ			IRQ_GPIO(4)
++#define ETHERNET_IRQ_EDGE		GPIO_RISING_EDGE
++
++/*
++ * Bit masks for various registers
++ */
++
++
++/* control port */
++#define IDP_CONTROL_PORT_PCSLOT0_0	(1 << 0)
++#define IDP_CONTROL_PORT_PCSLOT0_1	(1 << 1)
++#define IDP_CONTROL_PORT_PCSLOT0_2	(1 << 2)
++#define IDP_CONTROL_PORT_PCSLOT0_3	(1 << 3)
++#define IDP_CONTROL_PORT_PCSLOT1_1	(1 << 4)
++#define IDP_CONTROL_PORT_PCSLOT1_2	(1 << 5)
++#define IDP_CONTROL_PORT_PCSLOT1_3	(1 << 6)
++#define IDP_CONTROL_PORT_PCSLOT1_4	(1 << 7)
++#define IDP_CONTROL_PORT_SERIAL1_EN	(1 << 9)
++#define IDP_CONTROL_PORT_SERIAL2_EN	(1 << 10)
++#define IDP_CONTROL_PORT_SERIAL3_EN	(1 << 11)
++#define IDP_CONTROL_PORT_IRDA_FIR	(1 << 12)
++#define IDP_CONTROL_PORT_IRDA_M0	(1 << 13)
++#define IDP_CONTROL_PORT_IRDA_M1	(1 << 14)
++#define IDP_CONTROL_PORT_I2S_PWR	(1 << 15)
++#define IDP_CONTROL_PORT_FLASH_WP	(1 << 19)
++#define IDP_CONTROL_PORT_MILL_EN	(1 << 20)
++#define IDP_CONTROL_PORT_LCD_PWR	(1 << 21)
++#define IDP_CONTROL_PORT_LCD_BKLEN	(1 << 22)
++#define IDP_CONTROL_PORT_LCD_ENAVLCD	(1 << 23)
++
++/*
++ * Macros for LCD Driver
++ */
++
++#ifdef CONFIG_FB_PXA
++
++#define FB_BACKLIGHT_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_BKLEN, IDP_CONTROL_PORT_LCD_BKLEN)
++#define FB_BACKLIGHT_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_BKLEN)
++
++#define FB_PWR_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_PWR, IDP_CONTROL_PORT_LCD_PWR)
++#define FB_PWR_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_PWR)
++
++#define FB_VLCD_ON() WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_LCD_ENAVLCD, IDP_CONTROL_PORT_LCD_ENAVLCD)
++#define FB_VLCD_OFF() WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_LCD_ENAVLCD)
++
++#endif
++
++
++/*
++ * Macros for LED Driver
++ */
++
++/* leds 0 = ON */
++#define IDP_HB_LED	0x1
++#define IDP_BUSY_LED	0x2
++
++#define IDP_LEDS_MASK	(IDP_HB_LED | IDP_BUSY_LED)
++
++#define IDP_WRITE_LEDS(value) 	WRITE_IDP_CPLD_LED_CONTROL(value, IDP_LEDS_MASK)
++
++/*
++ * macros for MTD driver
++ */
++
++#define FLASH_WRITE_PROTECT_DISABLE()	WRITE_IDP_CONTROL_PORT(0, IDP_CONTROL_PORT_FLASH_WP)
++#define FLASH_WRITE_PROTECT_ENABLE()	WRITE_IDP_CONTROL_PORT(IDP_CONTROL_PORT_FLASH_WP, IDP_CONTROL_PORT_FLASH_WP)
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/innokom.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,47 @@
++/*
++ * linux/include/asm-arm/arch-pxa/innokom.h
++ *
++ * (c) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix
++ *
++ * 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
++ */
++
++/* 
++ * GPIOs 
++ */
++#define GPIO_INNOKOM_RESET	3
++#define GPIO_INNOKOM_SW_UPDATE	11
++#define GPIO_INNOKOM_ETH	59
++
++/* 
++ * ethernet chip (SMSC91C111) 
++ */
++#define INNOKOM_ETH_PHYS	PXA_CS5_PHYS
++#define INNOKOM_ETH_BASE	(0xf0000000)	/* phys 0x14000000 */
++#define INNOKOM_ETH_SIZE	(1*1024*1024)
++#define INNOKOM_ETH_IRQ		IRQ_GPIO(GPIO_INNOKOM_ETH)
++#define INNOKOM_ETH_IRQ_EDGE	GPIO_RISING_EDGE
++
++/*
++ * virtual to physical conversion macros
++ */
++#define INNOKOM_P2V(x)		((x) - INNOKOM_FPGA_PHYS + INNOKOM_FPGA_VIRT)
++#define INNOKOM_V2P(x)		((x) - INNOKOM_FPGA_VIRT + INNOKOM_FPGA_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __INNOKOM_REG(x)	(*((volatile unsigned long *)INNOKOM_P2V(x)))
++#else
++#  define __INNOKOM_REG(x)	INNOKOM_P2V(x)
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/io.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,34 @@
++/*
++ * linux/include/asm-arm/arch-pxa/io.h
++ *
++ * Author:	Nicolas Pitre
++ * Created:	Jun 15, 2001
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __ASM_ARM_ARCH_IO_H
++#define __ASM_ARM_ARCH_IO_H
++
++#define IO_SPACE_LIMIT 0xffffffff
++
++/*
++ * We don't actually have real ISA nor PCI buses, but there is so many 
++ * drivers out there that might just work if we fake them...
++ */
++#define __io(a)			(a)
++#define __mem_pci(a)		((unsigned long)(a))
++#define __mem_isa(a)		((unsigned long)(a))
++
++/*
++ * Generic virtual read/write
++ */
++#define __arch_getw(a)		(*(volatile unsigned short *)(a))
++#define __arch_putw(v,a)	(*(volatile unsigned short *)(a) = (v))
++
++#define iomem_valid_addr(iomem,sz)	(1)
++#define iomem_to_phys(iomem)		(iomem)
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/irq.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,19 @@
++/*
++ * linux/include/asm-arm/arch-pxa/irq.h
++ * 
++ * Author:	Nicolas Pitre
++ * Created:	Jun 15, 2001
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define fixup_irq(x)	(x)
++
++/*
++ * This prototype is required for cascading of multiplexed interrupts.
++ * Since it doesn't exist elsewhere, we'll put it here for now.
++ */
++extern void do_IRQ(int irq, struct pt_regs *regs);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/irqs.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,137 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/irqs.h
++ *  
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define PXA_IRQ_SKIP	7	/* The first 7 IRQs are not yet used */
++#define PXA_IRQ(x)		((x) - PXA_IRQ_SKIP)
++
++#define IRQ_HWUART	PXA_IRQ(7)	/* HWUART Transmit/Receive/Error */
++#define	IRQ_GPIO0	PXA_IRQ(8)	/* GPIO0 Edge Detect */
++#define	IRQ_GPIO1	PXA_IRQ(9)	/* GPIO1 Edge Detect */
++#define	IRQ_GPIO_2_80	PXA_IRQ(10)	/* GPIO[2-80] Edge Detect */
++#define	IRQ_USB		PXA_IRQ(11)	/* USB Service */
++#define	IRQ_PMU		PXA_IRQ(12)	/* Performance Monitoring Unit */
++#define	IRQ_I2S		PXA_IRQ(13)	/* I2S Interrupt */
++#define	IRQ_AC97	PXA_IRQ(14)	/* AC97 Interrupt */
++#define IRQ_ASSP	PXA_IRQ(15)	/* Audio SSP Service Request */
++#define IRQ_NSSP	PXA_IRQ(16)	/* Network SSP Service Request */
++#define	IRQ_LCD		PXA_IRQ(17)	/* LCD Controller Service Request */
++#define	IRQ_I2C		PXA_IRQ(18)	/* I2C Service Request */
++#define	IRQ_ICP		PXA_IRQ(19)	/* ICP Transmit/Receive/Error */
++#define	IRQ_STUART	PXA_IRQ(20)	/* STUART Transmit/Receive/Error */
++#define	IRQ_BTUART	PXA_IRQ(21)	/* BTUART Transmit/Receive/Error */
++#define	IRQ_FFUART	PXA_IRQ(22)	/* FFUART Transmit/Receive/Error*/
++#define	IRQ_MMC		PXA_IRQ(23)	/* MMC Status/Error Detection */
++#define	IRQ_SSP		PXA_IRQ(24)	/* SSP Service Request */
++#define	IRQ_DMA 	PXA_IRQ(25)	/* DMA Channel Service Request */
++#define	IRQ_OST0 	PXA_IRQ(26)	/* OS Timer match 0 */
++#define	IRQ_OST1 	PXA_IRQ(27)	/* OS Timer match 1 */
++#define	IRQ_OST2 	PXA_IRQ(28)	/* OS Timer match 2 */
++#define	IRQ_OST3 	PXA_IRQ(29)	/* OS Timer match 3 */
++#define	IRQ_RTC1Hz	PXA_IRQ(30)	/* RTC HZ Clock Tick */
++#define	IRQ_RTCAlrm	PXA_IRQ(31)	/* RTC Alarm */
++
++#define GPIO_2_80_TO_IRQ(x)	\
++			PXA_IRQ((x) - 2 + 32)
++#define IRQ_GPIO(x)	(((x) < 2) ? (IRQ_GPIO0 + (x)) : GPIO_2_80_TO_IRQ(x))
++
++#define IRQ_TO_GPIO_2_80(i)	\
++			((i) - PXA_IRQ(32) + 2)
++#define IRQ_TO_GPIO(i)	((i) - (((i) > IRQ_GPIO1) ? IRQ_GPIO(2) - 2 : IRQ_GPIO(0)))
++
++#define	NR_IRQS		(IRQ_GPIO(80) + 1)
++
++#if defined(CONFIG_SA1111)
++
++#define IRQ_SA1111_START	(IRQ_GPIO(80) + 1)
++#define SA1111_IRQ(x)		(IRQ_SA1111_START + (x))
++
++#define IRQ_GPAIN0		SA1111_IRQ(0)
++#define IRQ_GPAIN1		SA1111_IRQ(1)
++#define IRQ_GPAIN2		SA1111_IRQ(2)
++#define IRQ_GPAIN3		SA1111_IRQ(3)
++#define IRQ_GPBIN0		SA1111_IRQ(4)
++#define IRQ_GPBIN1		SA1111_IRQ(5)
++#define IRQ_GPBIN2		SA1111_IRQ(6)
++#define IRQ_GPBIN3		SA1111_IRQ(7)
++#define IRQ_GPBIN4		SA1111_IRQ(8)
++#define IRQ_GPBIN5		SA1111_IRQ(9)
++#define IRQ_GPCIN0		SA1111_IRQ(10)
++#define IRQ_GPCIN1		SA1111_IRQ(11)
++#define IRQ_GPCIN2		SA1111_IRQ(12)
++#define IRQ_GPCIN3		SA1111_IRQ(13)
++#define IRQ_GPCIN4		SA1111_IRQ(14)
++#define IRQ_GPCIN5		SA1111_IRQ(15)
++#define IRQ_GPCIN6		SA1111_IRQ(16)
++#define IRQ_GPCIN7		SA1111_IRQ(17)
++#define IRQ_MSTXINT		SA1111_IRQ(18)
++#define IRQ_MSRXINT		SA1111_IRQ(19)
++#define IRQ_MSSTOPERRINT	SA1111_IRQ(20)
++#define IRQ_TPTXINT		SA1111_IRQ(21)
++#define IRQ_TPRXINT		SA1111_IRQ(22)
++#define IRQ_TPSTOPERRINT	SA1111_IRQ(23)
++#define SSPXMTINT	SA1111_IRQ(24)
++#define SSPRCVINT	SA1111_IRQ(25)
++#define SSPROR		SA1111_IRQ(26)
++#define AUDXMTDMADONEA	SA1111_IRQ(32)
++#define AUDRCVDMADONEA	SA1111_IRQ(33)
++#define AUDXMTDMADONEB	SA1111_IRQ(34)
++#define AUDRCVDMADONEB	SA1111_IRQ(35)
++#define AUDTFSR		SA1111_IRQ(36)
++#define AUDRFSR		SA1111_IRQ(37)
++#define AUDTUR		SA1111_IRQ(38)
++#define AUDROR		SA1111_IRQ(39)
++#define AUDDTS		SA1111_IRQ(40)
++#define AUDRDD		SA1111_IRQ(41)
++#define AUDSTO		SA1111_IRQ(42)
++#define USBPWR		SA1111_IRQ(43)
++#define NIRQHCIM	SA1111_IRQ(44)
++#define HCIBUFFACC	SA1111_IRQ(45)
++#define HCIRMTWKP	SA1111_IRQ(46)
++#define NHCIMFCIR	SA1111_IRQ(47)
++#define PORT_RESUME	SA1111_IRQ(48)
++#define S0_READY_NINT	SA1111_IRQ(49)
++#define S1_READY_NINT	SA1111_IRQ(50)
++#define S0_CD_VALID	SA1111_IRQ(51)
++#define S1_CD_VALID	SA1111_IRQ(52)
++#define S0_BVD1_STSCHG	SA1111_IRQ(53)
++#define S1_BVD1_STSCHG	SA1111_IRQ(54)
++
++#define SA1111_IRQ_MAX	SA1111_IRQ(54)
++
++#undef NR_IRQS
++#define NR_IRQS		(SA1111_IRQ_MAX + 1)
++
++#endif	// defined(CONFIG_SA1111)
++
++#if defined(CONFIG_ARCH_LUBBOCK) || defined(CONFIG_ARCH_PXA_IDP) 
++#if CONFIG_SA1111
++#define LUBBOCK_IRQ(x)	(SA1111_IRQ_MAX + 1 + (x))
++#else
++#define LUBBOCK_IRQ(x)	(IRQ_GPIO(80) + 1 + (x))
++#endif
++
++#define LUBBOCK_SD_IRQ		LUBBOCK_IRQ(0)
++#define LUBBOCK_SA1111_IRQ	LUBBOCK_IRQ(1)
++#define LUBBOCK_USB_IRQ		LUBBOCK_IRQ(2)
++#define LUBBOCK_ETH_IRQ		LUBBOCK_IRQ(3)
++#define LUBBOCK_UCB1400_IRQ	LUBBOCK_IRQ(4)
++#define LUBBOCK_BB_IRQ		LUBBOCK_IRQ(5)
++#define LUBBOCK_USB_DISC_IRQ	LUBBOCK_IRQ(6)	/* usb disconnect */
++#define LUBBOCK_LAST_IRQ	LUBBOCK_IRQ(6)
++
++#undef NR_IRQS
++#define NR_IRQS		(LUBBOCK_LAST_IRQ + 1)
++
++#endif	// CONFIG_ARCH_LUBBOCK
++
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/keyboard.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/keyboard.h
++ *
++ *  This file contains the architecture specific keyboard definitions
++ */
++
++#ifndef _PXA_KEYBOARD_H
++#define _PXA_KEYBOARD_H
++
++#include <linux/config.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++
++extern struct kbd_ops_struct *kbd_ops;
++
++#define kbd_disable_irq()	do { } while(0);
++#define kbd_enable_irq()	do { } while(0);
++
++extern int sa1111_kbd_init_hw(void);
++
++static inline void kbd_init_hw(void)
++{
++	if (machine_is_lubbock())
++		sa1111_kbd_init_hw();
++}
++
++
++#endif  /* _PXA_KEYBOARD_H */
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/lubbock.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,113 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/lubbock.h
++ *
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define LUBBOCK_FPGA_PHYS	PXA_CS2_PHYS
++#define LUBBOCK_FPGA_VIRT	(0xf0000000)	/* phys 0x08000000 */
++#define LUBBOCK_ETH_PHYS	PXA_CS3_PHYS
++#define LUBBOCK_ETH_VIRT	(0xf1000000)
++#define LUBBOCK_SA1111_BASE	(0xf4000000)	/* phys 0x10000000 */
++
++#define LUB_P2V(x)		((x) - LUBBOCK_FPGA_PHYS + LUBBOCK_FPGA_VIRT)
++#define LUB_V2P(x)		((x) - LUBBOCK_FPGA_VIRT + LUBBOCK_FPGA_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __LUB_REG(x)		(*((volatile unsigned long *)LUB_P2V(x)))
++#else
++#  define __LUB_REG(x)		LUB_P2V(x)
++#endif
++
++/* board level registers in the CPLD: (offsets from CPLD_BASE) */
++
++#define WHOAMI			0	// card ID's (see programmers manual)
++#define HEX_LED			0x10	// R/W access to 8 7 segment displays
++#define DISC_BLNK_LED		0x40 	// R/W [15-8] enables for hex leds, [7-0] discrete LEDs
++#define CONF_SWITCHES		0x50	// RO [1] flash wrt prot, [0] 0= boot from rom, 1= flash
++#define USER_SWITCHES		0x60	// RO [15-8] dip switches, [7-0] 2 hex encoding switches
++#define MISC_WR			0x80	// R/W various system controls -see manual
++#define MISC_RD			0x90	// RO various system status bits -see manual
++//#define LUB_IRQ_MASK_EN		0xC0    // R/W 0= mask, 1= enable of TS, codec, ethernet, USB, SA1111, and card det. irq's
++//#define LUB_IRQ_SET_CLR		0xD0	// R/W 1= set, 0 = clear IRQ's from TS, codec, etc...
++//#define LUB_GP			0x100	// R/W [15-0] 16 bits of general purpose I/o for hacking
++
++
++/* FPGA register physical addresses */
++#define _LUB_WHOAMI		(LUBBOCK_FPGA_PHYS + 0x000)
++#define _LUB_HEXLED		(LUBBOCK_FPGA_PHYS + 0x010)
++#define _LUB_DISC_BLNK_LED	(LUBBOCK_FPGA_PHYS + 0x040)
++#define _LUB_CONF_SWITCHES	(LUBBOCK_FPGA_PHYS + 0x050)
++#define _LUB_USER_SWITCHES	(LUBBOCK_FPGA_PHYS + 0x060)
++#define _LUB_MISC_WR		(LUBBOCK_FPGA_PHYS + 0x080)
++#define _LUB_MISC_RD		(LUBBOCK_FPGA_PHYS + 0x090)
++#define _LUB_IRQ_MASK_EN	(LUBBOCK_FPGA_PHYS + 0x0C0)
++#define _LUB_IRQ_SET_CLR	(LUBBOCK_FPGA_PHYS + 0x0D0)
++#define _LUB_GP			(LUBBOCK_FPGA_PHYS + 0x100)
++
++/* FPGA register virtual addresses */
++#define LUB_WHOAMI		__LUB_REG(_LUB_WHOAMI)
++#define LUB_HEXLED		__LUB_REG(_LUB_HEXLED)		
++#define LUB_DISC_BLNK_LED	__LUB_REG(_LUB_DISC_BLNK_LED)	
++#define LUB_CONF_SWITCHES	__LUB_REG(_LUB_CONF_SWITCHES)	
++#define LUB_USER_SWITCHES	__LUB_REG(_LUB_USER_SWITCHES)	
++#define LUB_MISC_WR		__LUB_REG(_LUB_MISC_WR)	
++#define LUB_MISC_RD		__LUB_REG(_LUB_MISC_RD)		
++#define LUB_IRQ_MASK_EN		__LUB_REG(_LUB_IRQ_MASK_EN)
++#define LUB_IRQ_SET_CLR		__LUB_REG(_LUB_IRQ_SET_CLR)		
++#define LUB_GP			__LUB_REG(_LUB_GP)	
++
++/* GPIOs */
++
++#define GPIO_LUBBOCK_IRQ	0
++#define IRQ_GPIO_LUBBOCK_IRQ	IRQ_GPIO0
++
++
++/*
++ * LED macros
++ */
++
++#define LEDS_BASE LUB_DISC_BLNK_LED
++
++// 8 discrete leds available for general use:
++
++#define D28	0x1
++#define D27	0x2
++#define D26	0x4
++#define D25	0x8
++#define D24	0x10
++#define D23	0x20
++#define D22	0x40
++#define D21	0x80
++
++/* Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays so
++*  be sure to not monkey with them here.
++*/
++
++#define HEARTBEAT_LED	D28
++#define SYS_BUSY_LED    D27
++#define HEXLEDS_BASE LUB_HEXLED
++
++#define HEARTBEAT_LED_ON  (LEDS_BASE &= ~HEARTBEAT_LED)
++#define HEARTBEAT_LED_OFF (LEDS_BASE |= HEARTBEAT_LED)
++#define SYS_BUSY_LED_OFF  (LEDS_BASE |= SYS_BUSY_LED)
++#define SYS_BUSY_LED_ON   (LEDS_BASE &= ~SYS_BUSY_LED)
++
++// use x = D26-D21 for these, please...
++#define DISCRETE_LED_ON(x) (LEDS_BASE &= ~(x))
++#define DISCRETE_LED_OFF(x) (LEDS_BASE |= (x))
++
++#ifndef __ASSEMBLY__
++
++//extern int hexled_val = 0;
++
++#endif
++
++#define BUMP_COUNTER (HEXLEDS_BASE = hexled_val++)
++#define DEC_COUNTER (HEXLEDS_BASE = hexled_val--)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/memory.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,106 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/memory.h
++ * 
++ * Author:	Nicolas Pitre
++ * Copyright:	(C) 2001 MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __ASM_ARCH_MEMORY_H
++#define __ASM_ARCH_MEMORY_H
++
++
++/*
++ * Task size: 3GB
++ */
++#define TASK_SIZE	(0xc0000000UL)
++#define TASK_SIZE_26	(0x04000000UL)
++
++/*
++ * This decides where the kernel will search for a free chunk of vm
++ * space during mmap's.
++ */
++#define TASK_UNMAPPED_BASE (TASK_SIZE / 3)
++
++/*
++ * Page offset: 3GB
++ */
++#define PAGE_OFFSET	(0xc0000000UL)
++
++/*
++ * Physical DRAM offset.
++ */
++#define PHYS_OFFSET	(0xa0000000UL)
++
++/*
++ * physical vs virtual ram conversion
++ */
++#define __virt_to_phys__is_a_macro
++#define __phys_to_virt__is_a_macro
++#define __virt_to_phys(x)	((x) - PAGE_OFFSET + PHYS_OFFSET)
++#define __phys_to_virt(x)	((x) - PHYS_OFFSET + PAGE_OFFSET)
++
++/*
++ * Virtual view <-> DMA view memory address translations
++ * virt_to_bus: Used to translate the virtual address to an
++ *		address suitable to be passed to set_dma_addr
++ * bus_to_virt: Used to convert an address for DMA operations
++ *		to an address that the kernel can use.
++ */
++#define __virt_to_bus__is_a_macro
++#define __bus_to_virt__is_a_macro
++#define __virt_to_bus(x)	 __virt_to_phys(x)
++#define __bus_to_virt(x)	 __phys_to_virt(x)
++
++#ifdef CONFIG_DISCONTIGMEM
++/*
++ * The nodes are matched with the physical SDRAM banks as follows:
++ *
++ * 	node 0:  0xa0000000-0xa3ffffff	-->  0xc0000000-0xc3ffffff
++ * 	node 1:  0xa4000000-0xa7ffffff	-->  0xc4000000-0xc7ffffff
++ * 	node 2:  0xa8000000-0xabffffff	-->  0xc8000000-0xcbffffff
++ * 	node 3:  0xac000000-0xafffffff	-->  0xcc000000-0xcfffffff
++ */
++
++#define NR_NODES	4
++
++/*
++ * Given a kernel address, find the home node of the underlying memory.
++ */
++#define KVADDR_TO_NID(addr) (((unsigned long)(addr) - PAGE_OFFSET) >> 26)
++
++/*
++ * Given a page frame number, convert it to a node id.
++ */
++#define PFN_TO_NID(pfn)		(((pfn) - PHYS_PFN_OFFSET) >> (26 - PAGE_SHIFT))
++
++/*
++ * Given a kaddr, ADDR_TO_MAPBASE finds the owning node of the memory
++ * and returns the mem_map of that node.
++ */
++#define ADDR_TO_MAPBASE(kaddr)	NODE_MEM_MAP(KVADDR_TO_NID(kaddr))
++
++/*
++ * Given a page frame number, find the owning node of the memory
++ * and returns the mem_map of that node.
++ */
++#define PFN_TO_MAPBASE(pfn)	NODE_MEM_MAP(PFN_TO_NID(pfn))
++
++/*
++ * Given a kaddr, LOCAL_MEM_MAP finds the owning node of the memory
++ * and returns the index corresponding to the appropriate page in the
++ * node's mem_map.
++ */
++#define LOCAL_MAP_NR(addr) \
++	(((unsigned long)(addr) & 0x03ffffff) >> PAGE_SHIFT)
++
++#else
++
++#define PFN_TO_NID(addr)	(0)
++
++#endif
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/param.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,3 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/param.h
++ */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/pcmcia.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,65 @@
++/*
++ * linux/include/asm-arm/arch-pxa/pcmcia.h
++ *
++ * Author:	George Davis
++ * Created:	Jan 10, 2002
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *
++ * Originally based upon linux/include/asm-arm/arch-sa1100/pcmcia.h
++ *
++ */
++
++#ifndef _ASM_ARCH_PCMCIA
++#define _ASM_ARCH_PCMCIA
++
++
++/* Ideally, we'd support up to MAX_SOCK sockets, but PXA250 only
++ * provides support for a maximum of two.
++ */
++#define PXA_PCMCIA_MAX_SOCK   (2)
++
++
++#ifndef __ASSEMBLY__
++
++struct pcmcia_init {
++  void (*handler)(int irq, void *dev, struct pt_regs *regs);
++};
++
++struct pcmcia_state {
++  unsigned detect: 1,
++            ready: 1,
++             bvd1: 1,
++             bvd2: 1,
++           wrprot: 1,
++            vs_3v: 1,
++            vs_Xv: 1;
++};
++
++struct pcmcia_state_array {
++  unsigned int size;
++  struct pcmcia_state *state;
++};
++
++struct pcmcia_irq_info {
++  unsigned int sock;
++  unsigned int irq;
++};
++
++struct pcmcia_low_level {
++  int (*init)(struct pcmcia_init *);
++  int (*shutdown)(void);
++  int (*socket_state)(struct pcmcia_state_array *);
++  int (*get_irq_info)(struct pcmcia_irq_info *);
++  int (*configure_socket)(unsigned int, socket_state_t *);
++};
++
++extern struct pcmcia_low_level *pcmcia_low_level;
++
++#endif  /* __ASSEMBLY__ */
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/pxa-regs.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,1327 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/pxa-regs.h
++ *  
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef _PXA_REGS_H_
++#define _PXA_REGS_H_
++
++#include "bitfield.h"
++
++
++// FIXME hack so that SA-1111.h will work [cb]
++
++#ifndef __ASSEMBLY__
++typedef unsigned short  Word16 ;
++typedef unsigned int    Word32 ;
++typedef Word32          Word ;
++typedef Word            Quad [4] ;
++typedef void            *Address ;
++typedef void            (*ExcpHndlr) (void) ;
++#endif
++
++/*
++ * PXA Chip selects
++ */
++
++#define PXA_CS0_PHYS	0x00000000
++#define PXA_CS1_PHYS	0x04000000
++#define PXA_CS2_PHYS	0x08000000
++#define PXA_CS3_PHYS	0x0C000000
++#define PXA_CS4_PHYS	0x10000000
++#define PXA_CS5_PHYS	0x14000000
++
++
++/*
++ * Personal Computer Memory Card International Association (PCMCIA) sockets
++ */
++
++#define PCMCIAPrtSp	0x04000000	/* PCMCIA Partition Space [byte]   */
++#define PCMCIASp	(4*PCMCIAPrtSp)	/* PCMCIA Space [byte]             */
++#define PCMCIAIOSp	PCMCIAPrtSp	/* PCMCIA I/O Space [byte]         */
++#define PCMCIAAttrSp	PCMCIAPrtSp	/* PCMCIA Attribute Space [byte]   */
++#define PCMCIAMemSp	PCMCIAPrtSp	/* PCMCIA Memory Space [byte]      */
++
++#define PCMCIA0Sp	PCMCIASp	/* PCMCIA 0 Space [byte]           */
++#define PCMCIA0IOSp	PCMCIAIOSp	/* PCMCIA 0 I/O Space [byte]       */
++#define PCMCIA0AttrSp	PCMCIAAttrSp	/* PCMCIA 0 Attribute Space [byte] */
++#define PCMCIA0MemSp	PCMCIAMemSp	/* PCMCIA 0 Memory Space [byte]    */
++
++#define PCMCIA1Sp	PCMCIASp	/* PCMCIA 1 Space [byte]           */
++#define PCMCIA1IOSp	PCMCIAIOSp	/* PCMCIA 1 I/O Space [byte]       */
++#define PCMCIA1AttrSp	PCMCIAAttrSp	/* PCMCIA 1 Attribute Space [byte] */
++#define PCMCIA1MemSp	PCMCIAMemSp	/* PCMCIA 1 Memory Space [byte]    */
++
++#define _PCMCIA(Nb)	        	/* PCMCIA [0..1]                   */ \
++                	(0x20000000 + (Nb)*PCMCIASp)
++#define _PCMCIAIO(Nb)	_PCMCIA (Nb)	/* PCMCIA I/O [0..1]               */
++#define _PCMCIAAttr(Nb)	        	/* PCMCIA Attribute [0..1]         */ \
++                	(_PCMCIA (Nb) + 2*PCMCIAPrtSp)
++#define _PCMCIAMem(Nb)	        	/* PCMCIA Memory [0..1]            */ \
++                	(_PCMCIA (Nb) + 3*PCMCIAPrtSp)
++
++#define _PCMCIA0	_PCMCIA (0)	/* PCMCIA 0                        */
++#define _PCMCIA0IO	_PCMCIAIO (0)	/* PCMCIA 0 I/O                    */
++#define _PCMCIA0Attr	_PCMCIAAttr (0)	/* PCMCIA 0 Attribute              */
++#define _PCMCIA0Mem	_PCMCIAMem (0)	/* PCMCIA 0 Memory                 */
++
++#define _PCMCIA1	_PCMCIA (1)	/* PCMCIA 1                        */
++#define _PCMCIA1IO	_PCMCIAIO (1)	/* PCMCIA 1 I/O                    */
++#define _PCMCIA1Attr	_PCMCIAAttr (1)	/* PCMCIA 1 Attribute              */
++#define _PCMCIA1Mem	_PCMCIAMem (1)	/* PCMCIA 1 Memory                 */
++
++
++
++/*
++ * DMA Controller
++ */
++
++#define DCSR0		__REG(0x40000000)  /* DMA Control / Status Register for Channel 0 */
++#define DCSR1		__REG(0x40000004)  /* DMA Control / Status Register for Channel 1 */
++#define DCSR2		__REG(0x40000008)  /* DMA Control / Status Register for Channel 2 */
++#define DCSR3		__REG(0x4000000c)  /* DMA Control / Status Register for Channel 3 */
++#define DCSR4		__REG(0x40000010)  /* DMA Control / Status Register for Channel 4 */
++#define DCSR5		__REG(0x40000014)  /* DMA Control / Status Register for Channel 5 */
++#define DCSR6		__REG(0x40000018)  /* DMA Control / Status Register for Channel 6 */
++#define DCSR7		__REG(0x4000001c)  /* DMA Control / Status Register for Channel 7 */
++#define DCSR8		__REG(0x40000020)  /* DMA Control / Status Register for Channel 8 */
++#define DCSR9		__REG(0x40000024)  /* DMA Control / Status Register for Channel 9 */
++#define DCSR10		__REG(0x40000028)  /* DMA Control / Status Register for Channel 10 */
++#define DCSR11		__REG(0x4000002c)  /* DMA Control / Status Register for Channel 11 */
++#define DCSR12		__REG(0x40000030)  /* DMA Control / Status Register for Channel 12 */
++#define DCSR13		__REG(0x40000034)  /* DMA Control / Status Register for Channel 13 */
++#define DCSR14		__REG(0x40000038)  /* DMA Control / Status Register for Channel 14 */
++#define DCSR15		__REG(0x4000003c)  /* DMA Control / Status Register for Channel 15 */
++
++#define DCSR(x)		__REG2(0x40000000, (x) << 2)
++
++#define DCSR_RUN	(1 << 31)	/* Run Bit (read / write) */
++#define DCSR_NODESC	(1 << 30)	/* No-Descriptor Fetch (read / write) */
++#define DCSR_STOPIRQEN	(1 << 29)	/* Stop Interrupt Enable (read / write) */
++#define DCSR_REQPEND	(1 << 8)	/* Request Pending (read-only) */
++#define DCSR_STOPSTATE	(1 << 3)	/* Stop State (read-only) */
++#define DCSR_ENDINTR	(1 << 2)	/* End Interrupt (read / write) */
++#define DCSR_STARTINTR	(1 << 1)	/* Start Interrupt (read / write) */
++#define DCSR_BUSERR	(1 << 0)	/* Bus Error Interrupt (read / write) */
++
++#define DINT		__REG(0x400000f0)  /* DMA Interrupt Register */
++
++#define DRCMR0		__REG(0x40000100)  /* Request to Channel Map Register for DREQ 0 */
++#define DRCMR1		__REG(0x40000104)  /* Request to Channel Map Register for DREQ 1 */
++#define DRCMR2		__REG(0x40000108)  /* Request to Channel Map Register for I2S receive Request */
++#define DRCMR3		__REG(0x4000010c)  /* Request to Channel Map Register for I2S transmit Request */
++#define DRCMR4		__REG(0x40000110)  /* Request to Channel Map Register for BTUART receive Request */
++#define DRCMR5		__REG(0x40000114)  /* Request to Channel Map Register for BTUART transmit Request. */
++#define DRCMR6		__REG(0x40000118)  /* Request to Channel Map Register for FFUART receive Request */
++#define DRCMR7		__REG(0x4000011c)  /* Request to Channel Map Register for FFUART transmit Request */
++#define DRCMR8		__REG(0x40000120)  /* Request to Channel Map Register for AC97 microphone Request */
++#define DRCMR9		__REG(0x40000124)  /* Request to Channel Map Register for AC97 modem receive Request */
++#define DRCMR10		__REG(0x40000128)  /* Request to Channel Map Register for AC97 modem transmit Request */
++#define DRCMR11		__REG(0x4000012c)  /* Request to Channel Map Register for AC97 audio receive Request */
++#define DRCMR12		__REG(0x40000130)  /* Request to Channel Map Register for AC97 audio transmit Request */
++#define DRCMR13		__REG(0x40000134)  /* Request to Channel Map Register for SSP receive Request */
++#define DRCMR14		__REG(0x40000138)  /* Request to Channel Map Register for SSP transmit Request */
++#define DRCMR15		__REG(0x4000013c)  /* Reserved */
++#define DRCMR16		__REG(0x40000140)  /* Reserved */
++#define DRCMR17		__REG(0x40000144)  /* Request to Channel Map Register for ICP receive Request */
++#define DRCMR18		__REG(0x40000148)  /* Request to Channel Map Register for ICP transmit Request */
++#define DRCMR19		__REG(0x4000014c)  /* Request to Channel Map Register for STUART receive Request */
++#define DRCMR20		__REG(0x40000150)  /* Request to Channel Map Register for STUART transmit Request */
++#define DRCMR21		__REG(0x40000154)  /* Request to Channel Map Register for MMC receive Request */
++#define DRCMR22		__REG(0x40000158)  /* Request to Channel Map Register for MMC transmit Request */
++#define DRCMR23		__REG(0x4000015c)  /* Reserved */
++#define DRCMR24		__REG(0x40000160)  /* Reserved */
++#define DRCMR25		__REG(0x40000164)  /* Request to Channel Map Register for USB endpoint 1 Request */
++#define DRCMR26		__REG(0x40000168)  /* Request to Channel Map Register for USB endpoint 2 Request */
++#define DRCMR27		__REG(0x4000016C)  /* Request to Channel Map Register for USB endpoint 3 Request */
++#define DRCMR28		__REG(0x40000170)  /* Request to Channel Map Register for USB endpoint 4 Request */
++#define DRCMR29		__REG(0x40000174)  /* Reserved */
++#define DRCMR30		__REG(0x40000178)  /* Request to Channel Map Register for USB endpoint 6 Request */
++#define DRCMR31		__REG(0x4000017C)  /* Request to Channel Map Register for USB endpoint 7 Request */
++#define DRCMR32		__REG(0x40000180)  /* Request to Channel Map Register for USB endpoint 8 Request */
++#define DRCMR33		__REG(0x40000184)  /* Request to Channel Map Register for USB endpoint 9 Request */
++#define DRCMR34		__REG(0x40000188)  /* Reserved */
++#define DRCMR35		__REG(0x4000018C)  /* Request to Channel Map Register for USB endpoint 11 Request */
++#define DRCMR36		__REG(0x40000190)  /* Request to Channel Map Register for USB endpoint 12 Request */
++#define DRCMR37		__REG(0x40000194)  /* Request to Channel Map Register for USB endpoint 13 Request */
++#define DRCMR38		__REG(0x40000198)  /* Request to Channel Map Register for USB endpoint 14 Request */
++#define DRCMR39		__REG(0x4000019C)  /* Reserved */
++
++#define DRCMRRXSADR	DRCMR2
++#define DRCMRTXSADR	DRCMR3
++#define DRCMRRXBTRBR	DRCMR4
++#define DRCMRTXBTTHR	DRCMR5
++#define DRCMRRXFFRBR	DRCMR6
++#define DRCMRTXFFTHR	DRCMR7
++#define DRCMRRXMCDR	DRCMR8
++#define DRCMRRXMODR	DRCMR9
++#define DRCMRTXMODR	DRCMR10
++#define DRCMRRXPCDR	DRCMR11
++#define DRCMRTXPCDR	DRCMR12
++#define DRCMRRXSSDR	DRCMR13
++#define DRCMRTXSSDR	DRCMR14
++#define DRCMRRXICDR	DRCMR17
++#define DRCMRTXICDR	DRCMR18
++#define DRCMRRXSTRBR	DRCMR19
++#define DRCMRTXSTTHR	DRCMR20
++#define DRCMRRXMMC	DRCMR21
++#define DRCMRTXMMC	DRCMR22
++
++#define DRCMR_MAPVLD	(1 << 7)	/* Map Valid (read / write) */
++#define DRCMR_CHLNUM	0x0f		/* mask for Channel Number (read / write) */
++
++#define DDADR0		__REG(0x40000200)  /* DMA Descriptor Address Register Channel 0 */
++#define DSADR0		__REG(0x40000204)  /* DMA Source Address Register Channel 0 */
++#define DTADR0		__REG(0x40000208)  /* DMA Target Address Register Channel 0 */
++#define DCMD0		__REG(0x4000020c)  /* DMA Command Address Register Channel 0 */
++#define DDADR1		__REG(0x40000210)  /* DMA Descriptor Address Register Channel 1 */
++#define DSADR1		__REG(0x40000214)  /* DMA Source Address Register Channel 1 */
++#define DTADR1		__REG(0x40000218)  /* DMA Target Address Register Channel 1 */
++#define DCMD1		__REG(0x4000021c)  /* DMA Command Address Register Channel 1 */
++#define DDADR2		__REG(0x40000220)  /* DMA Descriptor Address Register Channel 2 */
++#define DSADR2		__REG(0x40000224)  /* DMA Source Address Register Channel 2 */
++#define DTADR2		__REG(0x40000228)  /* DMA Target Address Register Channel 2 */
++#define DCMD2		__REG(0x4000022c)  /* DMA Command Address Register Channel 2 */
++#define DDADR3		__REG(0x40000230)  /* DMA Descriptor Address Register Channel 3 */
++#define DSADR3		__REG(0x40000234)  /* DMA Source Address Register Channel 3 */
++#define DTADR3		__REG(0x40000238)  /* DMA Target Address Register Channel 3 */
++#define DCMD3		__REG(0x4000023c)  /* DMA Command Address Register Channel 3 */
++#define DDADR4		__REG(0x40000240)  /* DMA Descriptor Address Register Channel 4 */
++#define DSADR4		__REG(0x40000244)  /* DMA Source Address Register Channel 4 */
++#define DTADR4		__REG(0x40000248)  /* DMA Target Address Register Channel 4 */
++#define DCMD4		__REG(0x4000024c)  /* DMA Command Address Register Channel 4 */
++#define DDADR5		__REG(0x40000250)  /* DMA Descriptor Address Register Channel 5 */
++#define DSADR5		__REG(0x40000254)  /* DMA Source Address Register Channel 5 */
++#define DTADR5		__REG(0x40000258)  /* DMA Target Address Register Channel 5 */
++#define DCMD5		__REG(0x4000025c)  /* DMA Command Address Register Channel 5 */
++#define DDADR6		__REG(0x40000260)  /* DMA Descriptor Address Register Channel 6 */
++#define DSADR6		__REG(0x40000264)  /* DMA Source Address Register Channel 6 */
++#define DTADR6		__REG(0x40000268)  /* DMA Target Address Register Channel 6 */
++#define DCMD6		__REG(0x4000026c)  /* DMA Command Address Register Channel 6 */
++#define DDADR7		__REG(0x40000270)  /* DMA Descriptor Address Register Channel 7 */
++#define DSADR7		__REG(0x40000274)  /* DMA Source Address Register Channel 7 */
++#define DTADR7		__REG(0x40000278)  /* DMA Target Address Register Channel 7 */
++#define DCMD7		__REG(0x4000027c)  /* DMA Command Address Register Channel 7 */
++#define DDADR8		__REG(0x40000280)  /* DMA Descriptor Address Register Channel 8 */
++#define DSADR8		__REG(0x40000284)  /* DMA Source Address Register Channel 8 */
++#define DTADR8		__REG(0x40000288)  /* DMA Target Address Register Channel 8 */
++#define DCMD8		__REG(0x4000028c)  /* DMA Command Address Register Channel 8 */
++#define DDADR9		__REG(0x40000290)  /* DMA Descriptor Address Register Channel 9 */
++#define DSADR9		__REG(0x40000294)  /* DMA Source Address Register Channel 9 */
++#define DTADR9		__REG(0x40000298)  /* DMA Target Address Register Channel 9 */
++#define DCMD9		__REG(0x4000029c)  /* DMA Command Address Register Channel 9 */
++#define DDADR10		__REG(0x400002a0)  /* DMA Descriptor Address Register Channel 10 */
++#define DSADR10		__REG(0x400002a4)  /* DMA Source Address Register Channel 10 */
++#define DTADR10		__REG(0x400002a8)  /* DMA Target Address Register Channel 10 */
++#define DCMD10		__REG(0x400002ac)  /* DMA Command Address Register Channel 10 */
++#define DDADR11		__REG(0x400002b0)  /* DMA Descriptor Address Register Channel 11 */
++#define DSADR11		__REG(0x400002b4)  /* DMA Source Address Register Channel 11 */
++#define DTADR11		__REG(0x400002b8)  /* DMA Target Address Register Channel 11 */
++#define DCMD11		__REG(0x400002bc)  /* DMA Command Address Register Channel 11 */
++#define DDADR12		__REG(0x400002c0)  /* DMA Descriptor Address Register Channel 12 */
++#define DSADR12		__REG(0x400002c4)  /* DMA Source Address Register Channel 12 */
++#define DTADR12		__REG(0x400002c8)  /* DMA Target Address Register Channel 12 */
++#define DCMD12		__REG(0x400002cc)  /* DMA Command Address Register Channel 12 */
++#define DDADR13		__REG(0x400002d0)  /* DMA Descriptor Address Register Channel 13 */
++#define DSADR13		__REG(0x400002d4)  /* DMA Source Address Register Channel 13 */
++#define DTADR13		__REG(0x400002d8)  /* DMA Target Address Register Channel 13 */
++#define DCMD13		__REG(0x400002dc)  /* DMA Command Address Register Channel 13 */
++#define DDADR14		__REG(0x400002e0)  /* DMA Descriptor Address Register Channel 14 */
++#define DSADR14		__REG(0x400002e4)  /* DMA Source Address Register Channel 14 */
++#define DTADR14		__REG(0x400002e8)  /* DMA Target Address Register Channel 14 */
++#define DCMD14		__REG(0x400002ec)  /* DMA Command Address Register Channel 14 */
++#define DDADR15		__REG(0x400002f0)  /* DMA Descriptor Address Register Channel 15 */
++#define DSADR15		__REG(0x400002f4)  /* DMA Source Address Register Channel 15 */
++#define DTADR15		__REG(0x400002f8)  /* DMA Target Address Register Channel 15 */
++#define DCMD15		__REG(0x400002fc)  /* DMA Command Address Register Channel 15 */
++
++#define DDADR(x)	__REG2(0x40000200, (x) << 4)
++#define DSADR(x)	__REG2(0x40000204, (x) << 4)
++#define DTADR(x)	__REG2(0x40000208, (x) << 4)
++#define DCMD(x)		__REG2(0x4000020c, (x) << 4)
++
++#define DDADR_DESCADDR	0xfffffff0	/* Address of next descriptor (mask) */
++#define DDADR_STOP	(1 << 0)	/* Stop (read / write) */
++
++#define DCMD_INCSRCADDR	(1 << 31)	/* Source Address Increment Setting. */
++#define DCMD_INCTRGADDR	(1 << 30)	/* Target Address Increment Setting. */
++#define DCMD_FLOWSRC	(1 << 29)	/* Flow Control by the source. */
++#define DCMD_FLOWTRG	(1 << 28)	/* Flow Control by the target. */
++#define DCMD_STARTIRQEN	(1 << 22)	/* Start Interrupt Enable */
++#define DCMD_ENDIRQEN	(1 << 21)	/* End Interrupt Enable */
++#define DCMD_ENDIAN	(1 << 18)	/* Device Endian-ness. */
++#define DCMD_BURST8	(1 << 16)	/* 8 byte burst */
++#define DCMD_BURST16	(2 << 16)	/* 16 byte burst */
++#define DCMD_BURST32	(3 << 16)	/* 32 byte burst */
++#define DCMD_WIDTH1	(1 << 14)	/* 1 byte width */
++#define DCMD_WIDTH2	(2 << 14)	/* 2 byte width (HalfWord) */
++#define DCMD_WIDTH4	(3 << 14)	/* 4 byte width (Word) */
++#define DCMD_LENGTH	0x01fff		/* length mask (max = 8K - 1) */
++
++/* default combinations */
++#define DCMD_RXPCDR	(DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_RXMCDR	(DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_TXPCDR	(DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4)
++
++
++/*
++ * UARTs
++ */
++
++/* Full Function UART (FFUART) */
++#define FFUART		FFRBR
++#define FFRBR		__REG(0x40100000)  /* Receive Buffer Register (read only) */
++#define FFTHR		__REG(0x40100000)  /* Transmit Holding Register (write only) */
++#define FFIER		__REG(0x40100004)  /* Interrupt Enable Register (read/write) */
++#define FFIIR		__REG(0x40100008)  /* Interrupt ID Register (read only) */
++#define FFFCR		__REG(0x40100008)  /* FIFO Control Register (write only) */
++#define FFLCR		__REG(0x4010000C)  /* Line Control Register (read/write) */
++#define FFMCR		__REG(0x40100010)  /* Modem Control Register (read/write) */
++#define FFLSR		__REG(0x40100014)  /* Line Status Register (read only) */
++#define FFMSR		__REG(0x40100018)  /* Modem Status Register (read only) */
++#define FFSPR		__REG(0x4010001C)  /* Scratch Pad Register (read/write) */
++#define FFISR		__REG(0x40100020)  /* Infrared Selection Register (read/write) */
++#define FFDLL		__REG(0x40100000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
++#define FFDLH		__REG(0x40100004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
++
++/* Bluetooth UART (BTUART) */
++#define BTUART		BTRBR
++#define BTRBR		__REG(0x40200000)  /* Receive Buffer Register (read only) */
++#define BTTHR		__REG(0x40200000)  /* Transmit Holding Register (write only) */
++#define BTIER		__REG(0x40200004)  /* Interrupt Enable Register (read/write) */
++#define BTIIR		__REG(0x40200008)  /* Interrupt ID Register (read only) */
++#define BTFCR		__REG(0x40200008)  /* FIFO Control Register (write only) */
++#define BTLCR		__REG(0x4020000C)  /* Line Control Register (read/write) */
++#define BTMCR		__REG(0x40200010)  /* Modem Control Register (read/write) */
++#define BTLSR		__REG(0x40200014)  /* Line Status Register (read only) */
++#define BTMSR		__REG(0x40200018)  /* Modem Status Register (read only) */
++#define BTSPR		__REG(0x4020001C)  /* Scratch Pad Register (read/write) */
++#define BTISR		__REG(0x40200020)  /* Infrared Selection Register (read/write) */
++#define BTDLL		__REG(0x40200000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
++#define BTDLH		__REG(0x40200004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
++
++/* Standard UART (STUART) */
++#define STUART		STRBR
++#define STRBR		__REG(0x40700000)  /* Receive Buffer Register (read only) */
++#define STTHR		__REG(0x40700000)  /* Transmit Holding Register (write only) */
++#define STIER		__REG(0x40700004)  /* Interrupt Enable Register (read/write) */
++#define STIIR		__REG(0x40700008)  /* Interrupt ID Register (read only) */
++#define STFCR		__REG(0x40700008)  /* FIFO Control Register (write only) */
++#define STLCR		__REG(0x4070000C)  /* Line Control Register (read/write) */
++#define STMCR		__REG(0x40700010)  /* Modem Control Register (read/write) */
++#define STLSR		__REG(0x40700014)  /* Line Status Register (read only) */
++#define STMSR		__REG(0x40700018)  /* Reserved */
++#define STSPR		__REG(0x4070001C)  /* Scratch Pad Register (read/write) */
++#define STISR		__REG(0x40700020)  /* Infrared Selection Register (read/write) */
++#define STDLL		__REG(0x40700000)  /* Divisor Latch Low Register (DLAB = 1) (read/write) */
++#define STDLH		__REG(0x40700004)  /* Divisor Latch High Register (DLAB = 1) (read/write) */
++
++#define IER_DMAE	(1 << 7)	/* DMA Requests Enable */
++#define IER_UUE		(1 << 6)	/* UART Unit Enable */
++#define IER_NRZE	(1 << 5)	/* NRZ coding Enable */
++#define IER_RTIOE	(1 << 4)	/* Receiver Time Out Interrupt Enable */
++#define IER_MIE		(1 << 3)	/* Modem Interrupt Enable */
++#define IER_RLSE	(1 << 2)	/* Receiver Line Status Interrupt Enable */
++#define IER_TIE		(1 << 1)	/* Transmit Data request Interrupt Enable */
++#define IER_RAVIE	(1 << 0)	/* Receiver Data Available Interrupt Enable */
++
++#define IIR_FIFOES1	(1 << 7)	/* FIFO Mode Enable Status */
++#define IIR_FIFOES0	(1 << 6)	/* FIFO Mode Enable Status */
++#define IIR_TOD		(1 << 3)	/* Time Out Detected */
++#define IIR_IID2	(1 << 2)	/* Interrupt Source Encoded */
++#define IIR_IID1	(1 << 1)	/* Interrupt Source Encoded */
++#define IIR_IP		(1 << 0)	/* Interrupt Pending (active low) */
++
++#define FCR_ITL2	(1 << 7)	/* Interrupt Trigger Level */
++#define FCR_ITL1	(1 << 6)	/* Interrupt Trigger Level */
++#define FCR_RESETTF	(1 << 2)	/* Reset Transmitter FIFO */
++#define FCR_RESETRF	(1 << 1)	/* Reset Receiver FIFO */
++#define FCR_TRFIFOE	(1 << 0)	/* Transmit and Receive FIFO Enable */
++#define FCR_ITL_1	(0)
++#define FCR_ITL_8	(FCR_ITL1)
++#define FCR_ITL_16	(FCR_ITL2)
++#define FCR_ITL_32	(FCR_ITL2|FCR_ITL1)
++
++#define LCR_DLAB	(1 << 7)	/* Divisor Latch Access Bit */
++#define LCR_SB		(1 << 6)	/* Set Break */
++#define LCR_STKYP	(1 << 5)	/* Sticky Parity */
++#define LCR_EPS		(1 << 4)	/* Even Parity Select */
++#define LCR_PEN		(1 << 3)	/* Parity Enable */
++#define LCR_STB		(1 << 2)	/* Stop Bit */
++#define LCR_WLS1	(1 << 1)	/* Word Length Select */
++#define LCR_WLS0	(1 << 0)	/* Word Length Select */
++
++#define LSR_FIFOE	(1 << 7)	/* FIFO Error Status */
++#define LSR_TEMT	(1 << 6)	/* Transmitter Empty */
++#define LSR_TDRQ	(1 << 5)	/* Transmit Data Request */
++#define LSR_BI		(1 << 4)	/* Break Interrupt */
++#define LSR_FE		(1 << 3)	/* Framing Error */
++#define LSR_PE		(1 << 2)	/* Parity Error */
++#define LSR_OE		(1 << 1)	/* Overrun Error */
++#define LSR_DR		(1 << 0)	/* Data Ready */
++
++#define MCR_LOOP	(1 << 4)	*/ 
++#define MCR_OUT2	(1 << 3)	/* force MSR_DCD in loopback mode */
++#define MCR_OUT1	(1 << 2)	/* force MSR_RI in loopback mode */
++#define MCR_RTS		(1 << 1)	/* Request to Send */
++#define MCR_DTR		(1 << 0)	/* Data Terminal Ready */
++
++#define MSR_DCD		(1 << 7)	/* Data Carrier Detect */
++#define MSR_RI		(1 << 6)	/* Ring Indicator */
++#define MSR_DSR		(1 << 5)	/* Data Set Ready */
++#define MSR_CTS		(1 << 4)	/* Clear To Send */
++#define MSR_DDCD	(1 << 3)	/* Delta Data Carrier Detect */
++#define MSR_TERI	(1 << 2)	/* Trailing Edge Ring Indicator */
++#define MSR_DDSR	(1 << 1)	/* Delta Data Set Ready */
++#define MSR_DCTS	(1 << 0)	/* Delta Clear To Send */
++
++/*
++ * IrSR (Infrared Selection Register)
++ */
++#define STISR_RXPL      (1 << 4)        /* Receive Data Polarity */
++#define STISR_TXPL      (1 << 3)        /* Transmit Data Polarity */
++#define STISR_XMODE     (1 << 2)        /* Transmit Pulse Width Select */
++#define STISR_RCVEIR    (1 << 1)        /* Receiver SIR Enable */
++#define STISR_XMITIR    (1 << 0)        /* Transmitter SIR Enable */
++
++
++/*
++ * I2C registers
++ */
++
++#define IBMR		__REG(0x40301680)  /* I2C Bus Monitor Register - IBMR */
++#define IDBR		__REG(0x40301688)  /* I2C Data Buffer Register - IDBR */
++#define ICR		__REG(0x40301690)  /* I2C Control Register - ICR */
++#define ISR		__REG(0x40301698)  /* I2C Status Register - ISR */
++#define ISAR		__REG(0x403016A0)  /* I2C Slave Address Register - ISAR */
++
++#define ICR_START	(1 << 0)	   /* start bit */
++#define ICR_STOP	(1 << 1)	   /* stop bit */
++#define ICR_ACKNAK	(1 << 2)	   /* send ACK(0) or NAK(1) */
++#define ICR_TB		(1 << 3)	   /* transfer byte bit */
++#define ICR_MA		(1 << 4)	   /* master abort */
++#define ICR_SCLE	(1 << 5)	   /* master clock enable */
++#define ICR_IUE		(1 << 6)	   /* unit enable */
++#define ICR_GCD		(1 << 7)	   /* general call disable */
++#define ICR_ITEIE	(1 << 8)	   /* enable tx interrupts */
++#define ICR_IRFIE	(1 << 9)	   /* enable rx interrupts */
++#define ICR_BEIE	(1 << 10)	   /* enable bus error ints */
++#define ICR_SSDIE	(1 << 11)	   /* slave STOP detected int enable */
++#define ICR_ALDIE	(1 << 12)	   /* enable arbitration interrupt */
++#define ICR_SADIE	(1 << 13)	   /* slave address detected int enable */
++#define ICR_UR		(1 << 14)	   /* unit reset */
++
++#define ISR_RWM		(1 << 0)	   /* read/write mode */
++#define ISR_ACKNAK	(1 << 1)	   /* ack/nak status */
++#define ISR_UB		(1 << 2)	   /* unit busy */
++#define ISR_IBB		(1 << 3)	   /* bus busy */	
++#define ISR_SSD		(1 << 4)	   /* slave stop detected */
++#define ISR_ALD		(1 << 5)	   /* arbitration loss detected */
++#define ISR_ITE		(1 << 6)	   /* tx buffer empty */
++#define ISR_IRF		(1 << 7)	   /* rx buffer full */
++#define ISR_GCAD	(1 << 8)	   /* general call address detected */
++#define ISR_SAD		(1 << 9)	   /* slave address detected */
++#define ISR_BED		(1 << 10)	   /* bus error no ACK/NAK */
++
++
++/*
++ * Serial Audio Controller
++ */
++
++/* FIXME: This clash with SA1111 defines */
++#ifndef CONFIG_SA1111
++#define SACR0		__REG(0x40400000)  /* Global Control Register */
++#define SACR1		__REG(0x40400004)  /* Serial Audio I 2 S/MSB-Justified Control Register */
++#define SASR0		__REG(0x4040000C)  /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
++#define SAIMR		__REG(0x40400014)  /* Serial Audio Interrupt Mask Register */
++#define SAICR		__REG(0x40400018)  /* Serial Audio Interrupt Clear Register */
++#define SADIV		__REG(0x40400060)  /* Audio Clock Divider Register. */
++#define SADR		__REG(0x40400080)  /* Serial Audio Data Register (TX and RX FIFO access Register). */
++#endif
++
++
++/*
++ * AC97 Controller registers
++ */
++
++#define POCR		__REG(0x40500000)  /* PCM Out Control Register */
++#define POCR_FEIE	(1 << 3)	/* FIFO Error Interrupt Enable */
++
++#define PICR		__REG(0x40500004)  /* PCM In Control Register */
++#define PICR_FEIE	(1 << 3)	/* FIFO Error Interrupt Enable */
++
++#define MCCR		__REG(0x40500008)  /* Mic In Control Register */
++#define MCCR_FEIE	(1 << 3)	/* FIFO Error Interrupt Enable */
++
++#define GCR		__REG(0x4050000C)  /* Global Control Register */
++#define GCR_CDONE_IE	(1 << 19)	/* Command Done Interrupt Enable */
++#define GCR_SDONE_IE	(1 << 18)	/* Status Done Interrupt Enable */
++#define GCR_SECRDY_IEN	(1 << 9)	/* Secondary Ready Interrupt Enable */
++#define GCR_PRIRDY_IEN	(1 << 8)	/* Primary Ready Interrupt Enable */
++#define GCR_SECRES_IEN	(1 << 5)	/* Secondary Resume Interrupt Enable */
++#define GCR_PRIRES_IEN	(1 << 4)	/* Primary Resume Interrupt Enable */
++#define GCR_ACLINK_OFF	(1 << 3)	/* AC-link Shut Off */
++#define GCR_WARM_RST	(1 << 2)	/* AC97 Warm Reset */
++#define GCR_COLD_RST	(1 << 1)	/* AC'97 Cold Reset (0 = active) */
++#define GCR_GIE		(1 << 0)	/* Codec GPI Interrupt Enable */
++
++#define POSR		__REG(0x40500010)  /* PCM Out Status Register */
++#define POSR_FIFOE	(1 << 4)	/* FIFO error */
++
++#define PISR		__REG(0x40500014)  /* PCM In Status Register */
++#define PISR_FIFOE	(1 << 4)	/* FIFO error */
++
++#define MCSR		__REG(0x40500018)  /* Mic In Status Register */
++#define MCSR_FIFOE	(1 << 4)	/* FIFO error */
++
++#define GSR		__REG(0x4050001C)  /* Global Status Register */
++#define GSR_CDONE	(1 << 19)	/* Command Done */
++#define GSR_SDONE	(1 << 18)	/* Status Done */
++#define GSR_RDCS	(1 << 15)	/* Read Completion Status */
++#define GSR_BIT3SLT12	(1 << 14)	/* Bit 3 of slot 12 */
++#define GSR_BIT2SLT12	(1 << 13)	/* Bit 2 of slot 12 */
++#define GSR_BIT1SLT12	(1 << 12)	/* Bit 1 of slot 12 */
++#define GSR_SECRES	(1 << 11)	/* Secondary Resume Interrupt */
++#define GSR_PRIRES	(1 << 10)	/* Primary Resume Interrupt */
++#define GSR_SCR		(1 << 9)	/* Secondary Codec Ready */
++#define GSR_PCR		(1 << 8)	/*  Primary Codec Ready */
++#define GSR_MINT	(1 << 7)	/* Mic In Interrupt */
++#define GSR_POINT	(1 << 6)	/* PCM Out Interrupt */
++#define GSR_PIINT	(1 << 5)	/* PCM In Interrupt */
++#define GSR_MOINT	(1 << 2)	/* Modem Out Interrupt */
++#define GSR_MIINT	(1 << 1)	/* Modem In Interrupt */
++#define GSR_GSCI	(1 << 0)	/* Codec GPI Status Change Interrupt */
++
++#define CAR		__REG(0x40500020)  /* CODEC Access Register */
++#define CAR_CAIP	(1 << 0)	/* Codec Access In Progress */
++
++#define PCDR		__REG(0x40500040)  /* PCM FIFO Data Register */
++#define MCDR		__REG(0x40500060)  /* Mic-in FIFO Data Register */
++
++#define MOCR		__REG(0x40500100)  /* Modem Out Control Register */
++#define MOCR_FEIE	(1 << 3)	/* FIFO Error */
++
++#define MICR		__REG(0x40500108)  /* Modem In Control Register */
++#define MICR_FEIE	(1 << 3)	/* FIFO Error */
++
++#define MOSR		__REG(0x40500110)  /* Modem Out Status Register */
++#define MOSR_FIFOE	(1 << 4)	/* FIFO error */
++
++#define MISR		__REG(0x40500118)  /* Modem In Status Register */
++#define MISR_FIFOE	(1 << 4)	/* FIFO error */
++
++#define MODR		__REG(0x40500140)  /* Modem FIFO Data Register */
++
++#define PAC_REG_BASE	__REG(0x40500200)  /* Primary Audio Codec */
++#define SAC_REG_BASE	__REG(0x40500300)  /* Secondary Audio Codec */
++#define PMC_REG_BASE	__REG(0x40500400)  /* Primary Modem Codec */
++#define SMC_REG_BASE	__REG(0x40500500)  /* Secondary Modem Codec */
++
++
++/*
++ * USB Device Controller
++ */
++#define UDC_RES1	__REG(0x40600004)  /* UDC Undocumented - Reserved1 */
++#define UDC_RES2	__REG(0x40600008)  /* UDC Undocumented - Reserved2 */
++#define UDC_RES3	__REG(0x4060000C)  /* UDC Undocumented - Reserved3 */
++
++#define UDCCR		__REG(0x40600000)  /* UDC Control Register */
++#define UDCCR_UDE	(1 << 0)	/* UDC enable */
++#define UDCCR_UDA	(1 << 1)	/* UDC active */
++#define UDCCR_RSM	(1 << 2)	/* Device resume */
++#define UDCCR_RESIR	(1 << 3)	/* Resume interrupt request */
++#define UDCCR_SUSIR	(1 << 4)	/* Suspend interrupt request */
++#define UDCCR_SRM	(1 << 5)	/* Suspend/resume interrupt mask */
++#define UDCCR_RSTIR	(1 << 6)	/* Reset interrupt request */
++#define UDCCR_REM	(1 << 7)	/* Reset interrupt mask */
++
++#define UDCCS0		__REG(0x40600010)  /* UDC Endpoint 0 Control/Status Register */
++#define UDCCS0_OPR	(1 << 0)	/* OUT packet ready */
++#define UDCCS0_IPR	(1 << 1)	/* IN packet ready */
++#define UDCCS0_FTF	(1 << 2)	/* Flush Tx FIFO */
++#define UDCCS0_DRWF	(1 << 3)	/* Device remote wakeup feature */
++#define UDCCS0_SST	(1 << 4)	/* Sent stall */
++#define UDCCS0_FST	(1 << 5)	/* Force stall */
++#define UDCCS0_RNE	(1 << 6)	/* Receive FIFO no empty */
++#define UDCCS0_SA	(1 << 7)	/* Setup active */
++
++/* Bulk IN - Endpoint 1,6,11 */
++#define UDCCS1		__REG(0x40600014)  /* UDC Endpoint 1 (IN) Control/Status Register */
++#define UDCCS6		__REG(0x40600028)  /* UDC Endpoint 6 (IN) Control/Status Register */
++#define UDCCS11		__REG(0x4060003C)  /* UDC Endpoint 11 (IN) Control/Status Register */
++
++#define UDCCS_BI_TFS	(1 << 0)	/* Transmit FIFO service */
++#define UDCCS_BI_TPC	(1 << 1)	/* Transmit packet complete */
++#define UDCCS_BI_FTF	(1 << 2)	/* Flush Tx FIFO */
++#define UDCCS_BI_TUR	(1 << 3)	/* Transmit FIFO underrun */
++#define UDCCS_BI_SST	(1 << 4)	/* Sent stall */
++#define UDCCS_BI_FST	(1 << 5)	/* Force stall */
++#define UDCCS_BI_TSP	(1 << 7)	/* Transmit short packet */
++
++/* Bulk OUT - Endpoint 2,7,12 */
++#define UDCCS2		__REG(0x40600018)  /* UDC Endpoint 2 (OUT) Control/Status Register */
++#define UDCCS7		__REG(0x4060002C)  /* UDC Endpoint 7 (OUT) Control/Status Register */
++#define UDCCS12		__REG(0x40600040)  /* UDC Endpoint 12 (OUT) Control/Status Register */
++
++#define UDCCS_BO_RFS	(1 << 0)	/* Receive FIFO service */
++#define UDCCS_BO_RPC	(1 << 1)	/* Receive packet complete */
++#define UDCCS_BO_DME	(1 << 3)	/* DMA enable */
++#define UDCCS_BO_SST	(1 << 4)	/* Sent stall */
++#define UDCCS_BO_FST	(1 << 5)	/* Force stall */
++#define UDCCS_BO_RNE	(1 << 6)	/* Receive FIFO not empty */
++#define UDCCS_BO_RSP	(1 << 7)	/* Receive short packet */
++
++/* Isochronous IN - Endpoint 3,8,13 */
++#define UDCCS3		__REG(0x4060001C)  /* UDC Endpoint 3 (IN) Control/Status Register */
++#define UDCCS8		__REG(0x40600030)  /* UDC Endpoint 8 (IN) Control/Status Register */
++#define UDCCS13		__REG(0x40600044)  /* UDC Endpoint 13 (IN) Control/Status Register */
++
++#define UDCCS_II_TFS	(1 << 0)	/* Transmit FIFO service */
++#define UDCCS_II_TPC	(1 << 1)	/* Transmit packet complete */
++#define UDCCS_II_FTF	(1 << 2)	/* Flush Tx FIFO */
++#define UDCCS_II_TUR	(1 << 3)	/* Transmit FIFO underrun */
++#define UDCCS_II_TSP	(1 << 7)	/* Transmit short packet */
++
++/* Isochronous OUT - Endpoint 4,9,14 */
++#define UDCCS4		__REG(0x40600020)  /* UDC Endpoint 4 (OUT) Control/Status Register */
++#define UDCCS9		__REG(0x40600034)  /* UDC Endpoint 9 (OUT) Control/Status Register */
++#define UDCCS14		__REG(0x40600048)  /* UDC Endpoint 14 (OUT) Control/Status Register */
++
++#define UDCCS_IO_RFS	(1 << 0)	/* Receive FIFO service */
++#define UDCCS_IO_RPC	(1 << 1)	/* Receive packet complete */
++#define UDCCS_IO_ROF	(1 << 3)	/* Receive overflow */
++#define UDCCS_IO_DME	(1 << 3)	/* DMA enable */
++#define UDCCS_IO_RNE	(1 << 6)	/* Receive FIFO not empty */
++#define UDCCS_IO_RSP	(1 << 7)	/* Receive short packet */
++
++/* Interrupt IN - Endpoint 5,10,15 */
++#define UDCCS5		__REG(0x40600024)  /* UDC Endpoint 5 (Interrupt) Control/Status Register */
++#define UDCCS10		__REG(0x40600038)  /* UDC Endpoint 10 (Interrupt) Control/Status Register */
++#define UDCCS15		__REG(0x4060004C)  /* UDC Endpoint 15 (Interrupt) Control/Status Register */
++
++#define UDCCS_INT_TFS	(1 << 0)	/* Transmit FIFO service */
++#define UDCCS_INT_TPC	(1 << 1)	/* Transmit packet complete */
++#define UDCCS_INT_FTF	(1 << 2)	/* Flush Tx FIFO */
++#define UDCCS_INT_TUR	(1 << 3)	/* Transmit FIFO underrun */
++#define UDCCS_INT_SST	(1 << 4)	/* Sent stall */
++#define UDCCS_INT_FST	(1 << 5)	/* Force stall */
++#define UDCCS_INT_TSP	(1 << 7)	/* Transmit short packet */
++
++#define UFNRH		__REG(0x40600060)  /* UDC Frame Number Register High */
++#define UFNRL		__REG(0x40600064)  /* UDC Frame Number Register Low */
++#define UBCR2		__REG(0x40600068)  /* UDC Byte Count Reg 2 */
++#define UBCR4		__REG(0x4060006c)  /* UDC Byte Count Reg 4 */
++#define UBCR7		__REG(0x40600070)  /* UDC Byte Count Reg 7 */
++#define UBCR9		__REG(0x40600074)  /* UDC Byte Count Reg 9 */
++#define UBCR12		__REG(0x40600078)  /* UDC Byte Count Reg 12 */
++#define UBCR14		__REG(0x4060007c)  /* UDC Byte Count Reg 14 */
++#define UDDR0		__REG(0x40600080)  /* UDC Endpoint 0 Data Register */
++#define UDDR1		__REG(0x40600100)  /* UDC Endpoint 1 Data Register */
++#define UDDR2		__REG(0x40600180)  /* UDC Endpoint 2 Data Register */
++#define UDDR3		__REG(0x40600200)  /* UDC Endpoint 3 Data Register */
++#define UDDR4		__REG(0x40600400)  /* UDC Endpoint 4 Data Register */
++#define UDDR5		__REG(0x406000A0)  /* UDC Endpoint 5 Data Register */
++#define UDDR6		__REG(0x40600600)  /* UDC Endpoint 6 Data Register */
++#define UDDR7		__REG(0x40600680)  /* UDC Endpoint 7 Data Register */
++#define UDDR8		__REG(0x40600700)  /* UDC Endpoint 8 Data Register */
++#define UDDR9		__REG(0x40600900)  /* UDC Endpoint 9 Data Register */
++#define UDDR10		__REG(0x406000C0)  /* UDC Endpoint 10 Data Register */
++#define UDDR11		__REG(0x40600B00)  /* UDC Endpoint 11 Data Register */
++#define UDDR12		__REG(0x40600B80)  /* UDC Endpoint 12 Data Register */
++#define UDDR13		__REG(0x40600C00)  /* UDC Endpoint 13 Data Register */
++#define UDDR14		__REG(0x40600E00)  /* UDC Endpoint 14 Data Register */
++#define UDDR15		__REG(0x406000E0)  /* UDC Endpoint 15 Data Register */
++
++#define UICR0		__REG(0x40600050)  /* UDC Interrupt Control Register 0 */
++
++#define UICR0_IM0	(1 << 0)	/* Interrupt mask ep 0 */
++#define UICR0_IM1	(1 << 1)	/* Interrupt mask ep 1 */
++#define UICR0_IM2	(1 << 2)	/* Interrupt mask ep 2 */
++#define UICR0_IM3	(1 << 3)	/* Interrupt mask ep 3 */
++#define UICR0_IM4	(1 << 4)	/* Interrupt mask ep 4 */
++#define UICR0_IM5	(1 << 5)	/* Interrupt mask ep 5 */
++#define UICR0_IM6	(1 << 6)	/* Interrupt mask ep 6 */
++#define UICR0_IM7	(1 << 7)	/* Interrupt mask ep 7 */
++
++#define UICR1		__REG(0x40600054)  /* UDC Interrupt Control Register 1 */
++
++#define UICR1_IM8	(1 << 0)	/* Interrupt mask ep 8 */
++#define UICR1_IM9	(1 << 1)	/* Interrupt mask ep 9 */
++#define UICR1_IM10	(1 << 2)	/* Interrupt mask ep 10 */
++#define UICR1_IM11	(1 << 3)	/* Interrupt mask ep 11 */
++#define UICR1_IM12	(1 << 4)	/* Interrupt mask ep 12 */
++#define UICR1_IM13	(1 << 5)	/* Interrupt mask ep 13 */
++#define UICR1_IM14	(1 << 6)	/* Interrupt mask ep 14 */
++#define UICR1_IM15	(1 << 7)	/* Interrupt mask ep 15 */
++
++#define USIR0		__REG(0x40600058)  /* UDC Status Interrupt Register 0 */
++
++#define USIR0_IR0	(1 << 0)	/* Interrup request ep 0 */
++#define USIR0_IR1	(1 << 1)	/* Interrup request ep 1 */
++#define USIR0_IR2	(1 << 2)	/* Interrup request ep 2 */
++#define USIR0_IR3	(1 << 3)	/* Interrup request ep 3 */
++#define USIR0_IR4	(1 << 4)	/* Interrup request ep 4 */
++#define USIR0_IR5	(1 << 5)	/* Interrup request ep 5 */
++#define USIR0_IR6	(1 << 6)	/* Interrup request ep 6 */
++#define USIR0_IR7	(1 << 7)	/* Interrup request ep 7 */
++
++#define USIR1		__REG(0x4060005C)  /* UDC Status Interrupt Register 1 */
++
++#define USIR1_IR8	(1 << 0)	/* Interrup request ep 8 */
++#define USIR1_IR9	(1 << 1)	/* Interrup request ep 9 */
++#define USIR1_IR10	(1 << 2)	/* Interrup request ep 10 */
++#define USIR1_IR11	(1 << 3)	/* Interrup request ep 11 */
++#define USIR1_IR12	(1 << 4)	/* Interrup request ep 12 */
++#define USIR1_IR13	(1 << 5)	/* Interrup request ep 13 */
++#define USIR1_IR14	(1 << 6)	/* Interrup request ep 14 */
++#define USIR1_IR15	(1 << 7)	/* Interrup request ep 15 */
++
++
++/*
++ * Fast Infrared Communication Port
++ */
++
++#define ICCR0		__REG(0x40800000)  /* ICP Control Register 0 */
++#define ICCR1		__REG(0x40800004)  /* ICP Control Register 1 */
++#define ICCR2		__REG(0x40800008)  /* ICP Control Register 2 */
++#define ICDR		__REG(0x4080000c)  /* ICP Data Register */
++#define ICSR0		__REG(0x40800014)  /* ICP Status Register 0 */
++#define ICSR1		__REG(0x40800018)  /* ICP Status Register 1 */
++
++#define ICCR0_AME       (1 << 7)           /* Adress match enable */
++#define ICCR0_TIE       (1 << 6)           /* Transmit FIFO interrupt enable */ 
++#define ICCR0_RIE       (1 << 5)           /* Recieve FIFO interrupt enable */
++#define ICCR0_RXE       (1 << 4)           /* Receive enable */
++#define ICCR0_TXE       (1 << 3)           /* Transmit enable */
++#define ICCR0_TUS       (1 << 2)           /* Transmit FIFO underrun select */
++#define ICCR0_LBM       (1 << 1)           /* Loopback mode */
++#define ICCR0_ITR       (1 << 0)           /* IrDA transmission */
++
++#define ICSR0_FRE       (1 << 5)           /* Framing error */
++#define ICSR0_RFS       (1 << 4)           /* Receive FIFO service request */
++#define ICSR0_TFS       (1 << 3)           /* Transnit FIFO service request */
++#define ICSR0_RAB       (1 << 2)           /* Receiver abort */
++#define ICSR0_TUR       (1 << 1)           /* Trunsmit FIFO underun */
++#define ICSR0_EIF       (1 << 0)           /* End/Error in FIFO */
++
++#define ICSR1_ROR       (1 << 6)           /* Receiver FIFO underrun  */
++#define ICSR1_CRE       (1 << 5)           /* CRC error */
++#define ICSR1_EOF       (1 << 4)           /* End of frame */
++#define ICSR1_TNF       (1 << 3)           /* Transmit FIFO not full */
++#define ICSR1_RNE       (1 << 2)           /* Receive FIFO not empty */
++#define ICSR1_TBY       (1 << 1)           /* Tramsmiter busy flag */
++#define ICSR1_RSY       (1 << 0)           /* Recevier synchronized flag */
++
++
++/*
++ * Real Time Clock
++ */
++
++#define RCNR		__REG(0x40900000)  /* RTC Count Register */
++#define RTAR		__REG(0x40900004)  /* RTC Alarm Register */
++#define RTSR		__REG(0x40900008)  /* RTC Status Register */
++#define RTTR		__REG(0x4090000C)  /* RTC Timer Trim Register */
++
++#define RTSR_HZE	(1 << 3)	/* HZ interrupt enable */
++#define RTSR_ALE	(1 << 2)	/* RTC alarm interrupt enable */
++#define RTSR_HZ		(1 << 1)	/* HZ rising-edge detected */
++#define RTSR_AL		(1 << 0)	/* RTC alarm detected */
++
++
++/*
++ * OS Timer & Match Registers
++ */
++
++#define OSMR0		__REG(0x40A00000)  /* */
++#define OSMR1		__REG(0x40A00004)  /* */
++#define OSMR2		__REG(0x40A00008)  /* */
++#define OSMR3		__REG(0x40A0000C)  /* */
++#define OSCR		__REG(0x40A00010)  /* OS Timer Counter Register */
++#define OSSR		__REG(0x40A00014)  /* OS Timer Status Register */
++#define OWER		__REG(0x40A00018)  /* OS Timer Watchdog Enable Register */
++#define OIER		__REG(0x40A0001C)  /* OS Timer Interrupt Enable Register */
++
++#define OSSR_M3		(1 << 3)	/* Match status channel 3 */
++#define OSSR_M2		(1 << 2)	/* Match status channel 2 */
++#define OSSR_M1		(1 << 1)	/* Match status channel 1 */
++#define OSSR_M0		(1 << 0)	/* Match status channel 0 */
++
++#define OWER_WME	(1 << 0)	/* Watchdog Match Enable */
++
++#define OIER_E3		(1 << 3)	/* Interrupt enable channel 3 */
++#define OIER_E2		(1 << 2)	/* Interrupt enable channel 2 */
++#define OIER_E1		(1 << 1)	/* Interrupt enable channel 1 */
++#define OIER_E0		(1 << 0)	/* Interrupt enable channel 0 */
++
++
++/*
++ * Pulse Width Modulator
++ */
++
++#define PWM_CTRL0	__REG(0x40B00000)  /* PWM 0 Control Register */
++#define PWM_PWDUTY0	__REG(0x40B00004)  /* PWM 0 Duty Cycle Register */
++#define PWM_PERVAL0	__REG(0x40B00008)  /* PWM 0 Period Control Register */
++
++#define PWM_CTRL1	__REG(0x40C00000)  /* PWM 1Control Register */
++#define PWM_PWDUTY1	__REG(0x40C00004)  /* PWM 1 Duty Cycle Register */
++#define PWM_PERVAL1	__REG(0x40C00008)  /* PWM 1 Period Control Register */
++
++
++/*
++ * Interrupt Controller
++ */
++
++#define ICIP		__REG(0x40D00000)  /* Interrupt Controller IRQ Pending Register */
++#define ICMR		__REG(0x40D00004)  /* Interrupt Controller Mask Register */
++#define ICLR		__REG(0x40D00008)  /* Interrupt Controller Level Register */
++#define ICFP		__REG(0x40D0000C)  /* Interrupt Controller FIQ Pending Register */
++#define ICPR		__REG(0x40D00010)  /* Interrupt Controller Pending Register */
++#define ICCR		__REG(0x40D00014)  /* Interrupt Controller Control Register */
++
++
++/*
++ * General Purpose I/O
++ */
++
++#define GPLR0		__REG(0x40E00000)  /* GPIO Pin-Level Register GPIO<31:0> */
++#define GPLR1		__REG(0x40E00004)  /* GPIO Pin-Level Register GPIO<63:32> */
++#define GPLR2		__REG(0x40E00008)  /* GPIO Pin-Level Register GPIO<80:64> */
++
++#define GPDR0		__REG(0x40E0000C)  /* GPIO Pin Direction Register GPIO<31:0> */
++#define GPDR1		__REG(0x40E00010)  /* GPIO Pin Direction Register GPIO<63:32> */
++#define GPDR2		__REG(0x40E00014)  /* GPIO Pin Direction Register GPIO<80:64> */
++
++#define GPSR0		__REG(0x40E00018)  /* GPIO Pin Output Set Register GPIO<31:0> */
++#define GPSR1		__REG(0x40E0001C)  /* GPIO Pin Output Set Register GPIO<63:32> */
++#define GPSR2		__REG(0x40E00020)  /* GPIO Pin Output Set Register GPIO<80:64> */
++
++#define GPCR0		__REG(0x40E00024)  /* GPIO Pin Output Clear Register GPIO<31:0> */
++#define GPCR1		__REG(0x40E00028)  /* GPIO Pin Output Clear Register GPIO <63:32> */
++#define GPCR2		__REG(0x40E0002C)  /* GPIO Pin Output Clear Register GPIO <80:64> */
++
++#define GRER0		__REG(0x40E00030)  /* GPIO Rising-Edge Detect Register GPIO<31:0> */
++#define GRER1		__REG(0x40E00034)  /* GPIO Rising-Edge Detect Register GPIO<63:32> */
++#define GRER2		__REG(0x40E00038)  /* GPIO Rising-Edge Detect Register GPIO<80:64> */
++
++#define GFER0		__REG(0x40E0003C)  /* GPIO Falling-Edge Detect Register GPIO<31:0> */
++#define GFER1		__REG(0x40E00040)  /* GPIO Falling-Edge Detect Register GPIO<63:32> */
++#define GFER2		__REG(0x40E00044)  /* GPIO Falling-Edge Detect Register GPIO<80:64> */
++
++#define GEDR0		__REG(0x40E00048)  /* GPIO Edge Detect Status Register GPIO<31:0> */
++#define GEDR1		__REG(0x40E0004C)  /* GPIO Edge Detect Status Register GPIO<63:32> */
++#define GEDR2		__REG(0x40E00050)  /* GPIO Edge Detect Status Register GPIO<80:64> */
++
++#define GAFR0_L		__REG(0x40E00054)  /* GPIO Alternate Function Select Register GPIO<15:0> */
++#define GAFR0_U		__REG(0x40E00058)  /* GPIO Alternate Function Select Register GPIO<31:16> */
++#define GAFR1_L		__REG(0x40E0005C)  /* GPIO Alternate Function Select Register GPIO<47:32> */
++#define GAFR1_U		__REG(0x40E00060)  /* GPIO Alternate Function Select Register GPIO<63:48> */
++#define GAFR2_L		__REG(0x40E00064)  /* GPIO Alternate Function Select Register GPIO<79:64> */
++#define GAFR2_U		__REG(0x40E00068)  /* GPIO Alternate Function Select Register GPIO 80 */
++
++/* More handy macros.  The argument is a literal GPIO number. */
++
++#define GPIO_bit(x)	(1 << ((x) & 0x1f))
++#define GPLR(x)		__REG2(0x40E00000, ((x) & 0x60) >> 3)
++#define GPDR(x)		__REG2(0x40E0000C, ((x) & 0x60) >> 3)
++#define GPSR(x)		__REG2(0x40E00018, ((x) & 0x60) >> 3)
++#define GPCR(x)		__REG2(0x40E00024, ((x) & 0x60) >> 3)
++#define GRER(x)		__REG2(0x40E00030, ((x) & 0x60) >> 3)
++#define GFER(x)		__REG2(0x40E0003C, ((x) & 0x60) >> 3)
++#define GEDR(x)		__REG2(0x40E00048, ((x) & 0x60) >> 3)
++#define GAFR(x)		__REG2(0x40E00054, ((x) & 0x70) >> 2)
++
++/* GPIO alternate function assignments */
++
++#define GPIO1_RST		1	/* reset */
++#define GPIO6_MMCCLK		6	/* MMC Clock */
++#define GPIO8_48MHz		7	/* 48 MHz clock output */
++#define GPIO8_MMCCS0		8	/* MMC Chip Select 0 */
++#define GPIO9_MMCCS1		9	/* MMC Chip Select 1 */
++#define GPIO10_RTCCLK		10	/* real time clock (1 Hz) */
++#define GPIO11_3_6MHz		11	/* 3.6 MHz oscillator out */
++#define GPIO12_32KHz		12	/* 32 kHz out */
++#define GPIO13_MBGNT		13	/* memory controller grant */
++#define GPIO14_MBREQ		14	/* alternate bus master request */
++#define GPIO15_nCS_1		15	/* chip select 1 */
++#define GPIO16_PWM0		16	/* PWM0 output */
++#define GPIO17_PWM1		17	/* PWM1 output */
++#define GPIO18_RDY		18	/* Ext. Bus Ready */
++#define GPIO19_DREQ1		19	/* External DMA Request */
++#define GPIO20_DREQ0		20	/* External DMA Request */
++#define GPIO23_SCLK		23	/* SSP clock */
++#define GPIO24_SFRM		24	/* SSP Frame */
++#define GPIO25_STXD		25	/* SSP transmit */
++#define GPIO26_SRXD		26	/* SSP receive */
++#define GPIO27_SEXTCLK		27	/* SSP ext_clk */
++#define GPIO28_BITCLK		28	/* AC97/I2S bit_clk */
++#define GPIO29_SDATA_IN		29	/* AC97 Sdata_in0 / I2S Sdata_in */
++#define GPIO30_SDATA_OUT	30	/* AC97/I2S Sdata_out */
++#define GPIO31_SYNC		31	/* AC97/I2S sync */
++#define GPIO32_SDATA_IN1	32	/* AC97 Sdata_in1 */
++#define GPIO33_nCS_5		33	/* chip select 5 */
++#define GPIO34_FFRXD		34	/* FFUART receive */
++#define GPIO34_MMCCS0		34	/* MMC Chip Select 0 */
++#define GPIO35_FFCTS		35	/* FFUART Clear to send */
++#define GPIO36_FFDCD		36	/* FFUART Data carrier detect */
++#define GPIO37_FFDSR		37	/* FFUART data set ready */
++#define GPIO38_FFRI		38	/* FFUART Ring Indicator */
++#define GPIO39_MMCCS1		39	/* MMC Chip Select 1 */
++#define GPIO39_FFTXD		39	/* FFUART transmit data */
++#define GPIO40_FFDTR		40	/* FFUART data terminal Ready */
++#define GPIO41_FFRTS		41	/* FFUART request to send */
++#define GPIO42_BTRXD		42	/* BTUART receive data */
++#define GPIO43_BTTXD		43	/* BTUART transmit data */
++#define GPIO44_BTCTS		44	/* BTUART clear to send */
++#define GPIO45_BTRTS		45	/* BTUART request to send */
++#define GPIO46_ICPRXD		46	/* ICP receive data */
++#define GPIO46_STRXD		46	/* STD_UART receive data */
++#define GPIO47_ICPTXD		47	/* ICP transmit data */
++#define GPIO47_STTXD		47	/* STD_UART transmit data */
++#define GPIO48_nPOE		48	/* Output Enable for Card Space */
++#define GPIO49_nPWE		49	/* Write Enable for Card Space */
++#define GPIO50_nPIOR		50	/* I/O Read for Card Space */
++#define GPIO51_nPIOW		51	/* I/O Write for Card Space */
++#define GPIO52_nPCE_1		52	/* Card Enable for Card Space */
++#define GPIO53_nPCE_2		53	/* Card Enable for Card Space */
++#define GPIO53_MMCCLK		53	/* MMC Clock */
++#define GPIO54_MMCCLK		54	/* MMC Clock */
++#define GPIO54_pSKTSEL		54	/* Socket Select for Card Space */
++#define GPIO55_nPREG		55	/* Card Address bit 26 */
++#define GPIO56_nPWAIT		56	/* Wait signal for Card Space */
++#define GPIO57_nIOIS16		57	/* Bus Width select for I/O Card Space */
++#define GPIO58_LDD_0		58	/* LCD data pin 0 */
++#define GPIO59_LDD_1		59	/* LCD data pin 1 */
++#define GPIO60_LDD_2		60	/* LCD data pin 2 */
++#define GPIO61_LDD_3		61	/* LCD data pin 3 */
++#define GPIO62_LDD_4		62	/* LCD data pin 4 */
++#define GPIO63_LDD_5		63	/* LCD data pin 5 */
++#define GPIO64_LDD_6		64	/* LCD data pin 6 */
++#define GPIO65_LDD_7		65	/* LCD data pin 7 */
++#define GPIO66_LDD_8		66	/* LCD data pin 8 */
++#define GPIO66_MBREQ		66	/* alternate bus master req */
++#define GPIO67_LDD_9		67	/* LCD data pin 9 */
++#define GPIO67_MMCCS0		67	/* MMC Chip Select 0 */
++#define GPIO68_LDD_10		68	/* LCD data pin 10 */
++#define GPIO68_MMCCS1		68	/* MMC Chip Select 1 */
++#define GPIO69_LDD_11		69	/* LCD data pin 11 */
++#define GPIO69_MMCCLK		69	/* MMC_CLK */
++#define GPIO70_LDD_12		70	/* LCD data pin 12 */
++#define GPIO70_RTCCLK		70	/* Real Time clock (1 Hz) */
++#define GPIO71_LDD_13		71	/* LCD data pin 13 */
++#define GPIO71_3_6MHz		71	/* 3.6 MHz Oscillator clock */
++#define GPIO72_LDD_14		72	/* LCD data pin 14 */
++#define GPIO72_32kHz		72	/* 32 kHz clock */
++#define GPIO73_LDD_15		73	/* LCD data pin 15 */
++#define GPIO73_MBGNT		73	/* Memory controller grant */
++#define GPIO74_LCD_FCLK		74	/* LCD Frame clock */
++#define GPIO75_LCD_LCLK		75	/* LCD line clock */
++#define GPIO76_LCD_PCLK		76	/* LCD Pixel clock */
++#define GPIO77_LCD_ACBIAS	77	/* LCD AC Bias */
++#define GPIO78_nCS_2		78	/* chip select 2 */
++#define GPIO79_nCS_3		79	/* chip select 3 */
++#define GPIO80_nCS_4		80	/* chip select 4 */
++
++/* GPIO alternate function mode & direction */
++
++#define GPIO_IN			0x000
++#define GPIO_OUT		0x080
++#define GPIO_ALT_FN_1_IN	0x100
++#define GPIO_ALT_FN_1_OUT	0x180
++#define GPIO_ALT_FN_2_IN	0x200
++#define GPIO_ALT_FN_2_OUT	0x280
++#define GPIO_ALT_FN_3_IN	0x300
++#define GPIO_ALT_FN_3_OUT	0x380
++#define GPIO_MD_MASK_NR		0x07f
++#define GPIO_MD_MASK_DIR	0x080
++#define GPIO_MD_MASK_FN		0x300
++
++#define GPIO1_RTS_MD		( 1 | GPIO_ALT_FN_1_IN)
++#define GPIO6_MMCCLK_MD		( 6 | GPIO_ALT_FN_1_OUT)
++#define GPIO8_48MHz_MD		( 8 | GPIO_ALT_FN_1_OUT)
++#define GPIO8_MMCCS0_MD		( 8 | GPIO_ALT_FN_1_OUT)
++#define GPIO9_MMCCS1_MD		( 9 | GPIO_ALT_FN_1_OUT)
++#define GPIO10_RTCCLK_MD	(10 | GPIO_ALT_FN_1_OUT)
++#define GPIO11_3_6MHz_MD	(11 | GPIO_ALT_FN_1_OUT)
++#define GPIO12_32KHz_MD		(12 | GPIO_ALT_FN_1_OUT)
++#define GPIO13_MBGNT_MD		(13 | GPIO_ALT_FN_2_OUT)
++#define GPIO14_MBREQ_MD		(14 | GPIO_ALT_FN_1_IN)
++#define GPIO15_nCS_1_MD		(15 | GPIO_ALT_FN_2_OUT)
++#define GPIO16_PWM0_MD		(16 | GPIO_ALT_FN_2_OUT)
++#define GPIO17_PWM1_MD		(17 | GPIO_ALT_FN_2_OUT)
++#define GPIO18_RDY_MD		(18 | GPIO_ALT_FN_1_IN)
++#define GPIO19_DREQ1_MD		(19 | GPIO_ALT_FN_1_IN)
++#define GPIO20_DREQ0_MD		(20 | GPIO_ALT_FN_1_IN)
++#define GPIO23_SCLK_md		(23 | GPIO_ALT_FN_2_OUT)
++#define GPIO24_SFRM_MD		(24 | GPIO_ALT_FN_2_OUT)
++#define GPIO25_STXD_MD		(25 | GPIO_ALT_FN_2_OUT)
++#define GPIO26_SRXD_MD		(26 | GPIO_ALT_FN_1_IN)
++#define GPIO27_SEXTCLK_MD	(27 | GPIO_ALT_FN_1_IN)
++#define GPIO28_BITCLK_AC97_MD	(28 | GPIO_ALT_FN_1_IN)
++#define GPIO28_BITCLK_I2S_MD	(28 | GPIO_ALT_FN_2_IN)
++#define GPIO29_SDATA_IN_AC97_MD	(29 | GPIO_ALT_FN_1_IN)
++#define GPIO29_SDATA_IN_I2S_MD	(29 | GPIO_ALT_FN_2_IN)
++#define GPIO30_SDATA_OUT_AC97_MD	(30 | GPIO_ALT_FN_2_OUT)
++#define GPIO30_SDATA_OUT_I2S_MD	(30 | GPIO_ALT_FN_1_OUT)
++#define GPIO31_SYNC_AC97_MD	(31 | GPIO_ALT_FN_2_OUT)
++#define GPIO31_SYNC_I2S_MD	(31 | GPIO_ALT_FN_1_OUT)
++#define GPIO32_SDATA_IN1_AC97_MD	(32 | GPIO_ALT_FN_1_IN)
++#define GPIO33_nCS_5_MD		(33 | GPIO_ALT_FN_2_OUT)
++#define GPIO34_FFRXD_MD		(34 | GPIO_ALT_FN_1_IN)
++#define GPIO34_MMCCS0_MD	(34 | GPIO_ALT_FN_2_OUT)
++#define GPIO35_FFCTS_MD		(35 | GPIO_ALT_FN_1_IN)
++#define GPIO36_FFDCD_MD		(36 | GPIO_ALT_FN_1_IN)
++#define GPIO37_FFDSR_MD		(37 | GPIO_ALT_FN_1_IN)
++#define GPIO38_FFRI_MD		(38 | GPIO_ALT_FN_1_IN)
++#define GPIO39_MMCCS1_MD	(39 | GPIO_ALT_FN_1_OUT)
++#define GPIO39_FFTXD_MD		(39 | GPIO_ALT_FN_2_OUT)
++#define GPIO40_FFDTR_MD		(40 | GPIO_ALT_FN_2_OUT)
++#define GPIO41_FFRTS_MD		(41 | GPIO_ALT_FN_2_OUT)
++#define GPIO42_BTRXD_MD		(42 | GPIO_ALT_FN_1_IN)
++#define GPIO43_BTTXD_MD		(43 | GPIO_ALT_FN_2_OUT)
++#define GPIO44_BTCTS_MD		(44 | GPIO_ALT_FN_1_IN)
++#define GPIO45_BTRTS_MD		(45 | GPIO_ALT_FN_2_OUT)
++#define GPIO46_ICPRXD_MD	(46 | GPIO_ALT_FN_1_IN)
++#define GPIO46_STRXD_MD		(46 | GPIO_ALT_FN_2_IN)
++#define GPIO47_ICPTXD_MD	(47 | GPIO_ALT_FN_2_OUT)
++#define GPIO47_STTXD_MD		(47 | GPIO_ALT_FN_1_OUT)
++#define GPIO48_nPOE_MD		(48 | GPIO_ALT_FN_2_OUT)
++#define GPIO49_nPWE_MD		(49 | GPIO_ALT_FN_2_OUT)
++#define GPIO50_nPIOR_MD		(50 | GPIO_ALT_FN_2_OUT)
++#define GPIO51_nPIOW_MD		(51 | GPIO_ALT_FN_2_OUT)
++#define GPIO52_nPCE_1_MD	(52 | GPIO_ALT_FN_2_OUT)
++#define GPIO53_nPCE_2_MD	(53 | GPIO_ALT_FN_2_OUT)
++#define GPIO53_MMCCLK_MD	(53 | GPIO_ALT_FN_1_OUT)
++#define GPIO54_MMCCLK_MD	(54 | GPIO_ALT_FN_1_OUT)
++#define GPIO54_pSKTSEL_MD	(54 | GPIO_ALT_FN_2_OUT)
++#define GPIO55_nPREG_MD		(55 | GPIO_ALT_FN_2_OUT)
++#define GPIO56_nPWAIT_MD	(56 | GPIO_ALT_FN_1_IN)
++#define GPIO57_nIOIS16_MD	(57 | GPIO_ALT_FN_1_IN)
++#define GPIO58_LDD_0_MD		(58 | GPIO_ALT_FN_2_OUT)
++#define GPIO59_LDD_1_MD		(59 | GPIO_ALT_FN_2_OUT)
++#define GPIO60_LDD_2_MD		(60 | GPIO_ALT_FN_2_OUT)
++#define GPIO61_LDD_3_MD		(61 | GPIO_ALT_FN_2_OUT)
++#define GPIO62_LDD_4_MD		(62 | GPIO_ALT_FN_2_OUT)
++#define GPIO63_LDD_5_MD		(63 | GPIO_ALT_FN_2_OUT)
++#define GPIO64_LDD_6_MD		(64 | GPIO_ALT_FN_2_OUT)
++#define GPIO65_LDD_7_MD		(65 | GPIO_ALT_FN_2_OUT)
++#define GPIO66_LDD_8_MD		(66 | GPIO_ALT_FN_2_OUT)
++#define GPIO66_MBREQ_MD		(66 | GPIO_ALT_FN_1_IN)
++#define GPIO67_LDD_9_MD		(67 | GPIO_ALT_FN_2_OUT)
++#define GPIO67_MMCCS0_MD	(67 | GPIO_ALT_FN_1_OUT)
++#define GPIO68_LDD_10_MD	(68 | GPIO_ALT_FN_2_OUT)
++#define GPIO68_MMCCS1_MD	(68 | GPIO_ALT_FN_1_OUT)
++#define GPIO69_LDD_11_MD	(69 | GPIO_ALT_FN_2_OUT)
++#define GPIO69_MMCCLK_MD	(69 | GPIO_ALT_FN_1_OUT)
++#define GPIO70_LDD_12_MD	(70 | GPIO_ALT_FN_2_OUT)
++#define GPIO70_RTCCLK_MD	(70 | GPIO_ALT_FN_1_OUT)
++#define GPIO71_LDD_13_MD	(71 | GPIO_ALT_FN_2_OUT)
++#define GPIO71_3_6MHz_MD	(71 | GPIO_ALT_FN_1_OUT)
++#define GPIO72_LDD_14_MD	(72 | GPIO_ALT_FN_2_OUT)
++#define GPIO72_32kHz_MD		(72 | GPIO_ALT_FN_1_OUT)
++#define GPIO73_LDD_15_MD	(73 | GPIO_ALT_FN_2_OUT)
++#define GPIO73_MBGNT_MD		(73 | GPIO_ALT_FN_1_OUT)
++#define GPIO74_LCD_FCLK_MD	(74 | GPIO_ALT_FN_2_OUT)
++#define GPIO75_LCD_LCLK_MD	(75 | GPIO_ALT_FN_2_OUT)
++#define GPIO76_LCD_PCLK_MD	(76 | GPIO_ALT_FN_2_OUT)
++#define GPIO77_LCD_ACBIAS_MD	(77 | GPIO_ALT_FN_2_OUT)
++#define GPIO78_nCS_2_MD		(78 | GPIO_ALT_FN_2_OUT)
++#define GPIO79_nCS_3_MD		(79 | GPIO_ALT_FN_2_OUT)
++#define GPIO80_nCS_4_MD		(80 | GPIO_ALT_FN_2_OUT)
++
++
++/*
++ * Power Manager
++ */
++
++#define PMCR		__REG(0x40F00000)  /* Power Manager Control Register */
++#define PSSR		__REG(0x40F00004)  /* Power Manager Sleep Status Register */
++#define PSPR		__REG(0x40F00008)  /* Power Manager Scratch Pad Register */
++#define PWER		__REG(0x40F0000C)  /* Power Manager Wake-up Enable Register */
++#define PRER		__REG(0x40F00010)  /* Power Manager GPIO Rising-Edge Detect Enable Register */
++#define PFER		__REG(0x40F00014)  /* Power Manager GPIO Falling-Edge Detect Enable Register */
++#define PEDR		__REG(0x40F00018)  /* Power Manager GPIO Edge Detect Status Register */
++#define PCFR		__REG(0x40F0001C)  /* Power Manager General Configuration Register */
++#define PGSR0		__REG(0x40F00020)  /* Power Manager GPIO Sleep State Register for GP[31-0] */
++#define PGSR1		__REG(0x40F00024)  /* Power Manager GPIO Sleep State Register for GP[63-32] */
++#define PGSR2		__REG(0x40F00028)  /* Power Manager GPIO Sleep State Register for GP[84-64] */
++#define RCSR		__REG(0x40F00030)  /* Reset Controller Status Register */
++
++#define PSSR_RDH	(1 << 5)	/* Read Disable Hold */
++#define PSSR_PH		(1 << 4)	/* Peripheral Control Hold */
++#define PSSR_VFS	(1 << 2)	/* VDD Fault Status */
++#define PSSR_BFS	(1 << 1)	/* Battery Fault Status */
++#define PSSR_SSS	(1 << 0)	/* Software Sleep Status */
++
++#define PCFR_DS		(1 << 3)	/* Deep Sleep Mode */
++#define PCFR_FS		(1 << 2)	/* Float Static Chip Selects */
++#define PCFR_FP		(1 << 1)	/* Float PCMCIA controls */
++#define PCFR_OPDE	(1 << 0)	/* 3.6864 MHz oscillator power-down enable */
++
++#define RCSR_GPR	(1 << 3)	/* GPIO Reset */
++#define RCSR_SMR	(1 << 2)	/* Sleep Mode */
++#define RCSR_WDR	(1 << 1)	/* Watchdog Reset */
++#define RCSR_HWR	(1 << 0)	/* Hardware Reset */
++
++
++/*
++ * SSP Serial Port Registers
++ */
++
++#define SSCR0		__REG(0x41000000)  /* SSP Control Register 0 */
++#define SSCR1		__REG(0x41000004)  /* SSP Control Register 1 */
++#define SSSR		__REG(0x41000008)  /* SSP Status Register */
++#define SSITR		__REG(0x4100000C)  /* SSP Interrupt Test Register */
++#define SSDR		__REG(0x41000010)  /* (Write / Read) SSP Data Write Register/SSP Data Read Register */
++
++
++/*
++ * MultiMediaCard (MMC) controller
++ */
++
++#define MMC_STRPCL	__REG(0x41100000)  /* Control to start and stop MMC clock */
++#define MMC_STAT	__REG(0x41100004)  /* MMC Status Register (read only) */
++#define MMC_CLKRT	__REG(0x41100008)  /* MMC clock rate */
++#define MMC_SPI		__REG(0x4110000c)  /* SPI mode control bits */
++#define MMC_CMDAT	__REG(0x41100010)  /* Command/response/data sequence control */
++#define MMC_RESTO	__REG(0x41100014)  /* Expected response time out */
++#define MMC_RDTO	__REG(0x41100018)  /* Expected data read time out */
++#define MMC_BLKLEN	__REG(0x4110001c)  /* Block length of data transaction */
++#define MMC_NOB		__REG(0x41100020)  /* Number of blocks, for block mode */
++#define MMC_PRTBUF	__REG(0x41100024)  /* Partial MMC_TXFIFO FIFO written */
++#define MMC_I_MASK	__REG(0x41100028)  /* Interrupt Mask */
++#define MMC_I_REG	__REG(0x4110002c)  /* Interrupt Register (read only) */
++#define MMC_CMD		__REG(0x41100030)  /* Index of current command */
++#define MMC_ARGH	__REG(0x41100034)  /* MSW part of the current command argument */
++#define MMC_ARGL	__REG(0x41100038)  /* LSW part of the current command argument */
++#define MMC_RES		__REG(0x4110003c)  /* Response FIFO (read only) */
++#define MMC_RXFIFO	__REG(0x41100040)  /* Receive FIFO (read only) */
++#define MMC_TXFIFO	__REG(0x41100044)  /* Transmit FIFO (write only) */
++
++
++/*
++ * Core Clock
++ */
++
++#define CCCR		__REG(0x41300000)  /* Core Clock Configuration Register */
++#define CKEN		__REG(0x41300004)  /* Clock Enable Register */
++#define OSCC		__REG(0x41300008)  /* Oscillator Configuration Register */
++
++#define CCCR_N_MASK	0x0380		/* Run Mode Frequency to Turbo Mode Frequency Multiplier */
++#define CCCR_M_MASK	0x0060		/* Memory Frequency to Run Mode Frequency Multiplier */
++#define CCCR_L_MASK	0x001f		/* Crystal Frequency to Memory Frequency Multiplier */
++
++#define CKEN16_LCD	(1 << 16)	/* LCD Unit Clock Enable */
++#define CKEN14_I2C	(1 << 14)	/* I2C Unit Clock Enable */
++#define CKEN13_FICP	(1 << 13)	/* FICP Unit Clock Enable */
++#define CKEN12_MMC	(1 << 12)	/* MMC Unit Clock Enable */
++#define CKEN11_USB	(1 << 11)	/* USB Unit Clock Enable */
++#define CKEN8_I2S	(1 << 8)	/* I2S Unit Clock Enable */
++#define CKEN7_BTUART	(1 << 7)	/* BTUART Unit Clock Enable */
++#define CKEN6_FFUART	(1 << 6)	/* FFUART Unit Clock Enable */
++#define CKEN5_STUART	(1 << 5)	/* STUART Unit Clock Enable */
++#define CKEN3_SSP	(1 << 3)	/* SSP Unit Clock Enable */
++#define CKEN2_AC97	(1 << 2)	/* AC97 Unit Clock Enable */
++#define CKEN1_PWM1	(1 << 1)	/* PWM1 Clock Enable */
++#define CKEN0_PWM0	(1 << 0)	/* PWM0 Clock Enable */
++
++#define OSCC_OON	(1 << 1)	/* 32.768kHz OON (write-once only bit) */
++#define OSCC_OOK	(1 << 0)	/* 32.768kHz OOK (read-only bit) */
++
++
++/*
++ * LCD
++ */
++
++#define LCCR0		__REG(0x44000000)  /* LCD Controller Control Register 0 */
++#define LCCR1		__REG(0x44000004)  /* LCD Controller Control Register 1 */
++#define LCCR2		__REG(0x44000008)  /* LCD Controller Control Register 2 */
++#define LCCR3		__REG(0x4400000C)  /* LCD Controller Control Register 3 */
++#define DFBR0		__REG(0x44000020)  /* DMA Channel 0 Frame Branch Register */
++#define DFBR1		__REG(0x44000024)  /* DMA Channel 1 Frame Branch Register */
++#define LCSR		__REG(0x44000038)  /* LCD Controller Status Register */
++#define LIIDR		__REG(0x4400003C)  /* LCD Controller Interrupt ID Register */
++#define TMEDRGBR	__REG(0x44000040)  /* TMED RGB Seed Register */
++#define TMEDCR		__REG(0x44000044)  /* TMED Control Register */
++
++#define FDADR0		__REG(0x44000200)  /* DMA Channel 0 Frame Descriptor Address Register */
++#define FSADR0		__REG(0x44000204)  /* DMA Channel 0 Frame Source Address Register */
++#define FIDR0		__REG(0x44000208)  /* DMA Channel 0 Frame ID Register */
++#define LDCMD0		__REG(0x4400020C)  /* DMA Channel 0 Command Register */
++#define FDADR1		__REG(0x44000210)  /* DMA Channel 1 Frame Descriptor Address Register */
++#define FSADR1		__REG(0x44000214)  /* DMA Channel 1 Frame Source Address Register */
++#define FIDR1		__REG(0x44000218)  /* DMA Channel 1 Frame ID Register */
++#define LDCMD1		__REG(0x4400021C)  /* DMA Channel 1 Command Register */
++
++#define LCCR0_ENB	(1 << 0)	/* LCD Controller enable */
++#define LCCR0_CMS	(1 << 1)	/* Color = 0, Monochrome = 1 */
++#define LCCR0_SDS	(1 << 2)	/* Single Panel = 0, Dual Panel = 1 */
++#define LCCR0_LDM	(1 << 3)	/* LCD Disable Done Mask */
++#define LCCR0_SFM	(1 << 4)	/* Start of frame mask */
++#define LCCR0_IUM	(1 << 5)	/* Input FIFO underrun mask */
++#define LCCR0_EFM	(1 << 6)	/* End of Frame mask */
++#define LCCR0_PAS	(1 << 7)	/* Passive = 0, Active = 1 */
++#define LCCR0_BLE	(1 << 8)	/* Little Endian = 0, Big Endian = 1 */
++#define LCCR0_DPD	(1 << 9)	/* Double Pixel mode, 4 pixel value = 0, 8 pixle values = 1 */
++#define LCCR0_DIS	(1 << 10)	/* LCD Disable */
++#define LCCR0_QDM	(1 << 11)	/* LCD Quick Disable mask */
++#define LCCR0_PDD	(0xff << 12)	/* Palette DMA request delay */
++#define LCCR0_PDD_S	12
++#define LCCR0_BM	(1 << 20) 	/* Branch mask */
++#define LCCR0_OUM	(1 << 21)	/* Output FIFO underrun mask */
++
++#define LCCR1_PPL       Fld (10, 0)      /* Pixels Per Line - 1 */
++#define LCCR1_DisWdth(Pixel)            /* Display Width [1..800 pix.]  */ \
++                        (((Pixel) - 1) << FShft (LCCR1_PPL))
++
++#define LCCR1_HSW       Fld (6, 10)     /* Horizontal Synchronization     */
++#define LCCR1_HorSnchWdth(Tpix)         /* Horizontal Synchronization     */ \
++                                        /* pulse Width [1..64 Tpix]       */ \
++                        (((Tpix) - 1) << FShft (LCCR1_HSW))
++
++#define LCCR1_ELW       Fld (8, 16)     /* End-of-Line pixel clock Wait    */
++                                        /* count - 1 [Tpix]                */
++#define LCCR1_EndLnDel(Tpix)            /*  End-of-Line Delay              */ \
++                                        /*  [1..256 Tpix]                  */ \
++                        (((Tpix) - 1) << FShft (LCCR1_ELW))
++
++#define LCCR1_BLW       Fld (8, 24)     /* Beginning-of-Line pixel clock   */
++                                        /* Wait count - 1 [Tpix]           */
++#define LCCR1_BegLnDel(Tpix)            /*  Beginning-of-Line Delay        */ \
++                                        /*  [1..256 Tpix]                  */ \
++                        (((Tpix) - 1) << FShft (LCCR1_BLW))
++
++
++#define LCCR2_LPP       Fld (10, 0)     /* Line Per Panel - 1              */
++#define LCCR2_DisHght(Line)             /*  Display Height [1..1024 lines] */ \
++                        (((Line) - 1) << FShft (LCCR2_LPP))
++
++#define LCCR2_VSW       Fld (6, 10)     /* Vertical Synchronization pulse  */
++                                        /* Width - 1 [Tln] (L_FCLK)        */
++#define LCCR2_VrtSnchWdth(Tln)          /*  Vertical Synchronization pulse */ \
++                                        /*  Width [1..64 Tln]              */ \
++                        (((Tln) - 1) << FShft (LCCR2_VSW))
++
++#define LCCR2_EFW       Fld (8, 16)     /* End-of-Frame line clock Wait    */
++                                        /* count [Tln]                     */
++#define LCCR2_EndFrmDel(Tln)            /*  End-of-Frame Delay             */ \
++                                        /*  [0..255 Tln]                   */ \
++                        ((Tln) << FShft (LCCR2_EFW))
++
++#define LCCR2_BFW       Fld (8, 24)     /* Beginning-of-Frame line clock   */
++                                        /* Wait count [Tln]                */
++#define LCCR2_BegFrmDel(Tln)            /*  Beginning-of-Frame Delay       */ \
++                                        /*  [0..255 Tln]                   */ \
++                        ((Tln) << FShft (LCCR2_BFW))
++
++#if 0
++#define LCCR3_PCD	(0xff)		/* Pixel clock divisor */
++#define LCCR3_ACB	(0xff << 8)	/* AC Bias pin frequency */
++#define LCCR3_ACB_S	8
++#endif
++
++#define LCCR3_API	(0xf << 16)	/* AC Bias pin trasitions per interrupt */
++#define LCCR3_API_S	16
++#define LCCR3_VSP	(1 << 20)	/* vertical sync polarity */
++#define LCCR3_HSP	(1 << 21)	/* horizontal sync polarity */
++#define LCCR3_PCP	(1 << 22)	/* pixel clock polarity */
++#define LCCR3_OEP	(1 << 23)	/* output enable polarity */
++#if 0
++#define LCCR3_BPP	(7 << 24)	/* bits per pixel */
++#define LCCR3_BPP_S	24
++#endif
++#define LCCR3_DPC	(1 << 27)	/* double pixel clock mode */
++
++
++#define LCCR3_PCD       Fld (8, 0)      /* Pixel Clock Divisor */
++#define LCCR3_PixClkDiv(Div)            /* Pixel Clock Divisor */ \
++                        (((Div) << FShft (LCCR3_PCD)))
++
++
++#define LCCR3_BPP       Fld (3, 24)     /* Bit Per Pixel */
++#define LCCR3_Bpp(Bpp)                  /* Bit Per Pixel */ \
++                        (((Bpp) << FShft (LCCR3_BPP)))
++
++#define LCCR3_ACB       Fld (8, 8)      /* AC Bias */
++#define LCCR3_Acb(Acb)                  /* BAC Bias */ \
++                        (((Acb) << FShft (LCCR3_ACB)))
++
++#define LCCR3_HorSnchH  (LCCR3_HSP*0)   /*  Horizontal Synchronization     */
++                                        /*  pulse active High              */
++#define LCCR3_HorSnchL  (LCCR3_HSP*1)   /*  Horizontal Synchronization     */
++
++#define LCCR3_VrtSnchH  (LCCR3_VSP*0)   /*  Vertical Synchronization pulse */
++                                        /*  active High                    */
++#define LCCR3_VrtSnchL  (LCCR3_VSP*1)   /*  Vertical Synchronization pulse */
++                                        /*  active Low                     */
++
++#define LCSR_LDD	(1 << 0)	/* LCD Disable Done */
++#define LCSR_SOF	(1 << 1)	/* Start of frame */
++#define LCSR_BER	(1 << 2)	/* Bus error */
++#define LCSR_ABC	(1 << 3)	/* AC Bias count */
++#define LCSR_IUL	(1 << 4)	/* input FIFO underrun Lower panel */
++#define LCSR_IUU	(1 << 5)	/* input FIFO underrun Upper panel */
++#define LCSR_OU		(1 << 6)	/* output FIFO underrun */
++#define LCSR_QD		(1 << 7)	/* quick disable */
++#define LCSR_EOF	(1 << 8)	/* end of frame */
++#define LCSR_BS		(1 << 9)	/* branch status */
++#define LCSR_SINT	(1 << 10)	/* subsequent interrupt */
++
++#define LDCMD_PAL	(1 << 26)	/* instructs DMA to load palette buffer */
++
++#define LCSR_LDD	(1 << 0)	/* LCD Disable Done */
++#define LCSR_SOF	(1 << 1)	/* Start of frame */
++#define LCSR_BER	(1 << 2)	/* Bus error */
++#define LCSR_ABC	(1 << 3)	/* AC Bias count */
++#define LCSR_IUL	(1 << 4)	/* input FIFO underrun Lower panel */
++#define LCSR_IUU	(1 << 5)	/* input FIFO underrun Upper panel */
++#define LCSR_OU		(1 << 6)	/* output FIFO underrun */
++#define LCSR_QD		(1 << 7)	/* quick disable */
++#define LCSR_EOF	(1 << 8)	/* end of frame */
++#define LCSR_BS		(1 << 9)	/* branch status */
++#define LCSR_SINT	(1 << 10)	/* subsequent interrupt */
++
++#define LDCMD_PAL	(1 << 26)	/* instructs DMA to load palette buffer */
++
++/*
++ * Memory controller
++ */
++
++#define MDCNFG		__REG(0x48000000)  /* SDRAM Configuration Register 0 */
++#define MDREFR		__REG(0x48000004)  /* SDRAM Refresh Control Register */
++#define MSC0		__REG(0x48000008)  /* Static Memory Control Register 0 */
++#define MSC1		__REG(0x4800000C)  /* Static Memory Control Register 1 */
++#define MSC2		__REG(0x48000010)  /* Static Memory Control Register 2 */
++#define MECR		__REG(0x48000014)  /* Expansion Memory (PCMCIA/Compact Flash) Bus Configuration */
++#define SXLCR		__REG(0x48000018)  /* LCR value to be written to SDRAM-Timing Synchronous Flash */
++#define SXCNFG		__REG(0x4800001C)  /* Synchronous Static Memory Control Register */
++#define SXMRS		__REG(0x48000024)  /* MRS value to be written to Synchronous Flash or SMROM */
++#define MCMEM0		__REG(0x48000028)  /* Card interface Common Memory Space Socket 0 Timing */
++#define MCMEM1		__REG(0x4800002C)  /* Card interface Common Memory Space Socket 1 Timing */
++#define MCATT0		__REG(0x48000030)  /* Card interface Attribute Space Socket 0 Timing Configuration */
++#define MCATT1		__REG(0x48000034)  /* Card interface Attribute Space Socket 1 Timing Configuration */
++#define MCIO0		__REG(0x48000038)  /* Card interface I/O Space Socket 0 Timing Configuration */
++#define MCIO1		__REG(0x4800003C)  /* Card interface I/O Space Socket 1 Timing Configuration */
++#define MDMRS		__REG(0x48000040)  /* MRS value to be written to SDRAM */
++#define BOOT_DEF	__REG(0x48000044)  /* Read-Only Boot-Time Register. Contains BOOT_SEL and PKG_SEL */
++
++#define MDREFR_K2FREE	(1 << 25)	/* SDRAM Free-Running Control */
++#define MDREFR_K1FREE	(1 << 24)	/* SDRAM Free-Running Control */
++#define MDREFR_K0FREE	(1 << 23)	/* SDRAM Free-Running Control */
++#define MDREFR_SLFRSH	(1 << 22)	/* SDRAM Self-Refresh Control/Status */
++#define MDREFR_APD	(1 << 20)	/* SDRAM/SSRAM Auto-Power-Down Enable */
++#define MDREFR_K2DB2	(1 << 19)	/* SDCLK2 Divide by 2 Control/Status */
++#define MDREFR_K2RUN	(1 << 18)	/* SDCLK2 Run Control/Status */
++#define MDREFR_K1DB2	(1 << 17)	/* SDCLK1 Divide by 2 Control/Status */
++#define MDREFR_K1RUN	(1 << 16)	/* SDCLK1 Run Control/Status */
++#define MDREFR_E1PIN	(1 << 15)	/* SDCKE1 Level Control/Status */
++#define MDREFR_K0DB2	(1 << 14)	/* SDCLK0 Divide by 2 Control/Status */
++#define MDREFR_K0RUN	(1 << 13)	/* SDCLK0 Run Control/Status */
++#define MDREFR_E0PIN	(1 << 12)	/* SDCKE0 Level Control/Status */
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/serial.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,51 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/serial.h
++ * 
++ * Author:	Nicolas Pitre
++ * Copyright:	(C) 2001 MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++#define BAUD_BASE	921600
++
++/* Standard COM flags */
++#define STD_COM_FLAGS (ASYNC_SKIP_TEST)
++
++#define STD_SERIAL_PORT_DEFNS	\
++	{	\
++		type:			PORT_PXA,	\
++		xmit_fifo_size:		32,		\
++		baud_base:		BAUD_BASE,	\
++		iomem_base:		(void *)&FFUART,\
++		iomem_reg_shift:	2,		\
++		io_type:		SERIAL_IO_MEM32,\
++		irq:			IRQ_FFUART,	\
++		flags:			STD_COM_FLAGS,	\
++	}, {	\
++		type:			PORT_PXA,	\
++		xmit_fifo_size:		32,		\
++		baud_base:		BAUD_BASE,	\
++		iomem_base:		(void *)&BTUART,\
++		iomem_reg_shift:	2,		\
++		io_type:		SERIAL_IO_MEM32,\
++		irq:			IRQ_BTUART,	\
++		flags:			STD_COM_FLAGS,	\
++	}, {	\
++		type:			PORT_PXA,	\
++		xmit_fifo_size:		32,		\
++		baud_base:		BAUD_BASE,	\
++		iomem_base:		(void *)&STUART,\
++		iomem_reg_shift:	2,		\
++		io_type:		SERIAL_IO_MEM32,\
++		irq:			IRQ_STUART,	\
++		flags:			STD_COM_FLAGS,	\
++	}
++
++#define RS_TABLE_SIZE 8
++
++#define EXTRA_SERIAL_PORT_DEFNS
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/system.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,32 @@
++/*
++ * linux/include/asm-arm/arch-pxa/system.h
++ *
++ * Author:	Nicolas Pitre
++ * Created:	Jun 15, 2001
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include "hardware.h"
++
++static inline void arch_idle(void)
++{
++	cpu_do_idle();
++}
++
++static inline void arch_reset(char mode)
++{
++	if (mode == 's') {
++		/* Jump into ROM at address 0 */
++		cpu_reset(0);
++	} else {
++		/* Initialize the watchdog and let it fire */
++		OWER = OWER_WME;
++		OSSR = OSSR_M3;
++		OSMR3 = OSCR + 368640;	/* ... in 100 ms */
++	}
++}
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/time.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,86 @@
++/*
++ * linux/include/asm-arm/arch-pxa/time.h
++ *
++ * Author:	Nicolas Pitre
++ * Created:	Jun 15, 2001
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++static inline unsigned long pxa_get_rtc_time(void)
++{
++	return RCNR;
++}
++
++static int pxa_set_rtc(void)
++{
++	unsigned long current_time = xtime.tv_sec;
++
++	if (RTSR & RTSR_ALE) {
++		/* make sure not to forward the clock over an alarm */
++		unsigned long alarm = RTAR;
++		if (current_time >= alarm && alarm >= RCNR)
++			return -ERESTARTSYS;
++	}
++	RCNR = current_time;
++	return 0;
++}
++
++/* IRQs are disabled before entering here from do_gettimeofday() */
++static unsigned long pxa_gettimeoffset (void)
++{
++	unsigned long ticks_to_match, elapsed, usec;
++
++	/* Get ticks before next timer match */
++	ticks_to_match = OSMR0 - OSCR;
++
++	/* We need elapsed ticks since last match */
++	elapsed = LATCH - ticks_to_match;
++
++	/* Now convert them to usec */
++	usec = (unsigned long)(elapsed*tick)/LATCH;
++
++	return usec;
++}
++
++static void pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	long flags;
++	int next_match;
++
++	do_profile(regs);
++
++	/* Loop until we get ahead of the free running timer.
++	 * This ensures an exact clock tick count and time acuracy.
++	 * IRQs are disabled inside the loop to ensure coherence between
++	 * lost_ticks (updated in do_timer()) and the match reg value, so we
++	 * can use do_gettimeofday() from interrupt handlers.
++	 */
++	do {
++		do_leds();
++		do_set_rtc();
++		save_flags_cli( flags );
++		do_timer(regs);
++		OSSR = OSSR_M0;  /* Clear match on timer 0 */
++		next_match = (OSMR0 += LATCH);
++		restore_flags( flags );
++	} while( (signed long)(next_match - OSCR) <= 0 );
++}
++
++extern inline void setup_timer (void)
++{
++	gettimeoffset = pxa_gettimeoffset;
++	set_rtc = pxa_set_rtc;
++	xtime.tv_sec = pxa_get_rtc_time();
++	timer_irq.handler = pxa_timer_interrupt;
++	OSMR0 = 0;		/* set initial match at 0 */
++	OSSR = 0xf;		/* clear status on all timers */
++	setup_arm_irq(IRQ_OST0, &timer_irq);
++	OIER |= OIER_E0;	/* enable match on timer 0 to cause interrupts */
++	OSCR = 0;		/* initialize free-running timer, force first match */
++}
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/timex.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,17 @@
++/*
++ * linux/include/asm-arm/arch-pxa/timex.h
++ *
++ * Author:	Nicolas Pitre
++ * Created:	Jun 15, 2001
++ * Copyright:	MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * PXA250/210 timer
++ */
++#define CLOCK_TICK_RATE		3686400
++#define CLOCK_TICK_FACTOR	80
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/trizeps2.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,206 @@
++/*
++ *  linux/include/asm-arm/arch-pxa/trizeps2.h
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copyright (c) 2002 Luc De Cock, Teradyne DS, Ltd.
++ *
++ * 2002-10-10: Initial code started from idp.h
++ */
++
++
++/*
++ * Note: this file must be safe to include in assembly files
++ */
++
++/* comment out following if you have a board  with 32MB RAM */
++//#define PXA_TRIZEPS2_64MB	1
++#undef PXA_TRIZEPS2_64MB
++
++#define TRIZEPS2_FLASH_PHYS		(PXA_CS0_PHYS)
++#define TRIZEPS2_ALT_FLASH_PHYS		(PXA_CS1_PHYS)
++#define TRIZEPS2_MEDIAQ_PHYS		(PXA_CS3_PHYS)
++#define TRIZEPS2_IDE_PHYS		(PXA_CS5_PHYS + 0x03000000)
++#define TRIZEPS2_ETH_PHYS		(0x0C800000)
++#define TRIZEPS2_COREVOLT_PHYS		(PXA_CS5_PHYS + 0x03800000)
++#define TRIZEPS2_BCR_PHYS		(0x0E000000)
++#define TRIZEPS2_CPLD_PHYS		(0x0C000000)
++
++/*
++ * virtual memory map
++ */
++
++#define TRIZEPS2_IDE_BASE		(0xf0000000)
++#define TRIZEPS2_IDE_SIZE		(1*1024*1024)
++
++#define TRIZEPS2_ETH_BASE		(0xf1000000)
++#define TRIZEPS2_ETH_SIZE		(1*1024*1024)
++#define ETH_BASE		TRIZEPS2_ETH_BASE //smc9194 driver compatibility issue
++
++#define TRIZEPS2_COREVOLT_BASE	(TRIZEPS2_ETH_BASE + TRIZEPS2_ETH_SIZE)
++#define TRIZEPS2_COREVOLT_SIZE	(1*1024*1024)
++
++#define TRIZEPS2_BCR_BASE	(0xf0000000)
++#define TRIZEPS2_BCR_SIZE	(1*1024*1024)
++
++#define BCR_P2V(x)		((x) - TRIZEPS2_BCR_PHYS + TRIZEPS2_BCR_BASE)
++#define BCR_V2P(x)		((x) - TRIZEPS2_BCR_BASE + TRIZEPS2_BCR_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __BCR_REG(x)		(*((volatile unsigned short *)BCR_P2V(x)))
++#else
++#  define __BCR_REG(x)		BCR_P2V(x)
++#endif
++
++/* board level registers  */
++#define TRIZEPS2_CPLD_BASE	(0xf0100000)
++#define CPLD_P2V(x)             ((x) - TRIZEPS2_CPLD_PHYS + TRIZEPS2_CPLD_BASE)
++#define CPLD_V2P(x)             ((x) - TRIZEPS2_CPLD_BASE + TRIZEPS2_CPLD_PHYS)
++
++#ifndef __ASSEMBLY__
++#  define __CPLD_REG(x)         (*((volatile unsigned short *)CPLD_P2V(x)))
++#else
++#  define __CPLD_REG(x)         CPLD_P2V(x)
++#endif
++
++#define _TRIZEPS2_PCCARD_STATUS	(0x0c000000)
++#define TRIZEPS2_PCCARD_STATUS         __CPLD_REG(_TRIZEPS2_PCCARD_STATUS)
++
++/*
++ * CS memory timing via Static Memory Control Register (MSC0-2)
++ */
++
++#define MSC_CS(cs,val) ((val)<<((cs&1)<<4))
++
++#define MSC_RBUFF_SHIFT		15 
++#define MSC_RBUFF(x)		((x)<<MSC_RBUFF_SHIFT)
++#define MSC_RBUFF_SLOW		MSC_RBUFF(0)
++#define MSC_RBUFF_FAST		MSC_RBUFF(1)
++
++#define MSC_RRR_SHIFT		12
++#define MSC_RRR(x)		((x)<<MSC_RRR_SHIFT)
++
++#define MSC_RDN_SHIFT		8
++#define MSC_RDN(x)		((x)<<MSC_RDN_SHIFT)
++
++#define MSC_RDF_SHIFT		4
++#define MSC_RDF(x)		((x)<<MSC_RDF_SHIFT)
++
++#define MSC_RBW_SHIFT		3
++#define MSC_RBW(x)		((x)<<MSC_RBW_SHIFT)
++#define MSC_RBW_16		MSC_RBW(1)
++#define MSC_RBW_32		MSC_RBW(0)
++
++#define MSC_RT_SHIFT		0
++#define MSC_RT(x)		((x)<<MSC_RT_SHIFT)
++
++
++/*
++ * Bit masks for various registers
++ */
++// TRIZEPS2_BCR_PCCARD_PWR
++#define PCC_3V		(1 << 0)
++#define PCC_5V		(1 << 1)
++#define PCC_EN1		(1 << 2)
++#define PCC_EN0		(1 << 3)
++
++// TRIZEPS2_BCR_PCCARD_EN
++#define PCC_RESET	(1 << 6)
++#define PCC_ENABLE	(1 << 0)
++
++// TRIZEPS2_BSR_PCCARDx_STATUS
++#define _PCC_WRPROT	(1 << 7) // 7-4 read as low true
++#define _PCC_RESET	(1 << 6)
++#define _PCC_IRQ	(1 << 5)
++#define _PCC_INPACK	(1 << 4)
++#define PCC_BVD1	(1 << 0)
++#define PCC_BVD2	(1 << 1)
++#define PCC_VS1		(1 << 2)
++#define PCC_VS2		(1 << 3)
++
++// TRIZEPS2_BCR_CONTROL bits
++#define BCR_LCD_ON	(1 << 4)
++#define BCR_LCD_OFF	(0)
++#define BCR_LCD_MASK	(1 << 4)
++#define BCR_PCMCIA_RESET (1 << 7)
++#define BCR_PCMCIA_NORMAL (0)
++
++#define PCC_DETECT	(GPLR(24) & GPIO_bit(24))
++#define PCC_READY	(GPLR(1) & GPIO_bit(1))
++
++// Board Control Register
++#define _TRIZEPS2_BCR_CONTROL	(TRIZEPS2_BCR_PHYS)
++#define TRIZEPS2_BCR_CONTROL	__BCR_REG(_TRIZEPS2_BCR_CONTROL)
++
++// Board TTL-IO register
++#define TRIZEPS2_TTLIO_PHYS	(0x0d800000)
++#define TRIZEPS2_TTLIO_BASE	(0xf2000000)
++// various ioctl cmds
++#define TTLIO_RESET		0
++#define TTLIO_GET		1
++#define TTLIO_SET		2
++#define TTLIO_UNSET		3
++
++/*
++ * Macros for LCD Driver
++ */
++
++#ifdef CONFIG_FB_PXA
++
++#define FB_BACKLIGHT_ON()
++#define FB_BACKLIGHT_OFF()
++
++#define FB_PWR_ON()
++#define FB_PWR_OFF()
++
++#define FB_VLCD_ON()		WRITE_TRIZEPS2_BCR(BCR_LCD_ON,BCR_LCD_MASK);
++#define FB_VLCD_OFF()		WRITE_TRIZEPS2_BCR(BCR_LCD_OFF,BCR_LCD_MASK);
++
++#endif
++
++/* A listing of interrupts used by external hardware devices */
++
++#define GPIO_TOUCH_PANEL_IRQ		2
++#define TOUCH_PANEL_IRQ			IRQ_GPIO(GPIO_TOUCH_PANEL_IRQ)
++#define GPIO_ETHERNET_IRQ		19
++#define ETHERNET_IRQ			IRQ_GPIO(GPIO_ETHERNET_IRQ)
++#define GPIO_TTLIO_IRQ			23
++#define TTLIO_IRQ			IRQ_GPIO(GPIO_TTLIO_IRQ)
++
++#define TOUCH_PANEL_IRQ_EDGE		GPIO_FALLING_EDGE
++#define IDE_IRQ_EDGE			GPIO_RISING_EDGE
++#define ETHERNET_IRQ_EDGE		GPIO_RISING_EDGE
++
++#define PCMCIA_S_CD_VALID		IRQ_GPIO(24)
++#define PCMCIA_S_CD_VALID_EDGE		GPIO_BOTH_EDGES
++
++#define PCMCIA_S_RDYINT			IRQ_GPIO(1)
++#define PCMCIA_S_RDYINT_EDGE		GPIO_FALLING_EDGE
++
++/*
++ * macros for MTD driver
++ */
++
++#define FLASH_WRITE_PROTECT_DISABLE()	// ((TRIZEPS2_CPLD_FLASH_WE) &= ~(0x1))
++#define FLASH_WRITE_PROTECT_ENABLE()	// ((TRIZEPS2_CPLD_FLASH_WE) |= (0x1))
++
++/* shadow registers for write only registers */
++#ifndef __ASSEMBLY__
++extern unsigned short trizeps2_bcr_shadow;
++#endif
++
++/* 
++ * macros to write to write only register
++ *
++ * none of these macros are protected from 
++ * multiple drivers using them in interrupt context.
++ */
++
++#define WRITE_TRIZEPS2_BCR(value, mask) \
++{\
++	trizeps2_bcr_shadow = ((value & mask) | (trizeps2_bcr_shadow & ~mask));\
++	TRIZEPS2_BCR_CONTROL = trizeps2_bcr_shadow;\
++}
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/uncompress.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,42 @@
++/*
++ * linux/include/asm-arm/arch-pxa/uncompress.h
++ *  
++ * Author:	Nicolas Pitre
++ * Copyright:	(C) 2001 MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#define FFUART		((volatile unsigned long *)0x40100000)
++#define BTUART		((volatile unsigned long *)0x40200000)
++#define STUART		((volatile unsigned long *)0x40700000)
++
++#define UART		FFUART
++
++
++static __inline__ void putc(char c)
++{
++	while (!(UART[5] & 0x20));
++	UART[0] = c;
++}
++
++/*
++ * This does not append a newline
++ */
++static void puts(const char *s)
++{
++	while (*s) {
++		putc(*s);
++		if (*s == '\n')
++			putc('\r');
++		s++;
++	}
++}
++
++/*
++ * nothing to do
++ */
++#define arch_decomp_setup()
++#define arch_decomp_wdog()
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-pxa/vmalloc.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,23 @@
++/*
++ * linux/include/asm-arm/arch-pxa/vmalloc.h
++ * 
++ * Author:	Nicolas Pitre
++ * Copyright:	(C) 2001 MontaVista Software Inc.
++ * 
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/*
++ * Just any arbitrary offset to the start of the vmalloc VM area: the
++ * current 8MB value just means that there will be a 8MB "hole" after the
++ * physical memory until the kernel virtual memory starts.  That means that
++ * any out-of-bounds memory accesses will hopefully be caught.
++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced
++ * area for the same reason. ;)
++ */
++#define VMALLOC_OFFSET	  (8*1024*1024)
++#define VMALLOC_START	  (((unsigned long)high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
++#define VMALLOC_VMADDR(x) ((unsigned long)(x))
++#define VMALLOC_END       (0xe8000000)
+--- linux-2.4.25/include/asm-arm/assembler.h~2.4.25-vrs2-pxa1.patch	2000-08-13 18:54:15.000000000 +0200
++++ linux-2.4.25/include/asm-arm/assembler.h	2004-03-31 17:15:12.000000000 +0200
+@@ -13,3 +13,26 @@
+ 
+ #include <asm/proc/ptrace.h>
+ #include <asm/proc/assembler.h>
++
++/*
++ * Endian independent macros for shifting bytes within registers.
++ */
++#ifndef __ARMEB__
++#define pull            lsr
++#define push            lsl
++#define byte(x)         (x*8)
++#else
++#define pull            lsl
++#define push            lsr
++#define byte(x)         ((3-x)*8)
++#endif
++
++/*
++ * Data preload for architectures that support it
++ */
++#if __LINUX_ARM_ARCH__ >= 5
++#define PLD(code...)	code
++#else
++#define PLD(code...)
++#endif
++
+--- linux-2.4.25/include/asm-arm/bitops.h~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/bitops.h	2004-03-31 17:15:12.000000000 +0200
+@@ -91,6 +91,8 @@
+     return (((unsigned char *) addr)[nr >> 3] >> (nr & 7)) & 1;
+ }	
+ 
++#if __LINUX_ARM_ARCH__ < 5
++
+ /*
+  * ffz = Find First Zero in word. Undefined if no zero exists,
+  * so code should check against ~0UL first..
+@@ -117,6 +119,23 @@
+ 
+ #define ffs(x) generic_ffs(x)
+ 
++#else
++
++/*
++ * On ARMv5 and above those functions can be implemented around
++ * the clz instruction for much better code efficiency.
++ */
++
++extern __inline__ int generic_fls(int x);
++#define fls(x) \
++	( __builtin_constant_p(x) ? generic_fls(x) : \
++	  ({ int __r; asm("clz%?\t%0, %1" : "=r"(__r) : "r"(x)); 32-__r; }) )
++#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
++#define __ffs(x) (ffs(x) - 1)
++#define ffz(x) __ffs( ~(x) )
++
++#endif
++
+ /*
+  * hweightN: returns the hamming weight (i.e. the number
+  * of bits set) of a N-bit word
+--- linux-2.4.25/include/asm-arm/io.h~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/io.h	2004-03-31 17:15:12.000000000 +0200
+@@ -168,7 +168,7 @@
+  * devices.  This is the "generic" version.  The PCI specific version
+  * is in pci.h
+  */
+-extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle);
++extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, unsigned long flags);
+ extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle);
+ extern void consistent_sync(void *vaddr, size_t size, int rw);
+ 
+--- linux-2.4.25/include/asm-arm/memory.h~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/memory.h	2004-03-31 17:15:12.000000000 +0200
+@@ -123,6 +123,9 @@
+      ((unsigned)((page) - NODE_MEM_MAP(node)) < NODE_DATA(node)->node_size)); \
+ })
+ 
++/* We want large page mapping possible */
++#define VMALLOC_ALIGN		0x10000
++
+ #endif
+ 
+ /*
+--- linux-2.4.25/include/asm-arm/proc-armv/pgtable.h~2.4.25-vrs2-pxa1.patch	2001-08-12 20:14:00.000000000 +0200
++++ linux-2.4.25/include/asm-arm/proc-armv/pgtable.h	2004-03-31 17:15:12.000000000 +0200
+@@ -15,9 +15,6 @@
+ #ifndef __ASM_PROC_PGTABLE_H
+ #define __ASM_PROC_PGTABLE_H
+ 
+-#include <asm/proc/domain.h>
+-#include <asm/arch/vmalloc.h>
+-
+ /*
+  * entries per page directory level: they are two-level, so
+  * we don't really have any PMD directory.
+@@ -26,27 +23,92 @@
+ #define PTRS_PER_PMD		1
+ #define PTRS_PER_PGD		4096
+ 
+-/****************
+-* PMD functions *
+-****************/
+-
+-/* PMD types (actually level 1 descriptor) */
+-#define PMD_TYPE_MASK		0x0003
+-#define PMD_TYPE_FAULT		0x0000
+-#define PMD_TYPE_TABLE		0x0001
+-#define PMD_TYPE_SECT		0x0002
+-#define PMD_UPDATABLE		0x0010
+-#define PMD_SECT_CACHEABLE	0x0008
+-#define PMD_SECT_BUFFERABLE	0x0004
+-#define PMD_SECT_AP_WRITE	0x0400
+-#define PMD_SECT_AP_READ	0x0800
++/*
++ * Hardware page table definitions.
++ *
++ * + Level 1 descriptor (PMD)
++ *   - common
++ */
++#define PMD_TYPE_MASK		(3 << 0)
++#define PMD_TYPE_FAULT		(0 << 0)
++#define PMD_TYPE_TABLE		(1 << 0)
++#define PMD_TYPE_SECT		(2 << 0)
++#define PMD_UPDATABLE		(1 << 4)
+ #define PMD_DOMAIN(x)		((x) << 5)
++#define PMD_PROTECTION		(1 << 9)	/* v5 */
++/*
++ *   - section
++ */
++#define PMD_SECT_BUFFERABLE	(1 << 2)
++#define PMD_SECT_CACHEABLE	(1 << 3)
++#define PMD_SECT_AP_WRITE	(1 << 10)
++#define PMD_SECT_AP_READ	(1 << 11)
++#define PMD_SECT_TEX(x)		((x) << 12)	/* v5 */
++/*
++ *   - coarse table
++ */
++
++/*
++ * + Level 2 descriptor (PTE)
++ *   - common
++ */
++#define PTE_TYPE_MASK		(3 << 0)
++#define PTE_TYPE_FAULT		(0 << 0)
++#define PTE_TYPE_LARGE		(1 << 0)
++#define PTE_TYPE_SMALL		(2 << 0)
++#define PTE_TYPE_EXT		(3 << 0)	/* v5 */
++#define PTE_BUFFERABLE		(1 << 2)
++#define PTE_CACHEABLE		(1 << 3)
++
++/*
++ *   - extended small page/tiny page
++ */
++#define PTE_EXT_AP_UNO_SRO	(0 << 4)
++#define PTE_EXT_AP_UNO_SRW	(1 << 4)
++#define PTE_EXT_AP_URO_SRW	(2 << 4)
++#define PTE_EXT_AP_URW_SRW	(3 << 4)
++#define PTE_EXT_TEX(x)		((x) << 6)	/* v5 */
++
++/*
++ *   - small page
++ */
++#define PTE_SMALL_AP_UNO_SRO	(0x00 << 4)
++#define PTE_SMALL_AP_UNO_SRW	(0x55 << 4)
++#define PTE_SMALL_AP_URO_SRW	(0xaa << 4)
++#define PTE_SMALL_AP_URW_SRW	(0xff << 4)
++#define PTE_AP_READ		PTE_SMALL_AP_URO_SRW
++#define PTE_AP_WRITE		PTE_SMALL_AP_UNO_SRW
++
++/*
++ * "Linux" PTE definitions.
++ *
++ * We keep two sets of PTEs - the hardware and the linux version.
++ * This allows greater flexibility in the way we map the Linux bits
++ * onto the hardware tables, and allows us to have YOUNG and DIRTY
++ * bits.
++ *
++ * The PTE table pointer refers to the hardware entries; the "Linux"
++ * entries are stored 1024 bytes below.
++ */
++#define L_PTE_PRESENT		(1 << 0)
++#define L_PTE_YOUNG		(1 << 1)
++#define L_PTE_BUFFERABLE	(1 << 2)	/* matches PTE */
++#define L_PTE_CACHEABLE		(1 << 3)	/* matches PTE */
++#define L_PTE_USER		(1 << 4)
++#define L_PTE_WRITE		(1 << 5)
++#define L_PTE_EXEC		(1 << 6)
++#define L_PTE_DIRTY		(1 << 7)
++
++#ifndef __ASSEMBLY__
++
++#include <asm/proc/domain.h>
++#include <asm/arch/vmalloc.h>
+ 
+ #define _PAGE_USER_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_USER))
+ #define _PAGE_KERNEL_TABLE	(PMD_TYPE_TABLE | PMD_DOMAIN(DOMAIN_KERNEL))
+ 
+ #define pmd_bad(pmd)		(pmd_val(pmd) & 2)
+-#define set_pmd(pmdp,pmd)	cpu_set_pmd(pmdp,pmd)
++#define set_pmd(pmdp,pmd)	cpu_set_pmd(pmdp, pmd)
+ 
+ static inline pmd_t __mk_pmd(pte_t *ptep, unsigned long prot)
+ {
+@@ -75,49 +137,8 @@
+ 	return __phys_to_virt(ptr);
+ }
+ 
+-/****************
+-* PTE functions *
+-****************/
+-
+-/* PTE types (actually level 2 descriptor) */
+-#define PTE_TYPE_MASK		0x0003
+-#define PTE_TYPE_FAULT		0x0000
+-#define PTE_TYPE_LARGE		0x0001
+-#define PTE_TYPE_SMALL		0x0002
+-#define PTE_AP_READ		0x0aa0
+-#define PTE_AP_WRITE		0x0550
+-#define PTE_CACHEABLE		0x0008
+-#define PTE_BUFFERABLE		0x0004
+-
+ #define set_pte(ptep, pte)	cpu_set_pte(ptep,pte)
+ 
+-/* We now keep two sets of ptes - the physical and the linux version.
+- * This gives us many advantages, and allows us greater flexibility.
+- *
+- * The Linux pte's contain:
+- *  bit   meaning
+- *   0    page present
+- *   1    young
+- *   2    bufferable	- matches physical pte
+- *   3    cacheable	- matches physical pte
+- *   4    user
+- *   5    write
+- *   6    execute
+- *   7    dirty
+- *  8-11  unused
+- *  12-31 virtual page address
+- *
+- * These are stored at the pte pointer; the physical PTE is at -1024bytes
+- */
+-#define L_PTE_PRESENT		(1 << 0)
+-#define L_PTE_YOUNG		(1 << 1)
+-#define L_PTE_BUFFERABLE	(1 << 2)
+-#define L_PTE_CACHEABLE		(1 << 3)
+-#define L_PTE_USER		(1 << 4)
+-#define L_PTE_WRITE		(1 << 5)
+-#define L_PTE_EXEC		(1 << 6)
+-#define L_PTE_DIRTY		(1 << 7)
+-
+ /*
+  * The following macros handle the cache and bufferable bits...
+  */
+@@ -162,5 +183,8 @@
+  * Mark the prot value as uncacheable and unbufferable.
+  */
+ #define pgprot_noncached(prot)	__pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))
++#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)
++
++#endif /* __ASSEMBLY__ */
+ 
+ #endif /* __ASM_PROC_PGTABLE_H */
+--- linux-2.4.25/include/asm-arm/proc-armv/processor.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/include/asm-arm/proc-armv/processor.h	2004-03-31 17:15:12.000000000 +0200
+@@ -23,6 +23,9 @@
+ #define KERNEL_STACK_SIZE	PAGE_SIZE
+ 
+ struct context_save_struct {
++#ifdef CONFIG_CPU_XSCALE
++	long long acc0;
++#endif
+ 	unsigned long cpsr;
+ 	unsigned long r4;
+ 	unsigned long r5;
+@@ -35,7 +38,11 @@
+ 	unsigned long pc;
+ };
+ 
++#ifdef CONFIG_CPU_XSCALE
++#define INIT_CSS (struct context_save_struct){ 0, SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
++#else
+ #define INIT_CSS (struct context_save_struct){ SVC_MODE, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
++#endif
+ 
+ #define EXTRA_THREAD_STRUCT						\
+ 	unsigned int	domain;
+--- linux-2.4.25/include/asm-arm/proc-fns.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/include/asm-arm/proc-fns.h	2004-03-31 17:15:12.000000000 +0200
+@@ -124,6 +124,14 @@
+ #   define CPU_NAME sa1100
+ #  endif
+ # endif
++# ifdef CONFIG_CPU_XSCALE
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   define CPU_NAME xscale
++#  endif
++# endif
+ #endif
+ 
+ #ifndef MULTI_CPU
+--- linux-2.4.25/include/asm-arm/procinfo.h~2.4.25-vrs2-pxa1.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/procinfo.h	2004-03-31 17:15:12.000000000 +0200
+@@ -55,7 +55,8 @@
+ #define HWCAP_FAST_MULT	16
+ #define HWCAP_FPA	32
+ #define HWCAP_VFP	64
+-#define HWCAP_EDSP	128
++#define HWCAP_EDSP	128	/* El Segundo */
+ #define HWCAP_JAVA	256
++#define HWCAP_XSCALE	512	/* XScale DSP co-processor */
+ 
+ #endif
+--- linux-2.4.25/include/asm-arm/uaccess.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/include/asm-arm/uaccess.h	2004-03-31 17:15:12.000000000 +0200
+@@ -86,7 +86,7 @@
+ 			__get_user_x(__r1, __p, __e, 1, "lr");		\
+ 	       		break;						\
+ 		case 2:							\
+-			__get_user_x(__r1, __p, __e, 2, "r2", "lr");	\
++			__get_user_x(__r1, __p, __e, 2, "ip", "lr");	\
+ 			break;						\
+ 		case 4:							\
+ 	       		__get_user_x(__r1, __p, __e, 4, "lr");		\
+--- linux-2.4.25/include/linux/cramfs_fs_sb.h~2.4.25-vrs2-pxa1.patch	2001-07-20 01:14:53.000000000 +0200
++++ linux-2.4.25/include/linux/cramfs_fs_sb.h	2004-03-31 17:15:12.000000000 +0200
+@@ -10,6 +10,10 @@
+ 			unsigned long blocks;
+ 			unsigned long files;
+ 			unsigned long flags;
++#ifdef CONFIG_CRAMFS_LINEAR
++			unsigned long linear_phys_addr;
++			char *        linear_virt_addr;
++#endif
+ };
+ 
+ #endif
+--- linux-2.4.25/include/linux/i2c-id.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/include/linux/i2c-id.h	2004-03-31 17:15:12.000000000 +0200
+@@ -100,6 +100,10 @@
+ #define I2C_DRIVERID_SAA7191	57     /* video decoder                 */
+ #define I2C_DRIVERID_INDYCAM	58     /* SGI IndyCam			*/
+ 
++#define I2C_DRIVERID_DS1307	46	/* real time clock: DS1307	*/
++#define I2C_DRIVERID_24LC64	47	/* EEprom 24LC64		*/
++#define I2C_DRIVERID_FM24CLB4	48	/* EEprom FM24CLB4		*/
++
+ #define I2C_DRIVERID_EXP0	0xF0	/* experimental use id's	*/
+ #define I2C_DRIVERID_EXP1	0xF1
+ #define I2C_DRIVERID_EXP2	0xF2
+@@ -172,6 +176,8 @@
+ 
+ #define I2C_ALGO_OCP    0x120000	/* IBM or otherwise On-chip I2C algorithm */
+ 
++#define I2C_ALGO_PXA	0x400000	/* Intel PXA I2C algorithm  */
++
+ #define I2C_ALGO_EXP	0x800000	/* experimental			*/
+ 
+ #define I2C_ALGO_MASK	0xff0000	/* Mask for algorithms		*/
+--- linux-2.4.25/include/linux/serial.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/include/linux/serial.h	2004-03-31 17:15:12.000000000 +0200
+@@ -75,11 +75,13 @@
+ #define PORT_16654	11
+ #define PORT_16850	12
+ #define PORT_RSA	13	/* RSA-DV II/S card */
+-#define PORT_MAX	13
++#define PORT_PXA	14
++#define PORT_MAX	14
+ 
+ #define SERIAL_IO_PORT	0
+ #define SERIAL_IO_HUB6	1
+ #define SERIAL_IO_MEM	2
++#define SERIAL_IO_MEM32	3
+ 
+ struct serial_uart_config {
+ 	char	*name;
+--- linux-2.4.25/include/linux/serial_reg.h~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/include/linux/serial_reg.h	2004-03-31 17:15:12.000000000 +0200
+@@ -119,6 +119,14 @@
+ #define UART_IERX_SLEEP  0x10	/* Enable sleep mode */
+ 
+ /*
++ * The Intel PXA250/210 chip defines those bits
++ */
++#define UART_IER_DMAE	0x80	/* DMA Requests Enable */
++#define UART_IER_UUE	0x40	/* UART Unit Enable */
++#define UART_IER_NRZE	0x20	/* NRZ coding Enable */
++#define UART_IER_RTOIE	0x10	/* Receiver Time Out Interrupt Enable */
++
++/*
+  * These are the definitions for the Modem Control Register
+  */
+ #define UART_MCR_AFE	0x20	/* Enable auto-RTS/CTS (TI16C750) */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/mmc/ioctl.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,25 @@
++/*
++ *  linux/include/linux/mmc/ioctl.h
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *	$Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#ifndef __MMC_IOCTL_H__
++#define __MMC_IOCTL_H__
++
++#include <asm/ioctl.h>
++
++/* IOCTL commands provided by MMC subsystem */
++#define IOCMMCSTRNSMODE _IOW('I',0x0f01,int)
++#define IOCMMCGTRNSMODE _IOR('I',0x0f02,int)
++#define IOCMMCGCARDESC  _IOR('I',0x0f03,int) /* FIXME */
++#define IOCMMCGBLKSZMAX _IOR('I',0x0f04,ssize_t)
++#define IOCMMCGNOBMAX	_IOR('I',0x0f05,ssize_t)
++
++#endif /* __MMC_IOCTL_H__ */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/mmc/mmc.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,143 @@
++/*
++ *  linux/include/linux/mmc/mmc.h 
++ *
++ *  Author: Vladimir Shebordaev 
++ *  Copyright:  MontaVista Software Inc.
++ *
++ *  $Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#ifndef __MMC_H__
++#define __MMC_H__
++
++#include <linux/types.h>
++#include <mmc/types.h>
++
++/*
++ * MMC card type
++ */
++enum _mmc_type {
++    MMC_CARD_TYPE_RO = 1,
++    MMC_CARD_TYPE_RW,
++    MMC_CARD_TYPE_IO
++};
++
++/*
++ * MMC card state
++ */
++enum _mmc_state {
++    MMC_CARD_STATE_IDLE = 1,
++    MMC_CARD_STATE_READY,
++    MMC_CARD_STATE_IDENT,
++    MMC_CARD_STATE_STNBY,
++    MMC_CARD_STATE_TRAN,
++    MMC_CARD_STATE_DATA,
++    MMC_CARD_STATE_RCV,
++    MMC_CARD_STATE_DIS,
++    MMC_CARD_STATE_UNPLUGGED=0xff
++};
++
++/*
++ * Data transfer mode
++ */
++enum _mmc_transfer_mode {
++    MMC_TRANSFER_MODE_STREAM = 1,
++    MMC_TRANSFER_MODE_BLOCK_SINGLE,
++    MMC_TRANSFER_MODE_BLOCK_MULTIPLE,
++    MMC_TRANSFER_MODE_UNDEFINED = -1
++};
++
++struct _mmc_card_csd_rec { /* CSD register contents */
++/* FIXME: BYTE_ORDER */
++	u8	ecc:2,
++		file_format:2,
++		tmp_write_protect:1,
++		perm_write_protect:1,
++		copy:1,
++		file_format_grp:1;
++	u64	content_prot_app:1,
++		rsvd3:4,
++		write_bl_partial:1,
++		write_bl_len:4,
++		r2w_factor:3,
++		default_ecc:2,
++		wp_grp_enable:1,
++		wp_grp_size:5,
++		erase_grp_mult:5,
++		erase_grp_size:5,
++		c_size_mult:3,
++		vdd_w_curr_max:3,
++		vdd_w_curr_min:3,
++		vdd_r_curr_max:3,
++		vdd_r_curr_min:3,
++		c_size:12,
++		rsvd2:2,
++		dsr_imp:1,
++		read_blk_misalign:1,
++		write_blk_misalign:1,
++		read_bl_partial:1;
++
++	u16	read_bl_len:4,
++		ccc:12;
++	u8	tran_speed;
++	u8	nsac;
++	u8	taac;
++	u8	rsvd1:2,
++	  	spec_vers:4,
++		csd_structure:2;
++};
++
++struct _mmc_card_cid_rec { /* CID register contents */
++/* FIXME: BYTE_ORDER */
++	u8	mdt_year:4,
++		mdt_mon:4;
++	u32	psn;
++	u8	prv_minor:4,
++		prv_major:4;
++	u8	pnm[6];
++	u16	oid;
++	u8	mid;
++};
++
++/* 
++ * Public card description
++ */
++struct _mmc_card_info_rec {
++    mmc_type_t type;
++    mmc_transfer_mode_t transfer_mode; /* current data transfer mode */
++    __u16 rca;        /* card's RCA assigned during initialization */
++    struct _mmc_card_csd_rec csd;
++    struct _mmc_card_cid_rec cid;
++    __u32 tran_speed; /* kbits */
++    __u16 read_bl_len;
++    __u16 write_bl_len;
++    size_t capacity;    /* card's capacity in bytes */
++};
++
++/* 
++ * Micsellaneous defines
++ */
++#ifndef SEEK_SET
++#define SEEK_SET (0)
++#endif
++
++#ifndef SEEK_CUR
++#define SEEK_CUR (1)
++#endif
++
++#ifndef SEEK_END
++#define SEEK_END (2)
++#endif
++
++#ifndef TRUE
++#define TRUE (1)
++#endif
++
++#ifndef FALSE
++#define FALSE (0)
++#endif
++
++#endif /* __MMC_H__ */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/mmc/types.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,29 @@
++/*
++ *  linux/include/linux/mmc/types.h
++ *
++ *  Author:	Vladimir Shebordaev	
++ *  Copyright:	MontaVista Software Inc.
++ *
++ *	$Id$
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++#ifndef __MMC_TYPES_H__
++#define __MMC_TYPES_H__
++
++/* MMC card */
++typedef enum _mmc_type mmc_type_t;
++typedef enum _mmc_state mmc_state_t;
++typedef enum _mmc_transfer_mode mmc_transfer_mode_t;
++
++typedef struct _mmc_card_csd_rec mmc_card_csd_rec_t;
++typedef struct _mmc_card_cid_rec mmc_card_cid_rec_t;
++
++typedef struct _mmc_card_info_rec mmc_card_info_rec_t;
++typedef struct _mmc_card_info_rec *mmc_card_info_t;
++
++typedef enum _mmc_error mmc_error_t;
++
++#endif /* __MMC_TYPES_H__ */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/video/lcdctrl.h	2004-03-31 17:15:12.000000000 +0200
+@@ -0,0 +1,61 @@
++/*
++ *  lcdctrl.h
++ *
++ *  Generic LCD control for brightness, contrast, etc.
++ *  Device specific drivers implement a lcdctrl_device and
++ *  provides access to it via lcdctrl_device_get_ops().
++ *
++ *  Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ *  History:
++ *    Mar 2002: Initial version [FB]
++ * 
++ */
++#ifndef __LCD_CONTROL_H
++#define __LCD_CONTROL_H
++
++#define _LCDCTRL_IOCTL_ON		1
++#define _LCDCTRL_IOCTL_OFF		2
++#define _LCDCTRL_IOCTL_INTENSITY	3
++#define _LCDCTRL_IOCTL_BRIGHTNESS	4
++#define _LCDCTRL_IOCTL_CONTRAST		5
++#define _LCDCTRL_IOCTL_GET_BRIGHTNESS	6
++#define _LCDCTRL_IOCTL_GET_CONTRAST	7
++#define _LCDCTRL_IOCTL_GET_INTENSITY	8
++
++#define _LCD_CONTROL_NAME "lcdctrl"
++
++#define LCD_NO_SYNC     0
++#define LCD_SYNC_NEEDED 1
++
++int lcdctrl_enable( void);
++int lcdctrl_disable( void);
++
++/* intensity, contrast, and brightness take values
++ * between 0..100.
++ */
++int lcdctrl_set_intensity( int intensity);
++int lcdctrl_set_contrast( int contrast, int sync);
++int lcdctrl_set_brightness( int brightness);
++
++int lcdctrl_get_intensity( void);
++int lcdctrl_get_contrast( void);
++int lcdctrl_get_brightness( void);
++
++struct lcdctrl_device
++{
++	int (*init)( int*, int*, int*);
++	int (*enable)(void);
++	int (*disable)(void);
++	int (*set_intensity)( int i);
++	int (*set_brightness)( int b);
++	int (*set_contrast)( int c, int sync);
++};
++
++int lcdctrl_init( void);
++
++#endif
+--- linux-2.4.25/init/do_mounts.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/init/do_mounts.c	2004-03-31 17:15:12.000000000 +0200
+@@ -394,6 +394,16 @@
+ }
+ #endif
+ 
++#ifdef CONFIG_ROOT_CRAMFS_LINEAR
++static int __init mount_linear_cramfs_root(void)
++{
++	void *data = root_mount_data;
++	if (sys_mount("/dev/root","/root","cramfs",root_mountflags,data) == 0)
++		return 1;
++	return 0;
++}
++#endif
++
+ static int __init create_dev(char *name, kdev_t dev, char *devfs_name)
+ {
+ 	void *handle;
+@@ -759,6 +769,16 @@
+ 
+ static void __init mount_root(void)
+ {
++#ifdef CONFIG_ROOT_CRAMFS_LINEAR
++	if (ROOT_DEV == MKDEV(0, 0)) {
++		if (mount_linear_cramfs_root()) {
++			sys_chdir("/root");
++			ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev;
++			printk("VFS: Mounted root (linear cramfs filesystem).\n");
++			return;
++		}
++	}
++#endif
+ #ifdef CONFIG_ROOT_NFS
+        if (MAJOR(ROOT_DEV) == NFS_MAJOR
+            && MINOR(ROOT_DEV) == NFS_MINOR) {
+--- linux-2.4.25/mm/memory.c~2.4.25-vrs2-pxa1.patch	2004-03-31 17:15:09.000000000 +0200
++++ linux-2.4.25/mm/memory.c	2004-03-31 17:15:12.000000000 +0200
+@@ -1018,6 +1018,41 @@
+ 	return 1;	/* Minor fault */
+ 
+ bad_wp_page:
++	if (pte_present(pte) && pte_read(pte)) {
++		/*
++		 * Handle COW of XIP memory.
++		 * Note that the source memory actually isn't a ram page so
++		 * no struct page is associated to the source pte.
++		 */
++		char *dst;
++		int ret;
++
++		spin_unlock(&mm->page_table_lock);
++		new_page = alloc_page(GFP_HIGHUSER);
++		if (!new_page)
++			return -1;
++
++		/* copy XIP data to memory */
++		dst = kmap_atomic(new_page, KM_USER0);
++		ret = copy_from_user(dst, (void*)address, PAGE_SIZE);
++		kunmap_atomic(dst, KM_USER0);
++
++		/* make sure pte didn't change while we dropped the lock */
++		spin_lock(&mm->page_table_lock);
++		if (!ret && pte_same(*page_table, pte)) {
++			++mm->rss;
++			break_cow(vma, new_page, address, page_table);
++			lru_cache_add(new_page);
++			spin_unlock(&mm->page_table_lock);
++			return 1;	/* Minor fault */
++		}
++
++		/* pte changed: back off */
++		spin_unlock(&mm->page_table_lock);
++		page_cache_release(new_page);
++		return ret ? -1 : 1;
++	}
++
+ 	spin_unlock(&mm->page_table_lock);
+ 	printk("do_wp_page: bogus page at address %08lx\n", address);
+ 	return -1;
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch
index e69de29bb2..c5f370aee3 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/2.4.25-vrs2.patch
@@ -0,0 +1,86979 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.25/Documentation/Configure.help~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/Documentation/Configure.help	2004-03-31 17:15:08.000000000 +0200
+@@ -4837,6 +4837,13 @@
+   Say Y to enable support for Permedia2 AGP frame buffer card from
+   3Dlabs (aka `Graphic Blaster Exxtreme') on the PCI bus.
+ 
++Permedia3 support (EXPERIMENTAL)
++CONFIG_FB_PM3
++  This is the frame buffer device driver for the 3DLabs Permedia3
++  chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 &
++  similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000
++  and maybe other boards.
++
+ Phase5 CVisionPPC/BVisionPPC support
+ CONFIG_FB_PM2_CVPPC
+   Say Y to enable support for the Amiga Phase 5 CVisionPPC BVisionPPC
+@@ -13125,6 +13132,17 @@
+   The module will be called tmspci.o. If you want to compile it
+   as a module, say M here and read <file:Documentation/modules.txt>.
+ 
++Altera ether00 support
++CONFIG_ETHER00
++  This is the driver for Altera's ether00 ethernet mac IP core. Say
++  Y here if you want to build support for this into the kernel. It
++  is also available as a module (say M here) that can be inserted/
++  removed from the kernel at the same time as the PLD is configured. 
++  If this driver is running on an epxa10 development board then it 
++  will generate a suitable hw address based on the board serial 
++  number (MTD support is required for this). Otherwise you will 
++  need to set a suitable hw address using ifconfig.
++
+ Generic TMS380 ISA support
+ CONFIG_TMSISA
+   This tms380 module supports generic TMS380-based ISA cards.
+@@ -15069,6 +15087,16 @@
+   support" be compiled as a module for this driver to be used
+   properly.
+ 
++Altera's uart00 serial driver
++CONFIG_SERIAL_UART00
++  Say Y here if you want to use the hard logic uart on Excalibur. This 
++  driver also supports soft logic implentations of this uart core.
++
++Serial console on uart00 
++CONFIG_SERIAL_UART00_CONSOLE
++  Say Y here if you want to support a serial console on an Excalibur
++  hard logic uart or uart00 IP core.
++
+ USB ConnectTech WhiteHEAT Serial Driver
+ CONFIG_USB_SERIAL_WHITEHEAT
+   Say Y here if you want to use a ConnectTech WhiteHEAT 4 port
+@@ -19085,6 +19113,20 @@
+   <file:Documentation/modules.txt>.
+   The module will be called i2c-velleman.o.
+ 
++Guide GPIO adapter
++CONFIG_I2C_GUIDE
++  This supports the Iders GUIDE I2C bit-bashing adapter.  If you have
++  selected the GUIDE A07 as your ARM system type, you cannot deselect
++  this option, as it is required for proper operation of the GUIDE.
++
++  This interface uses /dev/i2c-0 (major 89, minor 0).
++
++  Say Y if you own such an adapter.
++
++  This driver is also available as a module. If you want to compile
++  it as a module, say M here and read Documentation/modules.txt. The
++  module will be called i2c-guide.o.
++
+ I2C PCF 8584 interfaces
+ CONFIG_I2C_ALGOPCF
+   This allows you to use a range of I2C adapters called PCF adapters.
+@@ -20230,6 +20272,17 @@
+   <file:Documentation/modules.txt>. The module will be called
+    softdog.o.
+ 
++SA1100 Internal Watchdog
++CONFIG_SA1100_WATCHDOG
++  Watchdog timer embedded into SA11x0 chips. This will reboot your
++  system when timeout is reached.
++  NOTE, that once enabled, this timer cannot be disabled.
++
++  This driver is also available as a module ( = code which can be
++  inserted in and removed from the running kernel whenever you want).
++  If you want to compile it as a module, say M here and read
++  Documentation/modules.txt. The module will be called sa1100_wdt.o.
++
+ Berkshire Products PC Watchdog
+ CONFIG_PCWATCHDOG
+   This is the driver for the Berkshire Products PC Watchdog card.
+@@ -21891,6 +21944,30 @@
+   from RME. If you want to acess advanced features of the card, read
+   Documentation/sound/rme96xx.
+ 
++Assabet audio (UDA1341) support
++CONFIG_SOUND_ASSABET_UDA1341
++  Say Y or M if you have an Intel Assabet evaluation board and want to
++  use the Philips UDA 1341 audio chip (the one that drives the stereo
++  audio output) on the SA1100 SSP port.
++
++Compaq iPAQ audio support
++CONFIG_SOUND_H3600_UDA1341
++  Say Y or M if you have a Compaq iPaq handheld computer and want to
++  use its Philips UDA 1341 audio chip.
++
++Audio support for SA1111/UDA1341
++CONFIG_SOUND_SA1111_UDA1341
++  Say Y or M if you have an SA11x0 system with a Philips UDA 1341
++  connected to the SA11x1. An example of such a system is the Intel
++  Assabet evaluation board connected to a Neponset expansion board.
++
++Generic DAC on the SA11x0 SSP port
++CONFIG_SOUND_SA1100SSP
++  Say Y or M if you have an SA-11x0 system with a DAC on the SSP port.
++  The LART has an Burr-Brown PCM 1710 digital to analog convertor on
++  the SSP port, so you want to say Y or M for the LART. It might work
++  on other SA-1100 platforms, too, but this is not tested.
++
+ Are you using a crosscompiler
+ CONFIG_CROSSCOMPILE
+   Say Y here if you are compiling the kernel on a different
+@@ -25594,6 +25671,20 @@
+   Say Y if configuring for a Pangolin.
+   Say N otherwise.
+ 
++Shannon
++CONFIG_SA1100_SHANNON
++  The Shannon (also known as a Tuxscreen, and also as a IS2630) was a
++  limited edition webphone produced by Philips. The Shannon is a SA1100
++  platform with a 640x480 LCD, touchscreen, CIR keyboard, PCMCIA slots,
++  and a telco interface.
++
++Simputer
++CONFIG_SA1100_SIMPUTER
++  Say Y here if you are using an Intel(R) StrongARM(R) SA-1110
++  based Simputer.  See http://www.simputer.org/ for information
++  on the Simputer. The Simputer software is actively maintained
++  by PicoPeta Simputers Pvt. Ltd. (http://www.picopeta.com)
++
+ Victor
+ CONFIG_SA1100_VICTOR
+   Say Y here if you are using a Visu Aide Intel(R) StrongARM(R)
+@@ -25601,6 +25692,14 @@
+   <http://www.visuaide.com/pagevictor.en.html> for information on
+   this system.
+ 
++Radisys Corp. Tulsa
++CONFIG_SA1100_PFS168
++  The Radisys Corp. PFS-168 (aka Tulsa) is an Intel� StrongArm� SA-1110 based
++  computer which includes the SA-1111 Microprocessor Companion Chip and other
++  custom I/O designed to add connectivity and multimedia features for vending
++  and business machine applications. Say Y here if you require support for
++  this target.
++
+ # Choice: cerf_ram
+ Cerf on-board RAM size
+ CONFIG_SA1100_CERF_8MB
+@@ -25668,37 +25767,65 @@
+   Say Y if you want support for the ARM920T processor.
+   Otherwise, say N.
+ 
+-Support ARM1020 processor
+-CONFIG_CPU_ARM1020
+-  The ARM1020 is the cached version of the ARM10 processor,
+-  with an addition of a floating-point unit.
++Support ARM922T processor
++CONFIG_CPU_ARM922T
++  The ARM922T is a version of the ARM920T, but with smaller
++  instruction and data caches. It is used in Altera's 
++  Excalibur XA device family.
+ 
+-  Say Y if you want support for the ARM1020 processor.
++  Say Y if you want support for the ARM922T processor.
+   Otherwise, say N.
+ 
+-Disable I-Cache
++Disable instruction cache
+ CONFIG_CPU_ICACHE_DISABLE
+-  Say Y here to disable the processor instruction cache. Unless
+-  you have a reason not to or are unsure, say N.
++  Say Y here to disable the processor instruction cache. Unless 
++  you have a reason to do this, say N.
+ 
+-Disable D-Cache
++Disable data cache
+ CONFIG_CPU_DCACHE_DISABLE
+-  Say Y here to disable the processor data cache. Unless
+-  you have a reason not to or are unsure, say N.
++  Say Y here to disable the processor data cache. Unless 
++  you have a reason to do this, say N.
+ 
+-Force write through D-cache
++Use data cache in writethrough mode
+ CONFIG_CPU_DCACHE_WRITETHROUGH
+-  Say Y here to use the data cache in write-through mode. Unless you
+-  specifically require this or are unsure, say N.
++  Say Y here to use the data cache in writethough mode. Unless you 
++  specifically require this, say N.
+ 
+-Round robin I and D cache replacement algorithm
++Support ARM1020 processor
++CONFIG_CPU_ARM1020
++  The ARM1020 is the 32K cached version of the ARM10 processor,
++  with an addition of a floating-point unit.
++
++  Say Y if you want support for the ARM1020 processor.
++  Otherwise, say N.
++
++Support ARM1022 processor
++CONFIG_CPU_ARM1022
++  The ARM1022E is the 16K cached version of the ARM10 processor,
++  with an addition of a floating-point unit.
++
++  Say Y if you want support for the ARM1022 processor.
++  Otherwise, say N.
++
++Force round-robin cache line replacement
+ CONFIG_CPU_CACHE_ROUND_ROBIN
+-  Say Y here to use the predictable round-robin cache replacement
+-  policy.  Unless you specifically require this or are unsure, say N.
++  Say Y here to force the caches to use a round-robin
++  algorithm when picking a cache line to evict. Unless you
++  specifically require this, say N.
++
++Disable the write buffer
++CONFIG_CPU_WB_DISABLE
++  Say Y here to turn off the write buffer (if possible)
++  Unless you specifically require this, say N. Note that
++  not all ARM processors allow the write buffer to be
++  disabled.
+ 
+ Disable branch prediction
+ CONFIG_CPU_BPREDICT_DISABLE
+-  Say Y here to disable branch prediction.  If unsure, say N.
++  The ARM10 family of processors support branch prediction,
++  which can significantly speed up execution of loops.
++  Say Y here to disable branch prediction. Unless you
++  specifically require this, say N.
+ 
+ Compressed boot loader in ROM/flash
+ CONFIG_ZBOOT_ROM
+@@ -25745,6 +25872,11 @@
+   Say Y here if you are using the inhand electronics OmniMeter.  See
+   <http://www.inhandelectronics.com/html/omni1.html> for details.
+ 
++HP Laboratories BadgePAD 4
++CONFIG_SA1100_BADGE4
++  Say Y here if you want to build a kernel for the HP Laboratories
++  BadgePAD 4.
++
+ Load kernel using Angel Debug Monitor
+ CONFIG_ANGELBOOT
+   Say Y if you plan to load the kernel using Angel, ARM Ltd's target
+@@ -25757,6 +25889,15 @@
+   board includes 2 serial ports, Ethernet, IRDA, and expansion headers.
+   It comes with 16 MB SDRAM and 8 MB flash ROM.
+ 
++GUIDEA07
++CONFIG_ARCH_GUIDEA07
++  Say Y if you are using a GUIDE (A07) board.
++
++  This board is based on the cs89712 processor and shares much common
++  hardware with the CDB89712 configuration.  When you select this
++  option and the CDB89712 becomes enabled also, don't worry.  It's
++  supposed to be that way.
++
+ CLPS-711X internal ROM bootstrap
+ CONFIG_EP72XX_ROM_BOOT
+   If you say Y here, your CLPS711x-based kernel will use the bootstrap
+@@ -25785,19 +25926,27 @@
+   You may say N here if you are going to load the Acorn FPEmulator
+   early in the bootup.
+ 
++Math emulation 80-bit support
++CONFIG_FPE_NWFPE_XP
++  Say Y to include 80-bit support in the kernel floating-point
++  emulator.  Otherwise, only 32 and 64-bit support is compiled in.
++  Note that gcc does not generate 80-bit operations by default,
++  so in most cases this option only enlarges the size of the
++  floating point emulator without any good reason.
++
++  You almost surely want to say N here.
++
+ FastFPE math emulation
+ CONFIG_FPE_FASTFPE
+   Say Y here to include the FAST floating point emulator in the kernel.
+-  This is an experimental much faster emulator which has only 32 bit
++  This is an experimental much faster emulator which now also has full
+   precision for the mantissa.  It does not support any exceptions.
+-  This makes it very simple, it is approximately 4-8 times faster than
+-  NWFPE.
++  It is very simple, and approximately 3-6 times faster than NWFPE.
+ 
+-  It should be sufficient for most programs.  It is definitely not
+-  suitable if you do scientific calculations that need double
+-  precision for iteration formulas that sum up lots of very small
+-  numbers.  If you do not feel you need a faster FP emulation you
+-  should better choose NWFPE.
++  It should be sufficient for most programs.  It may be not suitable
++  for scientific calculations, but you have to check this for yourself.
++  If you do not feel you need a faster FP emulation you should better
++  choose NWFPE.
+ 
+   It is also possible to say M to build the emulator as a module
+   (fastfpe.o).  But keep in mind that you should only load the FP
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/arm/Porting	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,135 @@
++Taken from list archive at http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2001-July/004064.html
++
++Initial definitions
++-------------------
++
++The following symbol definitions rely on you knowing the translation that
++__virt_to_phys() does for your machine.  This macro converts the passed
++virtual address to a physical address.  Normally, it is simply:
++
++		phys = virt - PAGE_OFFSET + PHYS_OFFSET
++
++
++Decompressor Symbols
++--------------------
++
++ZTEXTADDR
++	Start address of decompressor.  There's no point in talking about
++	virtual or physical addresses here, since the MMU will be off at
++	the time when you call the decompressor code.  You normally call
++	the kernel at this address to start it booting.  This doesn't have
++	to be located in RAM, it can be in flash or other read-only or
++	read-write addressable medium.
++
++ZBSSADDR
++	Start address of zero-initialised work area for the decompressor.
++	This must be pointing at RAM.  The decompressor will zero initialise
++	this for you.  Again, the MMU will be off.
++
++ZRELADDR
++	This is the address where the decompressed kernel will be written,
++	and eventually executed.  The following constraint must be valid:
++
++		__virt_to_phys(TEXTADDR) == ZRELADDR
++
++	The initial part of the kernel is carefully coded to be position
++	independent.
++
++INITRD_PHYS
++	Physical address to place the initial RAM disk.  Only relevant if
++	you are using the bootpImage stuff (which only works on the old
++	struct param_struct).
++
++INITRD_VIRT
++	Virtual address of the initial RAM disk.  The following  constraint
++	must be valid:
++
++		__virt_to_phys(INITRD_VIRT) == INITRD_PHYS
++
++PARAMS_PHYS
++	Physical address of the struct param_struct or tag list, giving the
++	kernel various parameters about its execution environment.
++
++
++Kernel Symbols
++--------------
++
++PHYS_OFFSET
++	Physical start address of the first bank of RAM.
++
++PAGE_OFFSET
++	Virtual start address of the first bank of RAM.  During the kernel
++	boot phase, virtual address PAGE_OFFSET will be mapped to physical
++	address PHYS_OFFSET, along with any other mappings you supply.
++	This should be the same value as TASK_SIZE.
++
++TASK_SIZE
++	The maximum size of a user process in bytes.  Since user space
++	always starts at zero, this is the maximum address that a user
++	process can access+1.  The user space stack grows down from this
++	address.
++
++	Any virtual address below TASK_SIZE is deemed to be user process
++	area, and therefore managed dynamically on a process by process
++	basis by the kernel.  I'll call this the user segment.
++
++	Anything above TASK_SIZE is common to all processes.  I'll call
++	this the kernel segment.
++
++	(In other words, you can't put IO mappings below TASK_SIZE, and
++	hence PAGE_OFFSET).
++
++TEXTADDR
++	Virtual start address of kernel, normally PAGE_OFFSET + 0x8000.
++	This is where the kernel image ends up.  With the latest kernels,
++	it must be located at 32768 bytes into a 128MB region.  Previous
++	kernels placed a restriction of 256MB here.
++
++DATAADDR
++	Virtual address for the kernel data segment.  Must not be defined
++	when using the decompressor.
++
++VMALLOC_START
++VMALLOC_END
++	Virtual addresses bounding the vmalloc() area.  There must not be
++	any static mappings in this area; vmalloc will overwrite them.
++	The addresses must also be in the kernel segment (see above).
++	Normally, the vmalloc() area starts VMALLOC_OFFSET bytes above the
++	last virtual RAM address (found using variable high_memory).
++
++VMALLOC_OFFSET
++	Offset normally incorporated into VMALLOC_START to provide a hole
++	between virtual RAM and the vmalloc area.  We do this to allow
++	out of bounds memory accesses (eg, something writing off the end
++	of the mapped memory map) to be caught.  Normally set to 8MB.
++
++Architecture Specific Macros
++----------------------------
++
++BOOT_MEM(pram,pio,vio)
++	`pram' specifies the physical start address of RAM.  Must always
++	be present, and should be the same as PHYS_OFFSET.
++
++	`pio' is the physical address of an 8MB region containing IO for
++	use with the debugging macros in arch/arm/kernel/debug-armv.S.
++
++	`vio' is the virtual address of the 8MB debugging region.
++
++	It is expected that the debugging region will be re-initialised
++	by the architecture specific code later in the code (via the
++	MAPIO function).
++
++BOOT_PARAMS
++	Same as, and see PARAMS_PHYS.
++
++FIXUP(func)
++	Machine specific fixups, run before memory subsystems have been
++	initialised.
++
++MAPIO(func)
++	Machine specific function to map IO areas (including the debug
++	region above).
++
++INITIRQ(func)
++	Machine specific function to initialise interrupts.
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/arm/mem_alignment	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,58 @@
++Too many problems poped up because of unnoticed misaligned memory access in
++kernel code lately.  Therefore the alignment fixup is now unconditionally
++configured in for SA11x0 based targets.  According to Alan Cox, this is a
++bad idea to configure it out, but Russell King has some good reasons for
++doing so on some f***ed up ARM architectures like the EBSA110.  However
++this is not the case on many design I'm aware of, like all SA11x0 based
++ones.
++
++Of course this is a bad idea to rely on the alignment trap to perform
++unaligned memory access in general.  If those access are predictable, you
++are better to use the macros provided by include/asm/unaligned.h.  The
++alignment trap can fixup misaligned access for the exception cases, but at
++a high performance cost.  It better be rare.
++
++Now for user space applications, it is possible to configure the alignment
++trap to SIGBUS any code performing unaligned access (good for debugging bad
++code), or even fixup the access by software like for kernel code.  The later
++mode isn't recommended for performance reasons (just think about the
++floating point emulation that works about the same way).  Fix your code
++instead!
++
++Please note that randomly changing the behaviour without good thought is
++real bad - it changes the behaviour of all unaligned instructions in user
++space, and might cause programs to fail unexpectedly.
++
++To change the alignment trap behavior, simply echo a number into
++/proc/sys/debug/alignment.  The number is made up from various bits:
++
++bit		behavior when set
++---		-----------------
++
++0		A user process performing an unaligned memory access
++		will cause the kernel to print a message indicating
++		process name, pid, pc, instruction, address, and the
++		fault code.
++
++1		The kernel will attempt to fix up the user process
++		performing the unaligned access.  This is of course
++		slow (think about the floating point emulator) and
++		not recommended for production use.
++
++2		The kernel will send a SIGBUS signal to the user process
++		performing the unaligned access.
++
++Note that not all combinations are supported - only values 0 through 5.
++(6 and 7 don't make sense).
++
++For example, the following will turn on the warnings, but without
++fixing up or sending SIGBUS signals:
++
++	echo 1 > /proc/sys/debug/alignment
++
++You can also read the content of the same file to get statistical
++information on unaligned access occurrences plus the current mode of
++operation for user space code.
++
++
++Nicolas Pitre, Mar 13, 2001.  Modified Russell King, Nov 30, 2001.
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/arm/memory.txt	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,74 @@
++		Kernel Memory Layout on ARM Linux
++
++		Russell King <rmk@arm.linux.org.uk>
++			April 27, 2003 (2.5.68)
++
++This document describes the virtual memory layout which the Linux
++kernel uses for ARM processors.  It indicates which regions are
++free for platforms to use, and which are used by generic code.
++
++The ARM CPU is capable of addressing a maximum of 4GB virtual memory
++space, and this must be shared between user space processes, the
++kernel, and hardware devices.
++
++As the ARM architecture matures, it becomes necessary to reserve
++certain regions of VM space for use for new facilities; therefore
++this document may reserve more VM space over time.
++
++Start		End		Use
++--------------------------------------------------------------------------
++ffff8000	ffffffff	copy_user_page / clear_user_page use.
++				For SA11xx and Xscale, this is used to
++				setup a minicache mapping.
++
++ffff1000	ffff7fff	Reserved.
++				Platforms must not use this address range.
++
++ffff0000	ffff0fff	CPU vector page.
++				The CPU vectors are mapped here if the
++				CPU supports vector relocation (control
++				register V bit.)
++
++ffe00000	fffeffff	Free for platform use, not recommended.
++
++ffc00000	ffdfffff	2MB consistent memory mapping.
++				Memory returned by the consistent_alloc
++				low level function will be dynamically
++				mapped here.
++
++ff000000	ffbfffff	Free for platform use, not recommended.
++
++VMALLOC_END	ff000000	Free for platform use, recommended.
++
++VMALLOC_START	VMALLOC_END	vmalloc() / ioremap() space.
++				Memory returned by vmalloc/ioremap will
++				be dynamically placed in this region.
++				VMALLOC_START may be based upon the value
++				of the high_memory variable.
++
++PAGE_OFFSET	high_memory	Kernel direct-mapped RAM region.
++				This maps the platforms RAM, and typically
++				maps all platform RAM in a 1:1 relationship.
++
++TASK_SIZE	PAGE_OFFSET	Kernel module space
++				Kernel modules inserted via insmod are
++				placed here using dynamic mappings.
++
++00001000	TASK_SIZE	User space mappings
++				Per-thread mappings are placed here via
++				the mmap() system call.
++
++00000000	00000fff	CPU vector page / null pointer trap
++				CPUs which do not support vector remapping
++				place their vector page here.  NULL pointer
++				dereferences by both the kernel and user
++				space are also caught via this mapping.
++
++Please note that mappings which collide with the above areas may result
++in a non-bootable kernel, or may cause the kernel to (eventually) panic
++at run time.
++
++Since future CPUs may impact the kernel mapping layout, user programs
++must not access any memory which is not mapped inside their 0x0001000
++to TASK_SIZE address range.  If they wish to access these areas, they
++must set up their own mappings using open() and mmap().
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/cpufreq/core.txt	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,94 @@
++     CPU frequency and voltage scaling code in the Linux(TM) kernel
++
++
++		         L i n u x    C P U F r e q
++
++			  C P U F r e q    C o r e
++
++
++		    Dominik Brodowski  <linux@brodo.de>
++		     David Kimdon <dwhedon@debian.org>
++
++
++
++   Clock scaling allows you to change the clock speed of the CPUs on the
++    fly. This is a nice method to save battery power, because the lower
++            the clock speed, the less power the CPU consumes.
++
++
++Contents:
++---------
++1.  CPUFreq core and interfaces
++2.  CPUFreq notifiers
++
++1. General Information
++=======================
++
++The CPUFreq core code is located in linux/kernel/cpufreq.c. This
++cpufreq code offers a standardized interface for the CPUFreq
++architecture drivers (those pieces of code that do actual
++frequency transitions), as well as to "notifiers". These are device
++drivers or other part of the kernel that need to be informed of
++policy changes (ex. thermal modules like ACPI) or of all
++frequency changes (ex. timing code) or even need to force certain
++speed limits (like LCD drivers on ARM architecture). Additionally, the
++kernel "constant" loops_per_jiffy is updated on frequency changes
++here.
++
++Reference counting is done by cpufreq_get_cpu and cpufreq_put_cpu,
++which make sure that the cpufreq processor driver is correctly
++registered with the core, and will not be unloaded until
++cpufreq_put_cpu is called.
++
++2. CPUFreq notifiers
++====================
++
++CPUFreq notifiers conform to the standard kernel notifier interface.
++See linux/include/linux/notifier.h for details on notifiers.
++
++There are two different CPUFreq notifiers - policy notifiers and
++transition notifiers.
++
++
++2.1 CPUFreq policy notifiers
++----------------------------
++
++These are notified when a new policy is intended to be set. Each
++CPUFreq policy notifier is called three times for a policy transition:
++
++1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if
++    they see a need for this - may it be thermal considerations or
++    hardware limitations.
++
++2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid
++    hardware failure.
++
++3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy
++   - if two hardware drivers failed to agree on a new policy before this
++   stage, the incompatible hardware shall be shut down, and the user
++   informed of this.
++
++The phase is specified in the second argument to the notifier.
++
++The third argument, a void *pointer, points to a struct cpufreq_policy
++consisting of five values: cpu, min, max, policy and max_cpu_freq. min 
++and max are the lower and upper frequencies (in kHz) of the new
++policy, policy the new policy, cpu the number of the affected CPU or
++CPUFREQ_ALL_CPUS for all CPUs; and max_cpu_freq the maximum supported
++CPU frequency. This value is given for informational purposes only.
++
++
++2.2 CPUFreq transition notifiers
++--------------------------------
++
++These are notified twice when the CPUfreq driver switches the CPU core
++frequency and this change has any external implications.
++
++The second argument specifies the phase - CPUFREQ_PRECHANGE or
++CPUFREQ_POSTCHANGE.
++
++The third argument is a struct cpufreq_freqs with the following
++values:
++cpu	- number of the affected CPU or CPUFREQ_ALL_CPUS
++old	- old frequency
++new	- new frequency
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/cpufreq/cpu-drivers.txt	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,210 @@
++     CPU frequency and voltage scaling code in the Linux(TM) kernel
++
++
++		         L i n u x    C P U F r e q
++
++			   C P U   D r i v e r s 
++
++		       - information for developers -
++
++
++		    Dominik Brodowski  <linux@brodo.de>
++
++
++
++   Clock scaling allows you to change the clock speed of the CPUs on the
++    fly. This is a nice method to save battery power, because the lower
++            the clock speed, the less power the CPU consumes.
++
++
++Contents:
++---------
++1.   What To Do?
++1.1  Initialization
++1.2  Per-CPU Initialization
++1.3  verify
++1.4  target or setpolicy?
++1.5  target
++1.6  setpolicy
++2.   Frequency Table Helpers
++
++
++
++1. What To Do?
++==============
++
++So, you just got a brand-new CPU / chipset with datasheets and want to
++add cpufreq support for this CPU / chipset? Great. Here are some hints
++on what is neccessary:
++
++
++1.1 Initialization
++------------------
++
++First of all, in an __initcall level 7 or later (preferrably
++module_init() so that your driver is modularized) function check
++whether this kernel runs on the right CPU and the right chipset. If
++so, register a struct cpufreq_driver with the CPUfreq core using
++cpufreq_register_driver()
++
++What shall this struct cpufreq_driver contain? 
++
++cpufreq_driver.name -		The name of this driver.
++
++cpufreq_driver.init -		A pointer to the per-CPU initialization 
++				function.
++
++cpufreq_driver.verify -		A pointer to a "verfication" funciton.
++
++cpufreq_driver.setpolicy _or_ 
++cpufreq_driver.target -		See below on the differences.
++
++And optionally
++
++cpufreq_driver.exit -		A pointer to a per-CPU cleanup function.
++
++cpufreq_driver.attr -		A pointer to a NULL-terminated list of
++				"struct freq_attr" which allow to
++				export values to sysfs.
++
++
++1.2 Per-CPU Initialization
++--------------------------
++
++Whenever a new CPU is registered with the device model, or after the
++cpufreq driver registers itself, the per-CPU initialization fucntion 
++cpufreq_driver.init is called. It takes a struct cpufreq_policy
++*policy as argument. What to do now?
++
++If necessary, activate the CPUfreq support on your CPU (unlock that
++register etc.).
++
++Then, the driver must fill in the following values:
++
++policy->cpuinfo.min_freq _and_
++policy->cpuinfo.max_freq -	the minimum and maximum frequency 
++				(in kHz) which is supported by 
++				this CPU
++policy->cpuinfo.transition_latency   the time it takes on this CPU to
++				switch between two frequencies (if
++				appropriate, else specify
++				CPUFREQ_ETERNAL)
++
++policy->cur			The current operating frequency of
++				this CPU (if appropriate)
++policy->min, 
++policy->max, 
++policy->policy and, if neccessary,
++policy->governor		must contain the "default policy" for
++				this CPU. A few moments later,
++				cpufreq_driver.verify and either
++				cpufreq_driver.setpolicy or
++				cpufreq_driver.target is called with
++				these values.
++
++For setting some of these values, the frequency table helpers might be
++helpful. See the section 2 for more information on them.
++
++
++1.3 verify
++------------
++
++When the user decides a new policy (consisting of
++"policy,governor,min,max") shall be set, this policy must be validated
++so that incompatible values can be corrected. For verifying these
++values, a frequency table helper and/or the
++cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned
++int min_freq, unsigned int max_freq) function might be helpful. See
++section 2 for details on frequency table helpers.
++
++You need to make sure that at least one valid frequency (or operating
++range) is within policy->min and policy->max. If necessary, increase
++policy->max fist, and only if this is no solution, decreas policy->min.
++
++
++1.4 target or setpolicy?
++----------------------------
++
++Most cpufreq drivers or even most cpu frequency scaling algorithms 
++only allow the CPU to be set to one frequency. For these, you use the
++->target call.
++
++Some cpufreq-capable processors switch the frequency between certain
++limits on their own. These shall use the ->setpolicy call
++
++
++1.4. target
++-------------
++
++The target call has three arguments: struct cpufreq_policy *policy,
++unsigned int target_frequency, unsigned int relation.
++
++The CPUfreq driver must set the new frequency when called here. The
++actual frequency must be determined using the following rules:
++
++- keep close to "target_freq"
++- policy->min <= new_freq <= policy->max (THIS MUST BE VALID!!!)
++- if relation==CPUFREQ_REL_L, try to select a new_freq higher than or equal
++  target_freq. ("L for lowest, but no lower than")
++- if relation==CPUFREQ_REL_H, try to select a new_freq lower than or equal
++  target_freq. ("H for highest, but no higher than")
++
++Here again the frequency table helper might assist you - see section 3
++for details.
++
++
++1.5 setpolicy
++---------------
++
++The setpolicy call only takes a struct cpufreq_policy *policy as
++argument. You need to set the lower limit of the in-processor or
++in-chipset dynamic frequency switching to policy->min, the upper limit
++to policy->max, and -if supported- select a performance-oriented
++setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a
++powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check
++the reference implementation in arch/i386/kernel/cpu/cpufreq/longrun.c
++
++
++
++2. Frequency Table Helpers
++==========================
++
++As most cpufreq processors only allow for being set to a few specific
++frequencies, a "frequency table" with some functions might assist in
++some work of the processor driver. Such a "frequency table" consists
++of an array of struct cpufreq_freq_table entries, with any value in
++"index" you want to use, and the corresponding frequency in
++"frequency". At the end of the table, you need to add a
++cpufreq_freq_table entry with frequency set to CPUFREQ_TABLE_END. And
++if you want to skip one entry in the table, set the frequency to 
++CPUFREQ_ENTRY_INVALID. The entries don't need to be in ascending
++order.
++
++By calling cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
++					struct cpufreq_frequency_table *table);
++the cpuinfo.min_freq and cpuinfo.max_freq values are detected, and
++policy->min and policy->max are set to the same values. This is
++helpful for the per-CPU initialization stage.
++
++int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
++                                   struct cpufreq_frequency_table *table);
++assures that at least one valid frequency is within policy->min and
++policy->max, and all other criteria are met. This is helpful for the
++->verify call.
++
++int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
++                                   struct cpufreq_frequency_table *table,
++                                   unsigned int target_freq,
++                                   unsigned int relation,
++                                   unsigned int *index);
++
++is the corresponding frequency table helper for the ->target
++stage. Just pass the values to this function, and the unsigned int
++index returns the number of the frequency table entry which contains
++the frequency the CPU shall be set to. PLEASE NOTE: This is not the
++"index" which is in this cpufreq_table_entry.index, but instead
++cpufreq_table[index]. So, the new frequency is
++cpufreq_table[index].frequency, and the value you stored into the
++frequency table "index" field is
++cpufreq_table[index].index.
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/cpufreq/governors.txt	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,155 @@
++     CPU frequency and voltage scaling code in the Linux(TM) kernel
++
++
++		         L i n u x    C P U F r e q
++
++		      C P U F r e q   G o v e r n o r s
++
++		   - information for users and developers -
++
++
++		    Dominik Brodowski  <linux@brodo.de>
++
++
++
++   Clock scaling allows you to change the clock speed of the CPUs on the
++    fly. This is a nice method to save battery power, because the lower
++            the clock speed, the less power the CPU consumes.
++
++
++Contents:
++---------
++1.   What is a CPUFreq Governor?
++
++2.   Governors In the Linux Kernel
++2.1  Performance
++2.2  Powersave
++2.3  Userspace
++
++3.   The Governor Interface in the CPUfreq Core
++
++
++
++1. What Is A CPUFreq Governor?
++==============================
++
++Most cpufreq drivers (in fact, all except one, longrun) or even most
++cpu frequency scaling algorithms only offer the CPU to be set to one
++frequency. In order to offer dynamic frequency scaling, the cpufreq
++core must be able to tell these drivers of a "target frequency". So
++these specific drivers will be transformed to offer a "->target"
++call instead of the existing "->setpolicy" call. For "longrun", all
++stays the same, though.
++
++How to decide what frequency within the CPUfreq policy should be used?
++That's done using "cpufreq governors". Two are already in this patch
++-- they're the already existing "powersave" and "performance" which
++set the frequency statically to the lowest or highest frequency,
++respectively. At least two more such governors will be ready for
++addition in the near future, but likely many more as there are various
++different theories and models about dynamic frequency scaling
++around. Using such a generic interface as cpufreq offers to scaling
++governors, these can be tested extensively, and the best one can be
++selected for each specific use.
++
++Basically, it's the following flow graph:
++
++CPU can be set to switch independetly	 |	   CPU can only be set
++      within specific "limits"		 |       to specific frequencies
++
++                                 "CPUfreq policy"
++		consists of frequency limits (policy->{min,max})
++  		     and CPUfreq governor to be used
++			 /		      \
++			/		       \
++		       /		       the cpufreq governor decides
++		      /			       (dynamically or statically)
++		     /			       what target_freq to set within
++		    /			       the limits of policy->{min,max}
++		   /			            \
++		  /				     \
++	Using the ->setpolicy call,		 Using the ->target call,
++	    the limits and the			  the frequency closest
++	     "policy" is set.			  to target_freq is set.
++						  It is assured that it
++						  is within policy->{min,max}
++
++
++2. Governors In the Linux Kernel
++================================
++
++2.1 Performance
++---------------
++
++The CPUfreq governor "performance" sets the CPU statically to the
++highest frequency within the borders of scaling_min_freq and
++scaling_max_freq.
++
++
++2.1 Powersave
++-------------
++
++The CPUfreq governor "powersave" sets the CPU statically to the
++lowest frequency within the borders of scaling_min_freq and
++scaling_max_freq.
++
++
++2.2 Userspace
++-------------
++
++The CPUfreq governor "userspace" allows the user, or any userspace
++program running with UID "root", to set the CPU to a specifc frequency
++by making a sysfs file "scaling_setspeed" available in the CPU-device
++directory.
++
++
++
++3. The Governor Interface in the CPUfreq Core
++=============================================
++
++A new governor must register itself with the CPUfreq core using
++"cpufreq_register_governor". The struct cpufreq_governor, which has to
++be passed to that function, must contain the following values:
++
++governor->name -	    A unique name for this governor
++governor->governor -	    The governor callback function
++governor->owner	-	    .THIS_MODULE for the governor module (if 
++			    appropriate)
++
++The governor->governor callback is called with the current (or to-be-set)
++cpufreq_policy struct for that CPU, and an unsigned int event. The
++following events are currently defined:
++
++CPUFREQ_GOV_START:   This governor shall start its duty for the CPU
++		     policy->cpu
++CPUFREQ_GOV_STOP:    This governor shall end its duty for the CPU
++		     policy->cpu
++CPUFREQ_GOV_LIMITS:  The limits for CPU policy->cpu have changed to
++		     policy->min and policy->max.
++
++If you need other "events" externally of your driver, _only_ use the
++cpufreq_governor_l(unsigned int cpu, unsigned int event) call to the
++CPUfreq core to ensure proper locking.
++
++
++The CPUfreq governor may call the CPU processor driver using one of
++these two functions:
++
++inline int cpufreq_driver_target(struct cpufreq_policy *policy,
++                                 unsigned int target_freq,
++                                 unsigned int relation);
++
++inline int cpufreq_driver_target_l(struct cpufreq_policy *policy,
++                                   unsigned int target_freq,
++                                   unsigned int relation);
++
++target_freq must be within policy->min and policy->max, of course.
++What's the difference between these two functions? When your governor
++still is in a direct code path of a call to governor->governor, the
++cpufreq_driver_sem lock is still held in the cpufreq core, and there's
++no need to lock it again (in fact, this would cause a deadlock). So
++use cpufreq_driver_target only in these cases. In all other cases (for
++example, when there's a "daemonized" function that wakes up every
++second), use cpufreq_driver_target_l to lock the cpufreq_driver_sem
++before the command is passed to the cpufreq processor driver.
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/cpufreq/index.txt	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,56 @@
++     CPU frequency and voltage scaling code in the Linux(TM) kernel
++
++
++		         L i n u x    C P U F r e q
++
++
++
++
++		    Dominik Brodowski  <linux@brodo.de>
++
++
++
++   Clock scaling allows you to change the clock speed of the CPUs on the
++    fly. This is a nice method to save battery power, because the lower
++            the clock speed, the less power the CPU consumes.
++
++
++
++Documents in this directory:
++----------------------------
++core.txt	-	General description of the CPUFreq core and
++			of CPUFreq notifiers
++
++cpu-drivers.txt -	How to implement a new cpufreq processor driver
++
++governors.txt	-	What are cpufreq governors and how to
++			implement them?
++
++index.txt	-	File index, Mailing list and Links (this document)
++
++user-guide.txt	-	User Guide to CPUFreq
++
++
++Mailing List
++------------
++There is a CPU frequency changing CVS commit and general list where
++you can report bugs, problems or submit patches. To post a message,
++send an email to cpufreq@www.linux.org.uk, to subscribe go to
++http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
++mailing list are available to subscribers at
++http://www.linux.org.uk/mailman/private/cpufreq/.
++
++
++Links
++-----
++the FTP archives:
++* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
++
++how to access the CVS repository:
++* http://cvs.arm.linux.org.uk/
++
++the CPUFreq Mailing list:
++* http://www.linux.org.uk/mailman/listinfo/cpufreq
++
++Clock and voltage scaling for the SA-1100:
++* http://www.lart.tudelft.nl/projects/scaling
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/cpufreq/user-guide.txt	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,166 @@
++     CPU frequency and voltage scaling code in the Linux(TM) kernel
++
++
++		         L i n u x    C P U F r e q
++
++			     U S E R   G U I D E
++
++
++		    Dominik Brodowski  <linux@brodo.de>
++
++
++
++   Clock scaling allows you to change the clock speed of the CPUs on the
++    fly. This is a nice method to save battery power, because the lower
++            the clock speed, the less power the CPU consumes.
++
++
++Contents:
++---------
++1. Supported Architectures and Processors
++1.1 ARM
++1.2 x86
++1.3 sparc64
++
++2. "Policy" / "Governor"?
++2.1 Policy
++2.2 Governor
++
++3. How to change the CPU cpufreq policy and/or speed
++3.1 Preferred interface: sysfs
++3.2 Deprecated interfaces
++
++
++
++1. Supported Architectures and Processors
++=========================================
++
++1.1 ARM
++-------
++
++The following ARM processors are supported by cpufreq:
++
++ARM Integrator
++ARM-SA1100
++ARM-SA1110
++
++
++1.2 x86
++-------
++
++The following processors for the x86 architecture are supported by cpufreq:
++
++AMD Elan - SC400, SC410
++AMD mobile K6-2+
++AMD mobile K6-3+
++Cyrix Media GXm
++Intel mobile PIII [*] and Intel mobile PIII-M on certain chipsets
++Intel Pentium 4, Intel Xeon
++National Semiconductors Geode GX
++Transmeta Crusoe
++varios processors on some ACPI 2.0-compatible systems [**]
++
++[*] only certain Intel mobile PIII processors are supported. If you
++know that you own a speedstep-capable processor, pass the option
++"speedstep_coppermine=1" to the module speedstep.o
++
++[**] Only if "ACPI Processor Performance States" are available
++to the ACPI<->BIOS interface.
++
++
++1.3 sparc64
++-----------
++
++The following processors for the sparc64 architecture are supported by
++cpufreq:
++
++UltraSPARC-III
++
++
++
++2. "Policy" / "Governor" ?
++==========================
++
++Some CPU frequency scaling-capable processor switch between varios
++frequencies and operating voltages "on the fly" without any kernel or
++user involvement. This guarantuees very fast switching to a frequency
++which is high enough to serve the user's needs, but low enough to save
++power.
++
++
++2.1 Policy
++----------
++
++On these systems, all you can do is select the lower and upper
++frequency limit as well as whether you want more aggressive
++power-saving or more instantly avaialble processing power.
++
++
++2.2 Governor
++------------
++
++On all other cpufreq implementations, these boundaries still need to
++be set. Then, a "governor" must be selected. Such a "governor" decides
++what speed the processor shall run within the boundaries. One such
++"governor" is the "userspace" governor. This one allows the user - or
++a yet-to-implement userspace program - to decide what specific speed
++the processor shall run at.
++
++
++3. How to change the CPU cpufreq policy and/or speed
++====================================================
++
++3.1 Preferred Interface: sysfs
++------------------------------
++
++The preferred interface is located in the sysfs filesystem. If you
++mounted it at /sys, the cpufreq interface is located in a subdirectory
++"cpufreq" within the cpu-device directory
++(e.g. /sys/devices/sys/cpu0/cpufreq/ for the first CPU).
++
++cpuinfo_min_freq :		this file shows the minimum operating
++				frequency the processor can run at(in kHz) 
++cpuinfo_max_freq :		this file shows the maximum operating
++				frequency the processor can run at(in kHz) 
++scaling_driver :		this file shows what cpufreq driver is
++				used to set the frequency on this CPU
++
++scaling_available_governors :	this file shows the CPUfreq governors
++				available in this kernel. You can see the
++				currently activated governor in
++
++scaling_governor,		and by "echoing" the name of another
++				governor you can change it. Please note
++				that some governors won't load - they only
++				work on some specific architectures or
++				processors.
++scaling_min_freq and 
++scaling_max_freq		show the current "policy limits" (in
++				kHz). By echoing new values into these
++				files, you can change these limits.
++
++
++If you have selected the "userspace" governor which allows you to
++set the CPU operating frequency to a specific value, you can read out
++the current frequency in
++
++scaling_setspeed.		By "echoing" a new frequency into this
++				you can change the speed of the CPU,
++				but only within the limits of
++				scaling_min_freq and scaling_max_freq.
++				
++
++3.2 Deprecated Interfaces
++-------------------------
++
++Depending on your kernel configuration, you might find the following 
++cpufreq-related files:
++/proc/cpufreq
++/proc/sys/cpu/*/speed
++/proc/sys/cpu/*/speed-min
++/proc/sys/cpu/*/speed-max
++
++These are files for deprecated interfaces to cpufreq, which offer far
++less functionality. Because of this, these interfaces aren't described
++here.
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/cpufreq-old	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,332 @@
++     CPU frequency and voltage scaling code in the Linux(TM) kernel
++
++
++		         L i n u x    C P U F r e q
++
++
++
++
++		     Dominik Brodowski <devel@brodo.de>
++
++
++
++   Clock scaling allows you to change the clock speed of the CPUs on the
++    fly. This is a nice method to save battery power, because the lower
++            the clock speed, the less power the CPU consumes.
++
++
++
++Contents:
++---------
++1.  Supported architectures
++2.  User interface
++2.1   Sample script for command line interface
++3.  CPUFreq core and interfaces
++3.1   General information
++3.2   CPUFreq notifiers
++3.3   CPUFreq architecture drivers
++4.  Mailing list and Links
++
++
++
++1. Supported architectures
++==========================
++
++Some architectures detect the lowest and highest possible speed
++settings, while others rely on user information on this. For the
++latter, a boot parameter is required, for the former, you can specify
++one to set the limits between speed settings may occur. 
++The boot parameter has the following syntax:
++
++     cpufreq=minspeed-maxspeed
++
++with both minspeed and maxspeed being given in kHz. To set the lower
++limit to 59 MHz and the upper limit to 221 MHz, specify:
++
++      cpufreq=59000-221000
++
++Check the "Speed Limits Detection" information below on whether
++the driver detects the lowest and highest allowed speed setting
++automatically.
++
++
++ARM Integrator:
++    SA 1100, SA1110
++--------------------------------
++    Speed Limits Detection: On Integrators, the minimum speed is set
++    and the maximum speed has to be specified using the boot
++    parameter. On SA11x0s, the frequencies are fixed (59 - 287 MHz)
++
++
++AMD Elan:
++    SC400, SC410
++--------------------------------
++    Speed Limits Detection: Not implemented. You need to specify the
++    minimum and maximum frequency in the boot parameter (see above).
++
++
++VIA Cyrix Longhaul:
++    VIA Samuel/CyrixIII, VIA Cyrix Samuel/C3, 
++    VIA Cyrix Ezra, VIA Cyrix Ezra-T
++--------------------------------
++    Speed Limits Detection: working. No need for boot parameters.
++    NOTE: Support for certain processors is currently disabled,
++    waiting on updated docs from VIA.
++
++
++Intel SpeedStep:
++    certain mobile Intel Pentium III (Coppermine), and all mobile
++    Intel Pentium III-M (Tulatin) and mobile Intel Pentium 4 P4-Ms.
++--------------------------------
++    Speed Limits Detection: working. No need for boot parameters.
++    NOTE: 
++    1.) mobile Intel Pentium III (Coppermine):
++        The SpeedStep interface may only be used on SpeedStep
++        capable processors. Unforunately, due to lack of documentation,
++        such detection is not yet possible on mobile Intel PIII
++        (Coppermine) processors. In order to activate SpeedStep on such a
++        processor, you have to remove one line manually in
++        linux/drivers/arch/i386/speedstep.c
++
++
++P4 CPU Clock Modulation:
++    Intel Pentium 4 Xeon processors
++--------------------------------
++    Speed Limits Detection: Not implemented. You need to specify the
++    minimum and maximum frequency in the boot parameter (see above).
++
++
++
++2. User Interface
++=================
++
++CPUFreq uses a "sysctl" interface which is located in 
++	/proc/sys/cpu/0/	  on UP (uniprocessor) kernels, or 
++	/proc/sys/cpu/any/	  on SMP (symmetric multiprocessoring) kernels.
++
++
++In this directory, you will find three files of importance for
++CPUFreq: speed-max, speed-min, and speed: 
++
++speed		    shows the current CPU frequency in kHz, 
++speed-min	    the minimal supported CPU frequency, and
++speed-max	    the maximal supported CPU frequency. 
++
++Please note that you might have to specify these limits as a boot
++parameter depending on the architecture (see above).
++
++
++To change the CPU frequency, "echo" the desired CPU frequency (in kHz)
++to speed. For example, to set the CPU speed to the lowest/highest
++allowed frequency do:
++
++root@notebook:# cat /proc/sys/cpu/0/speed-min > /proc/sys/cpu/0/speed
++root@notebook:# cat /proc/sys/cpu/0/speed-max > /proc/sys/cpu/0/speed
++
++
++2.1   Sample script for command line interface
++**********************************************
++
++
++Michael Ossmann <mike@ossmann.com> has written a small command line
++interface for the infinitely lazy.
++
++#!/bin/bash
++#
++# /usr/local/bin/freq
++#   simple command line interface to cpufreq
++
++[ -n "$1" ] && case "$1" in
++  "min" )
++    # set frequency to minimum
++    cat /proc/sys/cpu/0/speed-min >/proc/sys/cpu/0/speed
++    ;;
++  "max" )
++    # set frequency to maximum
++    cat /proc/sys/cpu/0/speed-max >/proc/sys/cpu/0/speed
++    ;;
++  * )
++    echo "Usage: $0 [min|max]"
++    echo "  min: set frequency to minimum and display new frequency"
++    echo "  max: set frequency to maximum and display new frequency"
++    echo "  no options: display current frequency"
++    exit 1
++    ;;
++esac
++
++# display current frequency
++cat /proc/sys/cpu/0/speed
++exit 0
++
++
++
++3.  CPUFreq core and interfaces
++===============================
++
++3.1   General information
++*************************
++
++The CPUFreq core code is located in linux/kernel/cpufreq.c. This
++cpufreq code offers a standardized interface for the CPUFreq
++architecture drivers (those pieces of code that do the actual
++frequency transition), as well as to "notifiers". These are device
++drivers or other part of the kernel that need to be informed of
++frequency changes (like timing code) or even need to force certain
++speed limits (like LCD drivers on ARM architecture). Aditionally, the
++kernel "constant" loops_per_jiffy is updated on frequency changes
++here.
++
++
++3.2   CPUFreq notifiers
++***********************
++
++CPUFreq notifiers are kernel code that need to be called to either
++a) define certain minimum or maximum speed settings,
++b) be informed of frequency changes in advance of the transition, or
++c) be informed of frequency changes directly after the transition.
++
++A standard kernel notifier interface is offered for this. See
++linux/include/linux/notifier.h for details on notifiers.
++
++
++Data and value passed to CPUFreq notifiers
++------------------------------------------
++The second argument passed to any notifier is an unsigned int stating
++the phase of the transition: 
++CPUFREQ_MINMAX during the process of determing a valid new CPU
++	       frequency,
++CPUFREQ_PRECHANGE right before the transition, and 
++CPUFREQ_POSTCHANGE right after the transition.
++
++The third argument, a void *pointer, points to a struct
++cpufreq_freqs. This consists of four values: min, max, cur and new.
++
++min and max are the current speed limits. Please note: Never update
++these values directly, use cpufreq_updateminmax(struct cpufreq_freqs
++*freqs, unsigned int min, unsigned int max) instead. cur is the
++current/old speed, and new is the new speed, but might only be valid
++on CPUFREQ_PRECHANGE or CPUFREQ_POSTCHANGE.
++
++Each notifier gets called all three times on any transition:
++
++CPUFREQ_MINMAX
++Here the notifier is supposed to update the min and max values to the
++limits the protected device / kernel code needs. As stated above,
++always use cpufreq_updateminmax for this.
++
++CPUFREQ_PRECHANGE
++CPUFREQ_POSTCHANGE
++Here the notifier is supposed to update all internal (e.g. device
++driver) code which is dependend on the CPU frequency.
++
++
++3.3   CPUFreq architecture drivers
++**********************************
++
++CPUFreq architecture drivers are the pieces of kernel code that
++actually perform CPU frequency transitions. These need to be
++initialised seperately (seperate initcalls), and may be
++modularized. They interact with the CPUFreq core in the following way:
++
++
++cpufreq_register()
++------------------
++cpufreq_register registers an arch driver to the CPUFreq core. Please
++note that only one arch driver may be registered at any time, -EBUSY
++is returned when an arch driver is already registered. The argument to
++cpufreq_register, cpufreq_driver_t driver, is described later.
++
++
++cpufreq_unregister()
++--------------------
++cpufreq_unregister unregisters an arch driver, e.g. on module
++unloading. Please note that there is no check done that this is called
++from the driver which actually registered itself to the core, so
++please only call this function when you are sure the arch driver got
++registered correctly before.
++
++
++struct cpufreq_driver
++----------------
++On initialisation, the arch driver is supposed to pass the following
++entries in struct cpufreq_driver cpufreq_driver:
++
++cpufreq_verify_t validate: This is a pointer to a function with the
++following definition: 
++     unsigned int validating_function (unsigned int kHz). 
++It is called right before a transition occurs. The proposed new
++speed setting is passed as an argument in kHz; the validating code
++should verify this is a valid speed setting which is currently
++supported by the CPU. It shall return the closest valid CPU frequency
++in kHz.
++
++cpufreq_setspeed_t setspeed: This is a pointer to a function with the
++following definition: 
++     void setspeed_function (unsigned int kHz). 
++This function shall perform the transition to the new CPU frequency 
++given as argument in kHz. Note that this argument is exactly the same
++as the one returned by cpufreq_verify_t validate.
++
++
++unsigned int freq.cur: The current CPU core frequency. Note that this
++is a requirement while the next two entries are optional.
++
++
++unsigned int freq.min (optional): The minimal CPU core frequency this
++CPU supports. This value may be limited further by the
++cpufreq_verify_t validate function, and so this value should be the
++minimal core frequency allowed "theoretically" on this system in this
++configuration.
++
++
++unsigned int freq.max (optional): The maximum CPU core frequency this
++CPU supports. This value may be limited further by the
++cpufreq_verify_t validate function, and so this value should be the
++maximum core frequency allowed "theoretically" on this system in this
++configuration.
++
++
++Some Requirements to CPUFreq architecture drivers
++-------------------------------------------------
++* Only call cpufreq_register() when the ability to switch CPU
++  frequencies is _verified_ or can't be missing
++* cpufreq_unregister() may only be called if cpufreq_register() has
++  been successfully(!) called before
++* All CPUs have to be set to the same speed whenever setspeed() is
++  called
++* Be aware that there is currently no error management in the
++  setspeed() code in the CPUFreq core. So only call yourself a
++  cpufreq_driver if you are really a working cpufreq_driver!
++
++
++
++4.  Mailing list and Links
++**************************
++
++
++Mailing List
++------------
++There is a CPU frequency changing CVS commit and general list where
++you can report bugs, problems or submit patches. To post a message,
++send an email to cpufreq@www.linux.org.uk, to subscribe go to
++http://www.linux.org.uk/mailman/listinfo/cpufreq. Previous post to the
++mailing list are available to subscribers at
++http://www.linux.org.uk/mailman/private/cpufreq/.
++
++
++Links
++-----
++the FTP archives:
++* ftp://ftp.linux.org.uk/pub/linux/cpufreq/
++
++how to access the CVS repository:
++* http://www.arm.linux.org.uk/cvs/
++
++the CPUFreq Mailing list:
++* http://www.linux.org.uk/mailman/listinfo/cpufreq
++
++Clock and voltage scaling for the SA-1100:
++* http://www.lart.tudelft.nl/projects/scaling
++
++CPUFreq project homepage
++* http://www.brodo.de/cpufreq/
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/l3/structure	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,36 @@
++L3 Bus Driver
++-------------
++
++The structure of the driver is as follows:
++
++	+----------+	+----------+	+----------+
++	| client 1 |	| client 2 |	| client 3 |
++	+-----^----+	+----^-----+	+----^-----+
++	      |		     |               |
++	+-----v--------------v---------------v-----+
++	|                                          |
++	+-----^-------+              +-------^-----+
++	      |	      |     core     |       |
++	+-----v----+  |	             |  +----v-----+
++	| device   |  |	             |  | device   |
++	| driver 1 |  |              |	| driver 2 |
++	+-----^----+  |              |  +----^-----+
++	      |	      |	  services   |       |
++	+-----v-------+              +-------v-----+
++	|                                          |
++	+-----------------^----^-------------------+
++			  |    |
++			  |  +-v---------+
++			  |  | algorithm |
++			  |  |  driver   |
++			  |  +-v---------+
++			  |    |
++			+-v----v-+
++			|  bus   |
++			| driver |
++			+--------+
++
++Clients talk to the core to attach device drivers and bus adapters, and
++to instruct device drivers to perform actions.  Device drivers then talk
++to the core to perform L3 bus transactions via the algorithm driver and
++ultimately bus driver.
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/Documentation/serial/driver	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,208 @@
++
++			Low Level Serial API
++			--------------------
++
++
++   $Id$
++
++
++This document is meant as a brief overview of some aspects of the new serial
++driver.  It is not complete, any questions you have should be directed to
++<rmk@arm.linux.org.uk>
++
++The reference implementation is contained within serial_amba.c.
++
++
++
++Low Level Serial Hardware Driver
++--------------------------------
++
++The low level serial hardware driver is responsible for supplying port
++information (defined by uart_port) and a set of control methods (defined
++by uart_ops) to the core serial driver.  The low level driver is also
++responsible for handling interrupts for the port, and providing any
++console support.
++
++
++Console Support
++---------------
++
++The serial core provides a few helper functions.  This includes identifing
++the correct port structure (via uart_get_console) and decoding command line
++arguments (uart_parse_options).
++
++
++Locking
++-------
++
++Generally, all locking is done by the core driver, except for the interrupt
++functions.  It is the responsibility of the low level hardware driver to
++perform the necessary locking there using info->lock. (since it is running
++in an interrupt, you only need to use spin_lock() and spin_unlock() from
++the interrupt handler).
++
++
++uart_ops
++--------
++
++The uart_ops structure is the main interface between serial_core and the
++hardware specific driver.  It contains all the methods to control the
++hardware.
++
++  tx_empty(port)
++	This function tests whether the transmitter fifo and shifter
++	for the port described by 'port' is empty.  If it is empty,
++	this function should return TIOCSER_TEMT, otherwise return 0.
++	If the port does not support this operation, then it should
++	return TIOCSER_TEMT.
++
++  set_mctrl(port, mctrl)
++	This function sets the modem control lines for port described
++	by 'port' to the state described by mctrl.  The relevant bits
++	of mctrl are:
++		- TIOCM_RTS	RTS signal.
++		- TIOCM_DTR	DTR signal.
++		- TIOCM_OUT1	OUT1 signal.
++		- TIOCM_OUT2	OUT2 signal.
++	If the appropriate bit is set, the signal should be driven
++	active.  If the bit is clear, the signal should be driven
++	inactive.
++
++  get_mctrl(port)
++	Returns the current state of modem control inputs.  The state
++	of the outputs should not be returned, since the core keeps
++	track of their state.  The state information should include:
++		- TIOCM_DCD	state of DCD signal
++		- TIOCM_CTS	state of CTS signal
++		- TIOCM_DSR	state of DSR signal
++		- TIOCM_RI	state of RI signal
++	The bit is set if the signal is currently driven active.  If
++	the port does not support CTS, DCD or DSR, the driver should
++	indicate that the signal is permanently active.  If RI is
++	not available, the signal should not be indicated as active.
++
++  stop_tx(port,from_tty)
++	Stop transmitting characters.  This might be due to the CTS
++	line becoming inactive or the tty layer indicating we want
++	to stop transmission.
++
++  start_tx(port,nonempty,from_tty)
++	start transmitting characters.  (incidentally, nonempty will
++	always be nonzero, and shouldn't be used - it will be dropped).
++
++  stop_rx(port)
++	Stop receiving characters; the port is in the process of
++	being closed.
++
++  enable_ms(port)
++	Enable the modem status interrupts.
++
++  break_ctl(port,ctl)
++	Control the transmission of a break signal.  If ctl is
++	nonzero, the break signal should be transmitted.  The signal
++	should be terminated when another call is made with a zero
++	ctl.
++
++  startup(port,info)
++	Grab any interrupt resources and initialise any low level driver
++	state.  Enable the port for reception.  It should not activate
++	RTS nor DTR; this will be done via a separate call to set_mctrl.
++
++  shutdown(port,info)
++	Disable the port, disable any break condition that may be in
++	effect, and free any interrupt resources.  It should not disable
++	RTS nor DTR; this will have already been done via a separate
++	call to set_mctrl.
++
++  change_speed(port,cflag,iflag,quot)
++	Change the port parameters, including word length, parity, stop
++	bits.  Update read_status_mask and ignore_status_mask to indicate
++	the types of events we are interested in receiving.  Relevant
++	cflag bits are:
++		CSIZE	- word size
++		CSTOPB	- 2 stop bits
++		PARENB	- parity enable
++		PARODD	- odd parity (when PARENB is in force)
++		CREAD	- enable reception of characters (if not set,
++			  still receive characters from the port, but
++			  throw them away.
++		CRTSCTS	- if set, enable CTS status change reporting
++		CLOCAL	- if not set, enable modem status change
++			  reporting.
++	Relevant iflag bits are:
++		INPCK	- enable frame and parity error events to be
++			  passed to the TTY layer.
++		BRKINT
++		PARMRK	- both of these enable break events to be
++			  passed to the TTY layer.
++
++		IGNPAR	- ignore parity and framing errors
++		IGNBRK	- ignore break errors,  If IGNPAR is also
++			  set, ignore overrun errors as well.
++	The interaction of the iflag bits is as follows (parity error
++	given as an example):
++	Parity error	INPCK	IGNPAR
++	None		n/a	n/a	character received
++	Yes		n/a	0	character discarded
++	Yes		0	1	character received, marked as
++					TTY_NORMAL
++	Yes		1	1	character received, marked as
++					TTY_PARITY
++
++  pm(port,state,oldstate)
++	perform any power management related activities on the specified
++	port.  state indicates the new state (defined by ACPI D0-D3),
++	oldstate indicates the previous state.  Essentially, D0 means
++	fully on, D3 means powered down.
++
++	This function should not be used to grab any resources.
++
++  type(port)
++	Return a pointer to a string constant describing the specified
++	port, or return NULL, in which case the string 'unknown' is
++	substituted.
++
++  release_port(port)
++	Release any memory and IO region resources currently in use by
++	the port.
++
++  request_port(port)
++	Request any memory and IO region resources required by the port.
++	If any fail, no resources should be registered when this function
++	returns, and it should return -EBUSY on failure.
++
++  config_port(port,type)
++	Perform any autoconfiguration steps required for the port.  `type`
++	contains a bit mask of the required configuration.  UART_CONFIG_TYPE
++	indicates that the port requires detection and identification.
++	port->type should be set to the type found, or PORT_UNKNOWN if
++	no port was detected.
++
++	UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal,
++	which should be probed using standard kernel autoprobing techniques.
++	This is not necessary on platforms where ports have interrupts
++	internally hard wired (eg, system on a chip implementations).
++
++  verify_port(port,serinfo)
++	Verify the new serial port information contained within serinfo is
++	suitable for this port type.
++
++  ioctl(port,cmd,arg)
++	Perform any port specific IOCTLs.  IOCTL commands must be defined
++	using the standard numbering system found in <asm/ioctl.h>
++
++
++Other notes
++-----------
++
++It is intended some day to drop the 'unused' entries from uart_port, and
++allow low level drivers to register their own individual uart_port's with
++the core.  This will allow drivers to use uart_port as a pointer to a
++structure containing both the uart_port entry with their own extensions,
++thus:
++
++	struct my_port {
++		struct uart_port	port;
++		int			my_stuff;
++	};
++
+--- linux-2.4.25/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/Makefile	2004-03-31 17:15:08.000000000 +0200
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 4
+ SUBLEVEL = 25
+-EXTRAVERSION =
++EXTRAVERSION =-vrs2
+ 
+ KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+ 
+@@ -137,7 +137,10 @@
+ 
+ DRIVERS-$(CONFIG_ACPI_BOOT) += drivers/acpi/acpi.o
+ DRIVERS-$(CONFIG_PARPORT) += drivers/parport/driver.o
+-DRIVERS-y += drivers/char/char.o \
++DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
++DRIVERS-$(CONFIG_L3) += drivers/l3/l3.o
++DRIVERS-y += drivers/serial/serial.o \
++	drivers/char/char.o \
+ 	drivers/block/block.o \
+ 	drivers/misc/misc.o \
+ 	drivers/net/net.o
+@@ -161,6 +164,7 @@
+ DRIVERS-y += drivers/cdrom/driver.o
+ endif
+ 
++DRIVERS-$(CONFIG_SSI) += drivers/ssi/ssi.o
+ DRIVERS-$(CONFIG_SOUND) += drivers/sound/sounddrivers.o
+ DRIVERS-$(CONFIG_PCI) += drivers/pci/driver.o
+ DRIVERS-$(CONFIG_MTD) += drivers/mtd/mtdlink.o
+@@ -186,7 +190,6 @@
+ DRIVERS-$(CONFIG_HIL) += drivers/hil/hil.o
+ DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
+ DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
+-DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
+ DRIVERS-$(CONFIG_PHONE) += drivers/telephony/telephony.o
+ DRIVERS-$(CONFIG_MD) += drivers/md/mddev.o
+ DRIVERS-$(CONFIG_GSC) += drivers/gsc/gscbus.o
+@@ -194,6 +197,8 @@
+ DRIVERS-$(CONFIG_HOTPLUG_PCI) += drivers/hotplug/vmlinux-obj.o
+ DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o
+ DRIVERS-$(CONFIG_CRYPTO) += crypto/crypto.o
++DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o
++DRIVERS-$(CONFIG_ARCH_AT91RM9200) += drivers/at91/at91drv.o
+ 
+ DRIVERS := $(DRIVERS-y)
+ 
+@@ -273,11 +278,6 @@
+ 
+ export	NETWORKS DRIVERS LIBS HEAD LDFLAGS LINKFLAGS MAKEBOOT ASFLAGS
+ 
+-.S.s:
+-	$(CPP) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -o $*.s $<
+-.S.o:
+-	$(CC) $(AFLAGS) $(AFLAGS_KERNEL) -traditional -c -o $*.o $<
+-
+ Version: dummy
+ 	@rm -f include/linux/compile.h
+ 
+--- linux-2.4.25/Rules.make~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/Rules.make	2004-03-31 17:15:08.000000000 +0200
+@@ -51,15 +51,15 @@
+ #
+ 
+ %.s: %.c
+-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -S $< -o $@
++	$(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$(*F)) $(CFLAGS_$@) -S $< -o $@
+ 
+ %.i: %.c
+-	$(CPP) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) $< > $@
++	$(CPP) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$(*F)) $(CFLAGS_$@) $< > $@
+ 
+ %.o: %.c
+-	$(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -c -o $@ $<
++	$(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$(*F)) $(CFLAGS_$@) -c -o $@ $<
+ 	@ ( \
+-	    echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$@))))' ; \
++	    echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$(*F)) $(CFLAGS_$@))),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$(*F)) $$(CFLAGS_$@))))' ; \
+ 	    echo 'FILES_FLAGS_UP_TO_DATE += $@' ; \
+ 	    echo 'endif' \
+ 	) > $(dir $@)/.$(notdir $@).flags
+@@ -272,7 +272,8 @@
+ endif # CONFIG_MODVERSIONS
+ 
+ ifneq "$(strip $(export-objs))" ""
+-$(export-objs): $(export-objs:.o=.c) $(TOPDIR)/include/linux/modversions.h
++$(export-objs): $(TOPDIR)/include/linux/modversions.h
++$(export-objs): %.o: %.c
+ 	$(CC) $(CFLAGS) $(EXTRA_CFLAGS_nostdinc) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(CFLAGS_$@) -DEXPORT_SYMTAB -c $(@:.o=.c)
+ 	@ ( \
+ 	    echo 'ifeq ($(strip $(subst $(comma),:,$(CFLAGS) $(EXTRA_CFLAGS_nostdinc) $(CFLAGS_$@) -DEXPORT_SYMTAB)),$$(strip $$(subst $$(comma),:,$$(CFLAGS) $$(EXTRA_CFLAGS_nostdinc) $$(CFLAGS_$@) -DEXPORT_SYMTAB)))' ; \
+--- linux-2.4.25/arch/alpha/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/alpha/config.in	2004-03-31 17:15:08.000000000 +0200
+@@ -7,6 +7,7 @@
+ define_bool CONFIG_UID16 n
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ mainmenu_name "Kernel configuration of Linux for Alpha machines"
+ 
+--- linux-2.4.25/arch/arm/Makefile~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/Makefile	2004-03-31 17:15:08.000000000 +0200
+@@ -52,7 +52,7 @@
+ 
+ CFLAGS_BOOT	:=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+ CFLAGS		+=$(apcs-y) $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Uarm
+-AFLAGS		+=$(apcs-y) $(arch-y) -mno-fpu -msoft-float
++AFLAGS		+=$(apcs-y) $(arch-y) -msoft-float
+ 
+ ifeq ($(CONFIG_CPU_26),y)
+ PROCESSOR	:= armo
+--- linux-2.4.25/arch/arm/boot/compressed/head.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/boot/compressed/head.S	2004-03-31 17:15:08.000000000 +0200
+@@ -40,6 +40,14 @@
+ 		.macro	writeb,	rb
+ 		strb	\rb, [r3, #0x3f8 << 2]
+ 		.endm
++#elif defined(CONFIG_ARCH_RISCSTATION)
++		.macro	loadsp,	rb
++		mov	\rb, #0x03000000
++		orr	\rb, \rb, #0x00010000
++		.endm
++		.macro	writeb,	rb
++		strb	\rb, [r3, #0x3f8 << 2]
++		.endm
+ #elif defined(CONFIG_ARCH_INTEGRATOR)
+ 		.macro	loadsp, rb
+ 		mov	\rb, #0x16000000
+@@ -396,6 +404,20 @@
+ 		mcr	p15, 0, r0, c1, c0, 0	@ load control register
+ 		mov	pc, r12
+ 
++__arm7_cache_on:
++		mov	r12, lr
++		bl	__setup_mmu
++		mov	r0, #0
++		mcr	p15, 0, r0, c7, c0, 0	@ invalidate whole cache v3
++		mcr	p15, 0, r0, c5, c0, 0	@ invalidate whole TLB v3
++		mcr	p15, 0, r3, c2, c0, 0	@ load page table pointer
++		mov	r0, #-1
++		mcr	p15, 0, r0, c3, c0, 0	@ load domain access control
++		mov	r0, #0x7d
++		mcr	p15, 0, r0, c1, c0, 0	@ load control register
++		mov	pc, r12
++
++
+ /*
+  * All code following this line is relocatable.  It is relocated by
+  * the above code to the end of the decompressed kernel image and
+@@ -480,9 +502,9 @@
+ 
+ 		.word	0x41007000		@ ARM7/710
+ 		.word	0xfff8fe00
++		b	__arm7_cache_on
+ 		b	__arm7_cache_off
+-		b	__arm7_cache_off
+-		mov	pc, lr
++		b	__armv3_cache_flush
+ 
+ 		.word	0x41807200		@ ARM720T (writethrough)
+ 		.word	0xffffff00
+@@ -490,14 +512,14 @@
+ 		b	__armv4_cache_off
+ 		mov	pc, lr
+ 
+-		.word	0x41129200		@ ARM920T
+-		.word	0xff00fff0
++		.word	0x41009200		@ ARM920T, ARM922T, ARM926TEJ-S
++		.word	0xff00ff90
+ 		b	__armv4_cache_on
+ 		b	__armv4_cache_off
+ 		b	__armv4_cache_flush
+ 
+-		.word	0x41029220		@ ARM922T
+-		.word	0xff00fff0
++		.word	0x4100a200		@ ARM1020T/E, ARM1022E, ARM1026TEJ-S
++		.word	0xff00ff90
+ 		b	__armv4_cache_on
+ 		b	__armv4_cache_off
+ 		b	__armv4_cache_flush
+--- linux-2.4.25/arch/arm/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/arm/config.in	2004-03-31 17:15:08.000000000 +0200
+@@ -144,6 +144,7 @@
+ mainmenu_option next_comment
+ comment 'AT91RM9200 Implementations'
+ dep_bool '  Atmel AT91RM9200 Development Board' CONFIG_ARCH_AT91RM9200DK $CONFIG_ARCH_AT91RM9200
++dep_bool '  Cogent CSB337' CONFIG_MACH_CSB337 $CONFIG_ARCH_AT91RM9200
+ endmenu
+ 
+ mainmenu_option next_comment
+@@ -189,6 +190,12 @@
+    define_bool CONFIG_ARCH_ACORN n
+ fi
+ 
++if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then
++   define_bool CONFIG_PLD y
++else
++   define_bool CONFIG_PLD n
++fi
++
+ #####################################################################
+ # Footbridge support
+ if [ "$CONFIG_ARCH_CO285" = "y" -o \
+@@ -315,26 +322,42 @@
+ # ARM922T
+ if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then
+    define_bool CONFIG_CPU_ARM922T y
+-   define_bool CONFIG_PLD y
+ else
+-   define_bool CONFIG_CPU_ARM922T n
+-   define_bool CONFIG_PLD n
++   if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
++      bool 'Support ARM922T(Excalibur) processor' CONFIG_ARM922T
++   else
++      define_bool CONFIG_CPU_ARM922T n
++   fi
+ fi
+ 
+ # ARM926T
+ if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+-   bool 'Support ARM926T processor' CONFIG_CPU_ARM926T
++   bool 'Support ARM926TEJ-S processor' CONFIG_CPU_ARM926T
+ else
+    define_bool CONFIG_CPU_ARM926T n
+ fi
+ 
+ # ARM1020
+ if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+-   bool 'Support ARM1020 processor' CONFIG_CPU_ARM1020
++   bool 'Support ARM1020T (Rev0) processor' CONFIG_CPU_ARM1020
+ else
+     define_bool CONFIG_CPU_ARM1020 n
+ fi
+ 
++# ARM1020E
++if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
++   bool 'Support ARM1020E (Rev1) processor' CONFIG_CPU_ARM1020E
++else
++    define_bool CONFIG_CPU_ARM1020E n
++fi
++
++# ARM1022
++if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
++   bool 'Support ARM1022 processor' CONFIG_CPU_ARM1020E
++else
++    define_bool CONFIG_CPU_ARM1022 n
++fi
++
+ # ARM1026EJ-S
+ if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then
+    bool 'Support ARM1026EJ-S processor' CONFIG_CPU_ARM1026
+@@ -388,25 +411,29 @@
+ 
+ if [ "$CONFIG_CPU_ARM720T" = "y" -o "$CONFIG_CPU_ARM920T" = "y" -o \
+      "$CONFIG_CPU_ARM922T" = "y" -o "$CONFIG_CPU_ARM926T" = "y" -o \
+-     "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_ARM1026" = "y" ]; then
++     "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_ARM1020E" = "y" -o \
++     "$CONFIG_CPU_ARM1022" = "y" -o "$CONFIG_CPU_ARM1026" = "y" ]; then
+    dep_bool 'Support Thumb instructions (EXPERIMENTAL)' CONFIG_ARM_THUMB $CONFIG_EXPERIMENTAL
+ fi
+ if [ "$CONFIG_CPU_ARM920T" = "y" -o "$CONFIG_CPU_ARM922T" = "y" -o \
+      "$CONFIG_CPU_ARM926T" = "y" -o "$CONFIG_CPU_ARM1020" = "y" -o \
++     "$CONFIG_CPU_ARM1020E" = "y" -o "$CONFIG_CPU_ARM1022" = "y" -o \
+      "$CONFIG_CPU_ARM1026" = "y" ]; then
+    bool 'Disable I-Cache' CONFIG_CPU_ICACHE_DISABLE
+    bool 'Disable D-Cache' CONFIG_CPU_DCACHE_DISABLE
+-   if [ "$CONFIG_CPU_DISABLE_DCACHE" = "n" ]; then
++   if [ "$CONFIG_CPU_DCACHE_DISABLE" = "n" ]; then
+       bool 'Force write through D-cache' CONFIG_CPU_DCACHE_WRITETHROUGH
+    fi
+ fi
+ if [ "$CONFIG_CPU_ARM926T" = "y" -o "$CONFIG_CPU_ARM1020" = "y" -o \
++     "$CONFIG_CPU_ARM1020E" = "y" -o "$CONFIG_CPU_ARM1022" = "y" -o \
+      "$CONFIG_CPU_ARM1026" = "y" ]; then
+    if [ "$CONFIG_CPU_ICACHE_DISABLE" = "n" -o "$CONFIG_CPU_DCACHE_DISABLE" = "n" ]; then
+       bool 'Round robin I and D cache replacement algorithm' CONFIG_CPU_CACHE_ROUND_ROBIN
+    fi
+ fi
+-if [ "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_ARM1026" = "y" ]; then
++if [ "$CONFIG_CPU_ARM1020" = "y" -o "$CONFIG_CPU_ARM1020E" = "y" -o \
++    "$CONFIG_CPU_ARM1026" = "y" -o "$CONFIG_CPU_ARM1022" = "y" ]; then
+    bool 'Disable branch prediction' CONFIG_CPU_BPREDICT_DISABLE
+ fi
+ 
+@@ -729,10 +756,7 @@
+ dep_bool '  Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL
+ dep_bool '    Kernel low-level debugging messages via footbridge serial port' CONFIG_DEBUG_DC21285_PORT $CONFIG_DEBUG_LL $CONFIG_FOOTBRIDGE
+ dep_bool '    Kernel low-level debugging messages via UART2' CONFIG_DEBUG_CLPS711X_UART2 $CONFIG_DEBUG_LL $CONFIG_ARCH_CLPS711X
+-
+-int 'Kernel messages buffer length shift (0 = default)' CONFIG_LOG_BUF_SHIFT 0
+-
+ endmenu
+ 
+-source crypto/Config.in
+ source lib/Config.in
++
+--- linux-2.4.25/arch/arm/def-configs/at91rm9200dk~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/arm/def-configs/at91rm9200dk	2004-03-31 17:15:08.000000000 +0200
+@@ -111,6 +111,7 @@
+ # AT91RM9200 Implementations
+ #
+ CONFIG_ARCH_AT91RM9200DK=y
++# CONFIG_MACH_CSB337 is not set
+ 
+ #
+ # CLPS711X/EP721X Implementations
+@@ -125,6 +126,7 @@
+ # CONFIG_ARCH_EP7211 is not set
+ # CONFIG_ARCH_EP7212 is not set
+ # CONFIG_ARCH_ACORN is not set
++# CONFIG_PLD is not set
+ # CONFIG_FOOTBRIDGE is not set
+ # CONFIG_FOOTBRIDGE_HOST is not set
+ # CONFIG_FOOTBRIDGE_ADDIN is not set
+@@ -135,9 +137,10 @@
+ # CONFIG_CPU_ARM720T is not set
+ CONFIG_CPU_ARM920T=y
+ # CONFIG_CPU_ARM922T is not set
+-# CONFIG_PLD is not set
+ # CONFIG_CPU_ARM926T is not set
+ # CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1020E is not set
++# CONFIG_CPU_ARM1022 is not set
+ # CONFIG_CPU_ARM1026 is not set
+ # CONFIG_CPU_SA110 is not set
+ # CONFIG_CPU_SA1100 is not set
+@@ -146,6 +149,7 @@
+ # CONFIG_ARM_THUMB is not set
+ # CONFIG_CPU_ICACHE_DISABLE is not set
+ # CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+ # CONFIG_DISCONTIGMEM is not set
+ 
+ #
+@@ -164,6 +168,7 @@
+ # CONFIG_BSD_PROCESS_ACCT is not set
+ CONFIG_SYSCTL=y
+ CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
+ # CONFIG_FPE_FASTFPE is not set
+ CONFIG_KCORE_ELF=y
+ # CONFIG_KCORE_AOUT is not set
+@@ -173,6 +178,9 @@
+ # CONFIG_PM is not set
+ # CONFIG_ARTHUR is not set
+ CONFIG_CMDLINE="mem=32M console=ttyS0,115200 initrd=0x20210000,3145728 root=/dev/ram rw"
++CONFIG_LEDS=y
++CONFIG_LEDS_TIMER=y
++# CONFIG_LEDS_CPU is not set
+ CONFIG_ALIGNMENT_TRAP=y
+ 
+ #
+@@ -204,6 +212,7 @@
+ # CONFIG_MTD_CFI_ADV_OPTIONS is not set
+ # CONFIG_MTD_CFI_INTELEXT is not set
+ CONFIG_MTD_CFI_AMDSTD=y
++# CONFIG_MTD_CFI_STAA is not set
+ # CONFIG_MTD_RAM is not set
+ # CONFIG_MTD_ROM is not set
+ # CONFIG_MTD_ABSENT is not set
+@@ -230,7 +239,9 @@
+ # CONFIG_MTD_AUTCPU12 is not set
+ # CONFIG_MTD_EDB7312 is not set
+ # CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_CEIVA is not set
+ # CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA is not set
+ 
+ #
+ # Self-contained MTD device drivers
+@@ -250,9 +261,9 @@
+ # NAND Flash Device Drivers
+ #
+ CONFIG_MTD_NAND=y
+-CONFIG_MTD_NAND_ECC=y
+ # CONFIG_MTD_NAND_VERIFY_WRITE is not set
+-CONFIG_MTD_AT91_SMARTMEDIA=y
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_AT91_SMARTMEDIA is not set
+ 
+ #
+ # Plug and Play configuration
+@@ -269,6 +280,7 @@
+ # CONFIG_BLK_CPQ_DA is not set
+ # CONFIG_BLK_CPQ_CISS_DA is not set
+ # CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_CISS_MONITOR_THREAD is not set
+ # CONFIG_BLK_DEV_DAC960 is not set
+ # CONFIG_BLK_DEV_UMEM is not set
+ # CONFIG_BLK_DEV_LOOP is not set
+@@ -276,6 +288,7 @@
+ CONFIG_BLK_DEV_RAM=y
+ CONFIG_BLK_DEV_RAM_SIZE=8192
+ CONFIG_BLK_DEV_INITRD=y
++# CONFIG_BLK_STATS is not set
+ 
+ #
+ # Multi-device support (RAID and LVM)
+@@ -312,6 +325,12 @@
+ # CONFIG_SYN_COOKIES is not set
+ # CONFIG_IPV6 is not set
+ # CONFIG_KHTTPD is not set
++
++#
++#    SCTP Configuration (EXPERIMENTAL)
++#
++CONFIG_IPV6_SCTP__=y
++# CONFIG_IP_SCTP is not set
+ # CONFIG_ATM is not set
+ # CONFIG_VLAN_8021Q is not set
+ # CONFIG_IPX is not set
+@@ -382,10 +401,12 @@
+ #
+ # CONFIG_ACENIC is not set
+ # CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
+ # CONFIG_MYRI_SBUS is not set
+ # CONFIG_NS83820 is not set
+ # CONFIG_HAMACHI is not set
+ # CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
+ # CONFIG_SK98LIN is not set
+ # CONFIG_TIGON3 is not set
+ # CONFIG_FDDI is not set
+@@ -455,6 +476,8 @@
+ # CONFIG_INPUT_MOUSEDEV is not set
+ # CONFIG_INPUT_JOYDEV is not set
+ # CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_MX1TS is not set
+ 
+ #
+ # Character devices
+@@ -502,6 +525,7 @@
+ #
+ CONFIG_I2C=y
+ # CONFIG_I2C_ALGOBIT is not set
++# CONFIG_SCx200_ACB is not set
+ # CONFIG_I2C_ALGOPCF is not set
+ CONFIG_I2C_AT91=y
+ CONFIG_I2C_CHARDEV=y
+@@ -528,6 +552,11 @@
+ #
+ # CONFIG_INPUT_GAMEPORT is not set
+ # CONFIG_QIC02_TAPE is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_IPMI_PANIC_EVENT is not set
++# CONFIG_IPMI_DEVICE_INTERFACE is not set
++# CONFIG_IPMI_KCS is not set
++# CONFIG_IPMI_WATCHDOG is not set
+ 
+ #
+ # Watchdog Cards
+@@ -536,12 +565,14 @@
+ CONFIG_WATCHDOG_NOWAYOUT=y
+ # CONFIG_ACQUIRE_WDT is not set
+ # CONFIG_ADVANTECH_WDT is not set
++# CONFIG_ALIM1535_WDT is not set
+ # CONFIG_ALIM7101_WDT is not set
+ # CONFIG_SC520_WDT is not set
+ # CONFIG_PCWATCHDOG is not set
+ # CONFIG_21285_WATCHDOG is not set
+ # CONFIG_977_WATCHDOG is not set
+ # CONFIG_SA1100_WATCHDOG is not set
++# CONFIG_EPXA_WATCHDOG is not set
+ # CONFIG_OMAHA_WATCHDOG is not set
+ CONFIG_AT91_WATCHDOG=y
+ # CONFIG_EUROTECH_WDT is not set
+@@ -551,11 +582,16 @@
+ # CONFIG_MIXCOMWD is not set
+ # CONFIG_60XX_WDT is not set
+ # CONFIG_SC1200_WDT is not set
++# CONFIG_SCx200_WDT is not set
+ # CONFIG_SOFT_WATCHDOG is not set
+ # CONFIG_W83877F_WDT is not set
+ # CONFIG_WDT is not set
+ # CONFIG_WDTPCI is not set
+ # CONFIG_MACHZ_WDT is not set
++# CONFIG_AMD7XX_TCO is not set
++# CONFIG_SCx200 is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
+ # CONFIG_NVRAM is not set
+ # CONFIG_RTC is not set
+ CONFIG_AT91_RTC=y
+@@ -568,6 +604,10 @@
+ #
+ # CONFIG_FTAPE is not set
+ # CONFIG_AGP is not set
++
++#
++# Direct Rendering Manager (XFree86 DRI support)
++#
+ # CONFIG_DRM is not set
+ 
+ #
+@@ -579,6 +619,7 @@
+ # File systems
+ #
+ # CONFIG_QUOTA is not set
++# CONFIG_QFMT_V2 is not set
+ # CONFIG_AUTOFS_FS is not set
+ # CONFIG_AUTOFS4_FS is not set
+ # CONFIG_REISERFS_FS is not set
+@@ -588,6 +629,9 @@
+ # CONFIG_ADFS_FS_RW is not set
+ # CONFIG_AFFS_FS is not set
+ # CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
+ # CONFIG_BFS_FS is not set
+ # CONFIG_EXT3_FS is not set
+ # CONFIG_JBD is not set
+@@ -605,6 +649,9 @@
+ # CONFIG_ISO9660_FS is not set
+ # CONFIG_JOLIET is not set
+ # CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
+ # CONFIG_MINIX_FS is not set
+ # CONFIG_VXFS_FS is not set
+ # CONFIG_NTFS_FS is not set
+@@ -624,6 +671,11 @@
+ # CONFIG_UDF_RW is not set
+ # CONFIG_UFS_FS is not set
+ # CONFIG_UFS_FS_WRITE is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_XFS_TRACE is not set
++# CONFIG_XFS_DEBUG is not set
+ 
+ #
+ # Network File Systems
+@@ -632,9 +684,11 @@
+ # CONFIG_INTERMEZZO_FS is not set
+ # CONFIG_NFS_FS is not set
+ # CONFIG_NFS_V3 is not set
++# CONFIG_NFS_DIRECTIO is not set
+ # CONFIG_ROOT_NFS is not set
+ # CONFIG_NFSD is not set
+ # CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
+ # CONFIG_SUNRPC is not set
+ # CONFIG_LOCKD is not set
+ # CONFIG_SMB_FS is not set
+@@ -648,7 +702,6 @@
+ # CONFIG_NCPFS_NLS is not set
+ # CONFIG_NCPFS_EXTRAS is not set
+ # CONFIG_ZISOFS_FS is not set
+-# CONFIG_ZLIB_FS_INFLATE is not set
+ 
+ #
+ # Partition Types
+@@ -674,16 +727,18 @@
+ # CONFIG_USB_DEBUG is not set
+ # CONFIG_USB_DEVICEFS is not set
+ # CONFIG_USB_BANDWIDTH is not set
+-# CONFIG_USB_LONG_TIMEOUT is not set
+ # CONFIG_USB_EHCI_HCD is not set
+ # CONFIG_USB_UHCI is not set
+ # CONFIG_USB_UHCI_ALT is not set
+ # CONFIG_USB_OHCI is not set
+ # CONFIG_USB_OHCI_SA1111 is not set
++# CONFIG_USB_SL811HS_ALT is not set
++# CONFIG_USB_SL811HS is not set
+ CONFIG_USB_OHCI_AT91=y
+ # CONFIG_USB_AUDIO is not set
+ # CONFIG_USB_EMI26 is not set
+ # CONFIG_USB_BLUETOOTH is not set
++# CONFIG_USB_MIDI is not set
+ # CONFIG_USB_STORAGE is not set
+ # CONFIG_USB_STORAGE_DEBUG is not set
+ # CONFIG_USB_STORAGE_DATAFAB is not set
+@@ -692,6 +747,7 @@
+ # CONFIG_USB_STORAGE_DPCM is not set
+ # CONFIG_USB_STORAGE_HP8200e is not set
+ # CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
+ # CONFIG_USB_STORAGE_JUMPSHOT is not set
+ # CONFIG_USB_ACM is not set
+ # CONFIG_USB_PRINTER is not set
+@@ -700,7 +756,10 @@
+ # CONFIG_USB_HIDDEV is not set
+ # CONFIG_USB_KBD is not set
+ # CONFIG_USB_MOUSE is not set
++# CONFIG_USB_AIPTEK is not set
+ # CONFIG_USB_WACOM is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
+ # CONFIG_USB_DC2XX is not set
+ # CONFIG_USB_MDC800 is not set
+ # CONFIG_USB_SCANNER is not set
+@@ -718,35 +777,16 @@
+ # USB Serial Converter support
+ #
+ # CONFIG_USB_SERIAL is not set
+-# CONFIG_USB_SERIAL_GENERIC is not set
+-# CONFIG_USB_SERIAL_BELKIN is not set
+-# CONFIG_USB_SERIAL_WHITEHEAT is not set
+-# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+-# CONFIG_USB_SERIAL_EMPEG is not set
+-# CONFIG_USB_SERIAL_FTDI_SIO is not set
+-# CONFIG_USB_SERIAL_VISOR is not set
+-# CONFIG_USB_SERIAL_IPAQ is not set
+-# CONFIG_USB_SERIAL_IR is not set
+-# CONFIG_USB_SERIAL_EDGEPORT is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+-# CONFIG_USB_SERIAL_KEYSPAN is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+-# CONFIG_USB_SERIAL_MCT_U232 is not set
+-# CONFIG_USB_SERIAL_KLSI is not set
+-# CONFIG_USB_SERIAL_PL2303 is not set
+-# CONFIG_USB_SERIAL_CYBERJACK is not set
+-# CONFIG_USB_SERIAL_XIRCOM is not set
+-# CONFIG_USB_SERIAL_OMNINET is not set
+ # CONFIG_USB_RIO500 is not set
+ # CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_TIGL is not set
+ # CONFIG_USB_BRLVGER is not set
++# CONFIG_USB_LCD is not set
++
++#
++# Support for USB gadgets
++#
++# CONFIG_USB_GADGET is not set
+ 
+ #
+ # Bluetooth support
+@@ -770,3 +810,10 @@
+ CONFIG_DEBUG_LL=y
+ # CONFIG_DEBUG_DC21285_PORT is not set
+ # CONFIG_DEBUG_CLPS711X_UART2 is not set
++
++#
++# Library routines
++#
++CONFIG_CRC32=y
++# CONFIG_ZLIB_INFLATE is not set
++# CONFIG_ZLIB_DEFLATE is not set
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/def-configs/csb337	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,760 @@
++#
++# Automatically generated by make menuconfig: don't edit
++#
++CONFIG_ARM=y
++# CONFIG_EISA is not set
++# CONFIG_SBUS is not set
++# CONFIG_MCA is not set
++CONFIG_UID16=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
++# CONFIG_GENERIC_BUST_SPINLOCK is not set
++# CONFIG_GENERIC_ISA_DMA is not set
++
++#
++# Code maturity level options
++#
++CONFIG_EXPERIMENTAL=y
++# CONFIG_OBSOLETE is not set
++
++#
++# Loadable module support
++#
++CONFIG_MODULES=y
++# CONFIG_MODVERSIONS is not set
++CONFIG_KMOD=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_ANAKIN is not set
++# CONFIG_ARCH_ARCA5K is not set
++# CONFIG_ARCH_CLPS7500 is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CO285 is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_CAMELOT is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_OMAHA is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_MX1ADS is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_RISCSTATION is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_SHARK is not set
++CONFIG_ARCH_AT91RM9200=y
++
++#
++# Archimedes/A5000 Implementations
++#
++# CONFIG_ARCH_ARC is not set
++# CONFIG_ARCH_A5K is not set
++
++#
++# Footbridge Implementations
++#
++# CONFIG_ARCH_CATS is not set
++# CONFIG_ARCH_PERSONAL_SERVER is not set
++# CONFIG_ARCH_EBSA285_ADDIN is not set
++# CONFIG_ARCH_EBSA285_HOST is not set
++# CONFIG_ARCH_NETWINDER is not set
++
++#
++# SA11x0 Implementations
++#
++# CONFIG_SA1100_ACCELENT is not set
++# CONFIG_SA1100_ASSABET is not set
++# CONFIG_ASSABET_NEPONSET is not set
++# CONFIG_SA1100_ADSAGC is not set
++# CONFIG_SA1100_ADSBITSY is not set
++# CONFIG_SA1100_ADSBITSYPLUS is not set
++# CONFIG_SA1100_BRUTUS is not set
++# CONFIG_SA1100_CEP is not set
++# CONFIG_SA1100_CERF is not set
++# CONFIG_SA1100_H3100 is not set
++# CONFIG_SA1100_H3600 is not set
++# CONFIG_SA1100_H3800 is not set
++# CONFIG_SA1100_H3XXX is not set
++# CONFIG_H3600_SLEEVE is not set
++# CONFIG_SA1100_EXTENEX1 is not set
++# CONFIG_SA1100_FLEXANET is not set
++# CONFIG_SA1100_FREEBIRD is not set
++# CONFIG_SA1100_FRODO is not set
++# CONFIG_SA1100_GRAPHICSCLIENT is not set
++# CONFIG_SA1100_GRAPHICSMASTER is not set
++# CONFIG_SA1100_HACKKIT is not set
++# CONFIG_SA1100_BADGE4 is not set
++# CONFIG_SA1100_JORNADA720 is not set
++# CONFIG_SA1100_HUW_WEBPANEL is not set
++# CONFIG_SA1100_ITSY is not set
++# CONFIG_SA1100_LART is not set
++# CONFIG_SA1100_NANOENGINE is not set
++# CONFIG_SA1100_OMNIMETER is not set
++# CONFIG_SA1100_PANGOLIN is not set
++# CONFIG_SA1100_PLEB is not set
++# CONFIG_SA1100_PT_SYSTEM3 is not set
++# CONFIG_SA1100_SHANNON is not set
++# CONFIG_SA1100_SHERMAN is not set
++# CONFIG_SA1100_SIMPAD is not set
++# CONFIG_SA1100_SIMPUTER is not set
++# CONFIG_SA1100_PFS168 is not set
++# CONFIG_SA1100_VICTOR is not set
++# CONFIG_SA1100_XP860 is not set
++# CONFIG_SA1100_YOPY is not set
++# CONFIG_SA1100_USB is not set
++# CONFIG_SA1100_USB_NETLINK is not set
++# CONFIG_SA1100_USB_CHAR is not set
++# CONFIG_SA1100_SSP is not set
++
++#
++# AT91RM9200 Implementations
++#
++# CONFIG_ARCH_AT91RM9200DK is not set
++CONFIG_MACH_CSB337=y
++
++#
++# CLPS711X/EP721X Implementations
++#
++# CONFIG_ARCH_AUTCPU12 is not set
++# CONFIG_ARCH_CDB89712 is not set
++# CONFIG_ARCH_CLEP7312 is not set
++# CONFIG_ARCH_EDB7211 is not set
++# CONFIG_ARCH_FORTUNET is not set
++# CONFIG_ARCH_GUIDEA07 is not set
++# CONFIG_ARCH_P720T is not set
++# CONFIG_ARCH_EP7211 is not set
++# CONFIG_ARCH_EP7212 is not set
++# CONFIG_ARCH_ACORN is not set
++# CONFIG_PLD is not set
++# CONFIG_FOOTBRIDGE is not set
++# CONFIG_FOOTBRIDGE_HOST is not set
++# CONFIG_FOOTBRIDGE_ADDIN is not set
++CONFIG_CPU_32=y
++# CONFIG_CPU_26 is not set
++# CONFIG_CPU_ARM610 is not set
++# CONFIG_CPU_ARM710 is not set
++# CONFIG_CPU_ARM720T is not set
++CONFIG_CPU_ARM920T=y
++# CONFIG_CPU_ARM922T is not set
++# CONFIG_CPU_ARM926T is not set
++# CONFIG_CPU_ARM1020 is not set
++# CONFIG_CPU_ARM1020E is not set
++# CONFIG_CPU_ARM1022 is not set
++# CONFIG_CPU_ARM1026 is not set
++# CONFIG_CPU_SA110 is not set
++# CONFIG_CPU_SA1100 is not set
++# CONFIG_CPU_32v3 is not set
++CONFIG_CPU_32v4=y
++# CONFIG_ARM_THUMB is not set
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_DISCONTIGMEM is not set
++
++#
++# General setup
++#
++# CONFIG_PCI is not set
++# CONFIG_ISA is not set
++# CONFIG_ISA_DMA is not set
++# CONFIG_ZBOOT_ROM is not set
++CONFIG_ZBOOT_ROM_TEXT=0
++CONFIG_ZBOOT_ROM_BSS=0
++# CONFIG_HOTPLUG is not set
++# CONFIG_PCMCIA is not set
++CONFIG_NET=y
++CONFIG_SYSVIPC=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++CONFIG_SYSCTL=y
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++CONFIG_KCORE_ELF=y
++# CONFIG_KCORE_AOUT is not set
++# CONFIG_BINFMT_AOUT is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_MISC is not set
++# CONFIG_PM is not set
++# CONFIG_ARTHUR is not set
++CONFIG_CMDLINE="mem=32M console=ttyS0,38400 initrd=0x20210000,3145728 root=/dev/ram rw"
++# CONFIG_LEDS is not set
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Parallel port support
++#
++# CONFIG_PARPORT is not set
++
++#
++# Memory Technology Devices (MTD)
++#
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++# CONFIG_MTD_PARTITIONS is not set
++# CONFIG_MTD_CONCAT is not set
++# CONFIG_MTD_REDBOOT_PARTS is not set
++# CONFIG_MTD_CMDLINE_PARTS is not set
++# CONFIG_MTD_AFS_PARTS is not set
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++CONFIG_MTD_CFI=y
++CONFIG_MTD_JEDECPROBE=y
++CONFIG_MTD_GEN_PROBE=y
++# CONFIG_MTD_CFI_ADV_OPTIONS is not set
++CONFIG_MTD_CFI_INTELEXT=y
++# CONFIG_MTD_CFI_AMDSTD is not set
++# CONFIG_MTD_CFI_STAA is not set
++# CONFIG_MTD_RAM is not set
++CONFIG_MTD_ROM=y
++# CONFIG_MTD_ABSENT is not set
++# CONFIG_MTD_OBSOLETE_CHIPS is not set
++# CONFIG_MTD_AMDSTD is not set
++# CONFIG_MTD_SHARP is not set
++# CONFIG_MTD_JEDEC is not set
++
++#
++# Mapping drivers for chip access
++#
++CONFIG_MTD_PHYSMAP=y
++CONFIG_MTD_PHYSMAP_START=10000000
++CONFIG_MTD_PHYSMAP_LEN=200000
++CONFIG_MTD_PHYSMAP_BUSWIDTH=2
++# CONFIG_MTD_NORA is not set
++# CONFIG_MTD_ARM_INTEGRATOR is not set
++# CONFIG_MTD_CDB89712 is not set
++# CONFIG_MTD_SA1100 is not set
++# CONFIG_MTD_DC21285 is not set
++# CONFIG_MTD_IQ80310 is not set
++# CONFIG_MTD_FORTUNET is not set
++# CONFIG_MTD_EPXA is not set
++# CONFIG_MTD_AUTCPU12 is not set
++# CONFIG_MTD_EDB7312 is not set
++# CONFIG_MTD_IMPA7 is not set
++# CONFIG_MTD_CEIVA is not set
++# CONFIG_MTD_PCI is not set
++# CONFIG_MTD_PCMCIA is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_PMC551 is not set
++# CONFIG_MTD_SLRAM is not set
++CONFIG_MTD_AT91_DATAFLASH=y
++# CONFIG_MTD_AT91_DATAFLASH_CARD is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLKMTD is not set
++# CONFIG_MTD_DOC1000 is not set
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOCPROBE is not set
++
++#
++# NAND Flash Device Drivers
++#
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_AT91_SMARTMEDIA is not set
++
++#
++# Plug and Play configuration
++#
++# CONFIG_PNP is not set
++# CONFIG_ISAPNP is not set
++
++#
++# Block devices
++#
++# CONFIG_BLK_DEV_FD is not set
++# CONFIG_BLK_DEV_XD is not set
++# CONFIG_PARIDE is not set
++# CONFIG_BLK_CPQ_DA is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_CISS_MONITOR_THREAD is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_LOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_SIZE=8192
++# CONFIG_BLK_DEV_INITRD is not set
++# CONFIG_BLK_STATS is not set
++
++#
++# Multi-device support (RAID and LVM)
++#
++# CONFIG_MD is not set
++# CONFIG_BLK_DEV_MD is not set
++# CONFIG_MD_LINEAR is not set
++# CONFIG_MD_RAID0 is not set
++# CONFIG_MD_RAID1 is not set
++# CONFIG_MD_RAID5 is not set
++# CONFIG_MD_MULTIPATH is not set
++# CONFIG_BLK_DEV_LVM is not set
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++# CONFIG_PACKET_MMAP is not set
++# CONFIG_NETLINK_DEV is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_FILTER is not set
++CONFIG_UNIX=y
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_INET_ECN is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_IPV6 is not set
++# CONFIG_KHTTPD is not set
++
++#
++#    SCTP Configuration (EXPERIMENTAL)
++#
++CONFIG_IPV6_SCTP__=y
++# CONFIG_IP_SCTP is not set
++# CONFIG_ATM is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++
++#
++# Appletalk devices
++#
++# CONFIG_DEV_APPLETALK is not set
++# CONFIG_DECNET is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_LLC is not set
++# CONFIG_NET_DIVERT is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_FASTROUTE is not set
++# CONFIG_NET_HW_FLOWCONTROL is not set
++
++#
++# QoS and/or fair queueing
++#
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++
++#
++# Network device support
++#
++CONFIG_NETDEVICES=y
++
++#
++# ARCnet devices
++#
++# CONFIG_ARCNET is not set
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_ETHERTAP is not set
++
++#
++# Ethernet (10 or 100Mbit)
++#
++CONFIG_NET_ETHERNET=y
++# CONFIG_ARM_AM79C961A is not set
++# CONFIG_ARM_CIRRUS is not set
++CONFIG_AT91_ETHER=y
++# CONFIG_AT91_ETHER_RMII is not set
++# CONFIG_SUNLANCE is not set
++# CONFIG_SUNBMAC is not set
++# CONFIG_SUNQE is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_NET_VENDOR_3COM is not set
++# CONFIG_LANCE is not set
++# CONFIG_NET_VENDOR_SMC is not set
++# CONFIG_NET_VENDOR_RACAL is not set
++# CONFIG_NET_ISA is not set
++# CONFIG_NET_PCI is not set
++# CONFIG_NET_POCKET is not set
++
++#
++# Ethernet (1000 Mbit)
++#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++# CONFIG_E1000 is not set
++# CONFIG_MYRI_SBUS is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_TIGON3 is not set
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PLIP is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++
++#
++# Wireless LAN (non-hamradio)
++#
++# CONFIG_NET_RADIO is not set
++
++#
++# Token Ring devices
++#
++# CONFIG_TR is not set
++# CONFIG_NET_FC is not set
++# CONFIG_RCPCI is not set
++# CONFIG_SHAPER is not set
++
++#
++# Wan interfaces
++#
++# CONFIG_WAN is not set
++
++#
++# Amateur Radio support
++#
++# CONFIG_HAMRADIO is not set
++
++#
++# IrDA (infrared) support
++#
++# CONFIG_IRDA is not set
++
++#
++# ATA/ATAPI/MFM/RLL support
++#
++# CONFIG_IDE is not set
++# CONFIG_BLK_DEV_HD is not set
++
++#
++# SCSI support
++#
++# CONFIG_SCSI is not set
++
++#
++# I2O device support
++#
++# CONFIG_I2O is not set
++# CONFIG_I2O_BLOCK is not set
++# CONFIG_I2O_LAN is not set
++# CONFIG_I2O_SCSI is not set
++# CONFIG_I2O_PROC is not set
++
++#
++# ISDN subsystem
++#
++# CONFIG_ISDN is not set
++
++#
++# Input core support
++#
++# CONFIG_INPUT is not set
++# CONFIG_INPUT_KEYBDEV is not set
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++# CONFIG_INPUT_EVDEV is not set
++# CONFIG_INPUT_UINPUT is not set
++# CONFIG_INPUT_MX1TS is not set
++
++#
++# Character devices
++#
++# CONFIG_VT is not set
++# CONFIG_SERIAL is not set
++# CONFIG_SERIAL_EXTENDED is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++CONFIG_AT91_SPIDEV=y
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_ANAKIN is not set
++# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
++# CONFIG_SERIAL_AMBA is not set
++# CONFIG_SERIAL_AMBA_CONSOLE is not set
++# CONFIG_SERIAL_CLPS711X is not set
++# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
++# CONFIG_SERIAL_21285 is not set
++# CONFIG_SERIAL_21285_OLD is not set
++# CONFIG_SERIAL_21285_CONSOLE is not set
++# CONFIG_SERIAL_UART00 is not set
++# CONFIG_SERIAL_UART00_CONSOLE is not set
++# CONFIG_SERIAL_SA1100 is not set
++# CONFIG_SERIAL_SA1100_CONSOLE is not set
++# CONFIG_SERIAL_OMAHA is not set
++# CONFIG_SERIAL_OMAHA_CONSOLE is not set
++CONFIG_SERIAL_AT91=y
++CONFIG_SERIAL_AT91_CONSOLE=y
++# CONFIG_SERIAL_8250 is not set
++# CONFIG_SERIAL_8250_CONSOLE is not set
++# CONFIG_SERIAL_8250_EXTENDED is not set
++# CONFIG_SERIAL_8250_MANY_PORTS is not set
++# CONFIG_SERIAL_8250_SHARE_IRQ is not set
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_MULTIPORT is not set
++# CONFIG_SERIAL_8250_HUB6 is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_UNIX98_PTYS is not set
++
++#
++# I2C support
++#
++CONFIG_I2C=y
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_SCx200_ACB is not set
++# CONFIG_I2C_ALGOPCF is not set
++CONFIG_I2C_AT91=y
++CONFIG_I2C_CHARDEV=y
++CONFIG_I2C_PROC=y
++CONFIG_I2C_DS1307=y
++
++#
++# L3 serial bus support
++#
++# CONFIG_L3 is not set
++# CONFIG_L3_ALGOBIT is not set
++# CONFIG_L3_BIT_SA1100_GPIO is not set
++# CONFIG_L3_SA1111 is not set
++# CONFIG_BIT_SA1100_GPIO is not set
++
++#
++# Mice
++#
++# CONFIG_BUSMOUSE is not set
++# CONFIG_MOUSE is not set
++
++#
++# Joysticks
++#
++# CONFIG_INPUT_GAMEPORT is not set
++# CONFIG_QIC02_TAPE is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_IPMI_PANIC_EVENT is not set
++# CONFIG_IPMI_DEVICE_INTERFACE is not set
++# CONFIG_IPMI_KCS is not set
++# CONFIG_IPMI_WATCHDOG is not set
++
++#
++# Watchdog Cards
++#
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_NOWAYOUT=y
++# CONFIG_ACQUIRE_WDT is not set
++# CONFIG_ADVANTECH_WDT is not set
++# CONFIG_ALIM1535_WDT is not set
++# CONFIG_ALIM7101_WDT is not set
++# CONFIG_SC520_WDT is not set
++# CONFIG_PCWATCHDOG is not set
++# CONFIG_21285_WATCHDOG is not set
++# CONFIG_977_WATCHDOG is not set
++# CONFIG_SA1100_WATCHDOG is not set
++# CONFIG_EPXA_WATCHDOG is not set
++# CONFIG_OMAHA_WATCHDOG is not set
++CONFIG_AT91_WATCHDOG=y
++# CONFIG_EUROTECH_WDT is not set
++# CONFIG_IB700_WDT is not set
++# CONFIG_WAFER_WDT is not set
++# CONFIG_I810_TCO is not set
++# CONFIG_MIXCOMWD is not set
++# CONFIG_60XX_WDT is not set
++# CONFIG_SC1200_WDT is not set
++# CONFIG_SCx200_WDT is not set
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_W83877F_WDT is not set
++# CONFIG_WDT is not set
++# CONFIG_WDTPCI is not set
++# CONFIG_MACHZ_WDT is not set
++# CONFIG_AMD7XX_TCO is not set
++# CONFIG_SCx200 is not set
++# CONFIG_SCx200_GPIO is not set
++# CONFIG_AMD_PM768 is not set
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++CONFIG_AT91_RTC=y
++# CONFIG_DTLK is not set
++# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
++
++#
++# Ftape, the floppy tape device driver
++#
++# CONFIG_FTAPE is not set
++# CONFIG_AGP is not set
++
++#
++# Direct Rendering Manager (XFree86 DRI support)
++#
++# CONFIG_DRM is not set
++
++#
++# Multimedia devices
++#
++# CONFIG_VIDEO_DEV is not set
++
++#
++# File systems
++#
++# CONFIG_QUOTA is not set
++# CONFIG_QFMT_V2 is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_REISERFS_FS is not set
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_ADFS_FS is not set
++# CONFIG_ADFS_FS_RW is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BEFS_DEBUG is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EXT3_FS is not set
++# CONFIG_JBD is not set
++# CONFIG_JBD_DEBUG is not set
++# CONFIG_FAT_FS is not set
++# CONFIG_MSDOS_FS is not set
++# CONFIG_UMSDOS_FS is not set
++# CONFIG_VFAT_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_TMPFS is not set
++CONFIG_RAMFS=y
++# CONFIG_ISO9660_FS is not set
++# CONFIG_JOLIET is not set
++# CONFIG_ZISOFS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_JFS_DEBUG is not set
++# CONFIG_JFS_STATISTICS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_NTFS_FS is not set
++# CONFIG_NTFS_RW is not set
++# CONFIG_HPFS_FS is not set
++CONFIG_PROC_FS=y
++CONFIG_DEVFS_FS=y
++CONFIG_DEVFS_MOUNT=y
++# CONFIG_DEVFS_DEBUG is not set
++# CONFIG_DEVPTS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_QNX4FS_RW is not set
++# CONFIG_ROMFS_FS is not set
++CONFIG_EXT2_FS=y
++# CONFIG_SYSV_FS is not set
++# CONFIG_UDF_FS is not set
++# CONFIG_UDF_RW is not set
++# CONFIG_UFS_FS is not set
++# CONFIG_UFS_FS_WRITE is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_XFS_QUOTA is not set
++# CONFIG_XFS_RT is not set
++# CONFIG_XFS_TRACE is not set
++# CONFIG_XFS_DEBUG is not set
++
++#
++# Network File Systems
++#
++# CONFIG_CODA_FS is not set
++# CONFIG_INTERMEZZO_FS is not set
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_DIRECTIO is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++# CONFIG_NFSD_V3 is not set
++# CONFIG_NFSD_TCP is not set
++CONFIG_SUNRPC=y
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++# CONFIG_SMB_FS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_NCPFS_PACKET_SIGNING is not set
++# CONFIG_NCPFS_IOCTL_LOCKING is not set
++# CONFIG_NCPFS_STRONG is not set
++# CONFIG_NCPFS_NFS_NS is not set
++# CONFIG_NCPFS_OS2_NS is not set
++# CONFIG_NCPFS_SMALLDOS is not set
++# CONFIG_NCPFS_NLS is not set
++# CONFIG_NCPFS_EXTRAS is not set
++# CONFIG_ZISOFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_SMB_NLS is not set
++# CONFIG_NLS is not set
++
++#
++# Multimedia Capabilities Port drivers
++#
++# CONFIG_MCP is not set
++# CONFIG_MCP_SA1100 is not set
++# CONFIG_MCP_UCB1200 is not set
++# CONFIG_MCP_UCB1200_AUDIO is not set
++# CONFIG_MCP_UCB1200_TS is not set
++
++#
++# USB support
++#
++# CONFIG_USB is not set
++
++#
++# Support for USB gadgets
++#
++# CONFIG_USB_GADGET is not set
++
++#
++# Bluetooth support
++#
++# CONFIG_BLUEZ is not set
++
++#
++# Kernel hacking
++#
++CONFIG_FRAME_POINTER=y
++CONFIG_DEBUG_USER=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_NO_PGT_CACHE is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_WAITQ is not set
++# CONFIG_DEBUG_BUGVERBOSE is not set
++# CONFIG_DEBUG_ERRORS is not set
++CONFIG_DEBUG_LL=y
++# CONFIG_DEBUG_DC21285_PORT is not set
++# CONFIG_DEBUG_CLPS711X_UART2 is not set
++
++#
++# Library routines
++#
++CONFIG_CRC32=y
++# CONFIG_ZLIB_INFLATE is not set
++# CONFIG_ZLIB_DEFLATE is not set
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/fastfpe/CPDO.S	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,682 @@
++/*
++The FP structure has 4 words reserved for each register, the first is used just
++for the sign in bit 31, the second and third are for the mantissa (unsigned
++integer, high 32 bit first) and the fourth is the exponent (signed integer).
++The mantissa is always normalized.
++
++If the exponent is 0x80000000, that is the most negative value, the number
++represented is 0 and both mantissa words are also 0.
++
++If the exponent is 0x7fffffff, that is the biggest positive value, the number
++represented is infinity if the high 32 mantissa bit are also 0, otherwise it is
++a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
++
++Decimal and packed decimal numbers are not supported yet.
++
++The parameters to these functions are r0=destination pointer, r1 and r2
++source pointers. r4 is the instruction. They may use r0-r8 and r14. They return
++to fastfpe_next, except CPDO_rnf_core which expects the return address in r14.
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_adf
++CPDO_adf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_adf_extra
++
++	cmp	r1,r2
++	bne	CPDO_suf_s
++
++CPDO_adf_s:
++	subs	r2,r7,r8
++	bge	CPDO_adf_2nd
++	
++	mov	r7,r8
++	rsb	r2,r2,#0
++	cmp	r2,#32
++	ble	CPDO_adf_1st2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r5,r3,lsr r2
++	mov	r3,#0
++	b	CPDO_adf_add
++
++CPDO_adf_1st2:
++	rsb	r8,r2,#32
++	mov	r5,r5,lsr r2
++	orr	r5,r5,r3,lsl r8
++	mov	r3,r3,lsr r2	@ 1. op normalized
++	b	CPDO_adf_add
++
++CPDO_adf_2nd:
++	cmp	r2,#32
++	ble	CPDO_adf_2nd2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r6,r4,lsr r2
++	mov	r4,#0
++	b	CPDO_adf_add
++
++CPDO_adf_2nd2:
++	rsb	r8,r2,#32
++	mov	r6,r6,lsr r2
++	orr	r6,r6,r4,lsl r8
++	mov	r4,r4,lsr r2	@ 2. op normalized
++
++CPDO_adf_add:
++	adds	r5,r5,r6
++	adcs	r3,r3,r4	@ do addition
++	bcc	CPDO_adf_end
++
++	add	r7,r7,#1
++	movs	r3,r3,rrx
++	mov	r5,r5,rrx	@ correct for overflow
++
++CPDO_adf_end:
++	cmp	r7,#0x20000000
++	bge	CPDO_inf
++
++	stmia	r0,{r1,r3,r5,r7}
++	b	fastfpe_next
++
++CPDO_adf_extra:
++	cmp	r7,#0x7fffffff		@ was it the 1st ?
++	bne	CPDO_infnan_2		@ no it was the 2nd
++	cmp	r8,#0x7fffffff		@ if 1st, 2nd too ?
++	bne	CPDO_infnan_1		@ no only 1st
++	cmp	r3,#0
++	cmpeq	r4,#0
++	bne	CPDO_nan_12
++	b	CPDO_inf
++
++/*---------------------------------------------------------------------------*/
++
++CPDO_infnan_1:
++	stmia	r0,{r1,r3,r5,r7}
++	b	fastfpe_next
++
++CPDO_infnan_2:
++	stmia	r0,{r2,r4,r6,r8}
++	b	fastfpe_next
++	
++CPDO_nan_12:
++	orr	r2,r3,r4
++	b	CPDO_inf_1
++
++CPDO_nan:
++	mov	r2,#0x40000000		@ create non signalling NaN
++	b	CPDO_inf_1
++
++CPDO_inf:
++	mov	r2,#0
++CPDO_inf_1:
++	mov	r3,#0
++	mov	r4,#0x7fffffff
++CPDO_store_1234:
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++CPDO_zero:
++	mov	r1,#0
++CPDO_zero_1:
++	mov	r2,#0
++	mov	r3,#0
++	mov	r4,#0x80000000
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_suf
++CPDO_suf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++CPDO_suf_l:
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_suf_extra
++
++	cmp	r1,r2
++	bne	CPDO_adf_s
++
++CPDO_suf_s:
++	subs	r2,r7,r8		@ determine greater number
++	bgt	CPDO_suf_2nd		@ first number is greater
++	blt	CPDO_suf_1st		@ second number is greater
++	cmp	r3,r4			@ also mantissa is important
++	cmpeq	r5,r6
++	bhi	CPDO_suf_2nd		@ first number is greater
++	beq	CPDO_zero
++
++CPDO_suf_1st:
++	eor	r1,r1,#0x80000000	@ second number is greater, invert sign
++	mov	r7,r8
++	rsb	r2,r2,#0
++	cmp	r2,#32
++	ble	CPDO_suf_1st2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r5,r3,lsr r2
++	mov	r3,#0
++	b	CPDO_suf_1st_sub
++
++CPDO_suf_1st2:
++	rsb	r8,r2,#32
++	mov	r5,r5,lsr r2
++	orr	r5,r5,r3,lsl r8
++	mov	r3,r3,lsr r2	@ 1. op normalized
++
++CPDO_suf_1st_sub:
++	subs	r5,r6,r5	@ do subtraction
++	sbc	r3,r4,r3
++	b	CPDO_suf_norm
++
++CPDO_suf_2nd:
++	cmp	r2,#32
++	ble	CPDO_suf_2nd2
++
++	sub	r2,r2,#32
++	cmp	r2,#32
++	movgt	r2,#32
++	mov	r6,r4,lsr r2
++	mov	r4,#0
++	b	CPDO_suf_2nd_sub
++
++CPDO_suf_2nd2:
++	rsb	r8,r2,#32
++	mov	r6,r6,lsr r2
++	orr	r6,r6,r4,lsl r8
++	mov	r4,r4,lsr r2	@ 2. op normalized
++
++CPDO_suf_2nd_sub:
++	subs	r5,r5,r6
++	sbc	r3,r3,r4	@ do subtraction
++
++CPDO_suf_norm:
++	teq	r3,#0		@ normalize 32bit
++	moveq	r3,r5
++	moveq	r5,#0
++	subeq	r7,r7,#32
++	
++	cmp	r3,#0x00010000	@ 16bit
++	movcc	r3,r3,lsl#16
++	orrcc	r3,r3,r5,lsr#16
++	movcc	r5,r5,lsl#16
++	subcc	r7,r7,#16
++	
++	cmp	r3,#0x01000000	@ 8bit
++	movcc	r3,r3,lsl#8
++	orrcc	r3,r3,r5,lsr#24
++	movcc	r5,r5,lsl#8
++	subcc	r7,r7,#8
++	
++	cmp	r3,#0x10000000	@ 4bit
++	movcc	r3,r3,lsl#4
++	orrcc	r3,r3,r5,lsr#28
++	movcc	r5,r5,lsl#4
++	subcc	r7,r7,#4
++	
++	cmp	r3,#0x40000000	@ 2bit
++	movcc	r3,r3,lsl#2
++	orrcc	r3,r3,r5,lsr#30
++	movcc	r5,r5,lsl#2
++	subcc	r7,r7,#2
++	
++	cmp	r3,#0x80000000	@ 1bit
++	movcc	r3,r3,lsl#1
++	orrcc	r3,r3,r5,lsr#31
++	movcc	r5,r5,lsl#1
++	subcc	r7,r7,#1
++
++	cmp	r7,#0xe0000000
++	ble	CPDO_zero_1
++
++	stmia	r0,{r1,r3,r5,r7}
++	b	fastfpe_next
++
++CPDO_suf_extra:
++	cmp	r7,#0x7fffffff		@ was it the 1st ?
++	eorne	r2,r2,#0x80000000	@ change sign, might have been INF
++	bne	CPDO_infnan_2		@ no it was the 2nd
++	cmp	r8,#0x7fffffff		@ if 1st, 2nd too ?
++	bne	CPDO_infnan_1		@ no only 1st
++	cmp	r3,#0
++	cmpeq	r4,#0
++	bne	CPDO_nan_12
++	b	CPDO_nan		@ here is difference with adf !
++
++/*---------------------------------------------------------------------------*/
++
++	.globl CPDO_rsf
++CPDO_rsf:
++	mov	r3,r2
++	ldmia	r1,{r2,r4,r6,r8}
++	ldmia	r3,{r1,r3,r5,r7}
++	b	CPDO_suf_l
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_muf
++CPDO_muf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_muf_extra
++	
++	eor	r1,r1,r2
++	adds	r8,r7,r8
++	bvs	CPDO_zero_1
++
++	umull	r7,r2,r3,r4
++	umull	r14,r3,r6,r3
++	adds	r7,r7,r3	@ r2|r7|r14 = r2|r7|#0 + #0|r3|r14
++	adc	r2,r2,#0
++	umull	r4,r3,r5,r4
++	adds	r14,r14,r4	@ r2|r7|r14 += #0|r3|r4
++	adcs	r7,r7,r3
++	adc	r2,r2,#0
++	umull	r4,r3,r5,r6
++	adds	r14,r14,r3	@ r2|r7|r14 += #0|#0|r3
++	adcs	r7,r7,#0
++	adcs	r2,r2,#0
++
++	bpl	CPDO_muf_norm
++	
++	add	r8,r8,#1
++	b	CPDO_muf_end
++	
++CPDO_muf_norm:
++	adds	r14,r14,r14
++	adcs	r7,r7,r7
++	adcs	r2,r2,r2
++
++CPDO_muf_end:
++	cmp	r8,#0x20000000
++	bge	CPDO_inf
++	cmp	r8,#0xe0000000
++	ble	CPDO_zero_1
++	stmia	r0,{r1,r2,r7,r8}
++	b	fastfpe_next
++
++CPDO_muf_extra:
++	cmp	r7,#0x7fffffff		@ was it the first?
++	bne	CPDO_muf_extra_2nd	@ no, so it was the second
++	cmp	r8,#0x7fffffff		@ yes, second too?
++	bne	CPDO_muf_extra_1st	@ no, only first
++	orr	r3,r3,r4		@ if both inf -> inf, otherwise nan
++	eor	r1,r1,r2		@ sign for the inf case
++	b	CPDO_infnan_1
++
++CPDO_muf_extra_1st:
++	cmp	r3,#0			@ is it a nan?
++	bne	CPDO_infnan_1
++	cmp	r8,#0x80000000		@ is the second 0?
++	beq	CPDO_nan
++	eor	r1,r1,r2		@ correct sign for inf
++	b	CPDO_inf
++
++CPDO_muf_extra_2nd:
++	cmp	r4,#0			@ is it a nan?
++	bne	CPDO_infnan_2
++	cmp	r7,#0x80000000		@ is the first 0?
++	beq	CPDO_nan
++	eor	r1,r1,r2		@ correct sign for inf
++	b	CPDO_inf
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_dvf
++CPDO_dvf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++CPDO_dvf_l:
++	cmp	r7,#0x7fffffff
++	cmpne	r8,#0x7fffffff
++	beq	CPDO_dvf_extra
++	cmp	r8,#0x80000000
++	beq	CPDO_dvf_by0
++
++	eor	r1,r1,r2
++	cmp	r7,#0x80000000
++	beq	CPDO_zero_1
++	
++	sub	r8,r7,r8
++	
++	mov	r2,#0
++	mov	r7,#1
++
++	cmp	r3,r4
++	cmpeq	r5,r6
++	bcs	CPDO_dvf_loop_
++
++	sub	r8,r8,#1
++
++CPDO_dvf_loop:
++	adds	r5,r5,r5
++	adcs	r3,r3,r3
++	bcs	CPDO_dvf_anyway
++CPDO_dvf_loop_:
++	subs	r5,r5,r6
++	sbcs	r3,r3,r4
++	bcs	CPDO_dvf_okay
++
++	adds	r5,r5,r6
++	adc	r3,r3,r4
++	adds	r7,r7,r7
++	adcs	r2,r2,r2
++	bcc	CPDO_dvf_loop
++	b	CPDO_dvf_end
++
++CPDO_dvf_anyway:
++	adcs	r7,r7,r7
++	adcs	r2,r2,r2
++	bcs	CPDO_dvf_end
++	subs	r5,r5,r6
++	sbc	r3,r3,r4
++	b	CPDO_dvf_loop
++
++CPDO_dvf_okay:
++	adcs	r7,r7,r7
++	adcs	r2,r2,r2
++	bcc	CPDO_dvf_loop
++
++CPDO_dvf_end:
++	b	CPDO_muf_end
++
++CPDO_dvf_by0:
++	cmp	R7,#0x80000000
++	beq	CPDO_nan		@ first also 0 -> nan
++	eor	r1,r1,r2		@ otherwise calculatesign for inf
++	b	CPDO_inf
++
++CPDO_dvf_extra:
++	cmp	r7,#0x7fffffff		@ was it the first?
++	bne	CPDO_dvf_extra_2nd	@ no, so it was the second
++	cmp	r8,#0x7fffffff		@ yes, second too?
++	bne	CPDO_dvf_extra_1st	@ no, only first
++	orrs	r3,r3,r4
++	beq	CPDO_nan		@ if both inf -> create nan
++	b	CPDO_nan_12		@ otherwise keep nan
++
++CPDO_dvf_extra_1st:
++	eor	r1,r1,r2		@ correct sign for inf
++	b	CPDO_infnan_1
++
++CPDO_dvf_extra_2nd:
++	cmp	r4,#0			@ is it a nan?
++	bne	CPDO_infnan_2
++	eor	r1,r1,r2		@ correct sign for zero
++	b	CPDO_zero_1
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_rdf
++CPDO_rdf:
++	mov	r3,r2
++	ldmia	r1,{r2,r4,r6,r8}
++	ldmia	r3,{r1,r3,r5,r7}
++	b	CPDO_dvf_l
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_rmf
++CPDO_rmf:
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_mvf
++CPDO_mvf:
++	ldmia	r2,{r1,r2,r3,r4}
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_mnf
++CPDO_mnf:
++	ldmia	r2,{r1,r2,r3,r4}
++	eor	r1,r1,#0x80000000
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_abs
++CPDO_abs:
++	ldmia	r2,{r1,r2,r3,r4}
++	bic	r1,r1,#0x80000000
++	stmia	r0,{r1,r2,r3,r4}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++	
++	.globl	CPDO_sqt
++CPDO_sqt:
++	ldmia	r2,{r1,r2,r3,r4}
++	cmp	r1,#0
++	bne	CPDO_nan
++	cmp	r4,#0x7fffffff
++	beq	CPDO_store_1234
++
++	tst	r4,r4,lsr#1		@carry=exponent bit 0
++	bcc	CPDO_sqt_exponenteven
++	adds	r3,r3,r3
++	adcs	r2,r2,r2		@carry is needed in loop!
++CPDO_sqt_exponenteven:
++	mov	r4,r4,asr #1
++	str	r4,[r0,#12]
++
++	mov	r4,#0x80000000
++	mov	r5,#0
++	sub	r2,r2,#0x80000000
++
++	mov	r8,#0x40000000
++	mov	r14,#0x80000000
++
++	mov	r1,#1
++	b	CPDO_sqt_loop1_first
++CPDO_sqt_loop1:
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++CPDO_sqt_loop1_first:
++	add	r6,r4,r8,lsr r1		@r7 const = r5
++	bcs	CPDO_sqt_loop1_1
++	cmp	r2,r6
++	cmpeq	r3,r5			@r5 for r7
++	bcc	CPDO_sqt_loop1_0
++CPDO_sqt_loop1_1:
++	orr	r4,r4,r14,lsr r1
++	subs	r3,r3,r5		@r5 for r7
++	sbc	r2,r2,r6
++CPDO_sqt_loop1_0:
++	add	r1,r1,#1
++	cmp	r1,#30
++	ble	CPDO_sqt_loop1
++
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++	bcs	CPDO_sqt_between_1
++	adds	r7,r5,#0x80000000
++	adc	r6,r4,#0
++	cmp	r2,r6
++	cmpeq	r3,r7
++	bcc	CPDO_sqt_between_0
++CPDO_sqt_between_1:
++	orr	r4,r4,#0x00000001
++	subs	r3,r3,r5
++	sbc	r2,r2,r4
++	subs	r3,r3,#0x80000000
++	sbc	r2,r2,#0
++CPDO_sqt_between_0:
++	mov	r1,#0
++
++CPDO_sqt_loop2:
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++	bcs	CPDO_sqt_loop2_1
++	adds	r7,r5,r8,lsr r1
++	adc	r6,r4,#0
++	cmp	r2,r6
++	cmpeq	r3,r7
++	bcc	CPDO_sqt_loop2_0
++CPDO_sqt_loop2_1:
++	orr	r5,r5,r14,lsr r1
++	subs	r3,r3,r5
++	sbc	r2,r2,r4
++	subs	r3,r3,r8,lsr r1
++	sbc	r2,r2,#0
++CPDO_sqt_loop2_0:
++	add	r1,r1,#1
++	cmp	r1,#30
++	ble	CPDO_sqt_loop2
++
++	adds	r3,r3,r3
++	adcs	r2,r2,r2
++	bcs	CPDO_sqt_after_1
++	cmp	r2,r6
++	cmpeq	r3,r7
++	bcc	CPDO_sqt_after_0
++CPDO_sqt_after_1:
++	orr	r5,r5,#0x00000001
++CPDO_sqt_after_0:
++
++	mov	r1,#0
++	stmia	r0,{r1,r4,r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++	
++	.globl	CPDO_rnd
++CPDO_rnd:
++	ldmia	r2,{r1,r2,r3,r5}
++        bl      CPDO_rnd_core
++
++CPDO_rnd_store:
++	stmia	r0,{r1,r2,r3,r5}
++    	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDO_rnd_core
++CPDO_rnd_core:
++	and	r4,r4,#0x00000060
++	add	pc,pc,r4,lsr#3
++	mov	r0,r0
++	b	CPDO_rnd_N
++	b	CPDO_rnd_P
++	b	CPDO_rnd_M
++	b	CPDO_rnd_Z
++	
++CPDO_rnd_N:
++	cmp	r5,#-1
++	blt	CPDO_rnd_zero
++	cmp	r5,#63
++	movge	pc,r14
++	mov	r4,#0x40000000
++	cmp	r5,#31
++	bge	CPDO_rnd_N_2
++
++	adds	r2,r2,r4,lsr r5
++	bcc	CPDO_rnd_end
++	b	CPDO_rnd_end_norm
++
++CPDO_rnd_N_2:
++CPDO_rnd_P_2:
++	sub	r6,r5,#32
++	adds	r3,r3,r4,ror r6	@ror ist needed to handle a -1 correctly
++	adcs	r2,r2,#0
++	bcc	CPDO_rnd_end
++	b	CPDO_rnd_end_norm
++
++CPDO_rnd_P:
++	tst	r1,#0x80000000
++	bne	CPDO_rnd_M_entry
++CPDO_rnd_P_entry:
++	cmp	r5,#0
++	blt	CPDO_rnd_P_small
++	cmp	r5,#63
++	movge	pc,r14
++	mov	r4,#0x7fffffff
++	cmp	r5,#32
++	bge	CPDO_rnd_P_2
++
++	adds	r3,r3,#0xffffffff
++	adcs	r2,r2,r4,lsr r5
++	bcc	CPDO_rnd_end
++	b	CPDO_rnd_end_norm
++
++CPDO_rnd_P_small:
++	cmp	r5,#0x80000000
++	moveq	pc,r14
++	b	CPDO_rnd_one
++
++CPDO_rnd_M:
++	tst	r1,#0x80000000
++	bne	CPDO_rnd_P_entry
++CPDO_rnd_M_entry:
++	cmp	r5,#0
++	blt	CPDO_rnd_zero
++	cmp	r5,#63
++	movge	pc,r14
++
++	b	CPDO_rnd_end
++	
++CPDO_rnd_Z:
++	cmp	r5,#0
++	blt	CPDO_rnd_zero
++	cmp	r5,#63
++	movge	pc,r14
++	b	CPDO_rnd_end
++
++CPDO_rnd_end_norm:
++	add	r5,r5,#1
++	movs	r2,r2,rrx
++	mov	r3,r3,rrx
++CPDO_rnd_end:
++	rsbs	r4,r5,#31
++	bmi	CPDO_rnd_end_2
++	mov     r3,#0
++	mov     r2,r2,lsr r4
++	mov	r2,r2,lsl r4
++	mov	pc,r14
++
++CPDO_rnd_end_2:
++	rsb	r4,r5,#63
++	mov	r3,r3,lsr r4
++	mov	r3,r3,lsl r4
++	mov	pc,r14
++
++CPDO_rnd_one:
++	mov	r2,#0x80000000
++	mov	r3,#0
++	mov	r5,#0
++	mov	pc,r14
++	
++CPDO_rnd_zero:
++	mov	r1,#0
++	mov	r2,#0
++	mov	r3,#0
++	mov	r5,#0x80000000
++	mov	pc,r14
++
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/fastfpe/CPDT.S	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,430 @@
++/*
++The FP structure has 4 words reserved for each register, the first is used just
++for the sign in bit 31, the second and third are for the mantissa (unsigned
++integer, high 32 bit first) and the fourth is the exponent (signed integer).
++The mantissa is always normalized.
++
++If the exponent is 0x80000000, that is the most negative value, the number
++represented is 0 and both mantissa words are also 0.
++
++If the exponent is 0x7fffffff, that is the biggest positive value, the number
++represented is infinity if the high 32 mantissa bit are also 0, otherwise it is
++a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
++
++Decimal and packed decimal numbers are not supported yet.
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_single
++CPDT_load_single:
++	ldr	r1,[r6]
++	
++	and	r2,r1,#0x80000000	@ r2 = sign
++	
++	mov	r5,r1,lsr#23
++	bics	r5,r5,#0x100
++	beq	CPDT_ls_e0		@ exponent = 0; zero/denormalized
++	teq	r5,#255
++	beq	CPDT_ls_e255		@ exponent = 255; infinity/NaN
++
++	sub     r5,r5,#127		@ r5 = exponent, remove normalized bias
++
++	mov	r3,r1,lsl#8
++	orr	r3,r3,#0x80000000
++	mov	r4,#0			@ r3,r4 = mantissa
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ls_e0:
++	movs	r3,r1,lsl#9
++	beq	CPDT_load_zero
++
++	mov	r5,#-127
++
++CPDT_ls_e0_norm:
++	tst	r3,#0x80000000
++	subeq	r5,r5,#1
++	moveq	r3,r3,lsl#1
++	beq	CPDT_ls_e0_norm
++
++	mov	r4,#0
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ls_e255:
++	mov	r3,r1,lsl#9
++	mov	r4,#0
++	mov	r5,#0x7fffffff
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_load_zero:
++	mov	r3,#0
++	mov	r4,#0
++	mov	r5,#0x80000000
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_double
++CPDT_load_double:
++	ldr	r1,[r6]
++	ldr	r6,[r6,#4]
++
++	and	r2,r1,#0x80000000	@ r2 = sign
++
++	mov	r5,r1,lsr#20
++	bics	r5,r5,#0x800
++	beq	CPDT_ld_e0		@ exponent = 0; zero/denormalized
++	add	r4,r5,#1
++	teq	r4,#2048
++	beq	CPDT_ld_e2047		@ exponent = 2047; infinity/NaN
++
++	add     r5,r5,#1
++	sub	r5,r5,#1024		@ r5 = exponent, remove normalized bias
++
++	mov	r3,r1,lsl#11
++	orr	r3,r3,#0x80000000
++	orr	r3,r3,r6,lsr #21
++	mov	r4,r6,lsl#11		@ r3,r4 = mantissa
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ld_e0:
++	mov	r3,r1,lsl#12
++	orr	r3,r3,r6,lsr#20
++	movs	r4,r6,lsl#12
++	teqeq	r3,#0
++	beq	CPDT_load_zero
++	
++	mov	r5,#1
++	sub	r5,r5,#1024
++
++CPDT_ld_e0_norm:
++	tst	r3,#0x80000000
++	subeq	r5,r5,#1
++	moveqs	r4,r4,lsl#1
++	adceq	r3,r3,r3
++	beq	CPDT_ld_e0_norm
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_ld_e2047:
++	mov	r3,r1,lsl#12
++	orr	r3,r3,r6,lsr#1
++	bic	r6,r6,#0x80000000
++	orr	r3,r3,r6		@ to get all fraction bits !
++	mov	r4,#0
++	mov	r5,#0x7fffffff
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_extended
++CPDT_load_extended:
++	ldr	r1,[r6]
++	ldr	r3,[r6,#4]
++	ldr	r4,[r6,#8]
++	
++	and	r2,r1,#0x80000000
++	bics	r5,r1,#0x80000000
++	beq	CPDT_le_e0
++	add	r1,r5,#1
++	teq	r4,#32768
++	beq	CPDT_le_e32767
++
++	add	r5,r5,#1
++	sub	r5,r5,#16384
++
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++CPDT_le_e0:
++	teq	r3,#0
++	teqeq	r4,#0
++	beq	CPDT_load_zero
++	
++	mov	r5,#2
++	sub	r5,r5,#16384
++	b	CPDT_ld_e0_norm
++
++CPDT_le_e32767:
++	mov	r3,r3,lsl#1
++	orr	r3,r3,r4,lsr#1
++	bic	r4,r4,#0x80000000
++	orr	r3,r3,r4
++	mov	r5,#0x7fffffff
++	stmia	r0,{r2-r5}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_load_decimal
++CPDT_load_decimal:
++	
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_single
++CPDT_store_single:
++	ldmia	r0,{r1-r4}
++	
++	cmp	r4,#-127
++	ble	CPDT_ss_e0
++	cmp	r4,#128
++	bge	CPDT_ss_e255
++
++	adds	r2,r2,#1<<7		@ round to nearest
++	bcs	CPDT_ss_rnd_ovfl	@ very very seldom taken
++
++CPDT_ss_store:
++	add	r4,r4,#127
++	orr	r1,r1,r4,lsl#23
++	
++	bic	r2,r2,#0x80000000
++	orr	r1,r1,r2,lsr#8
++
++	str	r1,[r6]
++	b	fastfpe_next
++
++CPDT_ss_rnd_ovfl:
++	add	r4,r4,#1
++	cmp	r4,#128
++	bge	CPDT_ss_e255
++
++	mov	r2,#0x80000000
++	mov	r3,#0
++	b	CPDT_ss_store
++
++CPDT_ss_e0:
++	cmp	r4,#-150
++	ble	CPDT_ss_zero
++
++	add	r4,r4,#126
++CPDT_ss_unnormalize:
++	mov	r2,r2,lsr#1
++	adds	r4,r4,#1
++	bne	CPDT_ss_unnormalize
++
++	orr	r1,r1,r2,lsr#8
++
++CPDT_ss_zero:
++	str	r1,[r6]
++	b	fastfpe_next
++
++CPDT_ss_e255:
++	cmp	r4,#0x7fffffff
++	bne	CPDT_ss_inf
++	cmp	r2,#0
++	beq	CPDT_ss_inf
++
++	orr	r1,r1,#0x00200000	@ for safety so that it is not INF
++	orr	r1,r1,r2,lsr#9		@ get highest bit of mantissa
++
++CPDT_ss_inf:
++	orr	r1,r1,#0x7f000000
++	orr	r1,r1,#0x00800000
++	str	r1,[r6]
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_double
++CPDT_store_double:
++	ldmia	r0,{r1-r4}
++	
++	cmp	r4,#1024		@ this check has to be first, or
++	bge	CPDT_sd_e2047		@ overflow can occur on second !
++	add	r0,r4,#3
++	cmp	r0,#-1023+3		@ cmp with -1023
++	ble	CPDT_sd_e0
++
++	adds	r3,r3,#1<<10		@ round to nearest
++	adcs	r2,r2,#0
++	bcs	CPDT_sd_rnd_ovfl	@ very very seldom taken
++
++CPDT_sd_store:
++	sub	r4,r4,#1
++	add	r4,r4,#1024
++	orr	r1,r1,r4,lsl#20
++	
++	bic	r2,r2,#0x80000000
++	orr	r1,r1,r2,lsr#11
++
++	mov	r2,r2,lsl#21
++	orr	r2,r2,r3,lsr#11
++
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++CPDT_sd_rnd_ovfl:
++	add	r4,r4,#1
++	cmp	r4,#1024
++	bge	CPDT_sd_e2047
++
++	mov	r2,#0x80000000
++	mov	r3,#0
++	b	CPDT_sd_store
++
++CPDT_sd_e0:
++	add	r0,r4,#1075-1024
++	cmp	r0,#-1024
++	ble	CPDT_sd_zero
++
++	add	r4,r4,#1024
++	sub	r4,r4,#2
++CPDT_sd_unnormalize:
++	movs	r2,r2,lsr#1
++	mov	r3,r3,rrx
++	adds	r4,r4,#1
++	bne	CPDT_sd_unnormalize
++
++	orr	r1,r1,r2,lsr#11
++	mov	r2,r2,lsl#21
++	orr	r2,r2,r3,lsr#11
++
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++CPDT_sd_zero:
++	mov	r2,#0
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++CPDT_sd_e2047:
++	cmp	r4,#0x7fffffff
++	bne	CPDT_sd_inf
++	cmp	r2,#0
++	beq	CPDT_sd_inf
++
++	orr	r1,r1,#0x00040000	@ for safety so that it is not INF
++	orr	r1,r1,r2,lsr#12		@ get highest bit of mantissa
++
++CPDT_sd_inf:
++	orr	r1,r1,#0x7f000000
++	orr	r1,r1,#0x00f00000
++	stmia	r6,{r1,r2}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_extended
++CPDT_store_extended:
++	ldmia	r0,{r1-r4}
++	
++	cmp	r4,#16384		@ this check has to be first, or
++	bge	CPDT_se_e32767		@ overflow can occur with second !
++	add	r0,r4,#63
++	cmp	r0,#-16383+63
++	ble	CPDT_se_e0
++
++	sub	r4,r4,#1
++	add	r4,r4,#16384
++	orr	r1,r1,r4
++	
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++
++CPDT_se_e0:
++	add	r0,r4,#16446-16384
++	cmp	r0,#-16384
++	ble	CPDT_se_zero
++
++	add	r4,r4,#16384
++	sub	r4,r4,#2
++CPDT_se_unnormalize:
++	movs	r2,r2,lsr#1
++	mov	r3,r3,rrx
++	adds	r4,r4,#1
++	bne	CPDT_se_unnormalize
++
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++	
++CPDT_se_zero:
++	mov	r2,#0
++	mov	r3,#0
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++
++CPDT_se_e32767:
++	cmp	r4,#0x7fffffff
++	bne	CPDT_se_inf
++	cmp	r2,#0
++	beq	CPDT_se_inf
++
++	mov	r2,r2,lsl#1
++	orr	r2,r2,#0x20000000
++
++CPDT_se_inf:
++	orr	r1,r1,#0x00007f00
++	orr	r1,r1,#0x000000ff
++	stmia	r6,{r1-r3}
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_store_decimal
++CPDT_store_decimal:
++
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_sfm
++CPDT_sfm:
++	add	r2,r10,r0,lsr#8
++	ldr	r4,[r2,#0]
++	ldr	r3,[r2,#4]
++	bic	r3,r3,#0x80000000
++	orr	r3,r3,r4
++	str	r3,[r6],#4
++	ldr	r3,[r2,#8]
++	str	r3,[r6],#4
++	ldr	r3,[r2,#12]
++	str	r3,[r6],#4
++
++	add	r0,r0,#1<<12
++	and	r0,r0,#7<<12
++	subs	r1,r1,#1
++	bne	CPDT_sfm
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPDT_lfm
++CPDT_lfm:
++	add	r2,r10,r0,lsr#8
++	ldr	r4,[r6],#4
++	and	r3,r4,#0x80000000
++	str	r3,[r2,#0]
++	ldr	r3,[r6],#4
++	str	r3,[r2,#8]
++	ldr	r3,[r6],#4
++	str	r3,[r2,#12]
++
++	cmp	r3,#0x80000000		@ does the exp indicate zero?
++	biceq	r4,r4,#0x80000000	@ if so, indicate 'denormalized'
++	beq	CPDT_lfm_storer4
++	cmp	r3,#0x7fffffff		@ does the exp indicate inf or NaN?
++	biceq	r4,r4,#0x80000000	@ if so, indicate 'denormalized'
++	beq	CPDT_lfm_storer4
++	orrne	r4,r4,#0x80000000	@ otherwise, set normalized bit
++
++CPDT_lfm_storer4:
++	str	r4,[r2,#4]
++
++	add	r0,r0,#1<<12
++	and	r0,r0,#7<<12
++	subs	r1,r1,#1
++	bne	CPDT_lfm
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/fastfpe/CPRT.S	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,185 @@
++/*
++The FP structure has 4 words reserved for each register, the first is used
++just
++for the sign in bit 31, the second and third are for the mantissa (unsigned
++integer, high 32 bit first) and the fourth is the exponent (signed integer).
++The mantissa is always normalized.
++
++If the exponent is 0x80000000, that is the most negative value, the number
++represented is 0 and both mantissa words are also 0.
++
++If the exponent is 0x7fffffff, that is the biggest positive value, the
++number
++represented is infinity if the high 32 mantissa bit are also 0, otherwise it
++is
++a NaN. The low 32 mantissa bit are 0 if the number represented is infinity.
++
++Decimal and packed decimal numbers are not supported yet.
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.text
++	.globl	CPRT_flt
++CPRT_flt:
++	add	r0,r13,r0,lsr#10
++	ldr	r2,[r0]
++	mov	r3,#0
++	cmp	r2,#0
++	beq	CPRT_flt_zero
++	
++	ands	r0,r2,#0x80000000
++	rsbne	r2,r2,#0
++	mov	r4,#31
++	
++	cmp	r2,#0x00010000
++	movcc	r2,r2,lsl#16
++	subcc	r4,r4,#16
++	
++	cmp	r2,#0x01000000
++	movcc	r2,r2,lsl#8
++	subcc	r4,r4,#8
++	
++	cmp	r2,#0x10000000
++	movcc	r2,r2,lsl#4
++	subcc	r4,r4,#4
++	
++	cmp	r2,#0x40000000
++	movcc	r2,r2,lsl#2
++	subcc	r4,r4,#2
++	
++	cmp	r2,#0x80000000
++	movcc	r2,r2,lsl#1
++	subcc	r4,r4,#1
++
++	stmia	r1,{r0,r2,r3,r4}
++	b	fastfpe_next
++
++CPRT_flt_zero:
++	mov	r0,#0
++	mov	r4,#0x80000000
++	stmia	r1,{r0,r2,r3,r4}
++	b	fastfpe_next
++	
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_fix
++CPRT_fix:
++	ldmia	r2,{r1,r2,r3,r5}
++	bl	CPDO_rnd_core
++	
++CPRT_back:
++	add	r0,r13,r0,lsr#10
++	cmp	r5,#0
++	blt	CPRT_int_zero
++	cmp	r5,#30
++	bgt	CPRT_overflow
++	
++	rsb	r5,r5,#31
++	mov	r2,r2,lsr r5
++	tst	r1,#0x80000000
++	rsbne	r2,r2,#0
++	
++	str	r2,[r0]
++	b	fastfpe_next
++
++CPRT_int_zero:
++	mov	r2,#0
++	str	r2,[r0]
++	b	fastfpe_next
++
++CPRT_overflow:
++	mov	r2,#0x80000000
++	tst	r1,#0x80000000
++	subeq	r2,r2,#1
++	str	r2,[r0]
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_wfs
++CPRT_wfs:
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_rfs
++CPRT_rfs:
++	add	r0,r13,r0,lsr#10
++	mov	r1,#0x02000000		@ Software Emulation, not Acorn FPE
++	str	r1,[r0]
++	b	fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_cmf
++CPRT_cmf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++
++CPRT_cmf_e:
++	ldr	r0,[r13,#16*4]
++	
++	cmp	r7,#0x7fffffff
++	bic	r0,r0,#0xf0000000
++
++	cmpeq	r3,#0xffffffff
++	beq	CPRT_cmf_unordered
++	cmp	r8,#0x7fffffff
++	cmpeq	r4,#0xffffffff
++	beq	CPRT_cmf_unordered
++
++	cmp	r1,r2
++	beq	CPRT_cmf_equalsign
++	b	CPRT_cmf_sign
++
++CPRT_cmf_equalsign:
++	cmp	r7,r8
++	beq	CPRT_cmf_equalexponent
++	bgt	CPRT_cmf_sign
++	b	CPRT_cmf_signb	
++
++CPRT_cmf_equalexponent:
++	cmp	r3,r4
++	cmpeq	r5,r6
++	beq	CPRT_cmf_equal
++	bhi	CPRT_cmf_sign
++	b	CPRT_cmf_signb
++
++CPRT_cmf_sign:
++	cmp     r7,#0x80000000		@ (0.0 == -0.0)?
++	cmpeq   r7,r8
++	beq     CPRT_cmf_equal
++	tst	r1,#0x80000000
++	orreq	r0,r0,#0x20000000
++	orrne	r0,r0,#0x80000000
++	str	r0,[r13,#16*4]
++	b	fastfpe_next
++
++CPRT_cmf_signb:
++	tst	r1,#0x80000000
++	orrne	r0,r0,#0x20000000
++	orreq	r0,r0,#0x80000000
++	str	r0,[r13,#16*4] 
++	b	fastfpe_next
++
++CPRT_cmf_equal:
++	orr	r0,r0,#0x60000000
++	str	r0,[r13,#16*4]
++	b	fastfpe_next
++
++CPRT_cmf_unordered:
++	orr	r0,r0,#0x10000000
++        str     r0,[r13,#16*4]
++        b       fastfpe_next
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	CPRT_cnf
++CPRT_cnf:
++	ldmia	r1,{r1,r3,r5,r7}
++	ldmia	r2,{r2,r4,r6,r8}
++	eor	r2,r2,#0x80000000
++	b	CPRT_cmf_e
++
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/fastfpe/Makefile	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,25 @@
++#
++# linux/arch/arm/fastfpe/Makefile
++#
++# Copyright (C) Peter Teichmann
++#
++
++O_TARGET := fast-math-emu.o
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++fastfpe-objs := module.o entry.o CPDO.o CPRT.o CPDT.o
++
++list-multi := fastfpe.o
++
++obj-$(CONFIG_FPE_FASTFPE) += fastfpe.o
++
++USE_STANDARD_AS_RULE := true
++
++include $(TOPDIR)/Rules.make
++
++fastfpe.o: $(fastfpe-objs)
++	 $(LD) -r -o $@ $(fastfpe-objs)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/fastfpe/entry.S	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,295 @@
++/*
++At entry the registers contain the following information:
++
++r14	return address for undefined exception return
++r9	return address for return from exception
++r13	user registers on stack, offset 0 up to offset 4*15 contains
++	registers r0..15, then the psr
++r10	FP workspace 35 words (init, reg[8][4], fpsr, fpcr)
++ 
++*/
++
++/*---------------------------------------------------------------------------*/
++
++	.data
++fp_const:
++	.word	0, 0x00000000, 0, 0x80000000	@ 0
++	.word	0, 0x80000000, 0,          0	@ 1
++	.word	0, 0x80000000, 0,          1	@ 2
++	.word	0, 0xc0000000, 0,          1	@ 3
++	.word	0, 0x80000000, 0,          2	@ 4
++	.word	0, 0xa0000000, 0,          2	@ 5
++	.word	0, 0x80000000, 0,	  -1	@ 0.5
++	.word	0, 0xa0000000, 0,          3	@ 10
++fp_undef:
++	.word	0
++fp_cond:
++	.word	0xf0f0	@ eq
++	.word	0x0f0f	@ ne
++	.word	0xcccc	@ cs
++	.word	0x3333	@ cc
++	.word	0xff00	@ mi
++	.word	0x00ff	@ pl
++	.word	0xaaaa	@ vs
++	.word	0x5555	@ vc
++	.word	0x0c0c	@ hi
++	.word	0xf3f3	@ ls
++	.word	0xaa55	@ ge
++	.word	0x55aa	@ lt
++	.word	0x0a05	@ gt
++	.word	0xf5fa	@ le
++	.word	0xffff	@ al
++	.word	0x0000	@ nv
++	
++/*---------------------------------------------------------------------------*/
++	
++	.text
++	.globl	fastfpe_enter
++fastfpe_enter:
++	ldr	r4,=fp_undef
++	str	r14,[r4]		@ to free one register
++	add	r10,r10,#4		@ to make the code simpler
++	ldr	r4,[r13,#60]		@ r4=saved PC
++	ldr	r4,[r4,#-4]		@ r4=trapped instruction
++	and	r1,r4,#0x00000f00	@ r1=coprocessor << 8
++next_enter:
++	cmp	r1,#1<<8		@ copro 1 ?
++	beq	copro_1
++	cmp	r1,#2<<8
++	movne	pc,r14
++
++copro_2:
++	and	r1,r4,#0x0f000000
++	cmp	r1,#0x0c000000          @ CPDT with post indexing
++        cmpne   r1,#0x0d000000          @ CPDT with pre indexing
++        beq     CPDT_M_enter
++	mov	pc,r14
++
++copro_1:
++	and	r1,r4,#0x0f000000
++	cmp	r1,#0x0e000000		@ CPDO
++	beq	CPDO_CPRT_enter
++	cmp	r1,#0x0c000000		@ CPDT with post indexing
++	cmpne	r1,#0x0d000000		@ CPDT with pre indexing
++	beq	CPDT_1_enter
++	mov	pc,r14
++
++/*---------------------------------------------------------------------------*/
++
++	.globl	fastfpe_next
++fastfpe_next:
++	ldr	r5,[r13,#60]
++next_after_cond:
++__x1:
++	ldrt	r4,[r5],#4
++	
++	ldr	r0,=fp_cond		@ check condition of next instruction
++	ldr	r1,[r13,#64]		@ psr containing flags
++	mov	r2,r4,lsr#28
++	mov	r1,r1,lsr#28
++	ldr	r0,[r0,r2,lsl#2]
++	mov	r0,r0,lsr r1
++	tst	r0,#1
++	beq	next_after_cond		@ must not necessarily have been an
++					@ FP instruction !
++	and	r1,r4,#0x0f000000	@ Test for copro instruction
++	cmp	r1,#0x0c000000
++	rsbgts	r0,r1,#0x0e000000	@ cmpgt #0x0e000000,r1
++	movlt	pc,r9			@ next is no copro instruction, return
++	
++	ands	r1,r4,#0x00000f00	@ r1 = coprocessor << 8
++	cmpne	r1,#3<<8
++	movge	pc,r9			@ copro = 0 or >=3, return
++		
++	str	r5,[r13,#60]		@ save updated pc
++	b	next_enter
++
++/*---------------------------------------------------------------------------*/
++
++undefined:
++	ldr	r4,=fp_undef
++	ldr	pc,[r4]	
++
++/*---------------------------------------------------------------------------*/
++
++CPDT_1_enter:
++	and	r5,r4,#0x000f0000	@ r5=base register number << 16
++	ldr	r6,[r13,r5,lsr#14]	@ r6=base address
++	cmp	r5,#0x000f0000		@ base register = pc ?
++	addeq	r6,r6,#4
++	and	r7,r4,#0x000000ff	@ r7=offset value
++
++	tst	r4,#0x00800000		@ up or down?
++	addne	r7,r6,r7,lsl#2
++	subeq	r7,r6,r7,lsl#2		@ r6=base address +/- offset
++	tst	r4,#0x01000000		@ preindexing ?
++	movne	r6,r7
++	tst	r4,#0x00200000		@ write back ?
++	cmpne	r5,#0x000f0000		@ base register = pc ?
++	strne	r7,[r13,r5,lsr#14]
++
++	and	r0,r4,#0x00007000	@ r0=fp register number << 12
++	add	r0,r10,r0,lsr#8		@ r0=address of fp register
++	mov	r1,#0
++	tst	r4,#0x00008000
++	orrne	r1,r1,#1		@ T0
++	tst	r4,#0x00400000
++	orrne	r1,r1,#2		@ T1
++	tst	r4,#0x00100000
++	orrne	r1,r1,#4		@ L/S
++
++	add	pc,pc,r1,lsl#2
++	mov	r0,r0
++	b	CPDT_store_single	@ these functions get 
++	b	CPDT_store_double	@ r0=address of fp register
++	b	CPDT_store_extended	@ r6=address of data
++	b	undefined		@ CPDT_store_decimal
++        b       CPDT_load_single
++        b       CPDT_load_double
++        b       CPDT_load_extended
++        b       undefined		@ CPDT_load_decimal
++
++/*---------------------------------------------------------------------------*/
++
++CPDT_M_enter:
++	and	r5,r4,#0x000f0000	@ r5=base register number << 16
++	ldr	r6,[r13,r5,lsr#14]	@ r6=base address
++	cmp	r5,#0x000f0000		@ base register = pc ?
++	addeq	r6,r6,#4
++	and	r7,r4,#0x000000ff	@ r7=offset value
++
++	tst	r4,#0x00800000		@ up or down?
++	addne	r7,r6,r7,lsl#2
++	subeq	r7,r6,r7,lsl#2		@ r7=base address +/- offset
++	tst	r4,#0x01000000		@ preindexing ?
++	movne	r6,r7
++	tst	r4,#0x00200000		@ write back ?
++	cmpne	r5,#0x000f0000		@ base register = pc ?
++	strne	r7,[r13,r5,lsr#14]
++
++	and	r0,r4,#0x00007000	@ r0=fp register number << 12
++	and	r1,r4,#0x00008000
++	mov	r1,r1,lsr#15		@ N0
++	and	r2,r4,#0x00400000
++	orrs	r1,r1,r2,lsr#21		@ N1
++	addeq	r1,r1,#4		@ r1=register count
++
++	tst	r4,#0x00100000		@ load/store
++	beq	CPDT_sfm
++	b	CPDT_lfm
++
++/*---------------------------------------------------------------------------*/
++
++CPDO_CPRT_enter:
++	tst	r4,#0x00000010
++	bne	CPRT_enter
++	
++	and	r0,r4,#0x00007000
++	add	r0,r10,r0,lsr#8		@ r0=address of Fd
++	and	r1,r4,#0x00070000
++	add	r1,r10,r1,lsr#12	@ r1=address of Fn
++	tst	r4,#0x00000008
++	bne	CPDO_const
++	and	r2,r4,#0x00000007
++	add	r2,r10,r2,lsl#4		@ r2=address of Fm
++	
++CPDO_constback:
++	and	r3,r4,#0x00f00000
++	tst	r4,#0x00008000
++	orrne	r3,r3,#0x01000000
++		
++	add	pc,pc,r3,lsr#18
++	mov	r0,r0
++	b	CPDO_adf
++	b	CPDO_muf
++	b	CPDO_suf
++	b	CPDO_rsf
++	b	CPDO_dvf
++	b	CPDO_rdf
++	b	undefined
++	b	undefined
++	b	undefined		@ CPDO_rmf
++	b	CPDO_muf
++	b	CPDO_dvf
++	b	CPDO_rdf
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	CPDO_mvf
++	b	CPDO_mnf
++	b	CPDO_abs
++	b	CPDO_rnd
++	b	CPDO_sqt
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	CPDO_rnd
++	b	fastfpe_next
++
++CPDO_const:
++	ldr	r2,=fp_const
++	and	r3,r4,#0x00000007
++	add	r2,r2,r3,lsl#4	
++	b	CPDO_constback
++	
++/*---------------------------------------------------------------------------*/
++
++CPRT_enter:
++	and	r0,r4,#0x0000f000	@ r0=Rd<<12
++	and	r1,r4,#0x00070000
++	add	r1,r10,r1,lsr#12	@ r1=address of Fn
++	tst	r4,#0x00000008
++	bne	CPRT_const
++	and	r2,r4,#0x00000007
++	add	r2,r10,r2,lsl#4		@ r2=address of Fm
++	
++CPRT_constback:
++	and	r3,r4,#0x00f00000
++		
++	add	pc,pc,r3,lsr#18
++	mov	r0,r0
++	b	CPRT_flt
++	b	CPRT_fix
++	b	CPRT_wfs
++	b	CPRT_rfs
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	undefined
++	b	CPRT_cmf
++	b	undefined
++	b	CPRT_cnf
++	b	undefined
++	b	CPRT_cmf
++	b	undefined
++	b	CPRT_cnf
++
++CPRT_const:
++	ldr	r2,=fp_const
++	and	r3,r4,#0x00000007
++	add	r2,r2,r3,lsl#4	
++	b	CPRT_constback
++	
++/*---------------------------------------------------------------------------*/
++
++	@ The fetch of the next instruction to emulate could fault
++
++	.section .fixup,"ax"
++	.align
++__f1:
++	mov	pc,r9
++	.previous
++	.section __ex_table,"a"
++	.align 3
++	.long	__x1,__f1
++	.previous
++	
++/*---------------------------------------------------------------------------*/
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/fastfpe/module.c	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,78 @@
++/*
++    Fast Floating Point Emulator
++    (c) Peter Teichmann <mail@peter-teichmann.de>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/init.h>
++
++#ifndef MODULE
++#define kern_fp_enter	fp_enter
++
++extern char fpe_type[];
++#endif
++
++static void (*orig_fp_enter)(void);	/* old kern_fp_enter value */
++extern void (*kern_fp_enter)(void);	/* current FP handler */
++extern void fastfpe_enter(void);	/* forward declarations */
++
++#ifdef MODULE
++/*
++ * Return 0 if we can be unloaded.  This can only happen if
++ * kern_fp_enter is still pointing at fastfpe_enter
++ */
++static int fpe_unload(void)
++{
++  return (kern_fp_enter == fastfpe_enter) ? 0 : 1;
++}
++#endif
++
++static int __init fpe_init(void)
++{
++#ifdef MODULE
++  if (!mod_member_present(&__this_module, can_unload))
++    return -EINVAL;
++  __this_module.can_unload = fpe_unload;
++#else
++  if (fpe_type[0] && strcmp(fpe_type, "fastfpe"))
++    return 0;
++#endif
++
++  printk("Fast Floating Point Emulator V0.9 (c) Peter Teichmann.\n");
++
++  /* Save pointer to the old FP handler and then patch ourselves in */
++  orig_fp_enter = kern_fp_enter;
++  kern_fp_enter = fastfpe_enter;
++
++  return 0;
++}
++
++static void __exit fpe_exit(void)
++{
++  /* Restore the values we saved earlier. */
++  kern_fp_enter = orig_fp_enter;
++}
++
++module_init(fpe_init);
++module_exit(fpe_exit);
++
++MODULE_AUTHOR("Peter Teichmann <mail@peter-teichmann.de>");
++MODULE_DESCRIPTION("Fast floating point emulator with full precision");
+--- linux-2.4.25/arch/arm/kernel/calls.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/calls.S	2004-03-31 17:15:08.000000000 +0200
+@@ -115,7 +115,7 @@
+ 		.long	SYMBOL_NAME(sys_ni_syscall)		/* was sys_profil */
+ 		.long	SYMBOL_NAME(sys_statfs)
+ /* 100 */	.long	SYMBOL_NAME(sys_fstatfs)
+-		.long	SYMBOL_NAME(sys_ni_syscall)
++		.long	SYMBOL_NAME(sys_ni_syscall)		/* 101 was sys_ioperm */
+ 		.long	SYMBOL_NAME(sys_socketcall)
+ 		.long	SYMBOL_NAME(sys_syslog)
+ 		.long	SYMBOL_NAME(sys_setitimer)
+@@ -126,7 +126,7 @@
+ 		.long	SYMBOL_NAME(sys_ni_syscall)		/* was sys_uname */
+ /* 110 */	.long	SYMBOL_NAME(sys_ni_syscall)		/* was sys_iopl */
+ 		.long	SYMBOL_NAME(sys_vhangup)
+-		.long	SYMBOL_NAME(sys_ni_syscall)
++		.long	SYMBOL_NAME(sys_ni_syscall)		/* 112 was sys_idle */
+ 		.long	SYMBOL_NAME(sys_syscall)		/* call a syscall */
+ 		.long	SYMBOL_NAME(sys_wait4)
+ /* 115 */	.long	SYMBOL_NAME(sys_swapoff)
+@@ -137,7 +137,7 @@
+ /* 120 */	.long	SYMBOL_NAME(sys_clone_wapper)
+ 		.long	SYMBOL_NAME(sys_setdomainname)
+ 		.long	SYMBOL_NAME(sys_newuname)
+-		.long	SYMBOL_NAME(sys_ni_syscall)
++		.long	SYMBOL_NAME(sys_ni_syscall)		/* 123 was sys_modify_ldt */
+ 		.long	SYMBOL_NAME(sys_adjtimex)
+ /* 125 */	.long	SYMBOL_NAME(sys_mprotect)
+ 		.long	SYMBOL_NAME(sys_sigprocmask)
+@@ -180,7 +180,7 @@
+ 		.long	SYMBOL_NAME(sys_arm_mremap)
+ 		.long	SYMBOL_NAME(sys_setresuid16)
+ /* 165 */	.long	SYMBOL_NAME(sys_getresuid16)
+-		.long	SYMBOL_NAME(sys_ni_syscall)
++		.long	SYMBOL_NAME(sys_ni_syscall)		/* 166 was sys_vm86 */
+ 		.long	SYMBOL_NAME(sys_query_module)
+ 		.long	SYMBOL_NAME(sys_poll)
+ 		.long	SYMBOL_NAME(sys_nfsservctl)
+--- linux-2.4.25/arch/arm/kernel/dma-rpc.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/dma-rpc.c	2004-03-31 17:15:08.000000000 +0200
+@@ -26,19 +26,6 @@
+ #include <asm/mach/dma.h>
+ #include <asm/hardware/iomd.h>
+ 
+-#if 0
+-typedef enum {
+-	dma_size_8	= 1,
+-	dma_size_16	= 2,
+-	dma_size_32	= 4,
+-	dma_size_128	= 16
+-} dma_size_t;
+-
+-typedef struct {
+-	dma_size_t	transfersize;
+-} dma_t;
+-#endif
+-
+ #define TRANSFER_SIZE	2
+ 
+ #define CURA	(0)
+@@ -48,10 +35,6 @@
+ #define CR	(IOMD_IO0CR - IOMD_IO0CURA)
+ #define ST	(IOMD_IO0ST - IOMD_IO0CURA)
+ 
+-#define state_prog_a	0
+-#define state_wait_a	1
+-#define state_wait_b	2
+-
+ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
+ {
+ 	unsigned long end, offset, flags = 0;
+@@ -65,7 +48,7 @@
+ 		if (end > PAGE_SIZE)
+ 			end = PAGE_SIZE;
+ 
+-		if (offset + (int) TRANSFER_SIZE > end)
++		if (offset + TRANSFER_SIZE >= end)
+ 			flags |= DMA_END_L;
+ 
+ 		sg->length = end - TRANSFER_SIZE;
+@@ -103,27 +86,31 @@
+ 		if (!(status & DMA_ST_INT))
+ 			return;
+ 
+-		if (status & DMA_ST_OFL && !dma->sg)
+-			break;
+-
+-		iomd_get_next_sg(&dma->cur_sg, dma);
++		if ((dma->state ^ status) & DMA_ST_AB)
++			iomd_get_next_sg(&dma->cur_sg, dma);
+ 
+ 		switch (status & (DMA_ST_OFL | DMA_ST_AB)) {
+ 		case DMA_ST_OFL:			/* OIA */
+ 		case DMA_ST_AB:				/* .IB */
+ 			iomd_writel(dma->cur_sg.dma_address, base + CURA);
+ 			iomd_writel(dma->cur_sg.length, base + ENDA);
++			dma->state = DMA_ST_AB;
+ 			break;
+ 
+ 		case DMA_ST_OFL | DMA_ST_AB:		/* OIB */
+ 		case 0:					/* .IA */
+ 			iomd_writel(dma->cur_sg.dma_address, base + CURB);
+ 			iomd_writel(dma->cur_sg.length, base + ENDB);
++			dma->state = 0;
+ 			break;
+ 		}
++
++		if (status & DMA_ST_OFL &&
++		    dma->cur_sg.length == (DMA_END_S|DMA_END_L))
++			break;
+ 	} while (1);
+ 
+-	iomd_writeb(0, base + CR);
++	dma->state = ~DMA_ST_AB;
+ 	disable_irq(irq);
+ }
+ 
+@@ -158,6 +145,7 @@
+ 		}
+ 
+ 		iomd_writeb(DMA_CR_C, dma_base + CR);
++		dma->state = DMA_ST_AB;
+ 	}
+ 		
+ 	if (dma->dma_mode == DMA_MODE_READ)
+@@ -171,13 +159,11 @@
+ {
+ 	unsigned long dma_base = dma->dma_base;
+ 	unsigned long flags;
+-	unsigned int ctrl;
+ 
+ 	local_irq_save(flags);
+-	ctrl = iomd_readb(dma_base + CR);
+-	if (ctrl & DMA_CR_E)
++	if (dma->state != ~DMA_ST_AB)
+ 		disable_irq(dma->dma_irq);
+-	iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR);
++	iomd_writeb(0, dma_base + CR);
+ 	local_irq_restore(flags);
+ }
+ 
+--- linux-2.4.25/arch/arm/kernel/entry-armv.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/entry-armv.S	2004-03-31 17:15:08.000000000 +0200
+@@ -677,12 +677,11 @@
+ 		mrs	r9, cpsr			@ Enable interrupts if they were
+ 		tst	r3, #I_BIT
+ 		biceq	r9, r9, #I_BIT			@ previously
+-		mov	r0, r2				@ *** remove once everyones in sync
+ /*
+  * This routine must not corrupt r9
+  */
+ #ifdef MULTI_CPU
+-		ldr	r4, .LCprocfns			@ pass r0, r3 to
++		ldr	r4, .LCprocfns			@ pass r2, r3 to
+ 		mov	lr, pc				@ processor code
+ 		ldr	pc, [r4]			@ call processor specific code
+ #else
+@@ -788,9 +787,8 @@
+ 		stmdb	r5, {sp, lr}^
+ 		alignment_trap r7, r7, __temp_abt
+ 		zero_fp
+-		mov	r0, r2				@ remove once everyones in sync
+ #ifdef MULTI_CPU
+-		ldr	r4, .LCprocfns			@ pass r0, r3 to
++		ldr	r4, .LCprocfns			@ pass r2, r3 to
+ 		mov	lr, pc				@ processor code
+ 		ldr	pc, [r4]			@ call processor specific code
+ #else
+@@ -840,7 +838,8 @@
+ 		adrsvc	al, r9, ret_from_exception	@ r9  = normal FP return
+ 		adrsvc	al, lr, fpundefinstr		@ lr  = undefined instr return
+ 
+-call_fpe:	get_current_task r10
++call_fpe:	enable_irq r10
++		get_current_task r10
+ 		mov	r8, #1
+ 		strb	r8, [r10, #TSK_USED_MATH]	@ set current->used_math
+ 		ldr	r4, .LCfp
+--- linux-2.4.25/arch/arm/kernel/head-armv.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/head-armv.S	2004-03-31 17:15:08.000000000 +0200
+@@ -1,7 +1,7 @@
+ /*
+  *  linux/arch/arm/kernel/head-armv.S
+  *
+- *  Copyright (C) 1994-1999 Russell King
++ *  Copyright (C) 1994-2003 Russell King
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License version 2 as
+@@ -163,10 +163,10 @@
+  */
+ 		.type	__ret, %function
+ __ret:		ldr	lr, __switch_data
+-		mcr	p15, 0, r0, c1, c0
+-		mrc	p15, 0, r0, c1, c0, 0		@ read it back.
+-		mov	r0, r0
+-		mov	r0, r0
++		mcr	p15, 0, r0, c1, c0, 0
++		mrc	p15, 0, r3, c0, c0, 0
++		mov	r3, r3
++		mov	r3, r3
+ 		mov	pc, lr
+ 
+ /*
+@@ -214,6 +214,11 @@
+  */
+ __create_page_tables:
+ 		pgtbl	r4, r5				@ page table address
++#if defined(CONFIG_CPU_DCACHE_DISABLE)
++		bic	r8, r8, #0x00c			@ clear B, C
++#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
++		bic	r8, r8, #0x004			@ clear B
++#endif
+ 
+ 		/*
+ 		 * Clear the 16K level 1 swapper page table
+--- linux-2.4.25/arch/arm/kernel/irq.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/irq.c	2004-03-31 17:15:08.000000000 +0200
+@@ -549,7 +549,7 @@
+ 		kfree(action);
+ 		goto out;
+ 	}
+-	printk(KERN_ERR "Trying to free free IRQ%d\n",irq);
++	printk(KERN_ERR "Trying to free IRQ%d\n",irq);
+ #ifdef CONFIG_DEBUG_ERRORS
+ 	__backtrace();
+ #endif
+--- linux-2.4.25/arch/arm/kernel/ptrace.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/ptrace.c	2004-03-31 17:15:08.000000000 +0200
+@@ -725,11 +725,8 @@
+ 		goto out_tsk;
+ 	}
+ 	ret = -ESRCH;
+-	if (!(child->ptrace & PT_PTRACED))
+-		goto out_tsk;
+-	if (child->state != TASK_STOPPED && request != PTRACE_KILL)
+-		goto out_tsk;
+-	if (child->p_pptr != current)
++	ret = ptrace_check_attach(child, request == PTRACE_KILL);
++	if (ret)
+ 		goto out_tsk;
+ 
+ 	ret = do_ptrace(request, child, addr, data);
+--- linux-2.4.25/arch/arm/kernel/semaphore.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/semaphore.c	2004-03-31 17:15:08.000000000 +0200
+@@ -193,7 +193,7 @@
+ 	bl	__down_interruptible		\n\
+ 	mov	ip, r0				\n\
+ 	ldmfd	sp!, {r0 - r3, pc}^		\n\
+-
++						\n\
+ 	.align	5				\n\
+ 	.globl	__down_trylock_failed		\n\
+ __down_trylock_failed:				\n\
+--- linux-2.4.25/arch/arm/kernel/signal.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/kernel/signal.c	2004-03-31 17:15:08.000000000 +0200
+@@ -641,10 +641,7 @@
+ 				/* FALLTHRU */
+ 
+ 			default:
+-				sigaddset(&current->pending.signal, signr);
+-				recalc_sigpending(current);
+-				current->flags |= PF_SIGNALED;
+-				do_exit(exit_code);
++				sig_exit(signr, exit_code, &info);
+ 				/* NOTREACHED */
+ 			}
+ 		}
+--- linux-2.4.25/arch/arm/lib/Makefile~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/lib/Makefile	2004-03-31 17:15:08.000000000 +0200
+@@ -15,7 +15,7 @@
+ 		   strnlen_user.o strchr.o strrchr.o testchangebit.o  \
+ 		   testclearbit.o testsetbit.o uaccess.o getuser.o    \
+ 		   putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o   \
+-		   ucmpdi2.o udivdi3.o lib1funcs.o
++		   ucmpdi2.o udivdi3.o lib1funcs.o div64.o
+ obj-m		:=
+ obj-n		:=
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/lib/div64.S	2004-03-31 17:15:08.000000000 +0200
+@@ -0,0 +1,59 @@
++#include <linux/linkage.h>
++
++#ifndef __ARMEB__
++ql	.req	r0			@ quotient low
++qh	.req	r1			@ quotient high
++onl	.req	r0			@ original dividend low
++onh	.req	r1			@ original dividend high
++nl	.req	r4			@ dividend low
++nh	.req	r5			@ dividend high
++res	.req	r4			@ result
++#else
++ql	.req	r1
++qh	.req	r0
++onl	.req	r1
++onh	.req	r0
++nl	.req	r5
++nh	.req	r4
++res	.req	r5
++#endif
++
++dl	.req	r3			@ divisor low
++dh	.req	r2			@ divsor high
++
++
++ENTRY(do_div64)
++	stmfd	sp!, {r4, r5, lr}
++	mov	nl, onl
++	movs	nh, onh			@ if high bits are zero
++	movne	lr, #33
++	moveq	lr, #1			@ only divide low bits
++	moveq	nh, onl
++
++	tst	dh, #0x80000000
++	bne	2f
++1:	cmp	nh, dh
++	bls	2f
++	add	lr, lr, #1
++	movs	dh, dh, lsl #1		@ left justify disor
++	bpl	1b
++
++2:	movs	nh, onh
++	moveq	dl, dh
++	moveq	dh, #0
++	movne	dl, #0
++	mov	ql, #0
++	mov	qh, #0
++3:	subs	ip, nl, dl		@ trial subtraction
++	sbcs	ip, nh, dh
++	movcs	nh, ip			@ only update if successful
++	subcs	nl, nl, dl		@ (repeat the subtraction)
++	adcs	ql, ql, ql		@ C=1 if successful, shift into
++	adc	qh, qh, qh		@ quotient
++	movs	dh, dh, lsr #1		@ shift base high part right
++	mov	dl, dl, rrx		@ shift base low part right
++	subs	lr, lr, #1
++	bne	3b
++
++	mov	r2, res
++	ldmfd	sp!, {r4, r5, pc}
+--- linux-2.4.25/arch/arm/lib/putuser.S~2.4.25-vrs2.patch	2001-10-11 18:04:57.000000000 +0200
++++ linux-2.4.25/arch/arm/lib/putuser.S	2004-03-31 17:15:09.000000000 +0200
+@@ -30,11 +30,11 @@
+ 
+ 	.global	__put_user_1
+ __put_user_1:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #1
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #1
++	cmp	r0, ip
+ 1:	strlsbt	r1, [r0]
+ 	movls	r0, #0
+ 	movls	pc, lr
+@@ -42,11 +42,11 @@
+ 
+ 	.global	__put_user_2
+ __put_user_2:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #2
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #2
++	cmp	r0, ip
+ 2:	strlsbt	r1, [r0], #1
+ 	movls	r1, r1, lsr #8
+ 3:	strlsbt	r1, [r0]
+@@ -56,11 +56,11 @@
+ 
+ 	.global	__put_user_4
+ __put_user_4:
+-	bic	r2, sp, #0x1f00
+-	bic	r2, r2, #0x00ff
+-	ldr	r2, [r2, #TSK_ADDR_LIMIT]
+-	sub	r2, r2, #4
+-	cmp	r0, r2
++	bic	ip, sp, #0x1f00
++	bic	ip, ip, #0x00ff
++	ldr	ip, [ip, #TSK_ADDR_LIMIT]
++	sub	ip, ip, #4
++	cmp	r0, ip
+ 4:	strlst	r1, [r0]
+ 	movls	r0, #0
+ 	movls	pc, lr
+--- linux-2.4.25/arch/arm/mach-integrator/pci_v3.c~2.4.25-vrs2.patch	2003-06-13 16:51:29.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-integrator/pci_v3.c	2004-03-31 17:15:09.000000000 +0200
+@@ -21,7 +21,6 @@
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+ #include <linux/config.h>
+-#include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/pci.h>
+ #include <linux/ptrace.h>
+@@ -32,6 +31,7 @@
+ #include <linux/init.h>
+ 
+ #include <asm/hardware.h>
++#include <asm/io.h>
+ #include <asm/irq.h>
+ #include <asm/system.h>
+ #include <asm/mach/pci.h>
+@@ -447,15 +447,16 @@
+ #define SC_LBFADDR (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x20)
+ #define SC_LBFCODE (IO_ADDRESS(INTEGRATOR_SC_BASE) + 0x24)
+ 
+-static int v3_fault(unsigned long addr, struct pt_regs *regs)
++static int
++v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+ 	unsigned long pc = instruction_pointer(regs);
+ 	unsigned long instr = *(unsigned long *)pc;
+ #if 0
+ 	char buf[128];
+ 
+-	sprintf(buf, "V3 fault: address=0x%08lx, pc=0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
+-		addr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
++	sprintf(buf, "V3 fault: addr 0x%08lx, FSR 0x%03x, PC 0x%08lx [%08lx] LBFADDR=%08x LBFCODE=%02x ISTAT=%02x\n",
++		addr, fsr, pc, instr, __raw_readl(SC_LBFADDR), __raw_readl(SC_LBFCODE) & 255,
+ 		v3_readb(V3_LB_ISTAT));
+ 	printk(KERN_DEBUG "%s", buf);
+ 	printascii(buf);
+@@ -523,8 +524,6 @@
+ #endif
+ }
+ 
+-extern int (*external_fault)(unsigned long addr, struct pt_regs *regs);
+-
+ /*
+  * V3_LB_BASE? - local bus address
+  * V3_LB_MAP?  - pci bus address
+@@ -539,7 +538,10 @@
+ 	/*
+ 	 * Hook in our fault handler for PCI errors
+ 	 */
+-	external_fault = v3_fault;
++	hook_fault_code(4, v3_pci_fault, SIGBUS, "external abort on linefetch");
++	hook_fault_code(6, v3_pci_fault, SIGBUS, "external abort on linefetch");
++	hook_fault_code(8, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
++	hook_fault_code(10, v3_pci_fault, SIGBUS, "external abort on non-linefetch");
+ 
+ 	spin_lock_irqsave(&v3_lock, flags);
+ 
+@@ -629,7 +631,7 @@
+ #if 0
+ 	ret = request_irq(IRQ_LBUSTIMEOUT, lb_timeout, 0, "bus timeout", NULL);
+ 	if (ret)
+-		printk(KERN_ERR "PCI: unable to grab local bus timeout ".
++		printk(KERN_ERR "PCI: unable to grab local bus timeout "
+ 		       "interrupt: %d\n", ret);
+ #endif
+ }
+--- linux-2.4.25/arch/arm/mach-sa1100/pm.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/pm.c	2004-03-31 17:15:09.000000000 +0200
+@@ -21,6 +21,8 @@
+  *
+  * 2002-05-27:	Nicolas Pitre	Killed sleep.h and the kmalloced save array.
+  * 				Storage is local on the stack now.
++ * 2003-06-25:  Jeff Corrall <jcorrall@mac.com>
++ *			Saved the GPIO levels for resume after sleep.
+  */
+ #include <linux/config.h>
+ #include <linux/init.h>
+@@ -70,13 +72,20 @@
+ int pm_do_suspend(void)
+ {
+ 	unsigned long sleep_save[SLEEP_SAVE_SIZE];
++	unsigned long sleep_save_gpsr;
++	unsigned long sleep_save_gpcr;
++	unsigned long delta;
+ 
+ 	cli();
+ 
+ 	leds_event(led_stop);
+ 
+ 	/* preserve current time */
+-	RCNR = xtime.tv_sec;
++	delta = xtime.tv_sec - RCNR;
++
++	/* save the current state of the GPIO output pins */
++	sleep_save_gpsr = GPDR & GPLR;
++	sleep_save_gpcr = GPDR & ~GPLR;
+ 
+ 	/* save vital registers */
+ 	SAVE(OSCR);
+@@ -121,6 +130,10 @@
+ 	printk(KERN_DEBUG "*** made it back from resume\n");
+ #endif
+ 
++	/* restore GPIO output state before enabling the pins */
++	GPSR = sleep_save_gpsr;
++	GPCR = sleep_save_gpcr;
++
+ 	/* restore registers */
+ 	RESTORE(GPDR);
+ 	RESTORE(GRER);
+@@ -151,7 +164,7 @@
+ 	RESTORE(ICMR);
+ 
+ 	/* restore current time */
+-	xtime.tv_sec = RCNR;
++	xtime.tv_sec = RCNR + delta;
+ 
+ 	leds_event(led_start);
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/sa1100_usb.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,193 @@
++/*
++ * sa1100_usb.h
++ *
++ * Public interface to the sa1100 USB core. For use by client modules
++ * like usb-eth and usb-char.
++ *
++ */
++
++#ifndef _SA1100_USB_H
++#define _SA1100_USB_H
++#include <asm/byteorder.h>
++
++typedef void (*usb_callback_t)(int flag, int size);
++
++/* in usb_ctl.c (see also descriptor methods at bottom of file) */
++
++// Open the USB client for client and initialize data structures
++// to default values, but _do not_ start UDC.
++int sa1100_usb_open( const char * client_name );
++
++// Start UDC running
++int sa1100_usb_start( void );
++
++// Immediately stop udc, fire off completion routines w/-EINTR
++int sa1100_usb_stop( void ) ;
++
++// Disconnect client from usb core
++int sa1100_usb_close( void ) ;
++
++// set notify callback for when core reaches configured state
++// return previous pointer (if any)
++typedef void (*usb_notify_t)(void);
++usb_notify_t sa1100_set_configured_callback( usb_notify_t callback );
++
++/* in usb_send.c */
++int sa1100_usb_xmitter_avail( void );
++int sa1100_usb_send(char *buf, int len, usb_callback_t callback);
++void sa1100_usb_send_reset(void);
++
++/* in usb_recev.c */
++int sa1100_usb_recv(char *buf, int len, usb_callback_t callback);
++void sa1100_usb_recv_reset(void);
++
++//////////////////////////////////////////////////////////////////////////////
++// Descriptor Management
++//////////////////////////////////////////////////////////////////////////////
++
++#define DescriptorHeader \
++	__u8 bLength;        \
++	__u8 bDescriptorType
++
++
++// --- Device Descriptor -------------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u16 bcdUSB;		   	/* USB specification revision number in BCD */
++	 __u8  bDeviceClass;	/* USB class for entire device */
++	 __u8  bDeviceSubClass; /* USB subclass information for entire device */
++	 __u8  bDeviceProtocol; /* USB protocol information for entire device */
++	 __u8  bMaxPacketSize0; /* Max packet size for endpoint zero */
++	 __u16 idVendor;        /* USB vendor ID */
++	 __u16 idProduct;       /* USB product ID */
++	 __u16 bcdDevice;       /* vendor assigned device release number */
++	 __u8  iManufacturer;	/* index of manufacturer string */
++	 __u8  iProduct;        /* index of string that describes product */
++	 __u8  iSerialNumber;	/* index of string containing device serial number */
++	 __u8  bNumConfigurations; /* number fo configurations */
++} __attribute__ ((packed)) device_desc_t;
++
++// --- Configuration Descriptor ------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u16 wTotalLength;	    /* total # of bytes returned in the cfg buf 4 this cfg */
++	 __u8  bNumInterfaces;      /* number of interfaces in this cfg */
++	 __u8  bConfigurationValue; /* used to uniquely ID this cfg */
++	 __u8  iConfiguration;      /* index of string describing configuration */
++	 __u8  bmAttributes;        /* bitmap of attributes for ths cfg */
++	 __u8  MaxPower;		    /* power draw in 2ma units */
++} __attribute__ ((packed)) config_desc_t;
++
++// bmAttributes:
++enum { USB_CONFIG_REMOTEWAKE=0x20, USB_CONFIG_SELFPOWERED=0x40,
++	   USB_CONFIG_BUSPOWERED=0x80 };
++// MaxPower:
++#define USB_POWER( x)  ((x)>>1) /* convert mA to descriptor units of A for MaxPower */
++
++// --- Interface Descriptor ---------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u8  bInterfaceNumber;   /* Index uniquely identfying this interface */
++	 __u8  bAlternateSetting;  /* ids an alternate setting for this interface */
++	 __u8  bNumEndpoints;      /* number of endpoints in this interface */
++	 __u8  bInterfaceClass;    /* USB class info applying to this interface */
++	 __u8  bInterfaceSubClass; /* USB subclass info applying to this interface */
++	 __u8  bInterfaceProtocol; /* USB protocol info applying to this interface */
++	 __u8  iInterface;         /* index of string describing interface */
++} __attribute__ ((packed)) intf_desc_t;
++
++// --- Endpoint  Descriptor ---------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u8  bEndpointAddress;  /* 0..3 ep num, bit 7: 0 = 0ut 1= in */
++	 __u8  bmAttributes;      /* 0..1 = 0: ctrl, 1: isoc, 2: bulk 3: intr */
++	 __u16 wMaxPacketSize;    /* data payload size for this ep in this cfg */
++	 __u8  bInterval;         /* polling interval for this ep in this cfg */
++} __attribute__ ((packed)) ep_desc_t;
++
++// bEndpointAddress:
++enum { USB_OUT= 0, USB_IN=1 };
++#define USB_EP_ADDRESS(a,d) (((a)&0xf) | ((d) << 7))
++// bmAttributes:
++enum { USB_EP_CNTRL=0, USB_EP_BULK=2, USB_EP_INT=3 };
++
++// --- String Descriptor -------------------
++
++typedef struct {
++	 DescriptorHeader;
++	 __u16 bString[1];		  /* unicode string .. actaully 'n' __u16s */
++} __attribute__ ((packed)) string_desc_t;
++
++/*=======================================================
++ * Handy helpers when working with above
++ *
++ */
++// these are x86-style 16 bit "words" ...
++#define make_word_c( w ) __constant_cpu_to_le16(w)
++#define make_word( w )   __cpu_to_le16(w)
++
++// descriptor types
++enum { USB_DESC_DEVICE=1, USB_DESC_CONFIG=2, USB_DESC_STRING=3,
++	   USB_DESC_INTERFACE=4, USB_DESC_ENDPOINT=5 };
++
++
++/*=======================================================
++ * Default descriptor layout for SA-1100 and SA-1110 UDC
++ */
++
++/* "config descriptor buffer" - that is, one config,
++   ..one interface and 2 endpoints */
++struct cdb {
++	 config_desc_t cfg;
++	 intf_desc_t   intf;
++	 ep_desc_t     ep1;
++	 ep_desc_t     ep2;
++} __attribute__ ((packed));
++
++
++/* all SA device descriptors */
++typedef struct {
++	 device_desc_t dev;   /* device descriptor */
++	 struct cdb b;        /* bundle of descriptors for this cfg */
++} __attribute__ ((packed)) desc_t;
++
++
++/*=======================================================
++ * Descriptor API
++ */
++
++/* Get the address of the statically allocated desc_t structure
++   in the usb core driver. Clients can modify this between
++   the time they call sa1100_usb_open() and sa1100_usb_start()
++*/
++desc_t *
++sa1100_usb_get_descriptor_ptr( void );
++
++
++/* Set a pointer to the string descriptor at "index". The driver
++ ..has room for 8 string indicies internally. Index zero holds
++ ..a LANGID code and is set to US English by default. Inidices
++ ..1-7 are available for use in the config descriptors as client's
++ ..see fit. This pointer is assumed to be good as long as the
++ ..SA usb core is open (so statically allocate them). Returnes -EINVAL
++ ..if index out of range */
++int sa1100_usb_set_string_descriptor( int index, string_desc_t * p );
++
++/* reverse of above */
++string_desc_t *
++sa1100_usb_get_string_descriptor( int index );
++
++/* kmalloc() a string descriptor and convert "p" to unicode in it */
++string_desc_t *
++sa1100_usb_kmalloc_string_descriptor( const char * p );
++
++
++
++
++
++
++#endif /* _SA1100_USB_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/sa1111-ohci.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,140 @@
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/pci.h>
++#include <linux/mm.h>
++
++#ifdef CONFIG_USB_OHCI
++
++/*
++ * The SA-1111 errata says that the DMA hardware needs to be exercised
++ * before the clocks are turned on to work properly.  This code does
++ * a tiny dma transfer to prime to hardware.
++ *
++ *  What DMA errata?  I've checked October 1999 and February 2001, both
++ *  of which do not mention such a bug, let alone any details of this
++ *  work-around.
++ */
++static void __init sa1111_dma_setup(void)
++{
++	dma_addr_t dma_buf;
++	void * vbuf;
++
++	/* DMA init & setup */
++
++	/* WARNING: The SA-1111 L3 function is used as part of this
++	 * SA-1111 DMA errata workaround.
++	 *
++	 * N.B., When the L3 function is enabled, it uses GPIO_B<4:5>
++	 * and takes precedence over the PS/2 mouse and GPIO_B
++	 * functions. Refer to "Intel StrongARM SA-1111 Microprocessor
++	 * Companion Chip, Sect 10.2" for details.  So this "fix" may
++	 * "break" support of either PS/2 mouse or GPIO_B if
++	 * precautions are not taken to avoid collisions in
++	 * configuration and use of these pins. AFAIK, no precautions
++	 * are taken at this time. So it is likely that the action
++	 * taken here may cause problems in PS/2 mouse and/or GPIO_B
++	 * pin use elsewhere.
++	 *
++	 * But wait, there's more... What we're doing here is
++	 * obviously altogether a bad idea. We're indiscrimanately bit
++	 * flipping config for a few different functions here which
++	 * are "owned" by other drivers. This needs to be handled
++	 * better than it is being done here at this time.  */
++
++	/* prime the dma engine with a tiny dma */
++	SKPCR |= SKPCR_I2SCLKEN;
++	SKAUD |= SKPCR_L3CLKEN | SKPCR_SCLKEN;
++
++	SACR0 |= 0x00003305;
++	SACR1 = 0x00000000;
++
++	/*
++	 * We need memory below 1MB.
++	 *  NOTE: consistent_alloc gives you some random virtual
++	 *  address as its return value, and the DMA address via
++	 *  the dma_addr_t pointer.
++	 */
++	vbuf = consistent_alloc(GFP_KERNEL | GFP_DMA, 4, &dma_buf);
++
++	SADTSA = (unsigned long)dma_buf;
++	SADTCA = 4;
++
++	SADTCS |= 0x00000011;
++	SKPCR |= SKPCR_DCLKEN;
++
++	/* wait */
++	udelay(100);
++
++	/* clear reserved but, then disable SAC */
++	SACR0 &= ~(0x00000002);
++	SACR0 &= ~(0x00000001);
++
++	/* toggle bit clock direction */
++	SACR0 |= 0x00000004;
++	SACR0 &= ~(0x00000004);
++
++	SKAUD &= ~(SKPCR_L3CLKEN | SKPCR_SCLKEN);
++
++	SKPCR &= ~SKPCR_I2SCLKEN;
++
++	consistent_free(vbuf, 4, dma_buf);
++}
++
++/*
++ * reset the SA-1111 usb controller and turn on it's clocks
++ */
++int __init sa1111_ohci_hcd_init(void)
++{
++	unsigned int usb_reset = 0;
++
++	if (machine_is_xp860() ||
++	    machine_has_neponset() ||
++	    machine_is_pfs168() ||
++	    machine_is_badge4())
++		usb_reset = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
++
++	/*
++	 * turn on USB clocks
++	 */
++	SKPCR |= SKPCR_UCLKEN;
++	udelay(100);
++
++	/*
++	 * Force USB reset
++	 */
++	USB_RESET = USB_RESET_FORCEIFRESET;
++	USB_RESET |= USB_RESET_FORCEHCRESET;
++	udelay(100);
++
++	/*
++	 * Take out of reset
++	 */
++	USB_RESET = 0;
++
++	/*
++	 * set power sense and control lines (this from the diags code)
++	 */
++        USB_RESET = usb_reset;
++
++        /*
++         * Huh?  This is a _read only_ register --rmk
++         */
++	USB_STATUS = 0;
++
++	udelay(10);
++
++	/*
++	 * compensate for dma bug
++	 */
++	sa1111_dma_setup();
++
++	return 0;
++}
++
++void sa1111_ohci_hcd_cleanup(void)
++{
++	/* turn the USB clock off */
++	SKPCR &= ~SKPCR_UCLKEN;
++}
++
++#endif /* CONFIG_USB_OHCI */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb-char.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,723 @@
++/*
++ * (C) Copyright 2000-2001 Extenex 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., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *  usb-char.c
++ *
++ *  Miscellaneous character device interface for SA1100 USB function
++ *	driver.
++ *
++ *  Background:
++ *  The SA1100 function driver ported from the Compaq Itsy project
++ *  has an interface, usb-eth.c, to feed network packets over the
++ *  usb wire and into the Linux TCP/IP stack.
++ *
++ *  This file replaces that one with a simple character device
++ *  interface that allows unstructured "byte pipe" style reads and
++ *  writes over the USB bulk endpoints by userspace programs.
++ *
++ *  A new define, CONFIG_SA1100_USB_NETLINK, has been created that,
++ *  when set, (the default) causes the ethernet interface to be used.
++ *  When not set, this more pedestrian character interface is linked
++ *  in instead.
++ *
++ *  Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ *
++ *  ward.willats@extenex.com
++ *
++ *  To do:
++ *  - Can't dma into ring buffer directly with pci_map/unmap usb_recv
++ *    uses and get bytes out at the same time DMA is going on. Investigate:
++ *    a) changing usb_recv to use alloc_consistent() at client request; or
++ *    b) non-ring-buffer based data structures. In the meantime, I am using
++ *    a bounce buffer. Simple, but wasteful.
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/cache.h>
++#include <linux/poll.h>
++#include <linux/circ_buf.h>
++#include <linux/timer.h>
++
++#include <asm/io.h>
++#include <asm/semaphore.h>
++#include <asm/proc/page.h>
++#include <asm/mach-types.h>
++
++#include "usb-char.h"
++#include "sa1100_usb.h"
++
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Driver  Options
++//////////////////////////////////////////////////////////////////////////////
++
++#define VERSION 	"0.4"
++
++
++#define VERBOSITY 1
++
++#if VERBOSITY
++# define	PRINTK(x, a...)	printk (x, ## a)
++#else
++# define	PRINTK(x, a...)	/**/
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals - Macros - Enums - Structures
++//////////////////////////////////////////////////////////////////////////////
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++typedef int bool; enum { false = 0, true = 1 };
++
++static const char pszMe[] = "usbchr: ";
++
++static wait_queue_head_t wq_read;
++static wait_queue_head_t wq_write;
++static wait_queue_head_t wq_poll;
++
++/* Serialze multiple writers onto the transmit hardware
++.. since we sleep the writer during transmit to stay in
++.. sync. (Multiple writers don't make much sense, but..) */
++static DECLARE_MUTEX( xmit_sem );
++
++// size of usb DATA0/1 packets. 64 is standard maximum
++// for bulk transport, though most hosts seem to be able
++// to handle larger.
++#define TX_PACKET_SIZE 64
++#define RX_PACKET_SIZE 64
++#define RBUF_SIZE  (4*PAGE_SIZE)
++
++static struct wcirc_buf {
++  char *buf;
++  int in;
++  int out;
++} rx_ring = { NULL, 0, 0 };
++
++static struct {
++	 unsigned long  cnt_rx_complete;
++	 unsigned long  cnt_rx_errors;
++	 unsigned long  bytes_rx;
++	 unsigned long  cnt_tx_timeouts;
++	 unsigned long  cnt_tx_errors;
++	 unsigned long  bytes_tx;
++} charstats;
++
++
++static char * tx_buf = NULL;
++static char * packet_buffer = NULL;
++static int sending = 0;
++static int usb_ref_count = 0;
++static int last_tx_result = 0;
++static int last_rx_result = 0;
++static int last_tx_size = 0;
++static struct timer_list tx_timer;
++
++//////////////////////////////////////////////////////////////////////////////
++// Prototypes
++//////////////////////////////////////////////////////////////////////////////
++static char * 	what_the_f( int e );
++static void 	free_txrx_buffers( void );
++static void     twiddle_descriptors( void );
++static void     free_string_descriptors( void ) ;
++static int      usbc_open( struct inode *pInode, struct file *pFile );
++static void     rx_done_callback_packet_buffer( int flag, int size );
++
++static void     tx_timeout( unsigned long );
++static void     tx_done_callback( int flag, int size );
++
++static ssize_t  usbc_read( struct file *, char *, size_t, loff_t * );
++static ssize_t  usbc_write( struct file *, const char *, size_t, loff_t * );
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait );
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++                       unsigned int nCmd, unsigned long argument );
++static int      usbc_close( struct inode *pInode, struct file *pFile );
++
++#ifdef CONFIG_SA1100_EXTENEX1
++static void     extenex_configured_notify_proc( void );
++#endif
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++static char * what_the_f( int e )
++{
++	 char * p;
++	 switch( e ) {
++	 case 0:
++		  p = "noErr";
++		  break;
++	 case -ENODEV:
++		  p = "ENODEV - usb not in config state";
++		  break;
++	 case -EBUSY:
++		  p = "EBUSY - another request on the hardware";
++		  break;
++	 case -EAGAIN:
++		  p = "EAGAIN";
++		  break;
++	 case -EINTR:
++		  p = "EINTR - interrupted\n";
++		  break;
++	 case -EPIPE:
++		  p = "EPIPE - zero length xfer\n";
++		  break;
++	 default:
++		  p = "????";
++		  break;
++	 }
++	 return p;
++}
++
++static void free_txrx_buffers( void )
++{
++	 if ( rx_ring.buf != NULL ) {
++		  kfree( rx_ring.buf );
++		  rx_ring.buf = NULL;
++	 }
++	 if ( packet_buffer != NULL ) {
++		  kfree( packet_buffer );
++		  packet_buffer = NULL;
++	 }
++	 if ( tx_buf != NULL ) {
++		  kfree( tx_buf );
++		  tx_buf = NULL;
++	 }
++}
++
++/* twiddle_descriptors()
++ * It is between open() and start(). Setup descriptors.
++ */
++static void twiddle_descriptors( void )
++{
++	 desc_t * pDesc = sa1100_usb_get_descriptor_ptr();
++	 string_desc_t * pString;
++
++	 pDesc->b.ep1.wMaxPacketSize = make_word_c( RX_PACKET_SIZE );
++	 pDesc->b.ep1.bmAttributes   = USB_EP_BULK;
++	 pDesc->b.ep2.wMaxPacketSize = make_word_c( TX_PACKET_SIZE );
++	 pDesc->b.ep2.bmAttributes   = USB_EP_BULK;
++
++	 if ( machine_is_extenex1() ) {
++#ifdef CONFIG_SA1100_EXTENEX1
++		  pDesc->dev.idVendor = make_word_c( 0xC9F );
++		  pDesc->dev.idProduct = 1;
++		  pDesc->dev.bcdDevice = make_word_c( 0x0001 );
++		  pDesc->b.cfg.bmAttributes = USB_CONFIG_SELFPOWERED;
++		  pDesc->b.cfg.MaxPower = 0;
++
++		  pString = sa1100_usb_kmalloc_string_descriptor( "Extenex" );
++		  if ( pString ) {
++			   sa1100_usb_set_string_descriptor( 1, pString );
++			   pDesc->dev.iManufacturer = 1;
++		  }
++
++		  pString = sa1100_usb_kmalloc_string_descriptor( "Handheld Theater" );
++		  if ( pString ) {
++			   sa1100_usb_set_string_descriptor( 2, pString );
++			   pDesc->dev.iProduct = 2;
++		  }
++
++		  pString = sa1100_usb_kmalloc_string_descriptor( "00000000" );
++		  if ( pString ) {
++			   sa1100_usb_set_string_descriptor( 3, pString );
++			   pDesc->dev.iSerialNumber = 3;
++		  }
++
++		  pString = sa1100_usb_kmalloc_string_descriptor( "HHT Bulk Transfer" );
++		  if ( pString ) {
++			   sa1100_usb_set_string_descriptor( 4, pString );
++			   pDesc->b.intf.iInterface = 4;
++		  }
++		  sa1100_set_configured_callback( extenex_configured_notify_proc );
++#endif
++	 }
++}
++
++static void free_string_descriptors( void )
++{
++	 if ( machine_is_extenex1() ) {
++		  string_desc_t * pString;
++		  int i;
++		  for( i = 1 ; i <= 4 ; i++ ) {
++			   pString = sa1100_usb_get_string_descriptor( i );
++			   if ( pString )
++					kfree( pString );
++		  }
++	 }
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// ASYNCHRONOUS
++//////////////////////////////////////////////////////////////////////////////
++static  void kick_start_rx( void )
++{
++	 if ( usb_ref_count ) {
++		  int total_space  = CIRC_SPACE( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  if ( total_space >= RX_PACKET_SIZE ) {
++			   sa1100_usb_recv( packet_buffer,
++								RX_PACKET_SIZE,
++								rx_done_callback_packet_buffer
++						      );
++		  }
++	 }
++}
++/*
++ * rx_done_callback_packet_buffer()
++ * We have completed a DMA xfer into the temp packet buffer.
++ * Move to ring.
++ *
++ * flag values:
++ * on init,  -EAGAIN
++ * on reset, -EINTR
++ * on RPE, -EIO
++ * on short packet -EPIPE
++ */
++static void
++rx_done_callback_packet_buffer( int flag, int size )
++{
++	 charstats.cnt_rx_complete++;
++
++	 if ( flag == 0 || flag == -EPIPE ) {
++		  size_t n;
++
++		  charstats.bytes_rx += size;
++
++		  n = CIRC_SPACE_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  n = MIN( n, size );
++		  size -= n;
++
++		  memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer, n );
++		  rx_ring.in = (rx_ring.in + n) & (RBUF_SIZE-1);
++		  memcpy( &rx_ring.buf[ rx_ring.in ], packet_buffer + n, size );
++		  rx_ring.in = (rx_ring.in + size) & (RBUF_SIZE-1);
++
++		  wake_up_interruptible( &wq_read );
++		  wake_up_interruptible( &wq_poll );
++
++		  last_rx_result = 0;
++
++		  kick_start_rx();
++
++	 } else if ( flag != -EAGAIN ) {
++		  charstats.cnt_rx_errors++;
++		  last_rx_result = flag;
++		  wake_up_interruptible( &wq_read );
++		  wake_up_interruptible( &wq_poll );
++	 }
++	 else  /* init, start a read */
++		  kick_start_rx();
++}
++
++
++static void tx_timeout( unsigned long unused )
++{
++	printk( "%stx timeout\n", pszMe );
++	sa1100_usb_send_reset();
++	charstats.cnt_tx_timeouts++;
++}
++
++
++// on init, -EAGAIN
++// on reset, -EINTR
++// on TPE, -EIO
++static void tx_done_callback( int flags, int size )
++{
++	 if ( flags == 0 )
++		  charstats.bytes_tx += size;
++	 else
++		  charstats.cnt_tx_errors++;
++	 last_tx_size = size;
++	 last_tx_result = flags;
++	 sending = 0;
++	 wake_up_interruptible( &wq_write );
++	 wake_up_interruptible( &wq_poll );
++}
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Workers
++//////////////////////////////////////////////////////////////////////////////
++
++static int usbc_open( struct inode *pInode, struct file *pFile )
++{
++	 int retval = 0;
++
++	 PRINTK( KERN_DEBUG "%sopen()\n", pszMe );
++
++	 /* start usb core */
++	 retval = sa1100_usb_open( "usb-char" );
++	 if ( retval ) return retval;
++
++	 /* allocate memory */
++	 if ( usb_ref_count == 0 ) {
++		  tx_buf = (char*) kmalloc( TX_PACKET_SIZE, GFP_KERNEL | GFP_DMA );
++		  if ( tx_buf == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE TX BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++		  rx_ring.buf =
++			(char*) kmalloc( RBUF_SIZE, GFP_KERNEL );
++
++		  if ( rx_ring.buf == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE RX BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++
++		  packet_buffer =
++			(char*) kmalloc( RX_PACKET_SIZE, GFP_KERNEL | GFP_DMA  );
++
++		  if ( packet_buffer == NULL ) {
++			   printk( "%sARGHH! COULD NOT ALLOCATE RX PACKET BUFFER\n", pszMe );
++			   goto malloc_fail;
++		  }
++		  rx_ring.in = rx_ring.out = 0;
++		  memset( &charstats, 0, sizeof( charstats ) );
++		  sending = 0;
++		  last_tx_result = 0;
++		  last_tx_size = 0;
++	 }
++
++	 /* modify default descriptors */
++	 twiddle_descriptors();
++
++	 retval = sa1100_usb_start();
++	 if ( retval ) {
++		  printk( "%sAGHH! Could not USB core\n", pszMe );
++		  free_txrx_buffers();
++		  return retval;
++	 }
++	 usb_ref_count++;   /* must do _before_ kick_start() */
++	 MOD_INC_USE_COUNT;
++	 kick_start_rx();
++	 return 0;
++
++ malloc_fail:
++	 free_txrx_buffers();
++	 return -ENOMEM;
++}
++
++/*
++ * Read endpoint. Note that you can issue a read to an
++ * unconfigured endpoint. Eventually, the host may come along
++ * and configure underneath this module and data will appear.
++ */
++static ssize_t usbc_read( struct file *pFile, char *pUserBuffer,
++                        size_t stCount, loff_t *pPos )
++{
++	 ssize_t retval;
++	 int flags;
++	 DECLARE_WAITQUEUE( wait, current );
++
++	 PRINTK( KERN_DEBUG "%sread()\n", pszMe );
++
++	 local_irq_save( flags );
++	 if ( last_rx_result == 0 ) {
++		  local_irq_restore( flags );
++	 } else {  /* an error happended and receiver is paused */
++		  local_irq_restore( flags );
++		  last_rx_result = 0;
++		  kick_start_rx();
++	 }
++
++	 add_wait_queue( &wq_read, &wait );
++	 while( 1 ) {
++		  ssize_t bytes_avail;
++		  ssize_t bytes_to_end;
++
++		  set_current_state( TASK_INTERRUPTIBLE );
++
++		  /* snap ring buf state */
++		  local_irq_save( flags );
++		  bytes_avail  = CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  bytes_to_end = CIRC_CNT_TO_END( rx_ring.in, rx_ring.out, RBUF_SIZE );
++		  local_irq_restore( flags );
++
++		  if ( bytes_avail != 0 ) {
++			   ssize_t bytes_to_move = MIN( stCount, bytes_avail );
++			   retval = 0;		// will be bytes transfered
++			   if ( bytes_to_move != 0 ) {
++					size_t n = MIN( bytes_to_end, bytes_to_move );
++					if ( copy_to_user( pUserBuffer,
++									   &rx_ring.buf[ rx_ring.out ],
++									   n ) ) {
++						 retval = -EFAULT;
++						 break;
++					}
++					bytes_to_move -= n;
++ 					retval += n;
++					// might go 1 char off end, so wrap
++					rx_ring.out = ( rx_ring.out + n ) & (RBUF_SIZE-1);
++					if ( copy_to_user( pUserBuffer + n,
++									   &rx_ring.buf[ rx_ring.out ],
++									   bytes_to_move )
++						 ) {
++						 retval = -EFAULT;
++						 break;
++					}
++					rx_ring.out += bytes_to_move;		// cannot wrap
++					retval += bytes_to_move;
++					kick_start_rx();
++			   }
++			   break;
++		  }
++		  else if ( last_rx_result ) {
++			   retval = last_rx_result;
++			   break;
++		  }
++		  else if ( pFile->f_flags & O_NONBLOCK ) {  // no data, can't sleep
++			   retval = -EAGAIN;
++			   break;
++		  }
++		  else if ( signal_pending( current ) ) {   // no data, can sleep, but signal
++			   retval = -ERESTARTSYS;
++			   break;
++		  }
++		  schedule();					   			// no data, can sleep
++	 }
++	 set_current_state( TASK_RUNNING );
++	 remove_wait_queue( &wq_read, &wait );
++
++	 if ( retval < 0 )
++		  printk( "%sread error %d - %s\n", pszMe, retval, what_the_f( retval ) );
++	 return retval;
++}
++
++/*
++ * Write endpoint. This routine attempts to break the passed in buffer
++ * into usb DATA0/1 packet size chunks and send them to the host.
++ * (The lower-level driver tries to do this too, but easier for us
++ * to manage things here.)
++ *
++ * We are at the mercy of the host here, in that it must send an IN
++ * token to us to pull this data back, so hopefully some higher level
++ * protocol is expecting traffic to flow in that direction so the host
++ * is actually polling us. To guard against hangs, a 5 second timeout
++ * is used.
++ *
++ * This routine takes some care to only report bytes sent that have
++ * actually made it across the wire. Thus we try to stay in lockstep
++ * with the completion routine and only have one packet on the xmit
++ * hardware at a time. Multiple simultaneous writers will get
++ * "undefined" results.
++ *
++  */
++static ssize_t  usbc_write( struct file *pFile, const char * pUserBuffer,
++							 size_t stCount, loff_t *pPos )
++{
++	 ssize_t retval = 0;
++	 ssize_t stSent = 0;
++
++	 DECLARE_WAITQUEUE( wait, current );
++
++	 PRINTK( KERN_DEBUG "%swrite() %d bytes\n", pszMe, stCount );
++
++	 down( &xmit_sem );  // only one thread onto the hardware at a time
++
++	 while( stCount != 0 && retval == 0 ) {
++		  int nThisTime  = MIN( TX_PACKET_SIZE, stCount );
++		  copy_from_user( tx_buf, pUserBuffer, nThisTime );
++		  sending = nThisTime;
++ 		  retval = sa1100_usb_send( tx_buf, nThisTime, tx_done_callback );
++		  if ( retval < 0 ) {
++			   char * p = what_the_f( retval );
++			   printk( "%sCould not queue xmission. rc=%d - %s\n",
++					   pszMe, retval, p );
++			   sending = 0;
++			   break;
++		  }
++		  /* now have something on the diving board */
++		  add_wait_queue( &wq_write, &wait );
++		  tx_timer.expires = jiffies + ( HZ * 5 );
++		  add_timer( &tx_timer );
++		  while( 1 ) {
++			   set_current_state( TASK_INTERRUPTIBLE );
++			   if ( sending == 0 ) {  /* it jumped into the pool */
++					del_timer( &tx_timer );
++					retval = last_tx_result;
++					if ( retval == 0 ) {
++						 stSent		 += last_tx_size;
++						 pUserBuffer += last_tx_size;
++						 stCount     -= last_tx_size;
++					}
++					else
++						 printk( "%sxmission error rc=%d - %s\n",
++								 pszMe, retval, what_the_f(retval) );
++					break;
++			   }
++			   else if ( signal_pending( current ) ) {
++					del_timer( &tx_timer );
++					printk( "%ssignal\n", pszMe  );
++					retval = -ERESTARTSYS;
++					break;
++			   }
++			   schedule();
++		  }
++		  set_current_state( TASK_RUNNING );
++		  remove_wait_queue( &wq_write, &wait );
++	 }
++
++	 up( &xmit_sem );
++
++	 if ( 0 == retval )
++		  retval = stSent;
++	 return retval;
++}
++
++static unsigned int usbc_poll( struct file *pFile, poll_table * pWait )
++{
++	 unsigned int retval = 0;
++
++	 PRINTK( KERN_DEBUG "%poll()\n", pszMe );
++
++	 poll_wait( pFile, &wq_poll, pWait );
++
++	 if ( CIRC_CNT( rx_ring.in, rx_ring.out, RBUF_SIZE ) )
++		  retval |= POLLIN | POLLRDNORM;
++	 if ( sa1100_usb_xmitter_avail() )
++		  retval |= POLLOUT | POLLWRNORM;
++	 return retval;
++}
++
++static int usbc_ioctl( struct inode *pInode, struct file *pFile,
++                       unsigned int nCmd, unsigned long argument )
++{
++	 int retval = 0;
++
++	 switch( nCmd ) {
++
++	 case USBC_IOC_FLUSH_RECEIVER:
++		  sa1100_usb_recv_reset();
++		  rx_ring.in = rx_ring.out = 0;
++		  break;
++
++	 case USBC_IOC_FLUSH_TRANSMITTER:
++		  sa1100_usb_send_reset();
++		  break;
++
++	 case USBC_IOC_FLUSH_ALL:
++		  sa1100_usb_recv_reset();
++		  rx_ring.in = rx_ring.out = 0;
++		  sa1100_usb_send_reset();
++		  break;
++
++	 default:
++		  retval = -ENOIOCTLCMD;
++		  break;
++
++	 }
++	 return retval;
++}
++
++
++static int usbc_close( struct inode *pInode, struct file * pFile )
++{
++	PRINTK( KERN_DEBUG "%sclose()\n", pszMe );
++	if ( --usb_ref_count == 0 ) {
++		 down( &xmit_sem );
++		 sa1100_usb_stop();
++		 free_txrx_buffers();
++		 free_string_descriptors();
++		 del_timer( &tx_timer );
++		 sa1100_usb_close();
++		 up( &xmit_sem );
++	}
++    MOD_DEC_USE_COUNT;
++    return 0;
++}
++
++#ifdef CONFIG_SA1100_EXTENEX1
++#include "../../../drivers/char/ex_gpio.h"
++void extenex_configured_notify_proc( void )
++{
++	 if ( exgpio_play_string( "440,1:698,1" ) == -EAGAIN )
++		  printk( "%sWanted to BEEP but ex_gpio not open\n", pszMe );
++}
++#endif
++//////////////////////////////////////////////////////////////////////////////
++// Initialization
++//////////////////////////////////////////////////////////////////////////////
++
++static struct file_operations usbc_fops = {
++		owner:      THIS_MODULE,
++		open:		usbc_open,
++		read:		usbc_read,
++		write:		usbc_write,
++		poll:		usbc_poll,
++		ioctl:		usbc_ioctl,
++		release:	usbc_close,
++};
++
++static struct miscdevice usbc_misc_device = {
++    USBC_MINOR, "usb_char", &usbc_fops
++};
++
++/*
++ * usbc_init()
++ */
++
++int __init usbc_init( void )
++{
++	 int rc;
++
++#if !defined( CONFIG_ARCH_SA1100 )
++	 return -ENODEV;
++#endif
++
++	 if ( (rc = misc_register( &usbc_misc_device )) != 0 ) {
++		  printk( KERN_WARNING "%sCould not register device 10, "
++				  "%d. (%d)\n", pszMe, USBC_MINOR, rc );
++		  return -EBUSY;
++	 }
++
++	 // initialize wait queues
++	 init_waitqueue_head( &wq_read );
++	 init_waitqueue_head( &wq_write );
++	 init_waitqueue_head( &wq_poll );
++
++	 // initialize tx timeout timer
++	 init_timer( &tx_timer );
++	 tx_timer.function = tx_timeout;
++
++	  printk( KERN_INFO "USB Function Character Driver Interface"
++				  " - %s, (C) 2001, Extenex Corp.\n", VERSION
++		   );
++
++	 return rc;
++}
++
++void __exit usbc_exit( void )
++{
++}
++
++EXPORT_NO_SYMBOLS;
++
++module_init(usbc_init);
++module_exit(usbc_exit);
++
++
++
++// end: usb-char.c
++
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb-char.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2001 Extenex Corporation
++ *
++ * usb-char.h
++ *
++ * Character device emulation client for SA-1100 client usb core.
++ *
++ *
++ *
++ */
++#ifndef _USB_CHAR_H
++#define _USB_CHAR_H
++
++#define USBC_MAJOR 10      /* miscellaneous character device */
++#define USBC_MINOR 240     /* in the "reserved for local use" range */
++
++#define USBC_MAGIC 0x8E
++
++/* zap everything in receive ring buffer */
++#define USBC_IOC_FLUSH_RECEIVER    _IO( USBC_MAGIC, 0x01 )
++
++/* reset transmitter */
++#define USBC_IOC_FLUSH_TRANSMITTER _IO( USBC_MAGIC, 0x02 )
++
++/* do both of above */
++#define USBC_IOC_FLUSH_ALL         _IO( USBC_MAGIC, 0x03 )
++
++
++
++
++
++
++#endif /* _USB_CHAR_H */
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb-eth.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,447 @@
++ /*
++ * Ethernet driver for the SA1100 USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original initial ethernet test driver
++ * Copyright (c) Compaq Computer Corporation, 1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This is still work in progress...
++ *
++ * 19/02/2001 - Now we are compatible with generic usbnet driver. green@iXcelerator.com
++ * 09/03/2001 - Dropped 'framing' scheme, as it seems to cause a lot of problems with little benefit.
++ *		Now, since we do not know what size of packet we are receiving
++ *		last usb packet in sequence will always be less than max packet
++ *		receive endpoint can accept.
++ *		Now the only way to check correct start of frame is to compare
++ *		MAC address. Also now we are stalling on each receive error.
++ *
++ * 15/03/2001 - Using buffer to get data from UDC. DMA needs to have 8 byte
++ *		aligned buffer, but this breaks IP code (unaligned access).
++ *
++ * 01/04/2001 - stall endpoint operations appeared to be very unstable, so
++ *              they are disabled now.
++ *
++ * 03/06/2001 - Readded "zerocopy" receive path (tunable).
++ *
++ */
++
++// Define DMA_NO_COPY if you want data to arrive directly into the
++// receive network buffers, instead of arriving into bounce buffer
++// and then get copied to network buffer.
++// This does not work correctly right now.
++#undef DMA_NO_COPY
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/timer.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/random.h>
++
++#include "sa1100_usb.h"
++
++
++#define ETHERNET_VENDOR_ID 0x49f
++#define ETHERNET_PRODUCT_ID 0x505A
++#define MAX_PACKET 32768
++#define MIN(a, b) (((a) < (b)) ? (a) : (b))
++
++// Should be global, so that insmod can change these
++int usb_rsize=64;
++int usb_wsize=64;
++
++static struct usbe_info_t {
++  struct net_device *dev;
++  u16 packet_id;
++  struct net_device_stats stats;
++} usbe_info;
++
++static char usb_eth_name[16] = "usbf";
++static struct net_device usb_eth_device;
++static struct sk_buff *cur_tx_skb, *next_tx_skb;
++static struct sk_buff *cur_rx_skb, *next_rx_skb;
++static volatile int terminating;
++#ifndef DMA_NO_COPY
++static char *dmabuf; // we need that, as dma expect it's buffers to be aligned on 8 bytes boundary
++#endif
++
++static int usb_change_mtu (struct net_device *net, int new_mtu)
++{
++	if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET)
++		return -EINVAL;
++	// no second zero-length packet read wanted after mtu-sized packets
++	if (((new_mtu + sizeof (struct ethhdr)) % usb_rsize) == 0)
++		return -EDOM;
++
++	net->mtu = new_mtu;
++	return 0;
++}
++
++static struct sk_buff *
++usb_new_recv_skb(void)
++{
++	struct sk_buff *skb = alloc_skb( 2 + sizeof (struct ethhdr) + usb_eth_device.mtu,GFP_ATOMIC);
++
++	if (skb) {
++		skb_reserve(skb, 2);
++	}
++	return skb;
++}
++
++static u8 bcast_hwaddr[ETH_ALEN]={0xff,0xff,0xff,0xff,0xff,0xff};
++static void
++usb_recv_callback(int flag, int size)
++{
++	struct sk_buff *skb;
++
++	if (terminating)
++		return;
++
++	skb = cur_rx_skb;
++
++	/* flag validation */
++	if (flag == 0) {
++		if ( skb_tailroom (skb) < size ) { // hey! we are overloaded!!!
++			usbe_info.stats.rx_over_errors++;
++			goto error;
++		}
++#ifndef DMA_NO_COPY
++		memcpy(skb->tail,dmabuf,size);
++#endif
++		skb_put(skb, size);
++	} else {
++		if (flag == -EIO) {
++			usbe_info.stats.rx_errors++;
++		}
++		goto error;
++	}
++
++	/* validate packet length */
++	if (size == usb_rsize ) {
++		/* packet not complete yet */
++		skb = NULL;
++	}
++
++	/*
++	 * At this point skb is non null if we have a complete packet.
++	 * If so take a fresh skb right away and restart USB receive without
++	 * further delays, then process the packet.  Otherwise resume USB
++	 * receive on the current skb and exit.
++	 */
++
++	if (skb)
++		cur_rx_skb = next_rx_skb;
++#ifndef DMA_NO_COPY
++	sa1100_usb_recv(dmabuf, usb_rsize,
++			usb_recv_callback);
++#else
++	sa1100_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)),
++			usb_recv_callback);
++#endif
++	if (!skb)
++		return;
++
++	next_rx_skb = usb_new_recv_skb();
++	if (!next_rx_skb) {
++		/*
++		 * We can't aford loosing buffer space...
++		 * So we drop the current packet and recycle its skb.
++		 */
++		printk("%s: can't allocate new skb\n", __FUNCTION__);
++		usbe_info.stats.rx_dropped++;
++		skb_trim(skb, 0);
++		next_rx_skb = skb;
++		return;
++	}
++	if ( skb->len >= sizeof(struct ethhdr)) {
++		if (memcmp(skb->data,usb_eth_device.dev_addr,ETH_ALEN) && memcmp(skb->data,bcast_hwaddr,ETH_ALEN) ) {
++			// This frame is not for us. nor it is broadcast
++			usbe_info.stats.rx_frame_errors++;
++			kfree_skb(skb);
++			goto error;
++		}
++	}
++
++	if (skb->len) {
++		int     status;
++// FIXME: eth_copy_and_csum "small" packets to new SKB (small < ~200 bytes) ?
++
++		skb->dev = &usb_eth_device;
++		skb->protocol = eth_type_trans (skb, &usb_eth_device);
++		usbe_info.stats.rx_packets++;
++		usbe_info.stats.rx_bytes += skb->len;
++		skb->ip_summed = CHECKSUM_NONE;
++		status = netif_rx (skb);
++		if (status != NET_RX_SUCCESS)
++			printk("netif_rx failed with code %d\n",status);
++	} else {
++error:
++		/*
++		 * Error due to HW addr mismatch, or IO error.
++		 * Recycle the current skb and reset USB reception.
++		 */
++		skb_trim(cur_rx_skb, 0);
++//		if ( flag == -EINTR || flag == -EAGAIN ) // only if we are coming out of stall
++#ifndef DMA_NO_COPY
++			sa1100_usb_recv(dmabuf, usb_rsize, usb_recv_callback);
++#else
++			sa1100_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)), usb_recv_callback);
++#endif
++	}
++}
++
++
++static void
++usb_send_callback(int flag, int size)
++{
++	struct net_device *dev = usbe_info.dev;
++	struct net_device_stats *stats;
++	struct sk_buff *skb=cur_tx_skb;
++	int ret;
++
++	if (terminating)
++		return;
++
++	stats = &usbe_info.stats;
++	switch (flag) {
++	    case 0:
++		stats->tx_packets++;
++		stats->tx_bytes += size;
++		break;
++	    case -EIO:
++		stats->tx_errors++;
++		break;
++	    default:
++		stats->tx_dropped++;
++		break;
++	}
++
++	cur_tx_skb = next_tx_skb;
++	next_tx_skb = NULL;
++	dev_kfree_skb_irq(skb);
++	if (!cur_tx_skb)
++		return;
++
++	dev->trans_start = jiffies;
++	ret = sa1100_usb_send(cur_tx_skb->data, cur_tx_skb->len, usb_send_callback);
++	if (ret) {
++		/* If the USB core can't accept the packet, we drop it. */
++		dev_kfree_skb_irq(cur_tx_skb);
++		cur_tx_skb = NULL;
++		usbe_info.stats.tx_carrier_errors++;
++	}
++	netif_wake_queue(dev);
++}
++
++static int
++usb_eth_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	int ret;
++	unsigned long flags;
++
++	if (next_tx_skb) {
++		printk("%s: called with next_tx_skb != NULL\n", __FUNCTION__);
++		return 1;
++	}
++
++	if (skb_shared (skb)) {
++		struct sk_buff  *skb2 = skb_unshare(skb, GFP_ATOMIC);
++		if (!skb2) {
++			usbe_info.stats.tx_dropped++;
++			dev_kfree_skb(skb);
++			return 1;
++		}
++		skb = skb2;
++	}
++
++	if ((skb->len % usb_wsize) == 0) {
++		skb->len++; // other side will ignore this one, anyway.
++	}
++
++	local_irq_save(flags);
++	if (cur_tx_skb) {
++		next_tx_skb = skb;
++		netif_stop_queue(dev);
++	} else {
++		cur_tx_skb = skb;
++		dev->trans_start = jiffies;
++		ret = sa1100_usb_send(skb->data, skb->len, usb_send_callback);
++		if (ret) {
++			/* If the USB core can't accept the packet, we drop it. */
++			dev_kfree_skb(skb);
++			cur_tx_skb = NULL;
++			usbe_info.stats.tx_carrier_errors++;
++		}
++	}
++	local_irq_restore(flags);
++	return 0;
++}
++
++static void
++usb_xmit_timeout(struct net_device *dev )
++{
++	sa1100_usb_send_reset();
++	dev->trans_start = jiffies;
++	netif_wake_queue(dev);
++}
++
++
++static int
++usb_eth_open(struct net_device *dev)
++{
++	terminating = 0;
++	cur_tx_skb = next_tx_skb = NULL;
++	cur_rx_skb = usb_new_recv_skb();
++	next_rx_skb = usb_new_recv_skb();
++	if (!cur_rx_skb || !next_rx_skb) {
++		printk("%s: can't allocate new skb\n", __FUNCTION__);
++		if (cur_rx_skb)
++			kfree_skb(cur_rx_skb);
++		if (next_rx_skb)
++			kfree_skb(next_rx_skb);
++		return -ENOMEM;;
++	}
++
++	MOD_INC_USE_COUNT;
++#ifndef DMA_NO_COPY
++	sa1100_usb_recv(dmabuf, usb_rsize, usb_recv_callback);
++#else
++	sa1100_usb_recv(cur_rx_skb->tail, MIN(usb_rsize, skb_tailroom (cur_rx_skb)),
++			usb_recv_callback);
++#endif
++	return 0;
++}
++
++static int
++usb_eth_release(struct net_device *dev)
++{
++	terminating = 1;
++	sa1100_usb_send_reset();
++	sa1100_usb_recv_reset();
++	if (cur_tx_skb)
++		kfree_skb(cur_tx_skb);
++	if (next_tx_skb)
++		kfree_skb(next_tx_skb);
++	if (cur_rx_skb)
++		kfree_skb(cur_rx_skb);
++	if (next_rx_skb)
++		kfree_skb(next_rx_skb);
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static struct net_device_stats *
++usb_eth_stats(struct net_device *dev)
++{
++	struct usbe_info_t *priv =  (struct usbe_info_t*) dev->priv;
++	struct net_device_stats *stats=NULL;
++
++	if (priv)
++		stats = &priv->stats;
++	return stats;
++}
++
++static int
++usb_eth_probe(struct net_device *dev)
++{
++	u8 node_id [ETH_ALEN];
++
++	get_random_bytes (node_id, sizeof node_id);
++	node_id [0] &= 0xfe;    // clear multicast bit
++
++	/*
++	 * Assign the hardware address of the board:
++	 * generate it randomly, as there can be many such
++	 * devices on the bus.
++	 */
++	memcpy (dev->dev_addr, node_id, sizeof node_id);
++
++	dev->open = usb_eth_open;
++	dev->change_mtu = usb_change_mtu;
++	dev->stop = usb_eth_release;
++	dev->hard_start_xmit = usb_eth_xmit;
++	dev->get_stats = usb_eth_stats;
++	dev->watchdog_timeo = 1*HZ;
++	dev->tx_timeout = usb_xmit_timeout;
++	dev->priv = &usbe_info;
++
++	usbe_info.dev = dev;
++
++	/* clear the statistics */
++	memset(&usbe_info.stats, 0, sizeof(struct net_device_stats));
++
++	ether_setup(dev);
++	dev->flags &= ~IFF_MULTICAST;
++	dev->flags &= ~IFF_BROADCAST;
++	//dev->flags |= IFF_NOARP;
++
++	return 0;
++}
++
++#ifdef MODULE
++MODULE_PARM(usb_rsize, "1i");
++MODULE_PARM_DESC(usb_rsize, "number of bytes in packets from host to sa1100");
++MODULE_PARM(usb_wsize, "1i");
++MODULE_PARM_DESC(usb_wsize, "number of bytes in packets from sa1100 to host");
++#endif
++
++static int __init
++usb_eth_init(void)
++{
++	int rc;
++
++#ifndef DMA_NO_COPY
++	dmabuf = kmalloc( usb_rsize, GFP_KERNEL | GFP_DMA );
++	if (!dmabuf)
++		return -ENOMEM;
++#endif
++	strncpy(usb_eth_device.name, usb_eth_name, IFNAMSIZ);
++	usb_eth_device.init = usb_eth_probe;
++	if (register_netdev(&usb_eth_device) != 0)
++		return -EIO;
++
++	rc = sa1100_usb_open( "usb-eth" );
++	if ( rc == 0 ) {
++		 string_desc_t * pstr;
++		 desc_t * pd = sa1100_usb_get_descriptor_ptr();
++
++		 pd->b.ep1.wMaxPacketSize = make_word( usb_rsize );
++		 pd->b.ep2.wMaxPacketSize = make_word( usb_wsize );
++		 pd->dev.idVendor	  = ETHERNET_VENDOR_ID;
++		 pd->dev.idProduct     = ETHERNET_PRODUCT_ID;
++		 pstr = sa1100_usb_kmalloc_string_descriptor( "SA1100 USB NIC" );
++		 if ( pstr ) {
++			  sa1100_usb_set_string_descriptor( 1, pstr );
++			  pd->dev.iProduct = 1;
++		 }
++		 rc = sa1100_usb_start();
++	}
++	return rc;
++}
++
++module_init(usb_eth_init);
++
++static void __exit
++usb_eth_cleanup(void)
++{
++	string_desc_t * pstr;
++	sa1100_usb_stop();
++	sa1100_usb_close();
++	if ( (pstr = sa1100_usb_get_string_descriptor(1)) != NULL )
++		kfree( pstr );
++#ifndef DMA_NO_COPY
++	kfree(dmabuf);
++#endif
++	unregister_netdev(&usb_eth_device);
++}
++
++module_exit(usb_eth_cleanup);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb_ctl.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,774 @@
++ /*
++ *	Copyright (C) Compaq Computer Corporation, 1998, 1999
++ *  Copyright (C) Extenex Corporation, 2001
++ *
++ *  usb_ctl.c
++ *
++ *  SA1100 USB controller core driver.
++ *
++ *  This file provides interrupt routing and overall coordination
++ *  of the three endpoints in usb_ep0, usb_receive (1),  and usb_send (2).
++ *
++ *  Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/tqueue.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++
++#include "sa1100_usb.h"
++#include "usb_ctl.h"
++
++//////////////////////////////////////////////////////////////////////////////
++// Prototypes
++//////////////////////////////////////////////////////////////////////////////
++
++int usbctl_next_state_on_event( int event );
++static void udc_int_hndlr(int, void *, struct pt_regs *);
++static void initialize_descriptors( void );
++static void soft_connect_hook( int enable );
++static void udc_disable(void);
++static void udc_enable(void);
++
++#if CONFIG_PROC_FS
++#define PROC_NODE_NAME "sausb"
++static int usbctl_read_proc(char *page, char **start, off_t off,
++							int count, int *eof, void *data);
++#endif
++
++//////////////////////////////////////////////////////////////////////////////
++// Globals
++//////////////////////////////////////////////////////////////////////////////
++static const char pszMe[] = "usbctl: ";
++struct usb_info_t usbd_info;  /* global to ep0, usb_recv, usb_send */
++
++/* device descriptors */
++static desc_t desc;
++
++#define MAX_STRING_DESC 8
++static string_desc_t * string_desc_array[ MAX_STRING_DESC ];
++static string_desc_t sd_zero;  /* special sd_zero holds language codes */
++
++// called when configured
++static usb_notify_t configured_callback = NULL;
++
++enum {	kStateZombie  = 0,  kStateZombieSuspend  = 1,
++		kStateDefault = 2,  kStateDefaultSuspend = 3,
++		kStateAddr    = 4,  kStateAddrSuspend    = 5,
++		kStateConfig  = 6,  kStateConfigSuspend  = 7
++};
++
++static int device_state_machine[8][6] = {
++//                suspend               reset          resume     adddr config deconfig
++/* zombie */  {  kStateZombieSuspend,  kStateDefault, kError,    kError, kError, kError },
++/* zom sus */ {  kError, kStateDefault, kStateZombie, kError, kError, kError },
++/* default */ {  kStateDefaultSuspend, kError, kStateDefault, kStateAddr, kError, kError },
++/* def sus */ {  kError, kStateDefault, kStateDefault, kError, kError, kError },
++/* addr */    {  kStateAddrSuspend, kStateDefault, kError, kError, kStateConfig, kError },
++/* addr sus */{  kError, kStateDefault, kStateAddr, kError, kError, kError },
++/* config */  {  kStateConfigSuspend, kStateDefault, kError, kError, kError, kStateAddr },
++/* cfg sus */ {  kError, kStateDefault, kStateConfig, kError, kError, kError }
++};
++
++/* "device state" is the usb device framework state, as opposed to the
++   "state machine state" which is whatever the driver needs and is much
++   more fine grained
++*/
++static int sm_state_to_device_state[8] =
++//  zombie           zom suspend          default            default sus
++{ USB_STATE_POWERED, USB_STATE_SUSPENDED, USB_STATE_DEFAULT, USB_STATE_SUSPENDED,
++// addr              addr sus             config                config sus
++  USB_STATE_ADDRESS, USB_STATE_SUSPENDED, USB_STATE_CONFIGURED, USB_STATE_SUSPENDED
++};
++
++static char * state_names[8] =
++{ "zombie", "zombie suspended", "default", "default suspended",
++  "address", "address suspended", "configured", "config suspended"
++};
++
++static char * event_names[6] =
++{ "suspend", "reset", "resume",
++  "address assigned", "configure", "de-configure"
++};
++
++static char * device_state_names[] =
++{ "not attached", "attached", "powered", "default",
++  "address", "configured", "suspended" };
++
++static int sm_state = kStateZombie;
++
++//////////////////////////////////////////////////////////////////////////////
++// Async
++//////////////////////////////////////////////////////////////////////////////
++static void core_kicker(void);
++
++static inline void enable_resume_mask_suspend( void );
++static inline void enable_suspend_mask_resume(void);
++
++static void
++udc_int_hndlr(int irq, void *dev_id, struct pt_regs *regs)
++{
++  	__u32 status = Ser0UDCSR;
++
++	/* ReSeT Interrupt Request - UDC has been reset */
++	if ( status & UDCSR_RSTIR )
++	{
++		if ( usbctl_next_state_on_event( kEvReset ) != kError )
++		{
++			/* starting 20ms or so reset sequence now... */
++			printk("%sResetting\n", pszMe);
++			ep0_reset();  // just set state to idle
++			ep1_reset();  // flush dma, clear false stall
++			ep2_reset();  // flush dma, clear false stall
++		}
++		// mask reset ints, they flood during sequence, enable
++		// suspend and resume
++		Ser0UDCCR |= UDCCR_REM;    // mask reset
++		Ser0UDCCR &= ~(UDCCR_SUSIM | UDCCR_RESIM); // enable suspend and resume
++		UDC_flip(  Ser0UDCSR, status );	// clear all pending sources
++		return;		// <-- no reason to continue if resetting
++	}
++	// else we have done something other than reset, so be sure reset enabled
++	UDC_clear( Ser0UDCCR, UDCCR_REM );
++
++	/* RESume Interrupt Request */
++	if ( status & UDCSR_RESIR )
++	{
++		usbctl_next_state_on_event( kEvResume );
++		core_kicker();
++		enable_suspend_mask_resume();
++	}
++
++	/* SUSpend Interrupt Request */
++	if ( status & UDCSR_SUSIR )
++	{
++		usbctl_next_state_on_event( kEvSuspend );
++		enable_resume_mask_suspend();
++	}
++
++	UDC_flip(Ser0UDCSR, status); // clear all pending sources
++
++	if (status & UDCSR_EIR)
++		 ep0_int_hndlr();
++
++	if (status & UDCSR_RIR)
++		ep1_int_hndlr(status);
++
++	if (status & UDCSR_TIR)
++		ep2_int_hndlr(status);
++}
++
++static inline void enable_resume_mask_suspend( void )
++{
++	 int i = 0;
++
++	 while( 1 ) {
++		  Ser0UDCCR |= UDCCR_SUSIM; // mask future suspend events
++		  udelay( i );
++		  if ( (Ser0UDCCR & UDCCR_SUSIM) || (Ser0UDCSR & UDCSR_RSTIR) )
++			   break;
++		  if ( ++i == 50 ) {
++			   printk( "%senable_resume(): Could not set SUSIM %8.8X\n",
++					   pszMe, Ser0UDCCR );
++			   break;
++		  }
++	 }
++
++	 i = 0;
++	 while( 1 ) {
++		  Ser0UDCCR &= ~UDCCR_RESIM;
++		  udelay( i );
++		  if ( ( Ser0UDCCR & UDCCR_RESIM ) == 0
++			   ||
++			   (Ser0UDCSR & UDCSR_RSTIR)
++			 )
++			   break;
++		  if ( ++i == 50 ) {
++			   printk( "%senable_resume(): Could not clear RESIM %8.8X\n",
++					   pszMe, Ser0UDCCR );
++			   break;
++		  }
++	 }
++}
++
++static inline void enable_suspend_mask_resume(void)
++{
++	 int i = 0;
++	 while( 1 ) {
++		  Ser0UDCCR |= UDCCR_RESIM; // mask future resume events
++		  udelay( i );
++		  if ( Ser0UDCCR & UDCCR_RESIM || (Ser0UDCSR & UDCSR_RSTIR) )
++			   break;
++		  if ( ++i == 50 ) {
++			   printk( "%senable_suspend(): Could not set RESIM %8.8X\n",
++					   pszMe, Ser0UDCCR );
++			   break;
++		  }
++	 }
++	 i = 0;
++	 while( 1 ) {
++		  Ser0UDCCR &= ~UDCCR_SUSIM;
++		  udelay( i );
++		  if ( ( Ser0UDCCR & UDCCR_SUSIM ) == 0
++			   ||
++			   (Ser0UDCSR & UDCSR_RSTIR)
++			 )
++			   break;
++		  if ( ++i == 50 ) {
++			   printk( "%senable_suspend(): Could not clear SUSIM %8.8X\n",
++					   pszMe, Ser0UDCCR );
++			   break;
++		  }
++	 }
++}
++
++
++//////////////////////////////////////////////////////////////////////////////
++// Public Interface
++//////////////////////////////////////////////////////////////////////////////
++
++/* Open SA usb core on behalf of a client, but don't start running */
++
++int
++sa1100_usb_open( const char * client )
++{
++	 if ( usbd_info.client_name != NULL )
++		  return -EBUSY;
++
++	 usbd_info.client_name = (char*) client;
++	 memset(&usbd_info.stats, 0, sizeof(struct usb_stats_t));
++	 memset(string_desc_array, 0, sizeof(string_desc_array));
++
++	 /* hack to start in zombie suspended state */
++	 sm_state = kStateZombieSuspend;
++	 usbd_info.state = USB_STATE_SUSPENDED;
++
++	 /* create descriptors for enumeration */
++	 initialize_descriptors();
++
++	 printk( "%sOpened for %s\n", pszMe, client );
++	 return 0;
++}
++
++/* Start running. Must have called usb_open (above) first */
++int
++sa1100_usb_start( void )
++{
++	 if ( usbd_info.client_name == NULL ) {
++		  printk( "%s%s - no client registered\n",
++				  pszMe, __FUNCTION__ );
++		  return -EPERM;
++	 }
++
++	 /* start UDC internal machinery running */
++	 udc_enable();
++	 udelay( 100 );
++
++	 /* clear stall - receiver seems to start stalled? 19Jan01ww */
++	 /* also clear other stuff just to be thurough 22Feb01ww */
++	 UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC );
++	 UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC );
++
++	 /* mask everything */
++	 Ser0UDCCR = 0xFC;
++
++	 /* flush DMA and fire through some -EAGAINs */
++	 ep1_init( usbd_info.dmach_rx );
++	 ep2_init( usbd_info.dmach_tx );
++
++	 /* give endpoint notification we are starting */
++	 ep1_state_change_notify( USB_STATE_SUSPENDED );
++	 ep2_state_change_notify( USB_STATE_SUSPENDED );
++
++	 /* enable any platform specific hardware */
++	 soft_connect_hook( 1 );
++
++	/* clear all top-level sources */
++	 Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR   |
++		         UDCSR_RIR   | UDCSR_TIR   | UDCSR_SUSIR ;
++
++	 /* EXERIMENT - a short line in the spec says toggling this
++	  ..bit diddles the internal state machine in the udc to
++	  ..expect a suspend */
++	 Ser0UDCCR  |= UDCCR_RESIM;
++	 /* END EXPERIMENT 10Feb01ww */
++
++	 /* enable any platform specific hardware */
++	 soft_connect_hook( 1 );
++
++	 /* enable interrupts. If you are unplugged you will
++	    immediately get a suspend interrupt. If you are plugged
++	    and have a soft connect-circuit, you will get a reset
++        If you are plugged without a soft-connect, I think you
++	    also get suspend. In short, start with suspend masked
++	    and everything else enabled */
++	 UDC_write( Ser0UDCCR, UDCCR_SUSIM );
++
++	 printk( "%sStarted for %s\n", pszMe, usbd_info.client_name );
++	 return 0;
++}
++
++/* Stop USB core from running */
++int
++sa1100_usb_stop( void )
++{
++	 if ( usbd_info.client_name == NULL ) {
++		  printk( "%s%s - no client registered\n",
++				  pszMe, __FUNCTION__ );
++		  return -EPERM;
++	 }
++	 /* mask everything */
++	 Ser0UDCCR = 0xFC;
++	 ep1_reset();
++	 ep2_reset();
++	 udc_disable();
++	 printk( "%sStopped\n", pszMe );
++	 return 0;
++}
++
++/* Tell SA core client is through using it */
++int
++sa1100_usb_close( void )
++{
++	 if ( usbd_info.client_name == NULL ) {
++		  printk( "%s%s - no client registered\n",
++				  pszMe, __FUNCTION__ );
++		  return -EPERM;
++	 }
++	 usbd_info.client_name = NULL;
++	 printk( "%sClosed\n", pszMe );
++	 return 0;
++}
++
++/* set a proc to be called when device is configured */
++usb_notify_t sa1100_set_configured_callback( usb_notify_t func )
++{
++	 usb_notify_t retval = configured_callback;
++	 configured_callback = func;
++	 return retval;
++}
++
++/*====================================================
++ * Descriptor Manipulation.
++ * Use these between open() and start() above to setup
++ * the descriptors for your device.
++ *
++ */
++
++/* get pointer to static default descriptor */
++desc_t *
++sa1100_usb_get_descriptor_ptr( void ) { return &desc; }
++
++/* optional: set a string descriptor */
++int
++sa1100_usb_set_string_descriptor( int i, string_desc_t * p )
++{
++	 int retval;
++	 if ( i < MAX_STRING_DESC ) {
++		  string_desc_array[i] = p;
++		  retval = 0;
++	 } else {
++		  retval = -EINVAL;
++	 }
++	 return retval;
++}
++
++/* optional: get a previously set string descriptor */
++string_desc_t *
++sa1100_usb_get_string_descriptor( int i )
++{
++	 return ( i < MAX_STRING_DESC )
++		    ? string_desc_array[i]
++		    : NULL;
++}
++
++
++/* optional: kmalloc and unicode up a string descriptor */
++string_desc_t *
++sa1100_usb_kmalloc_string_descriptor( const char * p )
++{
++	 string_desc_t * pResult = NULL;
++
++	 if ( p ) {
++		  int len = strlen( p );
++		  int uni_len = len * sizeof( __u16 );
++		  pResult = (string_desc_t*) kmalloc( uni_len + 2, GFP_KERNEL ); /* ugh! */
++		  if ( pResult != NULL ) {
++			   int i;
++			   pResult->bLength = uni_len + 2;
++			   pResult->bDescriptorType = USB_DESC_STRING;
++			   for( i = 0; i < len ; i++ ) {
++					pResult->bString[i] = make_word( (__u16) p[i] );
++			   }
++		  }
++	 }
++	 return pResult;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Exports to rest of driver
++//////////////////////////////////////////////////////////////////////////////
++
++/* called by the int handler here and the two endpoint files when interesting
++   .."events" happen */
++
++int
++usbctl_next_state_on_event( int event )
++{
++	int next_state = device_state_machine[ sm_state ][ event ];
++	if ( next_state != kError )
++	{
++		int next_device_state = sm_state_to_device_state[ next_state ];
++		printk( "%s%s --> [%s] --> %s. Device in %s state.\n",
++				pszMe, state_names[ sm_state ], event_names[ event ],
++				state_names[ next_state ], device_state_names[ next_device_state ] );
++
++		sm_state = next_state;
++		if ( usbd_info.state != next_device_state )
++		{
++			if ( configured_callback != NULL
++				 &&
++				 next_device_state == USB_STATE_CONFIGURED
++				 &&
++				 usbd_info.state != USB_STATE_SUSPENDED
++			   ) {
++			  configured_callback();
++			}
++			usbd_info.state = next_device_state;
++			ep1_state_change_notify( next_device_state );
++			ep2_state_change_notify( next_device_state );
++		}
++	}
++#if 0
++	else
++		printk( "%s%s --> [%s] --> ??? is an error.\n",
++				pszMe, state_names[ sm_state ], event_names[ event ] );
++#endif
++	return next_state;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Private Helpers
++//////////////////////////////////////////////////////////////////////////////
++
++/* setup default descriptors */
++
++static void
++initialize_descriptors(void)
++{
++	desc.dev.bLength               = sizeof( device_desc_t );
++	desc.dev.bDescriptorType       = USB_DESC_DEVICE;
++	desc.dev.bcdUSB                = 0x100; /* 1.0 */
++	desc.dev.bDeviceClass          = 0xFF;	/* vendor specific */
++	desc.dev.bDeviceSubClass       = 0;
++	desc.dev.bDeviceProtocol       = 0;
++	desc.dev.bMaxPacketSize0       = 8;	/* ep0 max fifo size */
++	desc.dev.idVendor              = 0;	/* vendor ID undefined */
++	desc.dev.idProduct             = 0; /* product */
++	desc.dev.bcdDevice             = 0; /* vendor assigned device release num */
++	desc.dev.iManufacturer         = 0;	/* index of manufacturer string */
++	desc.dev.iProduct              = 0; /* index of product description string */
++	desc.dev.iSerialNumber         = 0;	/* index of string holding product s/n */
++	desc.dev.bNumConfigurations    = 1;
++
++	desc.b.cfg.bLength             = sizeof( config_desc_t );
++	desc.b.cfg.bDescriptorType     = USB_DESC_CONFIG;
++	desc.b.cfg.wTotalLength        = make_word_c( sizeof(struct cdb) );
++	desc.b.cfg.bNumInterfaces      = 1;
++	desc.b.cfg.bConfigurationValue = 1;
++	desc.b.cfg.iConfiguration      = 0;
++	desc.b.cfg.bmAttributes        = USB_CONFIG_BUSPOWERED;
++	desc.b.cfg.MaxPower            = USB_POWER( 500 );
++
++	desc.b.intf.bLength            = sizeof( intf_desc_t );
++	desc.b.intf.bDescriptorType    = USB_DESC_INTERFACE;
++	desc.b.intf.bInterfaceNumber   = 0; /* unique intf index*/
++	desc.b.intf.bAlternateSetting  = 0;
++	desc.b.intf.bNumEndpoints      = 2;
++	desc.b.intf.bInterfaceClass    = 0xFF; /* vendor specific */
++	desc.b.intf.bInterfaceSubClass = 0;
++	desc.b.intf.bInterfaceProtocol = 0;
++	desc.b.intf.iInterface         = 0;
++
++	desc.b.ep1.bLength             = sizeof( ep_desc_t );
++	desc.b.ep1.bDescriptorType     = USB_DESC_ENDPOINT;
++	desc.b.ep1.bEndpointAddress    = USB_EP_ADDRESS( 1, USB_OUT );
++	desc.b.ep1.bmAttributes        = USB_EP_BULK;
++	desc.b.ep1.wMaxPacketSize      = make_word_c( 64 );
++	desc.b.ep1.bInterval           = 0;
++
++	desc.b.ep2.bLength             = sizeof( ep_desc_t );
++	desc.b.ep2.bDescriptorType     = USB_DESC_ENDPOINT;
++	desc.b.ep2.bEndpointAddress    = USB_EP_ADDRESS( 2, USB_IN );
++	desc.b.ep2.bmAttributes        = USB_EP_BULK;
++	desc.b.ep2.wMaxPacketSize      = make_word_c( 64 );
++	desc.b.ep2.bInterval           = 0;
++
++	/* set language */
++	/* See: http://www.usb.org/developers/data/USB_LANGIDs.pdf */
++	sd_zero.bDescriptorType = USB_DESC_STRING;
++	sd_zero.bLength         = sizeof( string_desc_t );
++	sd_zero.bString[0]      = make_word_c( 0x409 ); /* American English */
++	sa1100_usb_set_string_descriptor( 0, &sd_zero );
++}
++
++/* soft_connect_hook()
++ * Some devices have platform-specific circuitry to make USB
++ * not seem to be plugged in, even when it is. This allows
++ * software to control when a device 'appears' on the USB bus
++ * (after Linux has booted and this driver has loaded, for
++ * example). If you have such a circuit, control it here.
++ */
++static void
++soft_connect_hook( int enable )
++{
++#ifdef CONFIG_SA1100_EXTENEX1
++	 if (machine_is_extenex1() ) {
++		  if ( enable ) {
++			   PPDR |= PPC_USB_SOFT_CON;
++			   PPSR |= PPC_USB_SOFT_CON;
++		  } else {
++			   PPSR &= ~PPC_USB_SOFT_CON;
++			   PPDR &= ~PPC_USB_SOFT_CON;
++		  }
++	 }
++#endif
++}
++
++/* disable the UDC at the source */
++static void
++udc_disable(void)
++{
++	soft_connect_hook( 0 );
++	UDC_set( Ser0UDCCR, UDCCR_UDD );
++}
++
++
++/*  enable the udc at the source */
++static void
++udc_enable(void)
++{
++	UDC_clear(Ser0UDCCR, UDCCR_UDD);
++}
++
++// HACK DEBUG  3Mar01ww
++// Well, maybe not, it really seems to help!  08Mar01ww
++static void
++core_kicker( void )
++{
++	 __u32 car = Ser0UDCAR;
++	 __u32 imp = Ser0UDCIMP;
++	 __u32 omp = Ser0UDCOMP;
++
++	 UDC_set( Ser0UDCCR, UDCCR_UDD );
++	 udelay( 300 );
++	 UDC_clear(Ser0UDCCR, UDCCR_UDD);
++
++	 Ser0UDCAR = car;
++	 Ser0UDCIMP = imp;
++	 Ser0UDCOMP = omp;
++}
++
++//////////////////////////////////////////////////////////////////////////////
++// Proc Filesystem Support
++//////////////////////////////////////////////////////////////////////////////
++
++#if CONFIG_PROC_FS
++
++#define SAY( fmt, args... )  p += sprintf(p, fmt, ## args )
++#define SAYV(  num )         p += sprintf(p, num_fmt, "Value", num )
++#define SAYC( label, yn )    p += sprintf(p, yn_fmt, label, yn )
++#define SAYS( label, v )     p += sprintf(p, cnt_fmt, label, v )
++
++static int usbctl_read_proc(char *page, char **start, off_t off,
++			    int count, int *eof, void *data)
++{
++	 const char * num_fmt   = "%25.25s: %8.8lX\n";
++	 const char * cnt_fmt   = "%25.25s: %lu\n";
++	 const char * yn_fmt    = "%25.25s: %s\n";
++	 const char * yes       = "YES";
++	 const char * no        = "NO";
++	 unsigned long v;
++	 char * p = page;
++	 int len;
++
++ 	 SAY( "SA1100 USB Controller Core\n" );
++	 SAY( "USB state: %s (%s) %d\n",
++		  device_state_names[ sm_state_to_device_state[ sm_state ] ],
++		  state_names[ sm_state ],
++		  sm_state );
++
++	 SAYS( "ep0 bytes read", usbd_info.stats.ep0_bytes_read );
++	 SAYS( "ep0 bytes written", usbd_info.stats.ep0_bytes_written );
++	 SAYS( "ep0 FIFO read failures", usbd_info.stats.ep0_fifo_write_failures );
++	 SAYS( "ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures );
++
++	 SAY( "\n" );
++
++	 v = Ser0UDCAR;
++	 SAY( "%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v );
++	 v = Ser0UDCIMP;
++	 SAY( "%25.25s: %ld (%8.8lX)\n", "IN  max packet size", v+1, v );
++	 v = Ser0UDCOMP;
++	 SAY( "%25.25s: %ld (%8.8lX)\n", "OUT max packet size", v+1, v );
++
++	 v = Ser0UDCCR;
++	 SAY( "\nUDC Mask Register\n" );
++	 SAYV( v );
++	 SAYC( "UDC Active",                ( v & UDCCR_UDA ) ? yes : no );
++	 SAYC( "Suspend interrupts masked", ( v & UDCCR_SUSIM ) ? yes : no );
++	 SAYC( "Resume interrupts masked",  ( v & UDCCR_RESIM ) ? yes : no );
++	 SAYC( "Reset interrupts masked",   ( v & UDCCR_REM ) ? yes : no );
++
++	 v = Ser0UDCSR;
++	 SAY( "\nUDC Interrupt Request Register\n" );
++	 SAYV( v );
++	 SAYC( "Reset pending",      ( v & UDCSR_RSTIR ) ? yes : no );
++	 SAYC( "Suspend pending",    ( v & UDCSR_SUSIR ) ? yes : no );
++	 SAYC( "Resume pending",     ( v & UDCSR_RESIR ) ? yes : no );
++	 SAYC( "ep0 pending",        ( v & UDCSR_EIR )   ? yes : no );
++	 SAYC( "receiver pending",   ( v & UDCSR_RIR )   ? yes : no );
++	 SAYC( "tramsitter pending", ( v & UDCSR_TIR )   ? yes : no );
++
++#ifdef CONFIG_SA1100_EXTENEX1
++	 SAYC( "\nSoft connect", (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden" );
++#endif
++
++#if 0
++	 v = Ser0UDCCS0;
++	 SAY( "\nUDC Endpoint Zero Status Register\n" );
++	 SAYV( v );
++	 SAYC( "Out Packet Ready", ( v & UDCCS0_OPR ) ? yes : no );
++	 SAYC( "In Packet Ready",  ( v & UDCCS0_IPR ) ? yes : no );
++	 SAYC( "Sent Stall",       ( v & UDCCS0_SST ) ? yes : no );
++	 SAYC( "Force Stall",      ( v & UDCCS0_FST ) ? yes : no );
++	 SAYC( "Data End",         ( v & UDCCS0_DE )  ? yes : no );
++	 SAYC( "Data Setup End",   ( v & UDCCS0_SE )  ? yes : no );
++	 SAYC( "Serviced (SO)",    ( v & UDCCS0_SO )  ? yes : no );
++
++	 v = Ser0UDCCS1;
++	 SAY( "\nUDC Receiver Status Register\n" );
++	 SAYV( v );
++	 SAYC( "Receive Packet Complete", ( v & UDCCS1_RPC ) ? yes : no );
++	 SAYC( "Sent Stall",              ( v & UDCCS1_SST ) ? yes : no );
++	 SAYC( "Force Stall",             ( v & UDCCS1_FST ) ? yes : no );
++	 SAYC( "Receive Packet Error",    ( v & UDCCS1_RPE ) ? yes : no );
++	 SAYC( "Receive FIFO not empty",  ( v & UDCCS1_RNE ) ? yes : no );
++
++	 v = Ser0UDCCS2;
++	 SAY( "\nUDC Transmitter Status Register\n" );
++	 SAYV( v );
++	 SAYC( "FIFO has < 8 of 16 chars", ( v & UDCCS2_TFS ) ? yes : no );
++	 SAYC( "Transmit Packet Complete", ( v & UDCCS2_TPC ) ? yes : no );
++	 SAYC( "Transmit FIFO underrun",   ( v & UDCCS2_TUR ) ? yes : no );
++	 SAYC( "Transmit Packet Error",    ( v & UDCCS2_TPE ) ? yes : no );
++	 SAYC( "Sent Stall",               ( v & UDCCS2_SST ) ? yes : no );
++	 SAYC( "Force Stall",              ( v & UDCCS2_FST ) ? yes : no );
++#endif
++
++	 len = ( p - page ) - off;
++	 if ( len < 0 )
++		  len = 0;
++	 *eof = ( len <=count ) ? 1 : 0;
++	 *start = page + off;
++	 return len;
++}
++
++#endif  /* CONFIG_PROC_FS */
++
++//////////////////////////////////////////////////////////////////////////////
++// Module Initialization and Shutdown
++//////////////////////////////////////////////////////////////////////////////
++/*
++ * usbctl_init()
++ * Module load time. Allocate dma and interrupt resources. Setup /proc fs
++ * entry. Leave UDC disabled.
++ */
++int __init usbctl_init( void )
++{
++	int retval = 0;
++
++	udc_disable();
++
++	memset( &usbd_info, 0, sizeof( usbd_info ) );
++
++#if CONFIG_PROC_FS
++	create_proc_read_entry ( PROC_NODE_NAME, 0, NULL, usbctl_read_proc, NULL);
++#endif
++
++	/* setup rx dma */
++	retval = sa1100_request_dma(&usbd_info.dmach_rx, "USB receive", DMA_Ser0UDCRd);
++	if (retval) {
++		printk("%sunable to register for rx dma rc=%d\n", pszMe, retval );
++		goto err_rx_dma;
++	}
++
++	/* setup tx dma */
++	retval = sa1100_request_dma(&usbd_info.dmach_tx, "USB transmit", DMA_Ser0UDCWr);
++	if (retval) {
++		printk("%sunable to register for tx dma rc=%d\n",pszMe,retval);
++		goto err_tx_dma;
++	}
++
++	/* now allocate the IRQ. */
++	retval = request_irq(IRQ_Ser0UDC, udc_int_hndlr, SA_INTERRUPT,
++			  "SA USB core", NULL);
++	if (retval) {
++		printk("%sCouldn't request USB irq rc=%d\n",pszMe, retval);
++		goto err_irq;
++	}
++
++	printk( "SA1100 USB Controller Core Initialized\n");
++	return 0;
++
++err_irq:
++	sa1100_free_dma(usbd_info.dmach_tx);
++	usbd_info.dmach_tx = 0;
++err_tx_dma:
++	sa1100_free_dma(usbd_info.dmach_rx);
++	usbd_info.dmach_rx = 0;
++err_rx_dma:
++	return retval;
++}
++/*
++ * usbctl_exit()
++ * Release DMA and interrupt resources
++ */
++void __exit usbctl_exit( void )
++{
++    printk("Unloading SA1100 USB Controller\n");
++
++	udc_disable();
++
++#if CONFIG_PROC_FS
++    remove_proc_entry ( PROC_NODE_NAME, NULL);
++#endif
++
++    sa1100_free_dma(usbd_info.dmach_rx);
++    sa1100_free_dma(usbd_info.dmach_tx);
++    free_irq(IRQ_Ser0UDC, NULL);
++}
++
++EXPORT_SYMBOL( sa1100_usb_open );
++EXPORT_SYMBOL( sa1100_usb_start );
++EXPORT_SYMBOL( sa1100_usb_stop );
++EXPORT_SYMBOL( sa1100_usb_close );
++
++
++EXPORT_SYMBOL( sa1100_usb_get_descriptor_ptr );
++EXPORT_SYMBOL( sa1100_usb_set_string_descriptor );
++EXPORT_SYMBOL( sa1100_usb_get_string_descriptor );
++EXPORT_SYMBOL( sa1100_usb_kmalloc_string_descriptor );
++
++
++module_init( usbctl_init );
++module_exit( usbctl_exit );
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb_ctl.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,123 @@
++/*
++ *	Copyright (C)  Compaq Computer Corporation, 1998, 1999
++ *	Copyright (C)  Extenex Corporation 2001
++ *
++ *  usb_ctl.h
++ *
++ *  PRIVATE interface used to share info among components of the SA-1100 USB
++ *  core: usb_ctl, usb_ep0, usb_recv and usb_send. Clients of the USB core
++ *  should use sa1100_usb.h.
++ *
++ */
++
++#ifndef _USB_CTL_H
++#define _USB_CTL_H
++
++#include <asm/dma.h>  /* dmach_t */
++
++
++/*
++ * These states correspond to those in the USB specification v1.0
++ * in chapter 8, Device Framework.
++ */
++enum { USB_STATE_NOTATTACHED=0, USB_STATE_ATTACHED=1,USB_STATE_POWERED=2,
++	   USB_STATE_DEFAULT=3, USB_STATE_ADDRESS=4, USB_STATE_CONFIGURED=5,
++	   USB_STATE_SUSPENDED=6};
++
++struct usb_stats_t {
++	 unsigned long ep0_fifo_write_failures;
++	 unsigned long ep0_bytes_written;
++	 unsigned long ep0_fifo_read_failures;
++	 unsigned long ep0_bytes_read;
++};
++
++struct usb_info_t
++{
++	 char * client_name;
++	 dmach_t dmach_tx, dmach_rx;
++	 int state;
++	 unsigned char address;
++	 struct usb_stats_t stats;
++};
++
++/* in usb_ctl.c */
++extern struct usb_info_t usbd_info;
++
++/*
++ * Function Prototypes
++ */
++enum { kError=-1, kEvSuspend=0, kEvReset=1,
++	   kEvResume=2, kEvAddress=3, kEvConfig=4, kEvDeConfig=5 };
++int usbctl_next_state_on_event( int event );
++
++/* endpoint zero */
++void ep0_reset(void);
++void ep0_int_hndlr(void);
++
++/* receiver */
++void ep1_state_change_notify( int new_state );
++int  ep1_recv(void);
++int  ep1_init(int chn);
++void ep1_int_hndlr(int status);
++void ep1_reset(void);
++void ep1_stall(void);
++
++/* xmitter */
++void ep2_state_change_notify( int new_state );
++void ep2_reset(void);
++int  ep2_init(int chn);
++void ep2_int_hndlr(int status);
++void ep2_stall(void);
++
++#define UDC_write(reg, val) { \
++	int i = 10000; \
++	do { \
++	  	(reg) = (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: write %#x to %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while((reg) != (val)); \
++}
++
++#define UDC_set(reg, val) { \
++	int i = 10000; \
++	do { \
++		(reg) |= (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: set %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while(!((reg) & (val))); \
++}
++
++#define UDC_clear(reg, val) { \
++	int i = 10000; \
++	do { \
++		(reg) &= ~(val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: clear %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while((reg) & (val)); \
++}
++
++#define UDC_flip(reg, val) { \
++	int i = 10000; \
++	(reg) = (val); \
++	do { \
++		(reg) = (val); \
++		if (i-- <= 0) { \
++			printk( "%s [%d]: flip %#x of %p (%#x) failed\n", \
++				__FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++			break; \
++		} \
++	} while(((reg) & (val))); \
++}
++
++
++#define CHECK_ADDRESS { if ( Ser0UDCAR == 1 ) { printk("%s:%d I lost my address!!!\n",__FUNCTION__, __LINE__);}}
++#endif /* _USB_CTL_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb_ep0.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,911 @@
++/*
++ * Copyright (C) Extenex Corporation 2001
++ * Much folklore gleaned from original code:
++ *    Copyright (C) Compaq Computer Corporation, 1998, 1999
++ *
++ *  usb_ep0.c - SA1100 USB controller driver.
++ *              Endpoint zero management
++ *
++ *  Please see:
++ *    linux/Documentation/arm/SA1100/SA1100_USB
++ *  for details. (Especially since Intel docs are full of
++ *  errors about ep0 operation.) ward.willats@extenex.com.
++ *
++ * Intel also has a "Universal Serial Bus Client Device
++ * Validation for the StrongARM SA-1100 Microprocessor"
++ * document, which has flow charts and assembler test driver,
++ * but be careful, since it is just for validation and not
++ * a "real world" solution.
++ *
++ * A summary of three types of data-returning setups:
++ *
++ * 1. Setup request <= 8 bytes. That is, requests that can
++ *    be fullfilled in one write to the FIFO. DE is set
++ *    with IPR in queue_and_start_write(). (I don't know
++ *    if there really are any of these!)
++ *
++ * 2. Setup requests > 8 bytes (requiring more than one
++ *    IN to get back to the host), and we have at least
++ *    as much or more data than the host requested. In
++ *    this case we pump out everything we've got, and
++ *    when the final interrupt comes in due to the UDC
++ *    clearing the last IPR, we just set DE.
++ *
++ * 3. Setup requests > 8 bytes, but we don't have enough
++ *    data to satisfy the request. In this case, we send
++ *    everything we've got, and when the final interrupt
++ *    comes in due to the UDC clearing the last IPR
++ *    we write nothing to the FIFO and set both IPR and DE
++ *    so the UDC sends an empty packet and forces the host
++ *    to perform short packet retirement instead of stalling
++ *    out.
++ *
++ */
++
++#include <linux/delay.h>
++#include "sa1100_usb.h"  /* public interface */
++#include "usb_ctl.h"     /* private stuff */
++
++
++// 1 == lots of trace noise,  0 = only "important' stuff
++#define VERBOSITY 0
++
++enum { true = 1, false = 0 };
++typedef int bool;
++#ifndef MIN
++#define MIN( a, b ) ((a)<(b)?(a):(b))
++#endif
++
++#if 1 && !defined( ASSERT )
++#  define ASSERT(expr) \
++          if(!(expr)) { \
++          printk( "Assertion failed! %s,%s,%s,line=%d\n",\
++          #expr,__FILE__,__FUNCTION__,__LINE__); \
++          }
++#else
++#  define ASSERT(expr)
++#endif
++
++#if VERBOSITY
++#define PRINTKD(fmt, args...) printk( fmt , ## args)
++#else
++#define PRINTKD(fmt, args...)
++#endif
++
++/*================================================
++ * USB Protocol Stuff
++ */
++
++/* Request Codes   */
++enum { GET_STATUS=0,         CLEAR_FEATURE=1,     SET_FEATURE=3,
++	   SET_ADDRESS=5,        GET_DESCRIPTOR=6,	  SET_DESCRIPTOR=7,
++	   GET_CONFIGURATION=8,  SET_CONFIGURATION=9, GET_INTERFACE=10,
++	   SET_INTERFACE=11 };
++
++
++/* USB Device Requests */
++typedef struct
++{
++    __u8 bmRequestType;
++    __u8 bRequest;
++    __u16 wValue;
++    __u16 wIndex;
++    __u16 wLength;
++} usb_dev_request_t  __attribute__ ((packed));
++
++/***************************************************************************
++Prototypes
++***************************************************************************/
++/* "setup handlers" -- the main functions dispatched to by the
++   .. isr. These represent the major "modes" of endpoint 0 operaton */
++static void sh_setup_begin(void);				/* setup begin (idle) */
++static void sh_write( void );      				/* writing data */
++static void sh_write_with_empty_packet( void ); /* empty packet at end of xfer*/
++/* called before both sh_write routines above */
++static void common_write_preamble( void );
++
++/* other subroutines */
++static __u32  queue_and_start_write( void * p, int req, int act );
++static void write_fifo( void );
++static int read_fifo( usb_dev_request_t * p );
++static void get_descriptor( usb_dev_request_t * pReq );
++
++/* some voodo helpers  01Mar01ww */
++static void set_cs_bits( __u32 set_bits );
++static void set_de( void );
++static void set_ipr( void );
++static void set_ipr_and_de( void );
++static bool clear_opr( void );
++
++/***************************************************************************
++Inline Helpers
++***************************************************************************/
++
++/* Data extraction from usb_request_t fields */
++enum { kTargetDevice=0, kTargetInterface=1, kTargetEndpoint=2 };
++static inline int request_target( __u8 b ) { return (int) ( b & 0x0F); }
++
++static inline int windex_to_ep_num( __u16 w ) { return (int) ( w & 0x000F); }
++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); }
++
++/* following is hook for self-powered flag in GET_STATUS. Some devices
++   .. might like to override and return real info */
++static inline bool self_powered_hook( void ) { return true; }
++
++/* print string descriptor */
++static inline void psdesc( string_desc_t * p )
++{
++	 int i;
++	 int nchars = ( p->bLength - 2 ) / sizeof( __u16 );
++	 printk( "'" );
++	 for( i = 0 ; i < nchars ; i++ ) {
++		  printk( "%c", (char) p->bString[i] );
++	 }
++	 printk( "'\n" );
++}
++
++
++#if VERBOSITY
++/* "pcs" == "print control status" */
++static inline void pcs( void )
++{
++	 __u32 foo = Ser0UDCCS0;
++	 printk( "%8.8X: %s %s %s %s\n",
++			 foo,
++			 foo & UDCCS0_SE ? "SE" : "",
++			 foo & UDCCS0_OPR ? "OPR" : "",
++			 foo & UDCCS0_IPR ? "IPR" : "",
++			 foo & UDCCS0_SST ? "SST" : ""
++	 );
++}
++static inline void preq( usb_dev_request_t * pReq )
++{
++	 static char * tnames[] = { "dev", "intf", "ep", "oth" };
++	 static char * rnames[] = { "std", "class", "vendor", "???" };
++	 char * psz;
++	 switch( pReq->bRequest ) {
++	 case GET_STATUS: psz = "get stat"; break;
++	 case CLEAR_FEATURE: psz = "clr feat"; break;
++	 case SET_FEATURE: psz = "set feat"; break;
++	 case SET_ADDRESS: psz = "set addr"; break;
++	 case GET_DESCRIPTOR: psz = "get desc"; break;
++	 case SET_DESCRIPTOR: psz = "set desc"; break;
++	 case GET_CONFIGURATION: psz = "get cfg"; break;
++	 case SET_CONFIGURATION: psz = "set cfg"; break;
++	 case GET_INTERFACE: psz = "get intf"; break;
++	 case SET_INTERFACE: psz = "set intf"; break;
++	 default: psz = "unknown"; break;
++	 }
++	 printk( "- [%s: %s req to %s. dir=%s]\n", psz,
++			 rnames[ (pReq->bmRequestType >> 5) & 3 ],
++			 tnames[ pReq->bmRequestType & 3 ],
++			 ( pReq->bmRequestType & 0x80 ) ? "in" : "out" );
++}
++
++#else
++static inline void pcs( void ){}
++static inline void preq( void ){}
++#endif
++
++/***************************************************************************
++Globals
++***************************************************************************/
++static const char pszMe[] = "usbep0: ";
++
++/* pointer to current setup handler */
++static void (*current_handler)(void) = sh_setup_begin;
++
++/* global write struct to keep write
++   ..state around across interrupts */
++static struct {
++		unsigned char *p;
++		int bytes_left;
++} wr;
++
++/***************************************************************************
++Public Interface
++***************************************************************************/
++
++/* reset received from HUB (or controller just went nuts and reset by itself!)
++  so udc core has been reset, track this state here  */
++void
++ep0_reset(void)
++{
++	 /* reset state machine */
++	 current_handler = sh_setup_begin;
++	 wr.p = NULL;
++	 wr.bytes_left = 0;
++	 usbd_info.address=0;
++}
++
++/* handle interrupt for endpoint zero */
++void
++ep0_int_hndlr( void )
++{
++	 PRINTKD( "/\\(%d)\n", Ser0UDCAR );
++	 pcs();
++
++	 /* if not in setup begin, we are returning data.
++		execute a common preamble to both write handlers
++	 */
++	 if ( current_handler != sh_setup_begin )
++		  common_write_preamble();
++
++	 (*current_handler)();
++
++	 PRINTKD( "---\n" );
++	 pcs();
++	 PRINTKD( "\\/\n" );
++}
++
++/***************************************************************************
++Setup Handlers
++***************************************************************************/
++/*
++ * sh_setup_begin()
++ * This setup handler is the "idle" state of endpoint zero. It looks for OPR
++ * (OUT packet ready) to see if a setup request has been been received from the
++ * host. Requests without a return data phase are immediately handled. Otherwise,
++ * in the case of GET_XXXX the handler may be set to one of the sh_write_xxxx
++ * data pumpers if more than 8 bytes need to get back to the host.
++ *
++ */
++static void
++sh_setup_begin( void )
++{
++	 unsigned char status_buf[2];  /* returned in GET_STATUS */
++	 usb_dev_request_t req;
++	 int request_type;
++	 int n;
++	 __u32 cs_bits;
++	 __u32 address;
++	 __u32 cs_reg_in = Ser0UDCCS0;
++
++	 if (cs_reg_in & UDCCS0_SST) {
++		  PRINTKD( "%ssetup begin: sent stall. Continuing\n", pszMe );
++		  set_cs_bits( UDCCS0_SST );
++	}
++
++	 if ( cs_reg_in & UDCCS0_SE ) {
++		  PRINTKD( "%ssetup begin: Early term of setup. Continuing\n", pszMe );
++		  set_cs_bits( UDCCS0_SSE );  		 /* clear setup end */
++	 }
++
++	 /* Be sure out packet ready, otherwise something is wrong */
++	 if ( (cs_reg_in & UDCCS0_OPR) == 0 ) {
++		  /* we can get here early...if so, we'll int again in a moment  */
++		  PRINTKD( "%ssetup begin: no OUT packet available. Exiting\n", pszMe );
++		  goto sh_sb_end;
++	 }
++
++	 /* read the setup request */
++	 n = read_fifo( &req );
++	 if ( n != sizeof( req ) ) {
++		  printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. "
++				  " Stalling out...\n",
++				  pszMe, sizeof( req ), n );
++		  /* force stall, serviced out */
++		  set_cs_bits( UDCCS0_FST | UDCCS0_SO  );
++		  goto sh_sb_end;
++	 }
++
++	 /* Is it a standard request? (not vendor or class request) */
++	 request_type = type_code_from_request( req.bmRequestType );
++	 if ( request_type != 0 ) {
++		  printk( "%ssetup begin: unsupported bmRequestType: %d ignored\n",
++				  pszMe, request_type );
++		  set_cs_bits( UDCCS0_DE | UDCCS0_SO );
++		  goto sh_sb_end;
++	 }
++
++#if VERBOSITY
++	 {
++	 unsigned char * pdb = (unsigned char *) &req;
++	 PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ",
++			 pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7]
++		  );
++	 preq( &req );
++	 }
++#endif
++
++	 /* Handle it */
++	 switch( req.bRequest ) {
++
++		  /* This first bunch have no data phase */
++
++	 case SET_ADDRESS:
++		  address = (__u32) (req.wValue & 0x7F);
++		  /* when SO and DE sent, UDC will enter status phase and ack,
++			 ..propagating new address to udc core. Next control transfer
++			 ..will be on the new address. You can't see the change in a
++			 ..read back of CAR until then. (about 250us later, on my box).
++			 ..The original Intel driver sets S0 and DE and code to check
++			 ..that address has propagated here. I tried this, but it
++			 ..would only work sometimes! The rest of the time it would
++			 ..never propagate and we'd spin forever. So now I just set
++			 ..it and pray...
++		  */
++		  Ser0UDCAR = address;
++		  usbd_info.address = address;
++		  usbctl_next_state_on_event( kEvAddress );
++		  set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++		  printk( "%sI have been assigned address: %d\n", pszMe, address );
++		  break;
++
++
++	 case SET_CONFIGURATION:
++		  if ( req.wValue == 1 ) {
++			   /* configured */
++			   if (usbctl_next_state_on_event( kEvConfig ) != kError){
++								/* (re)set the out and in max packet sizes */
++					desc_t * pDesc = sa1100_usb_get_descriptor_ptr();
++					__u32 out = __le16_to_cpu( pDesc->b.ep1.wMaxPacketSize );
++					__u32 in  = __le16_to_cpu( pDesc->b.ep2.wMaxPacketSize );
++					Ser0UDCOMP = ( out - 1 );
++					Ser0UDCIMP = ( in - 1 );
++					printk( "%sConfigured (OMP=%8.8X IMP=%8.8X)\n", pszMe, out, in );
++			   }
++		  } else if ( req.wValue == 0 ) {
++			   /* de-configured */
++			   if (usbctl_next_state_on_event( kEvDeConfig ) != kError )
++					printk( "%sDe-Configured\n", pszMe );
++		  } else {
++			   printk( "%ssetup phase: Unknown "
++					   "\"set configuration\" data %d\n",
++					   pszMe, req.wValue );
++		  }
++		  set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++		  break;
++
++	 case CLEAR_FEATURE:
++		  /* could check data length, direction...26Jan01ww */
++		  if ( req.wValue == 0 ) { /* clearing ENDPOINT_HALT/STALL */
++			   int ep = windex_to_ep_num( req.wIndex );
++			   if ( ep == 1 ) {
++					printk( "%sclear feature \"endpoint halt\" "
++							" on receiver\n", pszMe );
++					ep1_reset();
++			   }
++			   else if ( ep == 2 ) {
++					printk( "%sclear feature \"endpoint halt\" "
++							"on xmitter\n", pszMe );
++					ep2_reset();
++			   } else {
++					printk( "%sclear feature \"endpoint halt\" "
++							"on unsupported ep # %d\n",
++							pszMe, ep );
++			   }
++		  } else {
++			   printk( "%sUnsupported feature selector (%d) "
++					   "in clear feature. Ignored.\n" ,
++					   pszMe, req.wValue );
++		  }
++		  set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++		  break;
++
++	 case SET_FEATURE:
++		  if ( req.wValue == 0 ) { /* setting ENDPOINT_HALT/STALL */
++			   int ep = windex_to_ep_num( req.wValue );
++			   if ( ep == 1 ) {
++					printk( "%set feature \"endpoint halt\" "
++							"on receiver\n", pszMe );
++					ep1_stall();
++			   }
++			   else if ( ep == 2 ) {
++					printk( "%sset feature \"endpoint halt\" "
++							" on xmitter\n", pszMe );
++					ep2_stall();
++			   } else {
++					printk( "%sset feature \"endpoint halt\" "
++							"on unsupported ep # %d\n",
++							pszMe, ep );
++			   }
++		  }
++		  else {
++			   printk( "%sUnsupported feature selector "
++					   "(%d) in set feature\n",
++					   pszMe, req.wValue );
++		  }
++		  set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++		  break;
++
++
++		  /* The rest have a data phase that writes back to the host */
++	 case GET_STATUS:
++		  /* return status bit flags */
++		  status_buf[0] = status_buf[1] = 0;
++		  n = request_target(req.bmRequestType);
++		  switch( n ) {
++		  case kTargetDevice:
++			   if ( self_powered_hook() )
++					status_buf[0] |= 1;
++			   break;
++		  case kTargetInterface:
++			   break;
++		  case kTargetEndpoint:
++			   /* return stalled bit */
++			   n = windex_to_ep_num( req.wIndex );
++			   if ( n == 1 )
++					status_buf[0] |= (Ser0UDCCS1 & UDCCS1_FST) >> 4;
++			   else if ( n == 2 )
++					status_buf[0] |= (Ser0UDCCS2 & UDCCS2_FST) >> 5;
++			   else {
++					printk( "%sUnknown endpoint (%d) "
++							"in GET_STATUS\n", pszMe, n );
++			   }
++			   break;
++		  default:
++			   printk( "%sUnknown target (%d) in GET_STATUS\n",
++					   pszMe, n );
++			   /* fall thru */
++			   break;
++		  }
++		  cs_bits  = queue_and_start_write( status_buf,
++											req.wLength,
++											sizeof( status_buf ) );
++		  set_cs_bits( cs_bits );
++		  break;
++	 case GET_DESCRIPTOR:
++		  get_descriptor( &req );
++		  break;
++
++	 case GET_CONFIGURATION:
++		  status_buf[0] = (usbd_info.state ==  USB_STATE_CONFIGURED)
++			   ? 1
++			   : 0;
++		  cs_bits = queue_and_start_write( status_buf, req.wLength, 1 );
++		  set_cs_bits( cs_bits );
++		  break;
++	 case GET_INTERFACE:
++		  printk( "%sfixme: get interface not supported\n", pszMe );
++		  cs_bits = queue_and_start_write( NULL, req.wLength, 0 );
++		  set_cs_bits( cs_bits );
++		  break;
++	 case SET_INTERFACE:
++		  printk( "%sfixme: set interface not supported\n", pszMe );
++		  set_cs_bits( UDCCS0_DE | UDCCS0_SO );
++		  break;
++	 default :
++		  printk("%sunknown request 0x%x\n", pszMe, req.bRequest);
++		  break;
++	 } /* switch( bRequest ) */
++
++sh_sb_end:
++	 return;
++
++}
++/*
++ * common_wrtie_preamble()
++ * Called before execution of sh_write() or sh_write_with_empty_packet()
++ * Handles common abort conditions.
++ *
++ */
++static void common_write_preamble( void )
++{
++	 /* If "setup end" has been set, the usb controller has
++		..terminated a setup transaction before we set DE. This
++		..happens during enumeration with some hosts. For example,
++		..the host will ask for our device descriptor and specify
++		..a return of 64 bytes. When we hand back the first 8, the
++		..host will know our max packet size and turn around and
++		..issue a new setup immediately. This causes the UDC to auto-ack
++		..the new setup and set SE. We must then "unload" (process)
++		..the new setup, which is what will happen after this preamble
++		..is finished executing.
++	 */
++	 __u32 cs_reg_in = Ser0UDCCS0;
++
++	 if ( cs_reg_in & UDCCS0_SE ) {
++		  PRINTKD( "%swrite_preamble(): Early termination of setup\n", pszMe );
++		  Ser0UDCCS0 =  UDCCS0_SSE;  		 /* clear setup end */
++		  current_handler = sh_setup_begin;
++	 }
++
++	 if ( cs_reg_in & UDCCS0_SST ) {
++		  PRINTKD( "%swrite_preamble(): UDC sent stall\n", pszMe );
++		  Ser0UDCCS0 = UDCCS0_SST;  		 /* clear setup end */
++		  current_handler = sh_setup_begin;
++	 }
++
++	 if ( cs_reg_in & UDCCS0_OPR ) {
++		  PRINTKD( "%swrite_preamble(): see OPR. Stopping write to "
++				   "handle new SETUP\n", pszMe );
++		  /* very rarely, you can get OPR and leftover IPR. Try to clear */
++		  UDC_clear( Ser0UDCCS0, UDCCS0_IPR );
++		  current_handler = sh_setup_begin;
++	 }
++}
++
++/*
++ * sh_write()
++ * This is the setup handler when we are in the data return phase of
++ * a setup request and have as much (or more) data than the host
++ * requested. If we enter this routine and bytes left is zero, the
++ * last data packet has gone (int is because IPR was just cleared)
++ * so we just set DE and reset. Otheriwse, we write another packet
++ * and set IPR.
++ */
++static void sh_write()
++{
++	 PRINTKD( "W\n" );
++
++	 if ( Ser0UDCCS0 & UDCCS0_IPR ) {
++		  PRINTKD( "%ssh_write(): IPR set, exiting\n", pszMe );
++		  return;
++	 }
++
++	 /* If bytes left is zero, we are coming in on the
++		..interrupt after the last packet went out. And
++		..we know we don't have to empty packet this transfer
++		..so just set DE and we are done */
++
++	 if ( 0 == wr.bytes_left ) {
++		  /* that's it, so data end  */
++		  set_de();
++		  wr.p = NULL;  				/* be anal */
++		  current_handler = sh_setup_begin;
++	 } else {
++		  /* Otherwise, more data to go */
++		  write_fifo();
++		  set_ipr();
++	 }
++}
++/*
++ * sh_write_with_empty_packet()
++ * This is the setup handler when we don't have enough data to
++ * satisfy the host's request. After we send everything we've got
++ * we must send an empty packet (by setting IPR and DE) so the
++ * host can perform "short packet retirement" and not stall.
++ *
++ */
++static void sh_write_with_empty_packet( void )
++{
++	 __u32 cs_reg_out = 0;
++	 PRINTKD( "WE\n" );
++
++	 if ( Ser0UDCCS0 & UDCCS0_IPR ) {
++		  PRINTKD( "%ssh_write(): IPR set, exiting\n", pszMe );
++		  return;
++	 }
++
++	 /* If bytes left is zero, we are coming in on the
++		..interrupt after the last packet went out.
++		..we must do short packet suff, so set DE and IPR
++	 */
++
++	 if ( 0 == wr.bytes_left ) {
++		  set_ipr_and_de();
++		  wr.p = NULL;
++		  current_handler = sh_setup_begin;
++		  PRINTKD( "%ssh_write empty() Sent empty packet \n", pszMe );
++	 }  else {
++		  write_fifo();				/* send data */
++		  set_ipr();				/* flag a packet is ready */
++	 }
++	 Ser0UDCCS0 = cs_reg_out;
++}
++
++/***************************************************************************
++Other Private Subroutines
++***************************************************************************/
++/*
++ * queue_and_start_write()
++ * p == data to send
++ * req == bytes host requested
++ * act == bytes we actually have
++ * Returns: bits to be flipped in ep0 control/status register
++ *
++ * Called from sh_setup_begin() to begin a data return phase. Sets up the
++ * global "wr"-ite structure and load the outbound FIFO with data.
++ * If can't send all the data, set appropriate handler for next interrupt.
++ *
++ */
++static __u32  queue_and_start_write( void * in, int req, int act )
++{
++	 __u32 cs_reg_bits = UDCCS0_IPR;
++	 unsigned char * p = (unsigned char*) in;
++
++	 PRINTKD( "Qr=%d a=%d\n",req,act );
++
++	/* thou shalt not enter data phase until the serviced OUT is clear */
++	 if ( ! clear_opr() ) {
++		  printk( "%sSO did not clear OPR\n", pszMe );
++		  return ( UDCCS0_DE | UDCCS0_SO ) ;
++	 }
++	 wr.p = p;
++	 wr.bytes_left = MIN( act, req );
++
++	 write_fifo();
++
++	 if ( 0 == wr.bytes_left ) {
++		  cs_reg_bits |= UDCCS0_DE;	/* out in 1 so data end */
++		  wr.p = NULL;  				/* be anal */
++	 }
++	 else if ( act < req )   /* we are going to short-change host */
++		  current_handler = sh_write_with_empty_packet; /* so need nul to not stall */
++	 else /* we have as much or more than requested */
++		  current_handler = sh_write;
++
++	 return cs_reg_bits; /* note: IPR was set uncondtionally at start of routine */
++}
++/*
++ * write_fifo()
++ * Stick bytes in the 8 bytes endpoint zero FIFO.
++ * This version uses a variety of tricks to make sure the bytes
++ * are written correctly. 1. The count register is checked to
++ * see if the byte went in, and the write is attempted again
++ * if not. 2. An overall counter is used to break out so we
++ * don't hang in those (rare) cases where the UDC reverses
++ * direction of the FIFO underneath us without notification
++ * (in response to host aborting a setup transaction early).
++ *
++ */
++static void write_fifo( void )
++{
++	int bytes_this_time = MIN( wr.bytes_left, 8 );
++	int bytes_written = 0;
++	int i=0;
++
++	PRINTKD( "WF=%d: ", bytes_this_time );
++
++	while( bytes_this_time-- ) {
++		 PRINTKD( "%2.2X ", *wr.p );
++		 i = 0;
++		 do {
++			  Ser0UDCD0 = *wr.p;
++			  udelay( 20 );  /* voodo 28Feb01ww */
++			  i++;
++		 } while( Ser0UDCWC == bytes_written && i < 10 );
++		 if ( i == 50 ) {
++			  printk( "%swrite_fifo: write failure\n", pszMe );
++			  usbd_info.stats.ep0_fifo_write_failures++;
++		 }
++
++		 wr.p++;
++		 bytes_written++;
++	}
++	wr.bytes_left -= bytes_written;
++
++	/* following propagation voodo so maybe caller writing IPR in
++	   ..a moment might actually get it to stick 28Feb01ww */
++	udelay( 300 );
++
++	usbd_info.stats.ep0_bytes_written += bytes_written;
++	PRINTKD( "L=%d WCR=%8.8X\n", wr.bytes_left, Ser0UDCWC );
++}
++/*
++ * read_fifo()
++ * Read 1-8 bytes out of FIFO and put in request.
++ * Called to do the initial read of setup requests
++ * from the host. Return number of bytes read.
++ *
++ * Like write fifo above, this driver uses multiple
++ * reads checked agains the count register with an
++ * overall timeout.
++ *
++ */
++static int
++read_fifo( usb_dev_request_t * request )
++{
++	int bytes_read = 0;
++	int fifo_count;
++	int i;
++
++	unsigned char * pOut = (unsigned char*) request;
++
++	fifo_count = ( Ser0UDCWC & 0xFF );
++
++	ASSERT( fifo_count <= 8 );
++	PRINTKD( "RF=%d ", fifo_count );
++
++	while( fifo_count-- ) {
++		 i = 0;
++		 do {
++			  *pOut = (unsigned char) Ser0UDCD0;
++			  udelay( 10 );
++		 } while( ( Ser0UDCWC & 0xFF ) != fifo_count && i < 10 );
++		 if ( i == 10 ) {
++			  printk( "%sread_fifo(): read failure\n", pszMe );
++			  usbd_info.stats.ep0_fifo_read_failures++;
++		 }
++		 pOut++;
++		 bytes_read++;
++	}
++
++	PRINTKD( "fc=%d\n", bytes_read );
++	usbd_info.stats.ep0_bytes_read++;
++	return bytes_read;
++}
++
++/*
++ * get_descriptor()
++ * Called from sh_setup_begin to handle data return
++ * for a GET_DESCRIPTOR setup request.
++ */
++static void get_descriptor( usb_dev_request_t * pReq )
++{
++	 __u32 cs_bits = 0;
++	 string_desc_t * pString;
++	 ep_desc_t * pEndpoint;
++
++	 desc_t * pDesc = sa1100_usb_get_descriptor_ptr();
++	 int type = pReq->wValue >> 8;
++	 int idx  = pReq->wValue & 0xFF;
++
++	 switch( type ) {
++	 case USB_DESC_DEVICE:
++		  cs_bits =
++			   queue_and_start_write( &pDesc->dev,
++									  pReq->wLength,
++									  pDesc->dev.bLength );
++		  break;
++
++		  // return config descriptor buffer, cfg, intf, 2 ep
++	 case USB_DESC_CONFIG:
++		  cs_bits =
++			   queue_and_start_write( &pDesc->b,
++									  pReq->wLength,
++									  sizeof( struct cdb ) );
++		  break;
++
++		  // not quite right, since doesn't do language code checking
++	 case USB_DESC_STRING:
++		  pString = sa1100_usb_get_string_descriptor( idx );
++		  if ( pString ) {
++			   if ( idx != 0 ) {  // if not language index
++					printk( "%sReturn string %d: ", pszMe, idx );
++					psdesc( pString );
++			   }
++			   cs_bits =
++					queue_and_start_write( pString,
++										   pReq->wLength,
++										   pString->bLength );
++		  }
++		  else {
++			   printk("%sunkown string index %d Stall.\n", pszMe, idx );
++			   cs_bits = ( UDCCS0_DE | UDCCS0_SO | UDCCS0_FST );
++		  }
++		  break;
++
++	 case USB_DESC_INTERFACE:
++		  if ( idx == pDesc->b.intf.bInterfaceNumber ) {
++			   cs_bits =
++					queue_and_start_write( &pDesc->b.intf,
++										   pReq->wLength,
++										   pDesc->b.intf.bLength );
++		  }
++		  break;
++
++	 case USB_DESC_ENDPOINT: /* correct? 21Feb01ww */
++		  if ( idx == 1 )
++			   pEndpoint = &pDesc->b.ep1;
++		  else if ( idx == 2 )
++			   pEndpoint = &pDesc->b.ep2;
++		  else
++			   pEndpoint = NULL;
++		  if ( pEndpoint ) {
++			   cs_bits =
++					queue_and_start_write( pEndpoint,
++										   pReq->wLength,
++										   pEndpoint->bLength );
++		  } else {
++			   printk("%sunkown endpoint index %d Stall.\n", pszMe, idx );
++			   cs_bits = ( UDCCS0_DE | UDCCS0_SO | UDCCS0_FST );
++		  }
++		  break;
++
++
++	 default :
++		  printk("%sunknown descriptor type %d. Stall.\n", pszMe, type );
++		  cs_bits = ( UDCCS0_DE | UDCCS0_SO | UDCCS0_FST );
++		  break;
++
++	 }
++	 set_cs_bits( cs_bits );
++}
++
++
++/* some voodo I am adding, since the vanilla macros just aren't doing it  1Mar01ww */
++
++#define ABORT_BITS ( UDCCS0_SST | UDCCS0_SE )
++#define OK_TO_WRITE (!( Ser0UDCCS0 & ABORT_BITS ))
++#define BOTH_BITS (UDCCS0_IPR | UDCCS0_DE)
++
++static void set_cs_bits( __u32 bits )
++{
++	 if ( bits & ( UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST ) )
++		  Ser0UDCCS0 = bits;
++	 else if ( (bits & BOTH_BITS) == BOTH_BITS )
++		  set_ipr_and_de();
++	 else if ( bits & UDCCS0_IPR )
++		  set_ipr();
++	 else if ( bits & UDCCS0_DE )
++		  set_de();
++}
++
++static void set_de( void )
++{
++	 int i = 1;
++	 while( 1 ) {
++		  if ( OK_TO_WRITE ) {
++				Ser0UDCCS0 |= UDCCS0_DE;
++		  } else {
++			   PRINTKD( "%sQuitting set DE because SST or SE set\n", pszMe );
++			   break;
++		  }
++		  if ( Ser0UDCCS0 & UDCCS0_DE )
++			   break;
++		  udelay( i );
++		  if ( ++i == 50  ) {
++			   printk( "%sDangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8X)\n",
++					   pszMe, UDCCS0_DE, Ser0UDCCS0 );
++			   break;
++		  }
++	 }
++}
++
++static void set_ipr( void )
++{
++	 int i = 1;
++	 while( 1 ) {
++		  if ( OK_TO_WRITE ) {
++				Ser0UDCCS0 |= UDCCS0_IPR;
++		  } else {
++			   PRINTKD( "%sQuitting set IPR because SST or SE set\n", pszMe );
++			   break;
++		  }
++		  if ( Ser0UDCCS0 & UDCCS0_IPR )
++			   break;
++		  udelay( i );
++		  if ( ++i == 50  ) {
++			   printk( "%sDangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8X)\n",
++					   pszMe, UDCCS0_IPR, Ser0UDCCS0 );
++			   break;
++		  }
++	 }
++}
++
++
++
++static void set_ipr_and_de( void )
++{
++	 int i = 1;
++	 while( 1 ) {
++		  if ( OK_TO_WRITE ) {
++			   Ser0UDCCS0 |= BOTH_BITS;
++		  } else {
++			   PRINTKD( "%sQuitting set IPR/DE because SST or SE set\n", pszMe );
++			   break;
++		  }
++		  if ( (Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS)
++			   break;
++		  udelay( i );
++		  if ( ++i == 50  ) {
++			   printk( "%sDangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8X)\n",
++					   pszMe, UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0 );
++			   break;
++		  }
++	 }
++}
++
++static bool clear_opr( void )
++{
++	 int i = 10000;
++	 bool is_clear;
++	 do {
++		  Ser0UDCCS0 = UDCCS0_SO;
++		  is_clear  = ! ( Ser0UDCCS0 & UDCCS0_OPR );
++		  if ( i-- <= 0 ) {
++			   printk( "%sclear_opr(): failed\n", pszMe );
++			   break;
++		  }
++	 } while( ! is_clear );
++	 return is_clear;
++}
++
++
++
++
++
++/* end usb_ep0.c */
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb_recv.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,205 @@
++/*
++ * Generic receive layer for the SA1100 USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This is still work in progress...
++ *
++ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++
++#include "sa1100_usb.h"
++#include "usb_ctl.h"
++
++
++static char *ep1_buf;
++static int ep1_len;
++static usb_callback_t ep1_callback;
++static char *ep1_curdmabuf;
++static dma_addr_t ep1_curdmapos;
++static int ep1_curdmalen;
++static int ep1_remain;
++static int dmachn_rx;
++static int rx_pktsize;
++
++static int naking;
++
++static void
++ep1_start(void)
++{
++	sa1100_dma_flush_all(dmachn_rx);
++	if (!ep1_curdmalen) {
++	  	ep1_curdmalen = rx_pktsize;
++		if (ep1_curdmalen > ep1_remain)
++			ep1_curdmalen = ep1_remain;
++		ep1_curdmapos = pci_map_single(NULL, ep1_curdmabuf, ep1_curdmalen,
++					       PCI_DMA_FROMDEVICE);
++	}
++	sa1100_dma_queue_buffer(dmachn_rx, NULL, ep1_curdmapos, ep1_curdmalen);
++	if ( naking ) {
++		/* turn off NAK of OUT packets, if set */
++		UDC_flip( Ser0UDCCS1, UDCCS1_RPC );
++		naking = 0;
++	}
++}
++
++static void
++ep1_done(int flag)
++{
++	int size = ep1_len - ep1_remain;
++
++	if (!ep1_len)
++		return;
++	if (ep1_curdmalen)
++		pci_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++				 PCI_DMA_FROMDEVICE);
++	ep1_len = ep1_curdmalen = 0;
++	if (ep1_callback) {
++		ep1_callback(flag, size);
++	}
++}
++
++void
++ep1_state_change_notify( int new_state )
++{
++
++}
++
++void
++ep1_stall( void )
++{
++	/* SET_FEATURE force stall at UDC */
++	UDC_set( Ser0UDCCS1, UDCCS1_FST );
++}
++
++int
++ep1_init(int chn)
++{
++	desc_t * pd = sa1100_usb_get_descriptor_ptr();
++	rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize );
++	dmachn_rx = chn;
++	sa1100_dma_flush_all(dmachn_rx);
++	ep1_done(-EAGAIN);
++	return 0;
++}
++
++void
++ep1_reset(void)
++{
++	desc_t * pd = sa1100_usb_get_descriptor_ptr();
++	rx_pktsize = __le16_to_cpu( pd->b.ep1.wMaxPacketSize );
++	sa1100_dma_flush_all(dmachn_rx);
++	UDC_clear(Ser0UDCCS1, UDCCS1_FST);
++	ep1_done(-EINTR);
++}
++
++void
++ep1_int_hndlr(int udcsr)
++{
++	dma_addr_t dma_addr;
++	unsigned int len;
++	int status = Ser0UDCCS1;
++
++	if ( naking ) printk( "%sEh? in ISR but naking = %d\n", "usbrx: ", naking );
++
++	if (status & UDCCS1_RPC) {
++
++		if (!ep1_curdmalen) {
++			printk("usb_recv: RPC for non-existent buffer\n");
++			naking=1;
++			return;
++		}
++
++		sa1100_dma_stop(dmachn_rx);
++
++		if (status & UDCCS1_SST) {
++			printk("usb_recv: stall sent OMP=%d\n",Ser0UDCOMP);
++			UDC_flip(Ser0UDCCS1, UDCCS1_SST);
++			ep1_done(-EIO); // UDC aborted current transfer, so we do
++			return;
++		}
++
++		if (status & UDCCS1_RPE) {
++		    printk("usb_recv: RPError %x\n", status);
++			UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++			ep1_done(-EIO);
++			return;
++		}
++
++		sa1100_dma_get_current(dmachn_rx, NULL, &dma_addr);
++		pci_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++				 PCI_DMA_FROMDEVICE);
++		len = dma_addr - ep1_curdmapos;
++		if (len < ep1_curdmalen) {
++			char *buf = ep1_curdmabuf + len;
++			while (Ser0UDCCS1 & UDCCS1_RNE) {
++				if (len >= ep1_curdmalen) {
++					printk("usb_recv: too much data in fifo\n");
++					break;
++				}
++				*buf++ = Ser0UDCDR;
++				len++;
++			}
++		} else if (Ser0UDCCS1 & UDCCS1_RNE) {
++			printk("usb_recv: fifo screwed, shouldn't contain data\n");
++			len = 0;
++		}
++		ep1_curdmalen = 0;  /* dma unmap already done */
++		ep1_remain -= len;
++		naking = 1;
++		ep1_done((len) ? 0 : -EPIPE);
++	}
++	/* else, you can get here if we are holding NAK */
++}
++
++int
++sa1100_usb_recv(char *buf, int len, usb_callback_t callback)
++{
++	int flags;
++
++	if (ep1_len)
++		return -EBUSY;
++
++	local_irq_save(flags);
++	ep1_buf = buf;
++	ep1_len = len;
++	ep1_callback = callback;
++	ep1_remain = len;
++	ep1_curdmabuf = buf;
++	ep1_curdmalen = 0;
++	ep1_start();
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++EXPORT_SYMBOL(sa1100_usb_recv);
++
++void
++sa1100_usb_recv_reset(void)
++{
++	ep1_reset();
++}
++
++EXPORT_SYMBOL(sa1100_usb_recv_reset);
++
++void
++sa1100_usb_recv_stall(void)
++{
++	ep1_stall();
++}
++
++EXPORT_SYMBOL(sa1100_usb_recv_stall);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mach-sa1100/usb_send.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,205 @@
++/*
++ * Generic xmit layer for the SA1100 USB client function
++ * Copyright (c) 2001 by Nicolas Pitre
++ *
++ * This code was loosely inspired by the original version which was
++ * Copyright (c) Compaq Computer Corporation, 1998-1999
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This is still work in progress...
++ *
++ * Please see linux/Documentation/arm/SA1100/SA1100_USB for details.
++ * 15/03/2001 - ep2_start now sets UDCAR to overcome something that is hardware
++ * 		bug, I think. green@iXcelerator.com
++ */
++
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/errno.h>
++#include <linux/delay.h> // for the massive_attack hack 28Feb01ww
++#include <asm/hardware.h>
++#include <asm/dma.h>
++#include <asm/system.h>
++#include <asm/byteorder.h>
++
++#include "sa1100_usb.h"
++#include "usb_ctl.h"
++
++
++static char *ep2_buf;
++static int ep2_len;
++static usb_callback_t ep2_callback;
++static dma_addr_t ep2_dma;
++static dma_addr_t ep2_curdmapos;
++static int ep2_curdmalen;
++static int ep2_remain;
++static int dmachn_tx;
++static int tx_pktsize;
++
++/* device state is changing, async */
++void
++ep2_state_change_notify( int new_state )
++{
++}
++
++/* set feature stall executing, async */
++void
++ep2_stall( void )
++{
++	UDC_set( Ser0UDCCS2, UDCCS2_FST );  /* force stall at UDC */
++}
++
++static void
++ep2_start(void)
++{
++	if (!ep2_len)
++		return;
++
++	ep2_curdmalen = tx_pktsize;
++	if (ep2_curdmalen > ep2_remain)
++		ep2_curdmalen = ep2_remain;
++
++	/* must do this _before_ queue buffer.. */
++	UDC_flip( Ser0UDCCS2,UDCCS2_TPC );  /* stop NAKing IN tokens */
++	UDC_write( Ser0UDCIMP, ep2_curdmalen-1 );
++
++	/* Remove if never seen...8Mar01ww */
++	{
++		 int massive_attack = 20;
++		 while ( Ser0UDCIMP != ep2_curdmalen-1 && massive_attack-- ) {
++			  printk( "usbsnd: Oh no you don't! Let me spin..." );
++			  udelay( 500 );
++			  printk( "and try again...\n" );
++			  UDC_write( Ser0UDCIMP, ep2_curdmalen-1 );
++		 }
++		 if ( massive_attack != 20 ) {
++			  if ( Ser0UDCIMP != ep2_curdmalen-1 )
++				   printk( "usbsnd: Massive attack FAILED :-( %d\n",
++						   20 - massive_attack );
++			  else
++				   printk( "usbsnd: Massive attack WORKED :-) %d\n",
++						   20 - massive_attack );
++		 }
++	}
++	/* End remove if never seen... 8Mar01ww */
++
++	Ser0UDCAR = usbd_info.address; // fighting stupid silicon bug
++	sa1100_dma_queue_buffer(dmachn_tx, NULL, ep2_curdmapos, ep2_curdmalen);
++}
++
++static void
++ep2_done(int flag)
++{
++	int size = ep2_len - ep2_remain;
++	if (ep2_len) {
++		pci_unmap_single(NULL, ep2_dma, ep2_len, PCI_DMA_TODEVICE);
++		ep2_len = 0;
++		if (ep2_callback)
++			ep2_callback(flag, size);
++	}
++}
++
++int
++ep2_init(int chn)
++{
++	desc_t * pd = sa1100_usb_get_descriptor_ptr();
++	tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize );
++	dmachn_tx = chn;
++	sa1100_dma_flush_all(dmachn_tx);
++	ep2_done(-EAGAIN);
++	return 0;
++}
++
++void
++ep2_reset(void)
++{
++	desc_t * pd = sa1100_usb_get_descriptor_ptr();
++	tx_pktsize = __le16_to_cpu( pd->b.ep2.wMaxPacketSize );
++	UDC_clear(Ser0UDCCS2, UDCCS2_FST);
++	sa1100_dma_flush_all(dmachn_tx);
++	ep2_done(-EINTR);
++}
++
++void
++ep2_int_hndlr(int udcsr)
++{
++	int status = Ser0UDCCS2;
++
++	if (Ser0UDCAR != usbd_info.address) // check for stupid silicon bug.
++		Ser0UDCAR = usbd_info.address;
++
++	UDC_flip(Ser0UDCCS2, UDCCS2_SST);
++
++	if (status & UDCCS2_TPC) {
++		sa1100_dma_flush_all(dmachn_tx);
++
++		if (status & (UDCCS2_TPE | UDCCS2_TUR)) {
++			printk("usb_send: transmit error %x\n", status);
++			ep2_done(-EIO);
++		} else {
++#if 1 // 22Feb01ww/Oleg
++			ep2_curdmapos += ep2_curdmalen;
++			ep2_remain -= ep2_curdmalen;
++#else
++			ep2_curdmapos += Ser0UDCIMP + 1; // this is workaround
++			ep2_remain -= Ser0UDCIMP + 1;    // for case when setting of Ser0UDCIMP was failed
++#endif
++
++			if (ep2_remain != 0) {
++				ep2_start();
++			} else {
++				ep2_done(0);
++			}
++		}
++	} else {
++		printk("usb_send: Not TPC: UDCCS2 = %x\n", status);
++	}
++}
++
++int
++sa1100_usb_send(char *buf, int len, usb_callback_t callback)
++{
++	int flags;
++
++	if (usbd_info.state != USB_STATE_CONFIGURED)
++		return -ENODEV;
++
++	if (ep2_len)
++		return -EBUSY;
++
++	local_irq_save(flags);
++	ep2_buf = buf;
++	ep2_len = len;
++	ep2_dma = pci_map_single(NULL, buf, len, PCI_DMA_TODEVICE);
++	ep2_callback = callback;
++	ep2_remain = len;
++	ep2_curdmapos = ep2_dma;
++	ep2_start();
++	local_irq_restore(flags);
++
++	return 0;
++}
++
++
++void
++sa1100_usb_send_reset(void)
++{
++	ep2_reset();
++}
++
++int sa1100_usb_xmitter_avail( void )
++{
++	if (usbd_info.state != USB_STATE_CONFIGURED)
++		return -ENODEV;
++	if (ep2_len)
++		return -EBUSY;
++	return 0;
++}
++
++
++EXPORT_SYMBOL(sa1100_usb_xmitter_avail);
++EXPORT_SYMBOL(sa1100_usb_send);
++EXPORT_SYMBOL(sa1100_usb_send_reset);
+--- linux-2.4.25/arch/arm/mm/Makefile~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -39,6 +39,8 @@
+ p-$(CONFIG_CPU_ARM925T)	+= proc-arm925.o
+ p-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o
+ p-$(CONFIG_CPU_ARM1020)	+= proc-arm1020.o
++p-$(CONFIG_CPU_ARM1020E) += proc-arm1020E.o
++p-$(CONFIG_CPU_ARM1022)	+= proc-arm1022.o
+ p-$(CONFIG_CPU_ARM1026)	+= proc-arm1026.o
+ p-$(CONFIG_CPU_SA110)	+= proc-sa110.o
+ p-$(CONFIG_CPU_SA1100)	+= proc-sa110.o
+--- linux-2.4.25/arch/arm/mm/alignment.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/alignment.c	2004-03-31 17:15:09.000000000 +0200
+@@ -11,7 +11,6 @@
+ #include <linux/config.h>
+ #include <linux/compiler.h>
+ #include <linux/signal.h>
+-#include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+@@ -19,7 +18,6 @@
+ #include <linux/ptrace.h>
+ #include <linux/mman.h>
+ #include <linux/mm.h>
+-#include <linux/interrupt.h>
+ #include <linux/proc_fs.h>
+ #include <linux/bitops.h>
+ #include <linux/init.h>
+@@ -30,9 +28,7 @@
+ #include <asm/pgtable.h>
+ #include <asm/unaligned.h>
+ 
+-extern void
+-do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
+-	    int error_code, struct pt_regs *regs);
++#include "fault.h"
+ 
+ /*
+  * 32-bit misaligned trap handler (c) 1998 San Mehat (CCC) -July 1998
+@@ -130,31 +126,6 @@
+ 	return count;
+ }
+ 
+-/*
+- * This needs to be done after sysctl_init, otherwise sys/ will be
+- * overwritten.  Actually, this shouldn't be in sys/ at all since
+- * it isn't a sysctl, and it doesn't contain sysctl information.
+- * We now locate it in /proc/cpu/alignment instead.
+- */
+-static int __init alignment_init(void)
+-{
+-	struct proc_dir_entry *res;
+-
+-	res = proc_mkdir("cpu", NULL);
+-	if (!res)
+-		return -ENOMEM;
+-
+-	res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res);
+-	if (!res)
+-		return -ENOMEM;
+-
+-	res->read_proc = proc_alignment_read;
+-	res->write_proc = proc_alignment_write;
+-
+-	return 0;
+-}
+-
+-__initcall(alignment_init);
+ #endif /* CONFIG_PROC_FS */
+ 
+ union offset_union {
+@@ -429,7 +400,7 @@
+ 	 * For alignment faults on the ARM922T/ARM920T the MMU  makes
+ 	 * the FSR (and hence addr) equal to the updated base address
+ 	 * of the multiple access rather than the restored value.
+-	 * Switch this messsage off if we've got a ARM92[02], otherwise
++	 * Switch this message off if we've got a ARM92[02], otherwise
+ 	 * [ls]dm alignment faults are noisy!
+ 	 */
+ #if !(defined CONFIG_CPU_ARM922T)  && !(defined CONFIG_CPU_ARM920T)
+@@ -486,7 +457,8 @@
+ 	return TYPE_ERROR;
+ }
+ 
+-int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs)
++static int
++do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+ 	union offset_union offset;
+ 	unsigned long instr, instrptr;
+@@ -541,7 +513,7 @@
+ 			case SHIFT_RORRRX:
+ 				if (shiftval == 0) {
+ 					offset.un >>= 1;
+-					if (regs->ARM_cpsr & CC_C_BIT)
++					if (regs->ARM_cpsr & PSR_C_BIT)
+ 						offset.un |= 1 << 31;
+ 				} else
+ 					offset.un = offset.un >> shiftval |
+@@ -577,7 +549,7 @@
+ 	/*
+ 	 * We got a fault - fix it up, or die.
+ 	 */
+-	do_bad_area(current, current->mm, addr, error_code, regs);
++	do_bad_area(current, current->mm, addr, fsr, regs);
+ 	return 0;
+ 
+  bad:
+@@ -594,8 +566,8 @@
+ 
+ 	if (ai_usermode & 1)
+ 		printk("Alignment trap: %s (%d) PC=0x%08lx Instr=0x%08lx "
+-		       "Address=0x%08lx Code 0x%02x\n", current->comm,
+-			current->pid, instrptr, instr, addr, error_code);
++		       "Address=0x%08lx FSR 0x%03x\n", current->comm,
++			current->pid, instrptr, instr, addr, fsr);
+ 
+ 	if (ai_usermode & 2)
+ 		goto fixup;
+@@ -607,3 +579,34 @@
+ 
+ 	return 0;
+ }
++
++/*
++ * This needs to be done after sysctl_init, otherwise sys/ will be
++ * overwritten.  Actually, this shouldn't be in sys/ at all since
++ * it isn't a sysctl, and it doesn't contain sysctl information.
++ * We now locate it in /proc/cpu/alignment instead.
++ */
++static int __init alignment_init(void)
++{
++#ifdef CONFIG_PROC_FS
++	struct proc_dir_entry *res;
++
++	res = proc_mkdir("cpu", NULL);
++	if (!res)
++		return -ENOMEM;
++
++	res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, res);
++	if (!res)
++		return -ENOMEM;
++
++	res->read_proc = proc_alignment_read;
++	res->write_proc = proc_alignment_write;
++#endif
++
++	hook_fault_code(1, do_alignment, SIGILL, "alignment exception");
++	hook_fault_code(3, do_alignment, SIGILL, "alignment exception");
++
++	return 0;
++}
++
++__initcall(alignment_init);
+--- linux-2.4.25/arch/arm/mm/fault-armv.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/fault-armv.c	2004-03-31 17:15:09.000000000 +0200
+@@ -2,116 +2,90 @@
+  *  linux/arch/arm/mm/fault-armv.c
+  *
+  *  Copyright (C) 1995  Linus Torvalds
+- *  Modifications for ARM processor (c) 1995-2001 Russell King
++ *  Modifications for ARM processor (c) 1995-2003 Russell King
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  */
+-#include <linux/config.h>
+-#include <linux/signal.h>
+ #include <linux/sched.h>
+ #include <linux/kernel.h>
+-#include <linux/errno.h>
+-#include <linux/string.h>
+ #include <linux/types.h>
+ #include <linux/ptrace.h>
+-#include <linux/mman.h>
+ #include <linux/mm.h>
+-#include <linux/interrupt.h>
+-#include <linux/proc_fs.h>
+ #include <linux/bitops.h>
+ #include <linux/init.h>
+ 
+-#include <asm/system.h>
+-#include <asm/uaccess.h>
+ #include <asm/pgalloc.h>
+ #include <asm/pgtable.h>
++#include <asm/io.h>
+ 
+-extern void show_pte(struct mm_struct *mm, unsigned long addr);
+-extern int do_page_fault(unsigned long addr, int error_code,
+-			 struct pt_regs *regs);
+-extern int do_translation_fault(unsigned long addr, int error_code,
+-				struct pt_regs *regs);
+-extern void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
+-			unsigned long addr, int error_code,
+-			struct pt_regs *regs);
+-
+-#ifdef CONFIG_ALIGNMENT_TRAP
+-extern int do_alignment(unsigned long addr, int error_code, struct pt_regs *regs);
+-#else
+-#define do_alignment do_bad
+-#endif
+-
++#include "fault.h"
+ 
+ /*
+  * Some section permission faults need to be handled gracefully.
+  * They can happen due to a __{get,put}_user during an oops.
+  */
+ static int
+-do_sect_fault(unsigned long addr, int error_code, struct pt_regs *regs)
++do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+ 	struct task_struct *tsk = current;
+-	do_bad_area(tsk, tsk->active_mm, addr, error_code, regs);
++	do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
+ 	return 0;
+ }
+ 
+ /*
+- * Hook for things that need to trap external faults.  Note that
+- * we don't guarantee that this will be the final version of the
+- * interface.
+- */
+-int (*external_fault)(unsigned long addr, struct pt_regs *regs);
+-
+-static int
+-do_external_fault(unsigned long addr, int error_code, struct pt_regs *regs)
+-{
+-	if (external_fault)
+-		return external_fault(addr, regs);
+-	return 1;
+-}
+-
+-/*
+  * This abort handler always returns "fault".
+  */
+ static int
+-do_bad(unsigned long addr, int error_code, struct pt_regs *regs)
++do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+ 	return 1;
+ }
+ 
+-static const struct fsr_info {
+-	int	(*fn)(unsigned long addr, int error_code, struct pt_regs *regs);
++static struct fsr_info {
++	int	(*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
+ 	int	sig;
+ 	const char *name;
+ } fsr_info[] = {
+ 	{ do_bad,		SIGSEGV, "vector exception"		   },
+-	{ do_alignment,		SIGILL,	 "alignment exception"		   },
++	{ do_bad,		SIGILL,	 "alignment exception"		   },
+ 	{ do_bad,		SIGKILL, "terminal exception"		   },
+-	{ do_alignment,		SIGILL,	 "alignment exception"		   },
+-	{ do_external_fault,	SIGBUS,	 "external abort on linefetch"	   },
++	{ do_bad,		SIGILL,	 "alignment exception"		   },
++	{ do_bad,		SIGBUS,	 "external abort on linefetch"	   },
+ 	{ do_translation_fault,	SIGSEGV, "section translation fault"	   },
+-	{ do_external_fault,	SIGBUS,	 "external abort on linefetch"	   },
++	{ do_bad,		SIGBUS,	 "external abort on linefetch"	   },
+ 	{ do_page_fault,	SIGSEGV, "page translation fault"	   },
+-	{ do_external_fault,	SIGBUS,	 "external abort on non-linefetch" },
++	{ do_bad,		SIGBUS,	 "external abort on non-linefetch" },
+ 	{ do_bad,		SIGSEGV, "section domain fault"		   },
+-	{ do_external_fault,	SIGBUS,	 "external abort on non-linefetch" },
++	{ do_bad,		SIGBUS,	 "external abort on non-linefetch" },
+ 	{ do_bad,		SIGSEGV, "page domain fault"		   },
+ 	{ do_bad,		SIGBUS,	 "external abort on translation"   },
+ 	{ do_sect_fault,	SIGSEGV, "section permission fault"	   },
+ 	{ do_bad,		SIGBUS,	 "external abort on translation"   },
+-	{ do_page_fault,	SIGSEGV, "page permission fault"	   }
++	{ do_page_fault,	SIGSEGV, "page permission fault"	   },
+ };
+ 
++void __init
++hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *),
++		int sig, const char *name)
++{
++	if (nr >= 0 && nr < ARRAY_SIZE(fsr_info)) {
++		fsr_info[nr].fn   = fn;
++		fsr_info[nr].sig  = sig;
++		fsr_info[nr].name = name;
++	}
++}
++
+ /*
+  * Dispatch a data abort to the relevant handler.
+  */
+ asmlinkage void
+-do_DataAbort(unsigned long addr, int error_code, struct pt_regs *regs, int fsr)
++do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+ 	const struct fsr_info *inf = fsr_info + (fsr & 15);
+ 
+-	if (!inf->fn(addr, error_code, regs))
++	if (!inf->fn(addr, fsr, regs))
+ 		return;
+ 
+ 	printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
+@@ -127,25 +101,28 @@
+ 	do_translation_fault(addr, 0, regs);
+ }
+ 
++static unsigned long shared_pte_mask = L_PTE_CACHEABLE;
++
+ /*
+  * We take the easy way out of this problem - we make the
+  * PTE uncacheable.  However, we leave the write buffer on.
+  */
+-static void adjust_pte(struct vm_area_struct *vma, unsigned long address)
++static int adjust_pte(struct vm_area_struct *vma, unsigned long address)
+ {
+ 	pgd_t *pgd;
+ 	pmd_t *pmd;
+ 	pte_t *pte, entry;
++	int ret = 0;
+ 
+ 	pgd = pgd_offset(vma->vm_mm, address);
+ 	if (pgd_none(*pgd))
+-		return;
++		goto no_pgd;
+ 	if (pgd_bad(*pgd))
+ 		goto bad_pgd;
+ 
+ 	pmd = pmd_offset(pgd, address);
+ 	if (pmd_none(*pmd))
+-		return;
++		goto no_pmd;
+ 	if (pmd_bad(*pmd))
+ 		goto bad_pmd;
+ 
+@@ -156,27 +133,30 @@
+ 	 * If this page isn't present, or is already setup to
+ 	 * fault (ie, is old), we can safely ignore any issues.
+ 	 */
+-	if (pte_present(entry) && pte_val(entry) & L_PTE_CACHEABLE) {
++	if (pte_present(entry) && pte_val(entry) & shared_pte_mask) {
+ 		flush_cache_page(vma, address);
+-		pte_val(entry) &= ~L_PTE_CACHEABLE;
++		pte_val(entry) &= ~shared_pte_mask;
+ 		set_pte(pte, entry);
+ 		flush_tlb_page(vma, address);
++		ret = 1;
+ 	}
+-	return;
++	return ret;
+ 
+ bad_pgd:
+ 	pgd_ERROR(*pgd);
+ 	pgd_clear(pgd);
+-	return;
++no_pgd:
++	return 0;
+ 
+ bad_pmd:
+ 	pmd_ERROR(*pmd);
+ 	pmd_clear(pmd);
+-	return;
++no_pmd:
++	return 0;
+ }
+ 
+ static void
+-make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page)
++make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty)
+ {
+ 	struct vm_area_struct *mpnt;
+ 	struct mm_struct *mm = vma->vm_mm;
+@@ -210,14 +190,17 @@
+ 		if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
+ 			continue;
+ 
++		off = mpnt->vm_start + (off << PAGE_SHIFT);
++
+ 		/*
+ 		 * Ok, it is within mpnt.  Fix it up.
+ 		 */
+-		adjust_pte(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
+-		aliases ++;
++		aliases += adjust_pte(mpnt, off);
+ 	}
+ 	if (aliases)
+ 		adjust_pte(vma, addr);
++	else if (dirty)
++		flush_cache_page(vma, addr);
+ }
+ 
+ /*
+@@ -242,11 +225,85 @@
+ 		return;
+ 	page = pfn_to_page(pfn);
+ 	if (page->mapping) {
+-		if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
++		int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
++
++		if (dirty) {
+ 			unsigned long kvirt = (unsigned long)page_address(page);
+ 			cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
+ 		}
+ 
+-		make_coherent(vma, addr, page);
++		make_coherent(vma, addr, page, dirty);
++	}
++}
++
++/*
++ * Check whether the write buffer has physical address aliasing
++ * issues.  If it has, we need to avoid them for the case where
++ * we have several shared mappings of the same object in user
++ * space.
++ */
++static int __init check_writebuffer(unsigned long *p1, unsigned long *p2)
++{
++	register unsigned long zero = 0, one = 1, val;
++
++	mb();
++	*p1 = one;
++	mb();
++	*p2 = zero;
++	mb();
++	val = *p1;
++	mb();
++	return val != zero;
++}
++
++static inline void *map_page(struct page *page)
++{
++	void *map;
++
++	map = __ioremap(page_to_phys(page), PAGE_SIZE, L_PTE_BUFFERABLE);
++	if (map)
++		get_page(page);
++	return map;
++}
++
++static inline void unmap_page(void *map)
++{
++	iounmap(map);
++}
++
++void __init check_writebuffer_bugs(void)
++{
++	struct page *page;
++	const char *reason;
++	unsigned long v = 1;
++
++	printk(KERN_INFO "CPU: Testing write buffer: ");
++
++	page = alloc_page(GFP_KERNEL);
++	if (page) {
++		unsigned long *p1, *p2;
++
++		p1 = map_page(page);
++		p2 = map_page(page);
++
++		if (p1 && p2) {
++			v = check_writebuffer(p1, p2);
++			reason = "enabling work-around";
++		} else {
++			reason = "unable to map memory\n";
++		}
++
++		unmap_page(p1);
++		unmap_page(p2);
++		put_page(page);
++	} else {
++		reason = "unable to grab page\n";
++	}
++
++	if (v) {
++		printk("FAIL - %s\n", reason);
++		shared_pte_mask |= L_PTE_BUFFERABLE;
++	} else {
++		printk("pass\n");
+ 	}
+ }
+--- linux-2.4.25/arch/arm/mm/fault-common.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/fault-common.c	2004-03-31 17:15:09.000000000 +0200
+@@ -11,21 +11,17 @@
+ #include <linux/config.h>
+ #include <linux/signal.h>
+ #include <linux/sched.h>
+-#include <linux/kernel.h>
+-#include <linux/errno.h>
+ #include <linux/string.h>
+-#include <linux/types.h>
+ #include <linux/ptrace.h>
+-#include <linux/mman.h>
+ #include <linux/mm.h>
+ #include <linux/interrupt.h>
+-#include <linux/proc_fs.h>
+ #include <linux/init.h>
+ 
+ #include <asm/system.h>
+-#include <asm/uaccess.h>
+ #include <asm/pgtable.h>
+-#include <asm/unaligned.h>
++#include <asm/uaccess.h>
++
++#include "fault.h"
+ 
+ #ifdef CONFIG_CPU_26
+ #define FAULT_CODE_WRITE	0x02
+@@ -34,13 +30,11 @@
+ #define READ_FAULT(m)		(!((m) & FAULT_CODE_WRITE))
+ #else
+ /*
+- * On 32-bit processors, we define "mode" to be zero when reading,
+- * non-zero when writing.  This now ties up nicely with the polarity
+- * of the 26-bit machines, and also means that we avoid the horrible
+- * gcc code for "int val = !other_val;".
++ * "code" is actually the FSR register.  Bit 11 set means the
++ * instruction was performing a write.
+  */
+-#define DO_COW(m)		(m)
+-#define READ_FAULT(m)		(!(m))
++#define DO_COW(code)		((code) & (1 << 11))
++#define READ_FAULT(code)	(!DO_COW(code))
+ #endif
+ 
+ /*
+@@ -54,16 +48,17 @@
+ 	if (!mm)
+ 		mm = &init_mm;
+ 
+-	printk(KERN_ALERT "mm = %p pgd = %p\n", mm, mm->pgd);
+-
+ 	fs = get_fs();
+ 	set_fs(get_ds());
++
+ 	do {
+-		pgd_t pg, *pgd = pgd_offset(mm, addr);
++		pgd_t pg, *pgd;
+ 		pmd_t pm, *pmd;
+ 		pte_t pt, *pte;
+ 
+-		printk(KERN_ALERT "*pgd = ");
++		printk(KERN_ALERT "pgd = %p\n", mm->pgd);
++		pgd = pgd_offset(mm, addr);
++		printk(KERN_ALERT "[%08lx] *pgd=", addr);
+ 
+ 		if (__get_user(pgd_val(pg), (unsigned long *)pgd)) {
+ 			printk("(faulted)");
+@@ -122,7 +117,7 @@
+  * Oops.  The kernel tried to access some page that wasn't present.
+  */
+ static void
+-__do_kernel_fault(struct mm_struct *mm, unsigned long addr, int error_code,
++__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
+ 		  struct pt_regs *regs)
+ {
+ 	unsigned long fixup;
+@@ -148,7 +143,7 @@
+ 		"paging request", addr);
+ 
+ 	show_pte(mm, addr);
+-	die("Oops", regs, error_code);
++	die("Oops", regs, fsr);
+ 	do_exit(SIGKILL);
+ }
+ 
+@@ -157,20 +152,20 @@
+  * User mode accesses just cause a SIGSEGV
+  */
+ static void
+-__do_user_fault(struct task_struct *tsk, unsigned long addr, int error_code,
+-		int code, struct pt_regs *regs)
++__do_user_fault(struct task_struct *tsk, unsigned long addr,
++		unsigned int fsr, int code, struct pt_regs *regs)
+ {
+ 	struct siginfo si;
+ 
+ #ifdef CONFIG_DEBUG_USER
+ 	printk(KERN_DEBUG "%s: unhandled page fault at pc=0x%08lx, "
+ 	       "lr=0x%08lx (bad address=0x%08lx, code %d)\n",
+-	       tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, error_code);
++	       tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, fsr);
+ 	show_regs(regs);
+ #endif
+ 
+ 	tsk->thread.address = addr;
+-	tsk->thread.error_code = error_code;
++	tsk->thread.error_code = fsr;
+ 	tsk->thread.trap_no = 14;
+ 	si.si_signo = SIGSEGV;
+ 	si.si_errno = 0;
+@@ -181,20 +176,20 @@
+ 
+ void
+ do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
+-	    int error_code, struct pt_regs *regs)
++	    unsigned int fsr, struct pt_regs *regs)
+ {
+ 	/*
+ 	 * If we are in kernel mode at this point, we
+ 	 * have no context to handle this fault with.
+ 	 */
+ 	if (user_mode(regs))
+-		__do_user_fault(tsk, addr, error_code, SEGV_MAPERR, regs);
++		__do_user_fault(tsk, addr, fsr, SEGV_MAPERR, regs);
+ 	else
+-		__do_kernel_fault(mm, addr, error_code, regs);
++		__do_kernel_fault(mm, addr, fsr, regs);
+ }
+ 
+ static int
+-__do_page_fault(struct mm_struct *mm, unsigned long addr, int error_code,
++__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
+ 		struct task_struct *tsk)
+ {
+ 	struct vm_area_struct *vma;
+@@ -212,7 +207,7 @@
+ 	 * memory access, so we can handle it.
+ 	 */
+ good_area:
+-	if (READ_FAULT(error_code)) /* read? */
++	if (READ_FAULT(fsr)) /* read? */
+ 		mask = VM_READ|VM_EXEC;
+ 	else
+ 		mask = VM_WRITE;
+@@ -227,7 +222,7 @@
+ 	 * than endlessly redo the fault.
+ 	 */
+ survive:
+-	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(error_code));
++	fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(fsr));
+ 
+ 	/*
+ 	 * Handle the "normal" cases first - successful and sigbus
+@@ -260,7 +255,7 @@
+ 	return fault;
+ }
+ 
+-int do_page_fault(unsigned long addr, int error_code, struct pt_regs *regs)
++int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+ {
+ 	struct task_struct *tsk;
+ 	struct mm_struct *mm;
+@@ -277,7 +272,7 @@
+ 		goto no_context;
+ 
+ 	down_read(&mm->mmap_sem);
+-	fault = __do_page_fault(mm, addr, error_code, tsk);
++	fault = __do_page_fault(mm, addr, fsr, tsk);
+ 	up_read(&mm->mmap_sem);
+ 
+ 	/*
+@@ -308,7 +303,7 @@
+ 		printk("VM: killing process %s\n", tsk->comm);
+ 		do_exit(SIGKILL);
+ 	} else
+-		__do_user_fault(tsk, addr, error_code, fault == -1 ?
++		__do_user_fault(tsk, addr, fsr, fault == -1 ?
+ 				SEGV_ACCERR : SEGV_MAPERR, regs);
+ 	return 0;
+ 
+@@ -323,7 +318,7 @@
+ 	 * or user mode.
+ 	 */
+ 	tsk->thread.address = addr;
+-	tsk->thread.error_code = error_code;
++	tsk->thread.error_code = fsr;
+ 	tsk->thread.trap_no = 14;
+ 	force_sig(SIGBUS, tsk);
+ #ifdef CONFIG_DEBUG_USER
+@@ -336,7 +331,7 @@
+ 		return 0;
+ 
+ no_context:
+-	__do_kernel_fault(mm, addr, error_code, regs);
++	__do_kernel_fault(mm, addr, fsr, regs);
+ 	return 0;
+ }
+ 
+@@ -357,21 +352,23 @@
+  * interrupt or a critical region, and should only copy the information
+  * from the master page table, nothing more.
+  */
+-int do_translation_fault(unsigned long addr, int error_code, struct pt_regs *regs)
++int do_translation_fault(unsigned long addr, unsigned int fsr,
++			 struct pt_regs *regs)
+ {
+ 	struct task_struct *tsk;
+-	struct mm_struct *mm;
+ 	int offset;
+ 	pgd_t *pgd, *pgd_k;
+ 	pmd_t *pmd, *pmd_k;
+ 
+ 	if (addr < TASK_SIZE)
+-		return do_page_fault(addr, error_code, regs);
++		return do_page_fault(addr, fsr, regs);
+ 
+ 	offset = __pgd_offset(addr);
+ 
+ 	/*
+ 	 * FIXME: CP15 C1 is write only on ARMv3 architectures.
++	 * You really need to read the value in the page table
++	 * register, not a copy.
+ 	 */
+ 	pgd = cpu_get_pgd() + offset;
+ 	pgd_k = init_mm.pgd + offset;
+@@ -395,8 +392,7 @@
+ 
+ bad_area:
+ 	tsk = current;
+-	mm  = tsk->active_mm;
+ 
+-	do_bad_area(tsk, mm, addr, error_code, regs);
++	do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
+ 	return 0;
+ }
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/fault.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,9 @@
++void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
++		 unsigned long addr, unsigned int fsr, struct pt_regs *regs);
++
++void show_pte(struct mm_struct *mm, unsigned long addr);
++
++int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
++
++int do_translation_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
++
+--- linux-2.4.25/arch/arm/mm/init.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/init.c	2004-03-31 17:15:09.000000000 +0200
+@@ -9,7 +9,6 @@
+  */
+ #include <linux/config.h>
+ #include <linux/signal.h>
+-#include <linux/sched.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+@@ -18,7 +17,6 @@
+ #include <linux/mman.h>
+ #include <linux/mm.h>
+ #include <linux/swap.h>
+-#include <linux/swapctl.h>
+ #include <linux/smp.h>
+ #include <linux/init.h>
+ #include <linux/bootmem.h>
+--- linux-2.4.25/arch/arm/mm/ioremap.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/ioremap.c	2004-03-31 17:15:09.000000000 +0200
+@@ -144,7 +144,7 @@
+ 	 */
+ 	offset = phys_addr & ~PAGE_MASK;
+ 	phys_addr &= PAGE_MASK;
+-	size = PAGE_ALIGN(last_addr) - phys_addr;
++	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
+ 
+ 	/*
+ 	 * Ok, go for it..
+--- linux-2.4.25/arch/arm/mm/mm-armv.c~2.4.25-vrs2.patch	2003-11-28 19:26:19.000000000 +0100
++++ linux-2.4.25/arch/arm/mm/mm-armv.c	2004-03-31 17:15:09.000000000 +0200
+@@ -9,7 +9,6 @@
+  *
+  *  Page table sludge for ARM v3 and v4 processor architectures.
+  */
+-#include <linux/sched.h>
+ #include <linux/mm.h>
+ #include <linux/init.h>
+ #include <linux/bootmem.h>
+@@ -390,6 +389,9 @@
+ 	init_maps->bufferable = 0;
+ 
+ 	create_mapping(init_maps);
++
++	flush_cache_all();
++	flush_tlb_all();
+ }
+ 
+ /*
+--- linux-2.4.25/arch/arm/mm/proc-arm1020.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm1020.S	2004-03-31 17:15:09.000000000 +0200
+@@ -65,18 +65,21 @@
+  *
+  * Returns:
+  *  r0 = address of abort
+- *  r1 != 0 if writing
+- *  r3 = FSR
++ *  r1 = FSR
++ *  r3 = corrupted
+  *  r4 = corrupted
+  */
+ 	.align	5
+ ENTRY(cpu_arm1020_data_abort)
+-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-	ldr	r1, [r2]			@ read aborted instruction
+-	and	r3, r3, #255
+-	tst	r1, r1, lsr #21 		@ C = bit 20
+-	sbc	r1, r1, r1			@ r1 = C - 1
++	tst	r3, #PSR_T_BIT
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
+ 	mov	pc, lr
+ 
+ /*
+@@ -170,10 +173,10 @@
+ #endif
+ 	subs	r3, r3, #1
+ 	cmp	r3, #0
+-	bge	2b				@ entries 3F to 0
++	bhs	2b				@ entries 3F to 0
+ 	subs	r1, r1, #1
+ 	cmp	r1, #0
+-	bge	1b				@ segments 7 to 0
++	bhs	1b				@ segments 7 to 0
+ #endif
+         
+ #ifndef CONFIG_CPU_ICACHE_DISABLE
+@@ -201,7 +204,7 @@
+ 	bic	r0, r0, #DCACHELINESIZE - 1
+ 	sub	r3, r1, r0
+ 	cmp	r3, #MAX_AREA_SIZE
+-	bgt	cpu_arm1020_cache_clean_invalidate_all_r2
++	bhi	cpu_arm1020_cache_clean_invalidate_all_r2
+ 	mcr	p15, 0, r3, c7, c10, 4
+ #ifndef CONFIG_CPU_DCACHE_DISABLE
+ 1:	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
+@@ -214,7 +217,7 @@
+ #endif
+ 	add	r0, r0, #DCACHELINESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ #endif
+ 
+ #ifndef CONFIG_CPU_ICACHE_DISABLE
+@@ -302,7 +305,7 @@
+ #endif
+ 	add	r0, r0, #DCACHELINESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ #else
+ 	/* D cache off, but still drain the write buffer */
+ 	mcr	p15, 0, r0, c7, c10, 4		@ Drain write buffer
+@@ -328,7 +331,7 @@
+ 	bic	r0, r0, #DCACHELINESIZE - 1
+ 	sub	r3, r1, r0
+ 	cmp	r3, #MAX_AREA_SIZE
+-	bgt	cpu_arm1020_cache_clean_invalidate_all_r2
++	bhi	cpu_arm1020_cache_clean_invalidate_all_r2
+ 	mcr	p15, 0, r3, c7, c10, 4
+ #ifndef CONFIG_CPU_DCACHE_DISABLE
+ 1:	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
+@@ -341,7 +344,7 @@
+ #endif
+ 	add	r0, r0, #DCACHELINESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ #endif
+ 
+ #ifndef CONFIG_CPU_BPREDICT_DISABLE
+@@ -488,7 +491,7 @@
+ 	mov	r0, r0
+ #endif
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 	mov	pc, lr
+ 
+ /*
+@@ -541,10 +544,10 @@
+ #endif
+ 	subs	r3, r3, #1
+ 	cmp	r3, #0
+-	bge	2b				@ entries 3F to 0
++	bhs	2b				@ entries 3F to 0
+ 	subs	r1, r1, #1
+ 	cmp	r1, #0
+-	bge	1b				@ segments 15 to 0
++	bhs	1b				@ segments 15 to 0
+ 
+ #endif
+ 	mov	r1, #0
+@@ -603,7 +606,7 @@
+ 	bic	r2, r2, #3
+ 	orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-	tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++	tst	r1, #LPTE_USER			@ User?
+ 	orrne	r2, r2, #HPTE_AP_READ
+ 
+ 	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+@@ -740,12 +743,12 @@
+ 
+ 	.type	cpu_arch_name, #object
+ cpu_arch_name:
+-	.asciz	"armv4"
++	.asciz	"armv5t"
+ 	.size	cpu_arch_name, . - cpu_arch_name
+ 
+ 	.type	cpu_elf_name, #object
+ cpu_elf_name:
+-	.asciz	"v4"
++	.asciz	"v5"
+ 	.size	cpu_elf_name, . - cpu_elf_name
+ 	.align
+ 
+@@ -753,9 +756,9 @@
+ 
+ 	.type	__arm1020_proc_info,#object
+ __arm1020_proc_info:
+-	.long	0x4100a200
+-	.long	0xff00fff0
+-	.long	0x00000c02			@ mmuflags
++	.long	0x4104a200			@ ARM 1020T (Architecture v5T)
++	.long	0xff0ffff0
++	.long	0x00000c0e			@ mmuflags
+ 	b	__arm1020_setup
+ 	.long	cpu_arch_name
+ 	.long	cpu_elf_name
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm1020E.S	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,718 @@
++/*
++ *  linux/arch/arm/mm/proc-arm1020E.S: MMU functions for ARM1020E
++ *
++ *  Copyright (C) 2000 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * 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
++ *
++ *
++ * These are the low level assembler for performing cache and TLB
++ * functions on the arm1020E.
++ */
++#include <linux/linkage.h>
++#include <linux/config.h>
++#include <asm/assembler.h>
++#include <asm/constants.h>
++#include <asm/procinfo.h>
++#include <asm/hardware.h>
++
++/*
++ * This is the maximum size of an area which will be invalidated
++ * using the single invalidate entry instructions.  Anything larger
++ * than this, and we go for the whole cache.
++ *
++ * This value should be chosen such that we choose the cheapest
++ * alternative.
++ */
++#define MAX_AREA_SIZE	32768
++
++/*
++ * the cache line size of the I and D cache
++ */
++#define DCACHELINESIZE	32
++#define ICACHELINESIZE	32
++
++/*
++ * and the page size
++ */
++#define LOG2PAGESIZE	12	/* == 4096 Bytes */
++#define PAGESIZE	(1 << LOG2PAGESIZE)
++
++/*
++ * create some useful conditional macro definitions
++ * we often need to know if we are ((not dcache disable) and writethrough) or ((not dcache disable) and writeback)
++ */
++#ifdef  CONFIG_CPU_DCACHE_DISABLE
++    #undef  CONFIG_CPU_DCACHE_WRITETHROUGH
++    #undef  CONFIG_CPU_DCACHE_WRITEBACK
++    #undef  CONFIG_CPU_DCACHE_ENABLE
++#else
++  #ifdef  CONFIG_CPU_DCACHE_WRITETHROUGH
++    #undef  CONFIG_CPU_DCACHE_WRITEBACK
++  #else
++    #define CONFIG_CPU_DCACHE_WRITEBACK
++  #endif
++    #define CONFIG_CPU_DCACHE_ENABLE
++#endif
++
++#ifdef  CONFIG_CPU_ICACHE_DISABLE
++    #undef  CONFIG_CPU_ICACHE_ENABLE
++#else
++    #define CONFIG_CPU_ICACHE_ENABLE
++#endif
++
++	.text
++
++/*
++ * cpu_arm1020E_data_abort()
++ *
++ * obtain information about current aborted instruction
++ * Note: we read user space.  This means we might cause a data
++ * abort here if the I-TLB and D-TLB aren't seeing the same
++ * picture.  Unfortunately, this does happen.  We live with it.
++ *
++ *  r2 = address of aborted instruction
++ *  r3 = cpsr
++ *
++ * Returns:
++ *  r0 = address of abort
++ *  r1 = FSR
++ *  r3 = corrupted
++ *  r4 = corrupted
++ */
++	.align	5
++ENTRY(cpu_arm1020E_data_abort)
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
++	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
++	tst	r3, #PSR_T_BIT
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_check_bugs()
++ */
++ENTRY(cpu_arm1020E_check_bugs)
++	mrs	ip, cpsr
++	bic	ip, ip, #F_BIT
++	msr	cpsr, ip
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_proc_init()
++ */
++ENTRY(cpu_arm1020E_proc_init)
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_proc_fin()
++ */
++ENTRY(cpu_arm1020E_proc_fin)
++	stmfd	sp!, {lr}
++	mov	ip, #F_BIT | I_BIT | SVC_MODE
++	msr	cpsr_c, ip
++	bl	cpu_arm1020E_cache_clean_invalidate_all
++	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
++	bic	r0, r0, #0x1000 		@ ...i............
++	bic	r0, r0, #0x000e 		@ ............wca.
++	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
++	ldmfd	sp!, {pc}
++
++/*
++ * cpu_arm1020E_reset(loc)
++ *
++ * Perform a soft reset of the system.	Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++	.align	5
++ENTRY(cpu_arm1020E_reset)
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
++	bic	ip, ip, #0x000f 		@ ............wcam
++	bic	ip, ip, #0x1100 		@ ...i...s........
++	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
++	mov	pc, r0
++
++/*
++ * cpu_arm1020E_do_idle()
++ */
++	.align	5
++ENTRY(cpu_arm1020E_do_idle)
++	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
++	mov	pc, lr
++
++/* ================================= CACHE ================================ */
++
++
++/*
++ * cpu_arm1020E_cache_clean_invalidate_all()
++ *
++ * clean and invalidate all cache lines
++ *
++ * Note:
++ *  1. we should preserve r0 and ip at all times
++ */
++	.align	5
++ENTRY(cpu_arm1020E_cache_clean_invalidate_all)
++	mov	r2, #1
++cpu_arm1020E_cache_clean_invalidate_all_r2:
++
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mov	r1, #0x0F << 5			@ 16 segments
++1:	orr	r3, r1, #63 << 26		@ 64 entries
++2:	mcr	p15, 0, r3, c7, c14, 2		@ clean and invalidate D index
++	subs	r3, r3, #1 << 26
++	bcs	2b
++	subs	r1, r1, #1 << 5
++	bcs	1b				@ segments 15 to 0
++#endif
++
++	mov	r1, #0
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r1, c7, c6, 0		@ invalidate D cache
++#endif
++
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	teq	r2, #0
++	mcrne	p15, 0, r1, c7, c5, 0		@ invalidate I cache
++#endif
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_cache_clean_invalidate_range(start, end, flags)
++ *
++ * clean and invalidate all cache lines associated with this area of memory
++ *
++ * start: Area start address
++ * end:   Area end address
++ * flags: nonzero for I cache as well
++ */
++	.align	5
++ENTRY(cpu_arm1020E_cache_clean_invalidate_range)
++	bic	r0, r0, #DCACHELINESIZE - 1
++	sub	r3, r1, r0
++	cmp	r3, #MAX_AREA_SIZE
++	bhs	cpu_arm1020E_cache_clean_invalidate_all_r2
++1:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	teq	r2, #0
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b				@ unsigned lower or same - must include end point (r1)!
++
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_flush_ram_page(page)
++ *
++ * clean and invalidate all cache lines associated with this area of memory
++ *
++ * page: page to clean and invalidate
++ */
++	.align	5
++ENTRY(cpu_arm1020E_flush_ram_page)
++	mov	r1, #PAGESIZE
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++1:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	subs	r1, r1, #DCACHELINESIZE
++	bne	1b
++
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* ================================ D-CACHE =============================== */
++
++/*
++ * cpu_arm1020E_dcache_invalidate_range(start, end)
++ *
++ * throw away all D-cached data in specified region without an obligation
++ * to write them back.	Note however that we must clean the D-cached entries
++ * around the boundaries if the start and/or end address are not cache
++ * aligned.
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ */
++	.align	5
++ENTRY(cpu_arm1020E_dcache_invalidate_range)
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	bic	r0, r0, #DCACHELINESIZE - 1
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	tst	r0, #DCACHELINESIZE - 1
++	bic	r0, r0, #DCACHELINESIZE - 1
++	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry at start
++	tst	r1, #DCACHELINESIZE - 1
++	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry at end
++#endif
++
++1:
++#ifdef CONFIG_CPU_DCACHE_ENABLE
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b
++
++	/* Even if the D cache is off still drain the write buffer */
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ Drain write buffer
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_dcache_clean_range(start, end)
++ *
++ * For the specified virtual address range, ensure that all caches contain
++ * clean data, such that peripheral accesses to the physical RAM fetch
++ * correct data.
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ */
++	.align	5
++ENTRY(cpu_arm1020E_dcache_clean_range)
++
++	mov	r2, #0
++
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	bic	r0, r0, #DCACHELINESIZE - 1
++	sub	r3, r1, r0
++	cmp	r3, #MAX_AREA_SIZE
++	bhs	cpu_arm1020E_cache_clean_invalidate_all_r2
++
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b
++#endif
++
++	mcr	p15, 0, r2, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_dcache_clean_page(page)
++ *
++ * Cleans a single page of dcache so that if we have any future aliased
++ * mappings, they will be consistent at the time that they are created.
++ *
++ * page: virtual address of page to clean from dcache
++ *
++ * Note:
++ *     we don't invalidate the entries since when we write the page
++ *     out to disk, the entries may get reloaded into the cache.
++ */
++	.align	5
++ENTRY(cpu_arm1020E_dcache_clean_page)
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++	mov	r1, #PAGESIZE
++1:
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #DCACHELINESIZE
++	subs	r1, r1, #DCACHELINESIZE
++	bne	1b
++#endif
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_dcache_clean_entry(addr)
++ *
++ * Clean the specified entry of any caches such that the MMU
++ * translation fetches will obtain correct data.
++ *
++ * addr: cache-unaligned virtual address
++ */
++	.align	5
++ENTRY(cpu_arm1020E_dcache_clean_entry)
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	bic	r0, r0, #DCACHELINESIZE - 1
++	mcr	p15, 0, r0, c7, c10, 1		@ clean single D entry
++#endif
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* ================================ I-CACHE =============================== */
++
++/*
++ * cpu_arm1020E_icache_invalidate_range(start, end)
++ *
++ * invalidate a range of virtual addresses from the Icache
++ *
++ * This is a little misleading, it is not intended to clean out
++ * the i-cache but to make sure that any data written to the
++ * range is made consistent.  This means that when we execute code
++ * in that region, everything works as we expect.
++ *
++ * This generally means writing back data in the Dcache and
++ * write buffer and invalidating the Icache over that region
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ *
++ * NOTE: ICACHELINESIZE == DCACHELINESIZE (so we don't need to
++ * loop twice, once for i-cache, once for d-cache)
++ */
++	.align	5
++ENTRY(cpu_arm1020E_icache_invalidate_range)
++	bic	r0, r0, #ICACHELINESIZE - 1
++	sub	r3, r1, r0
++	cmp	r3, #MAX_AREA_SIZE
++	movhs	r2, #1
++	bhs	cpu_arm1020E_cache_clean_invalidate_all_r2
++
++1:
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b				@ unsigned lower or same - includes r1 entry
++
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++ENTRY(cpu_arm1020E_icache_invalidate_page)
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++	add	r1, r0, #PAGESIZE
++	b	cpu_arm1020E_icache_invalidate_range
++
++/* ================================== TLB ================================= */
++
++/*
++ * cpu_arm1020E_tlb_invalidate_all()
++ *
++ * Invalidate all TLB entries
++ */
++	.align	5
++ENTRY(cpu_arm1020E_tlb_invalidate_all)
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D tlbs
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_tlb_invalidate_range(start, end)
++ *
++ * invalidate TLB entries covering the specified range
++ *
++ * start: range start address
++ * end:   range end address
++ */
++	.align	5
++ENTRY(cpu_arm1020E_tlb_invalidate_range)
++	sub	r3, r1, r0
++	cmp	r3, #256 * PAGESIZE
++	bhs	cpu_arm1020E_tlb_invalidate_all
++	mov	r3, #0
++	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
++	mov	r3, #PAGESIZE
++	sub	r3, r3, #1
++	bic	r0, r0, r3
++1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
++	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
++	add	r0, r0, #PAGESIZE
++	cmp	r0, r1
++	bls	1b
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_tlb_invalidate_page(page, flags)
++ *
++ * invalidate the TLB entries for the specified page.
++ *
++ * page:  page to invalidate
++ * flags: non-zero if we include the I TLB
++ */
++	.align	5
++ENTRY(cpu_arm1020E_tlb_invalidate_page)
++	mov	r3, #0
++	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++	teq	r1, #0
++	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
++	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
++	mov	pc, lr
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_arm1020E_set_pgd(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++	.align	5
++ENTRY(cpu_arm1020E_set_pgd)
++	stmfd	sp!, {lr}
++	bl	cpu_arm1020E_cache_clean_invalidate_all	@ preserves r0
++	mov	r1, #0
++	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
++	mcr	p15, 0, r1, c8, c7, 0		@ invalidate I & D TLBs
++	ldmfd	sp!, {pc}
++
++/*
++ * cpu_arm1020E_set_pmd(pmdp, pmd)
++ *
++ * Set a level 1 translation table entry, and clean it out of
++ * any caches such that the MMUs can load it correctly.
++ *
++ * pmdp: pointer to PMD entry
++ * pmd:  PMD value to store
++ */
++	.align	5
++ENTRY(cpu_arm1020E_set_pmd)
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	eor	r2, r1, #0x0a			@ C & Section
++	tst	r2, #0x0b
++	biceq	r1, r1, #4			@ clear bufferable bit
++#endif
++	str	r1, [r0]
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1020E_set_pte(ptep, pte)
++ *
++ * Set a PTE and flush it out
++ */
++	.align	5
++ENTRY(cpu_arm1020E_set_pte)
++	str	r1, [r0], #-1024		@ linux version
++
++	eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
++
++	bic	r2, r1, #0xff0
++	bic	r2, r2, #3
++	orr	r2, r2, #HPTE_TYPE_SMALL
++
++	tst	r1, #LPTE_USER			@ User?
++	orrne	r2, r2, #HPTE_AP_READ
++
++	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
++	orreq	r2, r2, #HPTE_AP_WRITE
++
++	tst	r1, #LPTE_PRESENT | LPTE_YOUNG	@ Present and Young?
++	movne	r2, #0
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	eor	r3, r2, #0x0a	@ C and Small Page?
++	tst	r3, #0x0b			@ if so..
++	biceq	r2, r2, #0x04	@ clear the bufferable bit
++#endif
++	str	r2, [r0]			@ hardware version
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++
++cpu_manu_name:
++	.asciz	"ARM"
++ENTRY(cpu_arm1020E_name)
++	.ascii	"Arm1020E"
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	.ascii	"i"
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	.ascii	"d"
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	.ascii	"(wt)"
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	.ascii	"(wb)"
++#endif
++#endif
++#ifndef CONFIG_CPU_BPREDICT_DISABLE
++	.ascii	"B"
++#endif
++#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
++	.ascii	"RR"
++#endif
++	.ascii	"\0"
++	.align
++
++	.section ".text.init", #alloc, #execinstr
++
++__arm1020E_setup:
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c7, 0		@ invalidate I,D caches on v4
++	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
++	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I,D TLBs on v4
++	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
++	mov	r0, #0x1f			@ Domains 0, 1 = client
++	mcr	p15, 0, r0, c3, c0, 0		@ load domain access register
++
++	mrc	p15, 0, r0, c1, c0, 0		@ Read current control register
++/*
++ * The only thing worth keeping from the initial control register is the endian bit
++ */
++
++	and	r0, r0, #0x0080			@ ........B....... Preserve  endian bit, zero all others.
++	orr	r0, r0, #0x0070			@ .........111.... Set the SBO (Should Be One) bits
++/*
++ * Turn on what we want.
++ */
++	orr	r0, r0, #0x0001 		@ ...............M Enable MMU (Alignment is special cased elsewhere)
++	orr	r0, r0, #0x0100 		@ .......S........ Enable system MMU protection
++	orr	r0, r0, #0x2000			@ ..V............. Enable high vectors
++
++#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
++	orr	r0, r0, #0x4000 		@ .R.............. Force round-robin replacement
++#endif
++
++#ifndef CONFIG_CPU_BPREDICT_DISABLE
++	orr	r0, r0, #0x0800 		@ ....Z........... Enable branch prediction
++#endif
++
++#ifdef CONFIG_CPU_DCACHE_ENABLE
++	orr	r0, r0, #0x0004 		@ .............C.. Enable D cache
++#endif
++#ifndef CONFIG_CPU_WB_DISABLE
++	orr	r0, r0, #0x0008 		@ ............W... Write Buffer enabled
++#endif
++
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	orr	r0, r0, #0x1000 		@ ...I............ Enable I Cache
++#endif
++
++	mov	pc, lr
++
++	.text
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ *	     come through these
++ */
++	.type	arm1020E_processor_functions, #object
++arm1020E_processor_functions:
++	.word	cpu_arm1020E_data_abort
++	.word	cpu_arm1020E_check_bugs
++	.word	cpu_arm1020E_proc_init
++	.word	cpu_arm1020E_proc_fin
++	.word	cpu_arm1020E_reset
++	.word	cpu_arm1020E_do_idle
++
++	/* cache */
++	.word	cpu_arm1020E_cache_clean_invalidate_all
++	.word	cpu_arm1020E_cache_clean_invalidate_range
++	.word	cpu_arm1020E_flush_ram_page
++
++	/* dcache */
++	.word	cpu_arm1020E_dcache_invalidate_range
++	.word	cpu_arm1020E_dcache_clean_range
++	.word	cpu_arm1020E_dcache_clean_page
++	.word	cpu_arm1020E_dcache_clean_entry
++
++	/* icache */
++	.word	cpu_arm1020E_icache_invalidate_range
++	.word	cpu_arm1020E_icache_invalidate_page
++
++	/* tlb */
++	.word	cpu_arm1020E_tlb_invalidate_all
++	.word	cpu_arm1020E_tlb_invalidate_range
++	.word	cpu_arm1020E_tlb_invalidate_page
++
++	/* pgtable */
++	.word	cpu_arm1020E_set_pgd
++	.word	cpu_arm1020E_set_pmd
++	.word	cpu_arm1020E_set_pte
++	.size	arm1020E_processor_functions, . - arm1020E_processor_functions
++
++	.type	cpu_arm1020E_info, #object
++cpu_arm1020E_info:
++	.long	cpu_manu_name
++	.long	cpu_arm1020E_name
++	.size	cpu_arm1020E_info, . - cpu_arm1020E_info
++
++	.type	cpu_arch_name, #object
++cpu_arch_name:
++	.asciz	"armv5te"
++	.size	cpu_arch_name, . - cpu_arch_name
++
++	.type	cpu_elf_name, #object
++cpu_elf_name:
++	.asciz	"v5"
++	.size	cpu_elf_name, . - cpu_elf_name
++	.align
++
++	.section ".proc.info", #alloc, #execinstr
++
++	.type	__arm1020E_proc_info,#object
++__arm1020E_proc_info:
++	.long	0x4105a200			@ ARM 1020E (Architecture v5TE)
++	.long	0xff0ffff0
++	.long	0x00000c1e			@ mmuflags
++	b	__arm1020E_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
++	.long	cpu_arm1020E_info
++	.long	arm1020E_processor_functions
++	.size	__arm1020E_proc_info, . - __arm1020E_proc_info
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm1022.S	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,716 @@
++/*
++ *  linux/arch/arm/mm/proc-arm1022.S: MMU functions for ARM1022E
++ *
++ *  Copyright (C) 2000 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * 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
++ *
++ *
++ * These are the low level assembler for performing cache and TLB
++ * functions on the arm1022E.
++ */
++#include <linux/linkage.h>
++#include <linux/config.h>
++#include <asm/assembler.h>
++#include <asm/constants.h>
++#include <asm/procinfo.h>
++#include <asm/hardware.h>
++
++/*
++ * This is the maximum size of an area which will be invalidated
++ * using the single invalidate entry instructions.  Anything larger
++ * than this, and we go for the whole cache.
++ *
++ * This value should be chosen such that we choose the cheapest
++ * alternative.
++ */
++#define MAX_AREA_SIZE	16384
++
++/*
++ * the cache line size of the I and D cache
++ */
++#define DCACHELINESIZE	32
++#define ICACHELINESIZE	32
++
++/*
++ * and the page size
++ */
++#define LOG2PAGESIZE	12	/* == 4096 Bytes */
++#define PAGESIZE	(1 << LOG2PAGESIZE)
++
++/*
++ * create some useful conditional macro definitions
++ * we often need to know if we are ((not dcache disable) and writethrough) or ((not dcache disable) and writeback)
++ */
++#ifdef  CONFIG_CPU_DCACHE_DISABLE
++    #undef  CONFIG_CPU_DCACHE_WRITETHROUGH
++    #undef  CONFIG_CPU_DCACHE_WRITEBACK
++    #undef  CONFIG_CPU_DCACHE_ENABLE
++#else
++  #ifdef  CONFIG_CPU_DCACHE_WRITETHROUGH
++    #undef  CONFIG_CPU_DCACHE_WRITEBACK
++  #else
++    #define CONFIG_CPU_DCACHE_WRITEBACK
++  #endif
++    #define CONFIG_CPU_DCACHE_ENABLE
++#endif
++
++#ifdef  CONFIG_CPU_ICACHE_DISABLE
++    #undef  CONFIG_CPU_ICACHE_ENABLE
++#else
++    #define CONFIG_CPU_ICACHE_ENABLE
++#endif
++
++	.text
++
++/*
++ * cpu_arm1022_data_abort()
++ *
++ * obtain information about current aborted instruction
++ * Note: we read user space.  This means we might cause a data
++ * abort here if the I-TLB and D-TLB aren't seeing the same
++ * picture.  Unfortunately, this does happen.  We live with it.
++ *
++ *  r2 = address of aborted instruction
++ *  r3 = cpsr
++ *
++ * Returns:
++ *  r0 = address of abort
++ *  r1 = FSR
++ *  r3 = corrupted
++ *  r4 = corrupted
++ */
++	.align	5
++ENTRY(cpu_arm1022_data_abort)
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
++	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
++	tst	r3, #PSR_T_BIT
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_check_bugs()
++ */
++ENTRY(cpu_arm1022_check_bugs)
++	mrs	ip, cpsr
++	bic	ip, ip, #F_BIT
++	msr	cpsr, ip
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_proc_init()
++ */
++ENTRY(cpu_arm1022_proc_init)
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_proc_fin()
++ */
++ENTRY(cpu_arm1022_proc_fin)
++	stmfd	sp!, {lr}
++	mov	ip, #F_BIT | I_BIT | SVC_MODE
++	msr	cpsr_c, ip
++	bl	cpu_arm1022_cache_clean_invalidate_all
++	mrc	p15, 0, r0, c1, c0, 0		@ ctrl register
++	bic	r0, r0, #0x1000 		@ ...i............
++	bic	r0, r0, #0x000e 		@ ............wca.
++	mcr	p15, 0, r0, c1, c0, 0		@ disable caches
++	ldmfd	sp!, {pc}
++
++/*
++ * cpu_arm1022_reset(loc)
++ *
++ * Perform a soft reset of the system.	Put the CPU into the
++ * same state as it would be if it had been reset, and branch
++ * to what would be the reset vector.
++ *
++ * loc: location to jump to for soft reset
++ */
++	.align	5
++ENTRY(cpu_arm1022_reset)
++	mov	ip, #0
++	mcr	p15, 0, ip, c7, c7, 0		@ invalidate I,D caches
++	mcr	p15, 0, ip, c7, c10, 4		@ drain WB
++	mcr	p15, 0, ip, c8, c7, 0		@ invalidate I & D TLBs
++	mrc	p15, 0, ip, c1, c0, 0		@ ctrl register
++	bic	ip, ip, #0x000f 		@ ............wcam
++	bic	ip, ip, #0x1100 		@ ...i...s........
++	mcr	p15, 0, ip, c1, c0, 0		@ ctrl register
++	mov	pc, r0
++
++/*
++ * cpu_arm1022_do_idle()
++ */
++	.align	5
++ENTRY(cpu_arm1022_do_idle)
++	mcr	p15, 0, r0, c7, c0, 4		@ Wait for interrupt
++	mov	pc, lr
++
++/* ================================= CACHE ================================ */
++
++
++/*
++ * cpu_arm1022_cache_clean_invalidate_all()
++ *
++ * clean and invalidate all cache lines
++ *
++ * Note:
++ *  1. we should preserve r0 and ip at all times
++ */
++	.align	5
++ENTRY(cpu_arm1022_cache_clean_invalidate_all)
++	mov	r2, #1
++cpu_arm1022_cache_clean_invalidate_all_r2:
++
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mov	r1, #7 << 5			@ 8 segments
++1:	orr	r3, r1, #63 << 26		@ 64 entries
++2:	mcr	p15, 0, r3, c7, c14, 2		@ clean and invalidate D index
++	subs	r3, r3, #1 << 26
++	bcs	2b
++	subs	r1, r1, #1 << 5
++	bcs	1b				@ segments 7 to 0
++#endif
++
++	mov	r1, #0
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r1, c7, c6, 0		@ invalidate D cache
++#endif
++
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	teq	r2, #0
++	mcrne	p15, 0, r1, c7, c5, 0		@ invalidate I cache
++#endif
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_cache_clean_invalidate_range(start, end, flags)
++ *
++ * clean and invalidate all cache lines associated with this area of memory
++ *
++ * start: Area start address
++ * end:   Area end address
++ * flags: nonzero for I cache as well
++ */
++	.align	5
++ENTRY(cpu_arm1022_cache_clean_invalidate_range)
++	bic	r0, r0, #DCACHELINESIZE - 1
++	sub	r3, r1, r0
++	cmp	r3, #MAX_AREA_SIZE
++	bhs	cpu_arm1022_cache_clean_invalidate_all_r2
++1:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	teq	r2, #0
++	mcrne	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b				@ unsigned lower or same - must include end point (r1)!
++
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_flush_ram_page(page)
++ *
++ * clean and invalidate all cache lines associated with this area of memory
++ *
++ * page: page to clean and invalidate
++ */
++	.align	5
++ENTRY(cpu_arm1022_flush_ram_page)
++	mov	r1, #PAGESIZE
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++1:
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c14, 1		@ clean and invalidate D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	subs	r1, r1, #DCACHELINESIZE
++	bne	1b
++
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* ================================ D-CACHE =============================== */
++
++/*
++ * cpu_arm1022_dcache_invalidate_range(start, end)
++ *
++ * throw away all D-cached data in specified region without an obligation
++ * to write them back.	Note however that we must clean the D-cached entries
++ * around the boundaries if the start and/or end address are not cache
++ * aligned.
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ */
++	.align	5
++ENTRY(cpu_arm1022_dcache_invalidate_range)
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	bic	r0, r0, #DCACHELINESIZE - 1
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	tst	r0, #DCACHELINESIZE - 1
++	bic	r0, r0, #DCACHELINESIZE - 1
++	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry at start
++	tst	r1, #DCACHELINESIZE - 1
++	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry at end
++#endif
++
++1:
++#ifdef CONFIG_CPU_DCACHE_ENABLE
++	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	mcr	p15, 0, r0, c7, c5, 1		@ invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b
++
++	/* Even if the D cache is off still drain the write buffer */
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ Drain write buffer
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_dcache_clean_range(start, end)
++ *
++ * For the specified virtual address range, ensure that all caches contain
++ * clean data, such that peripheral accesses to the physical RAM fetch
++ * correct data.
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ */
++	.align	5
++ENTRY(cpu_arm1022_dcache_clean_range)
++
++	mov	r2, #0
++
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	bic	r0, r0, #DCACHELINESIZE - 1
++	sub	r3, r1, r0
++	cmp	r3, #MAX_AREA_SIZE
++	bhs	cpu_arm1022_cache_clean_invalidate_all_r2
++
++1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b
++#endif
++
++	mcr	p15, 0, r2, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_dcache_clean_page(page)
++ *
++ * Cleans a single page of dcache so that if we have any future aliased
++ * mappings, they will be consistent at the time that they are created.
++ *
++ * page: virtual address of page to clean from dcache
++ *
++ * Note:
++ *     we don't invalidate the entries since when we write the page
++ *     out to disk, the entries may get reloaded into the cache.
++ */
++	.align	5
++ENTRY(cpu_arm1022_dcache_clean_page)
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++	mov	r1, #PAGESIZE
++1:
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++	add	r0, r0, #DCACHELINESIZE
++	subs	r1, r1, #DCACHELINESIZE
++	bne	1b
++#endif
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_dcache_clean_entry(addr)
++ *
++ * Clean the specified entry of any caches such that the MMU
++ * translation fetches will obtain correct data.
++ *
++ * addr: cache-unaligned virtual address
++ */
++	.align	5
++ENTRY(cpu_arm1022_dcache_clean_entry)
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	bic	r0, r0, #DCACHELINESIZE - 1
++	mcr	p15, 0, r0, c7, c10, 1		@ clean single D entry
++#endif
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/* ================================ I-CACHE =============================== */
++
++/*
++ * cpu_arm1022_icache_invalidate_range(start, end)
++ *
++ * invalidate a range of virtual addresses from the Icache
++ *
++ * This is a little misleading, it is not intended to clean out
++ * the i-cache but to make sure that any data written to the
++ * range is made consistent.  This means that when we execute code
++ * in that region, everything works as we expect.
++ *
++ * This generally means writing back data in the Dcache and
++ * write buffer and invalidating the Icache over that region
++ *
++ * start: virtual start address
++ * end:   virtual end address
++ *
++ * NOTE: ICACHELINESIZE == DCACHELINESIZE (so we don't need to
++ * loop twice, once for i-cache, once for d-cache)
++ */
++	.align	5
++ENTRY(cpu_arm1022_icache_invalidate_range)
++	bic	r0, r0, #ICACHELINESIZE - 1
++	sub	r3, r1, r0
++	cmp	r3, #MAX_AREA_SIZE
++	movhs	r2, #1
++	bhs	cpu_arm1022_cache_clean_invalidate_all_r2
++1:
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c10, 1		@ Clean D entry
++#endif
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	mcr	p15, 0, r0, c7, c5, 1		@ Invalidate I entry
++#endif
++	add	r0, r0, #DCACHELINESIZE
++	cmp	r0, r1
++	bls	1b				@ unsigned lower or same - includes r1 entry
++
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++ENTRY(cpu_arm1022_icache_invalidate_page)
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++	add	r1, r0, #PAGESIZE
++	b	cpu_arm1022_icache_invalidate_range
++
++/* ================================== TLB ================================= */
++
++/*
++ * cpu_arm1022_tlb_invalidate_all()
++ *
++ * Invalidate all TLB entries
++ */
++	.align	5
++ENTRY(cpu_arm1022_tlb_invalidate_all)
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I & D tlbs
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_tlb_invalidate_range(start, end)
++ *
++ * invalidate TLB entries covering the specified range
++ *
++ * start: range start address
++ * end:   range end address
++ */
++	.align	5
++ENTRY(cpu_arm1022_tlb_invalidate_range)
++	sub	r3, r1, r0
++	cmp	r3, #256 * PAGESIZE
++	bhs	cpu_arm1022_tlb_invalidate_all
++	mov	r3, #0
++	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
++	mov	r3, #PAGESIZE
++	sub	r3, r3, #1
++	bic	r0, r0, r3
++1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
++	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
++	add	r0, r0, #PAGESIZE
++	cmp	r0, r1
++	bls	1b
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_tlb_invalidate_page(page, flags)
++ *
++ * invalidate the TLB entries for the specified page.
++ *
++ * page:  page to invalidate
++ * flags: non-zero if we include the I TLB
++ */
++	.align	5
++ENTRY(cpu_arm1022_tlb_invalidate_page)
++	mov	r3, #0
++	mcr	p15, 0, r3, c7, c10, 4		@ drain WB
++	mov	r0, r0, LSR #LOG2PAGESIZE	@ round down to nearest page
++	mov	r0, r0, LSL #LOG2PAGESIZE
++	teq	r1, #0
++	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
++	mcrne	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
++	mov	pc, lr
++
++/* =============================== PageTable ============================== */
++
++/*
++ * cpu_arm1022_set_pgd(pgd)
++ *
++ * Set the translation base pointer to be as described by pgd.
++ *
++ * pgd: new page tables
++ */
++	.align	5
++ENTRY(cpu_arm1022_set_pgd)
++	stmfd	sp!, {lr}
++	bl	cpu_arm1022_cache_clean_invalidate_all	@ preserves r0
++	mov	r1, #0
++	mcr	p15, 0, r0, c2, c0, 0		@ load page table pointer
++	mcr	p15, 0, r1, c8, c7, 0		@ invalidate I & D TLBs
++	ldmfd	sp!, {pc}
++
++/*
++ * cpu_arm1022_set_pmd(pmdp, pmd)
++ *
++ * Set a level 1 translation table entry, and clean it out of
++ * any caches such that the MMUs can load it correctly.
++ *
++ * pmdp: pointer to PMD entry
++ * pmd:  PMD value to store
++ */
++	.align	5
++ENTRY(cpu_arm1022_set_pmd)
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	eor	r2, r1, #0x0a			@ C & Section
++	tst	r2, #0x0b
++	biceq	r1, r1, #4			@ clear bufferable bit
++#endif
++	str	r1, [r0]
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++/*
++ * cpu_arm1022_set_pte(ptep, pte)
++ *
++ * Set a PTE and flush it out
++ */
++	.align	5
++ENTRY(cpu_arm1022_set_pte)
++	str	r1, [r0], #-1024		@ linux version
++
++	eor	r1, r1, #LPTE_PRESENT | LPTE_YOUNG | LPTE_WRITE | LPTE_DIRTY
++
++	bic	r2, r1, #0xff0
++	bic	r2, r2, #3
++	orr	r2, r2, #HPTE_TYPE_SMALL
++
++	tst	r1, #LPTE_USER			@ User?
++	orrne	r2, r2, #HPTE_AP_READ
++
++	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
++	orreq	r2, r2, #HPTE_AP_WRITE
++
++	tst	r1, #LPTE_PRESENT | LPTE_YOUNG	@ Present and Young?
++	movne	r2, #0
++
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	eor	r3, r2, #0x0a	@ C and Small Page?
++	tst	r3, #0x0b			@ if so..
++	biceq	r2, r2, #0x04	@ clear the bufferable bit
++#endif
++	str	r2, [r0]			@ hardware version
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
++#endif
++	mov	r1, #0
++	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
++	mov	pc, lr
++
++
++cpu_manu_name:
++	.asciz	"ARM"
++ENTRY(cpu_arm1022_name)
++	.ascii	"Arm1022E"
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	.ascii	"i"
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	.ascii	"d"
++#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
++	.ascii	"(wt)"
++#endif
++#ifdef CONFIG_CPU_DCACHE_WRITEBACK
++	.ascii	"(wb)"
++#endif
++#endif
++#ifndef CONFIG_CPU_BPREDICT_DISABLE
++	.ascii	"B"
++#endif
++#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
++	.ascii	"RR"
++#endif
++	.ascii	"\0"
++	.align
++
++	.section ".text.init", #alloc, #execinstr
++
++__arm1022_setup:
++	mov	r0, #0
++	mcr	p15, 0, r0, c7, c7, 0		@ invalidate I,D caches on v4
++	mcr	p15, 0, r0, c7, c10, 4		@ drain write buffer on v4
++	mcr	p15, 0, r0, c8, c7, 0		@ invalidate I,D TLBs on v4
++	mcr	p15, 0, r4, c2, c0, 0		@ load page table pointer
++	mov	r0, #0x1f			@ Domains 0, 1 = client
++	mcr	p15, 0, r0, c3, c0, 0		@ load domain access register
++
++	mrc	p15, 0, r0, c1, c0, 0		@ Read current control register
++/*
++ * The only thing worth keeping from the initial control register is the endian bit
++ */
++
++	and	r0, r0, #0x0080			@ ........B....... Preserve  endian bit, zero all others.
++	orr	r0, r0, #0x0070			@ .........111.... Set the SBO (Should Be One) bits
++/*
++ * Turn on what we want.
++ */
++	orr	r0, r0, #0x0001 		@ ...............M Enable MMU (Alignment is special cased elsewhere)
++	orr	r0, r0, #0x0100 		@ .......S........ Enable system MMU protection
++	orr	r0, r0, #0x2000			@ ..V............. Enable high vectors
++
++#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
++	orr	r0, r0, #0x4000 		@ .R.............. Force round-robin replacement
++#endif
++
++#ifndef CONFIG_CPU_BPREDICT_DISABLE
++	orr	r0, r0, #0x0800 		@ ....Z........... Enable branch prediction
++#endif
++
++#ifdef CONFIG_CPU_DCACHE_ENABLE
++	orr	r0, r0, #0x0004 		@ .............C.. Enable D cache
++#endif
++#ifndef CONFIG_CPU_WB_DISABLE
++	orr	r0, r0, #0x0008 		@ ............W... Write Buffer enabled
++#endif
++
++#ifdef CONFIG_CPU_ICACHE_ENABLE
++	orr	r0, r0, #0x1000 		@ ...I............ Enable I Cache
++#endif
++
++	mov	pc, lr
++
++	.text
++
++/*
++ * Purpose : Function pointers used to access above functions - all calls
++ *	     come through these
++ */
++	.type	arm1022_processor_functions, #object
++arm1022_processor_functions:
++	.word	cpu_arm1022_data_abort
++	.word	cpu_arm1022_check_bugs
++	.word	cpu_arm1022_proc_init
++	.word	cpu_arm1022_proc_fin
++	.word	cpu_arm1022_reset
++	.word	cpu_arm1022_do_idle
++
++	/* cache */
++	.word	cpu_arm1022_cache_clean_invalidate_all
++	.word	cpu_arm1022_cache_clean_invalidate_range
++	.word	cpu_arm1022_flush_ram_page
++
++	/* dcache */
++	.word	cpu_arm1022_dcache_invalidate_range
++	.word	cpu_arm1022_dcache_clean_range
++	.word	cpu_arm1022_dcache_clean_page
++	.word	cpu_arm1022_dcache_clean_entry
++
++	/* icache */
++	.word	cpu_arm1022_icache_invalidate_range
++	.word	cpu_arm1022_icache_invalidate_page
++
++	/* tlb */
++	.word	cpu_arm1022_tlb_invalidate_all
++	.word	cpu_arm1022_tlb_invalidate_range
++	.word	cpu_arm1022_tlb_invalidate_page
++
++	/* pgtable */
++	.word	cpu_arm1022_set_pgd
++	.word	cpu_arm1022_set_pmd
++	.word	cpu_arm1022_set_pte
++	.size	arm1022_processor_functions, . - arm1022_processor_functions
++
++	.type	cpu_arm1022_info, #object
++cpu_arm1022_info:
++	.long	cpu_manu_name
++	.long	cpu_arm1022_name
++	.size	cpu_arm1022_info, . - cpu_arm1022_info
++
++	.type	cpu_arch_name, #object
++cpu_arch_name:
++	.asciz	"armv5t"
++	.size	cpu_arch_name, . - cpu_arch_name
++
++	.type	cpu_elf_name, #object
++cpu_elf_name:
++	.asciz	"v5"
++	.size	cpu_elf_name, . - cpu_elf_name
++	.align
++
++	.section ".proc.info", #alloc, #execinstr
++
++	.type	__arm1022_proc_info,#object
++__arm1022_proc_info:
++	.long	0x4100a220			@ ARM 1022
++	.long	0xff00fff0
++	.long	0x00000c1e			@ mmuflags
++	b	__arm1022_setup
++	.long	cpu_arch_name
++	.long	cpu_elf_name
++	.long	HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
++	.long	cpu_arm1022_info
++	.long	arm1022_processor_functions
++	.size	__arm1022_proc_info, . - __arm1022_proc_info
+--- linux-2.4.25/arch/arm/mm/proc-arm1026.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm1026.S	2004-03-31 17:15:09.000000000 +0200
+@@ -66,19 +66,24 @@
+  *
+  * Returns:
+  *  r0 = address of abort
+- *  r1 != 0 if writing
+- *  r3 = FSR
++ *  r1 = FSR, bit 11 set if writing
++ *  r3 = corrupted
+  *  r4 = corrupted
+  */
+ 	.align	5
+ ENTRY(cpu_arm1026_data_abort)
+-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
+-	and	r2, r3, #0b1101			@ Check for translation error
+-	sub	r1, r2, #0b0101
+-
+-	and	r3, r3, #255
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	tst	r3, #PSR_J_BIT			@ Java?
++	orrne	r1, r1, #1 << 11		@ always assume write
++	movne	pc, lr
++	tst	r3, #PSR_T_BIT
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
+ 	mov	pc, lr
+ 
+ /*
+@@ -254,7 +259,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm1026_dcache_invalidate_range)
+-#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	tst	r0, #DCACHELINESIZE - 1
+ 	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	tst	r1, #DCACHELINESIZE - 1
+@@ -279,7 +284,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm1026_dcache_clean_range)
+-#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	bic	r0, r0, #DCACHELINESIZE - 1
+ 	sub	r3, r1, r0
+ 	cmp	r3, #MAX_AREA_SIZE
+@@ -309,7 +314,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm1026_dcache_clean_page)
+-#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mov	r1, #PAGESIZE
+ 1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	add	r0, r0, #DCACHELINESIZE
+@@ -330,7 +335,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm1026_dcache_clean_entry)
+-#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ #endif
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+@@ -473,7 +478,7 @@
+ 	biceq	r1, r1, #4			@ clear bufferable bit
+ #endif
+ 	str	r1, [r0]
+-#ifndef CONFIG_CPU_ARM1026_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ #endif
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+@@ -494,7 +499,7 @@
+ 	bic	r2, r2, #3
+ 	orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-	tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++	tst	r1, #LPTE_USER			@ User?
+ 	orrne	r2, r2, #HPTE_AP_READ
+ 
+ 	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+@@ -634,12 +639,12 @@
+ 
+ 	.type	cpu_arch_name, #object
+ cpu_arch_name:
+-	.asciz	"armv5EJ"
++	.asciz	"armv5tej"
+ 	.size	cpu_arch_name, . - cpu_arch_name
+ 
+ 	.type	cpu_elf_name, #object
+ cpu_elf_name:
+-	.asciz	"v5EJ"
++	.asciz	"v5"
+ 	.size	cpu_elf_name, . - cpu_elf_name
+ 	.align
+ 
+--- linux-2.4.25/arch/arm/mm/proc-arm6,7.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm6,7.S	2004-03-31 17:15:09.000000000 +0200
+@@ -72,7 +72,7 @@
+ 1:		mcr	p15, 0, r0, c6, c0, 0		@ purge TLB
+ 		add	r0, r0, #4096
+ 		cmp	r0, r1
+-		blt	1b
++		blo	1b
+ 		mov	pc, lr
+ 
+ ENTRY(cpu_arm7_tlb_invalidate_range)
+@@ -85,7 +85,7 @@
+ 1:		mcr	p15, 0, r0, c6, c0, 0		@ purge TLB
+ 		add	r0, r0, #0x4000
+ 		cmp	r0, r1
+-		blt	1b
++		blo	1b
+ 		mov	pc, lr
+ #endif
+ 
+@@ -110,15 +110,13 @@
+  * Purpose : obtain information about current aborted instruction
+  *
+  * Returns : r0 = address of abort
+- *	   : r1 != 0 if writing
+- *	   : r3 = FSR
++ *	   : r1 = FSR, bit 11 set if writing
++ *	   : r3 = corrupted
+  *	   : sp = pointer to registers
+  */
+ 
+ ENTRY(cpu_arm6_data_abort)
+ 		ldr	r4, [r0]			@ read instruction causing problem
+-		tst	r4, r4, lsr #21			@ C = bit 20
+-		sbc	r1, r1, r1			@ r1 = C - 1
+ 		and	r2, r4, #14 << 24
+ 		teq	r2, #8 << 24			@ was it ldm/stm
+ 		bne	Ldata_simple
+@@ -144,14 +142,14 @@
+ 		addeq	r7, r0, r7, lsl #2		@ Do correction (signed)
+ Ldata_saver7:	str	r7, [sp, r5, lsr #14]		@ Put register
+ Ldata_simple:	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-		mrc	p15, 0, r3, c5, c0, 0		@ get FSR
+-		and	r3, r3, #255
++		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
++		bic	r1, r1, #1 << 11 | 1 << 10
++		tst	r4, #1 << 20
++		orreq	r1, r1, #1 << 11
+ 		mov	pc, lr
+ 
+ ENTRY(cpu_arm7_data_abort)
+ 		ldr	r4, [r0]			@ read instruction causing problem
+-		tst	r4, r4, lsr #21			@ C = bit 20
+-		sbc	r1, r1, r1			@ r1 = C - 1
+ 		and	r2, r4, #15 << 24
+ 		add	pc, pc, r2, lsr #22		@ Now branch to the relevent processing routine
+ 		movs	pc, lr
+@@ -336,7 +334,7 @@
+ 		bic	r2, r2, #3
+ 		orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-		tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++		tst	r1, #LPTE_USER			@ User?
+ 		orrne	r2, r2, #HPTE_AP_READ
+ 
+ 		tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+--- linux-2.4.25/arch/arm/mm/proc-arm720.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm720.S	2004-03-31 17:15:09.000000000 +0200
+@@ -97,7 +97,7 @@
+ 1:		mcr	p15, 0, r0, c8, c7, 1		@ flush TLB (v4)
+ 		add	r0, r0, #PAGESIZE
+ 		cmp	r0, r1
+-		blt	1b
++		blo	1b
+ 		mov	pc, lr
+ 
+ /*
+@@ -124,8 +124,8 @@
+  * picture.  Unfortunately, this does happen.  We live with it.
+  *
+  * Returns : r0 = address of abort
+- *	   : r1 != 0 if writing
+- *	   : r3 = FSR
++ *	   : r1 = FSR, bit 11 set if writing
++ *	   : r3 = corrupted
+  *	   : sp = pointer to registers
+  */
+ 
+@@ -150,16 +150,16 @@
+ 		addeq	r7, r0, r7, lsl #2		@ Do correction (signed)
+ Ldata_saver7:	str	r7, [sp, r5, lsr #14]		@ Put register
+ Ldata_simple:	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-		mrc	p15, 0, r3, c5, c0, 0		@ get FSR
+-		and	r3, r3, #255
++		mrc	p15, 0, r1, c5, c0, 0		@ get FSR
++		bic	r1, r1, #1 << 11 | 1 << 10
++		tst	r4, #1 << 20
++		orreq	r1, r1, #1 << 11
+ 		mov	pc, lr
+ 
+ ENTRY(cpu_arm720_data_abort)
+-		tst	r3, #T_BIT
++		tst	r3, #PSR_T_BIT
+ 		bne	.data_thumb_abort
+-		ldr	r4, [r0]			@ read instruction causing problem
+-		tst	r4, r4, lsr #21			@ C = bit 20
+-		sbc	r1, r1, r1			@ r1 = C - 1
++		ldr	r4, [r2]			@ read instruction causing problem
+ 		and	r2, r4, #15 << 24
+ 		add	pc, pc, r2, lsr #22		@ Now branch to the relevent processing routine
+ 		movs	pc, lr
+@@ -270,9 +270,9 @@
+ 		b	Ldata_saver7
+ 
+ .data_thumb_abort:
+-		ldrh	r4, [r0]			@ read instruction
+-		tst	r4, r4, lsr #12			@ C = bit 11
+-		sbc	r1, r1, r1			@ r1 = C - 1
++		ldrh	r4, [r2]			@ read instruction
++		tst	r4, #1 << 11
++		orrne	r4, r4, #1 << 20
+ 		and	r2, r4, #15 << 12
+ 		add	pc, pc, r2, lsr #10		@ lookup in table
+ 		nop
+@@ -318,8 +318,8 @@
+ 		and	r0, r0, #15			@ number of regs to transfer
+ 		ldr	r7, [sp, #13 << 2]
+ 		tst	r4, #1 << 11
+-		addne	r7, r7, r0, lsl #2		@ increment SP if PUSH
+-		subeq	r7, r7, r0, lsr #2		@ decrement SP if POP
++		addeq	r7, r7, r0, lsl #2		@ increment SP if PUSH
++		subne	r7, r7, r0, lsl #2		@ decrement SP if POP
+ 		str	r7, [sp, #13 << 2]
+ 		b	Ldata_simple
+ 
+@@ -336,7 +336,7 @@
+ 		and	r0, r0, #15			@ number of regs to transfer
+ 		and	r5, r4, #7 << 8
+ 		ldr	r7, [sp, r5, lsr #6]
+-		sub	r7, r7, r0, lsr #2		@ always decrement
++		sub	r7, r7, r0, lsl #2		@ always decrement
+ 		str	r7, [sp, r5, lsr #6]
+ 		b	Ldata_simple
+ 
+@@ -418,7 +418,7 @@
+ 		bic	r2, r2, #3
+ 		orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-		tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++		tst	r1, #LPTE_USER			@ User?
+ 		orrne	r2, r2, #HPTE_AP_READ
+ 
+ 		tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+--- linux-2.4.25/arch/arm/mm/proc-arm920.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm920.S	2004-03-31 17:15:09.000000000 +0200
+@@ -71,12 +71,16 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm920_data_abort)
+-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-	ldr	r1, [r2]			@ read aborted instruction
+-	and	r3, r3, #255
+-	tst	r1, r1, lsr #21			@ C = bit 20
+-	sbc	r1, r1, r1			@ r1 = C - 1
++
++	tst	r3, #PSR_T_BIT
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
+ 	mov	pc, lr
+ 	
+ /*
+@@ -186,10 +190,9 @@
+ 		.align	5
+ ENTRY(cpu_arm920_cache_clean_invalidate_range)
+ 	bic	r0, r0, #DCACHELINESIZE - 1	@ && added by PGM
+-	bic	r1, r1, #DCACHELINESIZE - 1     @ && added by DHM
+ 	sub	r3, r1, r0
+ 	cmp	r3, #MAX_AREA_SIZE
+-	bgt	cpu_arm920_cache_clean_invalidate_all_r2
++	bhi	cpu_arm920_cache_clean_invalidate_all_r2
+ 1:	teq	r2, #0
+ #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+@@ -207,7 +210,7 @@
+ 	add	r0, r0, #DCACHELINESIZE
+ #endif
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 
+ 	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
+ 	mov	pc, lr
+@@ -253,18 +256,17 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm920_dcache_invalidate_range)
+-#ifndef CONFIG_CPU_ARM920_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	tst	r0, #DCACHELINESIZE - 1
+ 	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	tst	r1, #DCACHELINESIZE - 1
+ 	mcrne	p15, 0, r1, c7, c10, 1		@ clean D entry
+ #endif		@ clean D entry
+ 	bic	r0, r0, #DCACHELINESIZE - 1
+-	bic	r1, r1, #DCACHELINESIZE - 1
+ 1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+ 	add	r0, r0, #DCACHELINESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 	mov	pc, lr
+ 
+ /*
+@@ -279,20 +281,17 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm920_dcache_clean_range)
+-#ifndef CONFIG_CPU_ARM920_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	bic	r0, r0, #DCACHELINESIZE - 1
+ 	sub	r1, r1, r0
+ 	cmp	r1, #MAX_AREA_SIZE
+ 	mov	r2, #0
+-	bgt	cpu_arm920_cache_clean_invalidate_all_r2
+-
+-	bic	r1, r1, #DCACHELINESIZE -1
+-	add	r1, r1, #DCACHELINESIZE
++	bhi	cpu_arm920_cache_clean_invalidate_all_r2
+ 
+ 1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	add	r0, r0, #DCACHELINESIZE
+ 	subs	r1, r1, #DCACHELINESIZE
+-	bpl	1b
++	bcs	1b
+ #endif
+ 	mcr	p15, 0, r2, c7, c10, 4		@ drain WB
+ 	mov	pc, lr
+@@ -312,7 +311,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm920_dcache_clean_page)
+-#ifndef CONFIG_CPU_ARM920_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mov	r1, #PAGESIZE
+ 1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	add	r0, r0, #DCACHELINESIZE
+@@ -333,7 +332,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm920_dcache_clean_entry)
+-#ifndef CONFIG_CPU_ARM920_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ #endif
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+@@ -365,16 +364,13 @@
+ 	bic	r0, r0, #ICACHELINESIZE - 1	@ Safety check
+ 	sub	r1, r1, r0
+ 	cmp	r1, #MAX_AREA_SIZE
+-	bgt	cpu_arm920_cache_clean_invalidate_all_r2
+-
+-	bic	r1, r1, #ICACHELINESIZE - 1
+-	add	r1, r1, #ICACHELINESIZE
++	bhi	cpu_arm920_cache_clean_invalidate_all_r2
+ 
+ 1:	mcr	p15, 0, r0, c7, c5, 1		@ Clean I entry
+ 	mcr	p15, 0, r0, c7, c10, 1		@ Clean D entry
+ 	add	r0, r0, #ICACHELINESIZE
+ 	subs	r1, r1, #ICACHELINESIZE
+-	bne	1b
++	bcs	1b
+ 
+ 	mov	r0, #0
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+@@ -418,13 +414,12 @@
+ 	mov	r3, #PAGESIZE
+ 	sub	r3, r3, #1
+ 	bic 	r0, r0, r3
+-	bic	r1, r1, r3
+ 
+ 1:	mcr	p15, 0, r0, c8, c6, 1		@ invalidate D TLB entry
+ 	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
+ 	add	r0, r0, #PAGESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 	mov	pc, lr
+ 
+ /*
+@@ -457,7 +452,6 @@
+ ENTRY(cpu_arm920_set_pgd)
+ 	mov	ip, #0
+ #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+-	/* Any reason why we don't use mcr p15, 0, r0, c7, c7, 0 here? --rmk */
+ 	mcr	p15, 0, ip, c7, c6, 0		@ invalidate D cache
+ #else
+ @ && 'Clean & Invalidate whole DCache'
+@@ -514,7 +508,7 @@
+ 	bic	r2, r2, #3
+ 	orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-	tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++	tst	r1, #LPTE_USER			@ User?
+ 	orrne	r2, r2, #HPTE_AP_READ
+ 
+ 	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+--- linux-2.4.25/arch/arm/mm/proc-arm922.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm922.S	2004-03-31 17:15:09.000000000 +0200
+@@ -62,17 +62,20 @@
+  *
+  * Returns:
+  *  r0 = address of abort
+- *  r1 != 0 if writing
+- *  r3 = FSR
++ *  r1 = FSR, bit 11 set if writing
++ *  r3 = corrupted
+  */
+ 	.align	5
+ ENTRY(cpu_arm922_data_abort)
+-	ldr	r1, [r0]			@ read aborted instruction
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-	tst	r1, r1, lsr #21			@ C = bit 20
+-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
+-	sbc	r1, r1, r1			@ r1 = C - 1
+-	and	r3, r3, #255
++	tst	r3, #PSR_T_BIT
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
+ 	mov	pc, lr
+ 	
+ /*
+@@ -185,7 +188,7 @@
+ 	bic	r1, r1, #DCACHELINESIZE - 1     @ && added by DHM
+ 	sub	r3, r1, r0
+ 	cmp	r3, #MAX_AREA_SIZE
+-	bgt	cpu_arm922_cache_clean_invalidate_all_r2
++	bhi	cpu_arm922_cache_clean_invalidate_all_r2
+ 1:	teq	r2, #0
+ #ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+@@ -203,7 +206,7 @@
+ 	add	r0, r0, #DCACHELINESIZE
+ #endif
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 
+ 	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
+ 	mov	pc, lr
+@@ -249,7 +252,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm922_dcache_invalidate_range)
+-#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	tst	r0, #DCACHELINESIZE - 1
+ 	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	tst	r1, #DCACHELINESIZE - 1
+@@ -260,7 +263,7 @@
+ 1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+ 	add	r0, r0, #DCACHELINESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 	mov	pc, lr
+ 
+ /*
+@@ -275,12 +278,12 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm922_dcache_clean_range)
+-#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	bic	r0, r0, #DCACHELINESIZE - 1
+ 	sub	r1, r1, r0
+ 	cmp	r1, #MAX_AREA_SIZE
+ 	mov	r2, #0
+-	bgt	cpu_arm922_cache_clean_invalidate_all_r2
++	bhi	cpu_arm922_cache_clean_invalidate_all_r2
+ 
+ 	bic	r1, r1, #DCACHELINESIZE -1
+ 	add	r1, r1, #DCACHELINESIZE
+@@ -308,7 +311,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm922_dcache_clean_page)
+-#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mov	r1, #PAGESIZE
+ 1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	add	r0, r0, #DCACHELINESIZE
+@@ -329,7 +332,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm922_dcache_clean_entry)
+-#ifndef CONFIG_CPU_ARM922_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ #endif
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+@@ -361,7 +364,7 @@
+ 	bic	r0, r0, #ICACHELINESIZE - 1	@ Safety check
+ 	sub	r1, r1, r0
+ 	cmp	r1, #MAX_AREA_SIZE
+-	bgt	cpu_arm922_cache_clean_invalidate_all_r2
++	bhi	cpu_arm922_cache_clean_invalidate_all_r2
+ 
+ 	bic	r1, r1, #ICACHELINESIZE - 1
+ 	add	r1, r1, #ICACHELINESIZE
+@@ -420,7 +423,7 @@
+ 	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
+ 	add	r0, r0, #PAGESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 	mov	pc, lr
+ 
+ /*
+@@ -510,7 +513,7 @@
+ 	bic	r2, r2, #3
+ 	orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-	tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++	tst	r1, #LPTE_USER			@ User?
+ 	orrne	r2, r2, #HPTE_AP_READ
+ 
+ 	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+--- linux-2.4.25/arch/arm/mm/proc-arm925.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm925.S	2004-03-31 17:15:09.000000000 +0200
+@@ -69,24 +69,24 @@
+  *
+  * Returns:
+  *  r0 = address of abort
+- *  r1 != 0 if writing
+- *  r3 = FSR
++ *  r1 = FSR, bit 11 set if writing
++ *  r3 = corrupted
+  *  r4 = corrupted
+  */
+ 	.align	5
+ ENTRY(cpu_arm925_data_abort)
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-	mrc	p15, 0, r4, c5, c0, 0		@ get FSR
+-
+-	tst	r3, #1<<5			@ Check for Thumb-bit (NE -> found)
+-	ldrneh	r1, [r2]			@ Read aborted Thumb instruction
+-	tstne	r1, r1, lsr #12 		@ C = bit 11
+-
+-	ldreq	r1, [r2]			@ Read aborted ARM instruction
+-	tsteq	r1, r1, lsr #21 		@ C = bit 20
+-
+-	sbc	r1, r1, r1			@ r1 = C - 1
+-	and	r3, r4, #255
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	tst	r3, #PSR_J_BIT			@ Java?
++	orrne	r1, r1, #1 << 11		@ always assume write
++	movne	pc, lr
++	tst	r3, #PSR_T_BIT			@ Thumb?
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ L = 0 -> write
++	orreq	r1, r1, #1 << 11		@ yes.
+ 	mov	pc, lr
+ 
+ /*
+@@ -207,7 +207,7 @@
+ 	bic	r1, r1, #DCACHELINESIZE - 1     @ && added by DHM
+ 	sub	r3, r1, r0
+ 	cmp	r3, #MAX_AREA_SIZE
+-	bgt	cpu_arm925_cache_clean_invalidate_all_r2
++	bhi	cpu_arm925_cache_clean_invalidate_all_r2
+ 1:	teq	r2, #0
+ #ifdef CONFIG_CPU_ARM925_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+@@ -225,7 +225,7 @@
+ 	add	r0, r0, #DCACHELINESIZE
+ #endif
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 
+ 	mcr	p15, 0, r1, c7, c10, 4		@ drain WB
+ 	mov	pc, lr
+@@ -282,7 +282,7 @@
+ 1:	mcr	p15, 0, r0, c7, c6, 1		@ invalidate D entry
+ 	add	r0, r0, #DCACHELINESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 	mov	pc, lr
+ 
+ /*
+@@ -302,7 +302,7 @@
+ 	sub	r1, r1, r0
+ 	cmp	r1, #MAX_AREA_SIZE
+ 	mov	r2, #0
+-	bgt	cpu_arm925_cache_clean_invalidate_all_r2
++	bhi	cpu_arm925_cache_clean_invalidate_all_r2
+ 
+ 	bic	r1, r1, #DCACHELINESIZE -1
+ 	add	r1, r1, #DCACHELINESIZE
+@@ -383,7 +383,7 @@
+ 	bic	r0, r0, #ICACHELINESIZE - 1	@ Safety check
+ 	sub	r1, r1, r0
+ 	cmp	r1, #MAX_AREA_SIZE
+-	bgt	cpu_arm925_cache_clean_invalidate_all_r2
++	bhi	cpu_arm925_cache_clean_invalidate_all_r2
+ 
+ 	bic	r1, r1, #ICACHELINESIZE - 1
+ 	add	r1, r1, #ICACHELINESIZE
+@@ -443,7 +443,7 @@
+ 	mcr	p15, 0, r0, c8, c5, 1		@ invalidate I TLB entry
+ 	add	r0, r0, #PAGESIZE
+ 	cmp	r0, r1
+-	blt	1b
++	blo	1b
+ 	mov	pc, lr
+ 
+ /*
+@@ -532,7 +532,7 @@
+ 	bic	r2, r2, #3
+ 	orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-	tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++	tst	r1, #LPTE_USER			@ User?
+ 	orrne	r2, r2, #HPTE_AP_READ
+ 
+ 	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+--- linux-2.4.25/arch/arm/mm/proc-arm926.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-arm926.S	2004-03-31 17:15:09.000000000 +0200
+@@ -66,28 +66,24 @@
+  *
+  * Returns:
+  *  r0 = address of abort
+- *  r1 != 0 if writing
+- *  r3 = FSR
++ *  r1 = FSR, bit 11 set if writing
++ *  r3 = corrupted
+  *  r4 = corrupted
+  */
+ 	.align	5
+ ENTRY(cpu_arm926_data_abort)
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-	mrc	p15, 0, r4, c5, c0, 0		@ get FSR
+-
+-	tst	r3, #1<<24			@ Check for Jbit (NE -> found)
+-	movne	r3, #-1 			@ Mark as writing
+-	bne	2f
+-
+-	tst	r3, #1<<5			@ Check for Thumb-bit (NE -> found)
+-	ldrneh	r1, [r2]			@ Read aborted Thumb instruction        
+-	ldreq	r1, [r2]			@ Read aborted ARM instruction
+-	movne	r1, r1, lsl #(20-12)		@ shift thumb bit 10 to ARM bit 20
+-	tsteq	r1, r1, lsr #21 		@ C = bit 20
+-
+-	sbc	r1, r1, r1			@ r1 = C - 1
+-2:
+-	and	r3, r4, #255
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	tst	r3, #PSR_J_BIT			@ Java?
++	orrne	r1, r1, #1 << 11		@ always assume write
++	movne	pc, lr
++	tst	r3, #PSR_T_BIT			@ Thumb?
++	ldrneh	r3, [r2]			@ read aborted thumb instruction
++	ldreq	r3, [r2]			@ read aborted ARM instruction
++	movne	r3, r3, lsl #(21 - 12)		@ move thumb bit 11 to ARM bit 20
++	tst	r3, #1 << 20			@ L = 0 -> write
++	orreq	r1, r1, #1 << 11		@ yes.
+ 	mov	pc, lr
+ 
+ /*
+@@ -263,7 +259,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm926_dcache_invalidate_range)
+-#ifndef CONFIG_CPU_ARM926_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	tst	r0, #DCACHELINESIZE - 1
+ 	mcrne	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	tst	r1, #DCACHELINESIZE - 1
+@@ -288,7 +284,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm926_dcache_clean_range)
+-#ifndef CONFIG_CPU_ARM926_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	bic	r0, r0, #DCACHELINESIZE - 1
+ 	sub	r3, r1, r0
+ 	cmp	r3, #MAX_AREA_SIZE
+@@ -318,7 +314,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm926_dcache_clean_page)
+-#ifndef CONFIG_CPU_ARM926_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mov	r1, #PAGESIZE
+ 1:	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ 	add	r0, r0, #DCACHELINESIZE
+@@ -339,7 +335,7 @@
+  */
+ 	.align	5
+ ENTRY(cpu_arm926_dcache_clean_entry)
+-#ifndef CONFIG_CPU_ARM926_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ #endif
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+@@ -482,7 +478,7 @@
+ 	biceq	r1, r1, #4			@ clear bufferable bit
+ #endif
+ 	str	r1, [r0]
+-#ifndef CONFIG_CPU_ARM926_WRITETHROUGH
++#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ 	mcr	p15, 0, r0, c7, c10, 1		@ clean D entry
+ #endif
+ 	mcr	p15, 0, r0, c7, c10, 4		@ drain WB
+@@ -503,7 +499,7 @@
+ 	bic	r2, r2, #3
+ 	orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-	tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++	tst	r1, #LPTE_USER			@ User?
+ 	orrne	r2, r2, #HPTE_AP_READ
+ 
+ 	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+--- linux-2.4.25/arch/arm/mm/proc-sa110.S~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/mm/proc-sa110.S	2004-03-31 17:15:09.000000000 +0200
+@@ -86,12 +86,12 @@
+ 	.align	5
+ ENTRY(cpu_sa110_data_abort)
+ ENTRY(cpu_sa1100_data_abort)
+-	mrc	p15, 0, r3, c5, c0, 0		@ get FSR
++	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
+ 	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
+-	ldr	r1, [r2]			@ read aborted instruction
+-	and	r3, r3, #255
+-	tst	r1, r1, lsr #21			@ C = bit 20
+-	sbc	r1, r1, r1			@ r1 = C - 1
++	ldr	r3, [r2]			@ read aborted instruction
++	bic	r1, r1, #1 << 11 | 1 << 10	@ clear bits 11 and 10 of FSR
++	tst	r3, #1 << 20			@ check write
++	orreq	r1, r1, #1 << 11
+ 	mov	pc, lr
+ 
+ /*
+@@ -551,7 +551,7 @@
+ 	bic	r2, r2, #3
+ 	orr	r2, r2, #HPTE_TYPE_SMALL
+ 
+-	tst	r1, #LPTE_USER | LPTE_EXEC	@ User or Exec?
++	tst	r1, #LPTE_USER			@ User?
+ 	orrne	r2, r2, #HPTE_AP_READ
+ 
+ 	tst	r1, #LPTE_WRITE | LPTE_DIRTY	@ Write and Dirty?
+--- linux-2.4.25/arch/arm/tools/mach-types~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/arm/tools/mach-types	2004-03-31 17:15:09.000000000 +0200
+@@ -6,7 +6,7 @@
+ # To add an entry into this database, please see Documentation/arm/README,
+ # or contact rmk@arm.linux.org.uk
+ #
+-# Last update: Sat Jun 28 12:10:54 2003
++# Last update: Tue Feb 10 17:10:34 2004
+ #
+ # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
+ #
+@@ -202,7 +202,7 @@
+ fester			SA1100_FESTER		FESTER			191
+ gpi			ARCH_GPI		GPI			192
+ smdk2410		ARCH_SMDK2410		SMDK2410		193
+-premium			ARCH_PREMIUM		PREMIUM			194
++i519			ARCH_I519		I519			194
+ nexio			SA1100_NEXIO		NEXIO			195
+ bitbox			SA1100_BITBOX		BITBOX			196
+ g200			SA1100_G200		G200			197
+@@ -228,7 +228,7 @@
+ arnold			SA1100_ARNOLD		ARNOLD			217
+ psiboard		SA1100_PSIBOARD		PSIBOARD		218
+ jz8028			ARCH_JZ8028		JZ8028			219
+-h5400			ARCH_IPAQ3		IPAQ3			220
++h5400			ARCH_H5400		H5400			220
+ forte			SA1100_FORTE		FORTE			221
+ acam			SA1100_ACAM		ACAM			222
+ abox			SA1100_ABOX		ABOX			223
+@@ -259,7 +259,7 @@
+ stork_egg		ARCH_STORK_EGG		STORK_EGG		248
+ wismo			SA1100_WISMO		WISMO			249
+ ezlinx			ARCH_EZLINX		EZLINX			250
+-at91rm9200		ARCH_AT91		AT91			251
++at91rm9200		ARCH_AT91RM9200		AT91RM9200		251
+ orion			ARCH_ORION		ORION			252
+ neptune			ARCH_NEPTUNE		NEPTUNE			253
+ hackkit			SA1100_HACKKIT		HACKKIT			254
+@@ -300,7 +300,7 @@
+ inhandelf3		ARCH_INHANDELF3		INHANDELF3		289
+ adi_coyote		ARCH_ADI_COYOTE		ADI_COYOTE		290
+ iyonix			ARCH_IYONIX		IYONIX			291
+-damicam_sa1110		ARCH_DAMICAM_SA1110	DAMICAM_SA1110		292
++damicam1		ARCH_DAMICAM_SA1110	DAMICAM_SA1110		292
+ meg03			ARCH_MEG03		MEG03			293
+ pxa_whitechapel		ARCH_PXA_WHITECHAPEL	PXA_WHITECHAPEL		294
+ nwsc			ARCH_NWSC		NWSC			295
+@@ -356,3 +356,111 @@
+ seedpxa_c2		ARCH_SEEDPXA_C2		SEEDPXA_C2		345
+ ixp4xx_mguardpci	ARCH_IXP4XX_MGUARD_PCI	IXP4XX_MGUARD_PCI	346
+ h1940			ARCH_H1940		H1940			347
++scorpio			ARCH_SCORPIO		SCORPIO			348
++viva			ARCH_VIVA		VIVA			349
++pxa_xcard		ARCH_PXA_XCARD		PXA_XCARD		350
++csb335			ARCH_CSB335		CSB335			351
++ixrd425			ARCH_IXRD425		IXRD425			352
++iq80315			ARCH_IQ80315		IQ80315			353
++nmp7312			ARCH_NMP7312		NMP7312			354
++cx861xx			ARCH_CX861XX		CX861XX			355
++enp2611			ARCH_ENP2611		ENP2611			356
++xda			SA1100_XDA		XDA			357
++csir_ims		ARCH_CSIR_IMS		CSIR_IMS		358
++ixp421_dnaeeth		ARCH_IXP421_DNAEETH	IXP421_DNAEETH		359
++pocketserv9200		ARCH_POCKETSERV9200	POCKETSERV9200		360
++toto			ARCH_TOTO		TOTO			361
++s3c2440			ARCH_S3C2440		S3C2440			362
++ks8695p			ARCH_KS8695P		KS8695P			363
++se4000			ARCH_SE4000		SE4000			364
++quadriceps		ARCH_QUADRICEPS		QUADRICEPS		365
++bronco			ARCH_BRONCO		BRONCO			366
++esl_wireless_tab	ARCH_ESL_WIRELESS_TABLETESL_WIRELESS_TABLET	367
++esl_sofcomp		ARCH_ESL_SOFCOMP	ESL_SOFCOMP		368
++s5c7375			ARCH_S5C7375		S5C7375			369
++spearhead		ARCH_SPEARHEAD		SPEARHEAD		370
++pantera			ARCH_PANTERA		PANTERA			371
++prayoglite		ARCH_PRAYOGLITE		PRAYOGLITE		372
++gumstik			ARCH_GUMSTIK		GUMSTIK			373
++rcube			ARCH_RCUBE		RCUBE			374
++rea_olv			ARCH_REA_OLV		REA_OLV			375
++pxa_iphone		ARCH_PXA_IPHONE		PXA_IPHONE		376
++s3c3410			ARCH_S3C3410		S3C3410			377
++espd_4510b		ARCH_ESPD_4510B		ESPD_4510B		378
++mp1x			ARCH_MP1X		MP1X			379
++at91rm9200tb		ARCH_AT91RM9200TB	AT91RM9200TB		380
++adsvgx			ARCH_ADSVGX		ADSVGX			381
++omap1610		ARCH_OMAP1610		OMAP1610		382
++pelee			ARCH_PELEE		PELEE			383
++e7xx			ARCH_E7XX		E7XX			384
++iq80331			ARCH_IQ80331		IQ80331			385
++versatile_pb		ARCH_VERSATILE_PB	VERSATILE_PB		387
++kev7a400		MACH_KEV7A400		KEV7A400		388
++lpd7a400		MACH_LPD7A400		LPD7A400		389
++lpd7a404		MACH_LPD7A404		LPD7A404		390
++fujitsu_camelot		ARCH_FUJITSU_CAMELOT	FUJITSU_CAMELOT		391
++janus2m			ARCH_JANUS2M		JANUS2M			392
++embtf			MACH_EMBTF		EMBTF			393
++hpm			MACH_HPM		HPM			394
++smdk2410tk		MACH_SMDK2410TK		SMDK2410TK		395
++smdk2410aj		MACH_SMDK2410AJ		SMDK2410AJ		396
++streetracer		MACH_STREETRACER	STREETRACER		397
++eframe			MACH_EFRAME		EFRAME			398
++csb337			MACH_CSB337		CSB337			399
++pxa_lark		MACH_PXA_LARK		PXA_LARK		400
++pxa_pnp2110		MACH_PNP2110		PNP2110			401
++tcc72x			MACH_TCC72X		TCC72X			402
++altair			MACH_ALTAIR		ALTAIR			403
++kc3			MACH_KC3		KC3			404
++sinteftd		MACH_SINTEFTD		SINTEFTD		405
++mainstone		MACH_MAINSTONE		MAINSTONE		406
++aday4x			MACH_ADAY4X		ADAY4X			407
++lite300			MACH_LITE300		LITE300			408
++s5c7376			MACH_S5C7376		S5C7376			409
++mt02			MACH_MT02		MT02			410
++mport3s			MACH_MPORT3S		MPORT3S			411
++ra_alpha		MACH_RA_ALPHA		RA_ALPHA		412
++xcep			MACH_XCEP		XCEP			413
++arcom_mercury		MACH_ARCOM_MERCURY	ARCOM_MERCURY		414
++stargate		MACH_STARGATE		STARGATE		415
++armadilloj		MACH_ARMADILLOJ		ARMADILLOJ		416
++elroy_jack		MACH_ELROY_JACK		ELROY_JACK		417
++backend			MACH_BACKEND		BACKEND			418
++s5linbox		MACH_S5LINBOX		S5LINBOX		419
++nomadik			MACH_NOMADIK		NOMADIK			420
++ia_cpu_9200		MACH_IA_CPU_9200	IA_CPU_9200		421
++at91_bja1		MACH_AT91_BJA1		AT91_BJA1		422
++corgi			MACH_CORGI		CORGI			423
++poodle			MACH_POODLE		POODLE			424
++ten			MACH_TEN		TEN			425
++roverp5p		MACH_ROVERP5P		ROVERP5P		426
++sc2700			MACH_SC2700		SC2700			427
++ex_eagle		MACH_EX_EAGLE		EX_EAGLE		428
++nx_pxa12		MACH_NX_PXA12		NX_PXA12		429
++nx_pxa5			MACH_NX_PXA5		NX_PXA5			430
++blackboard2		MACH_BLACKBOARD2	BLACKBOARD2		431
++i819			MACH_I819		I819			432
++ixmb995e		MACH_IXMB995E		IXMB995E		433
++skyrider		MACH_SKYRIDER		SKYRIDER		434
++skyhawk			MACH_SKYHAWK		SKYHAWK			435
++enterprise		MACH_ENTERPRISE		ENTERPRISE		436
++dep2410			MACH_DEP2410		DEP2410			437
++armcore			MACH_ARMCORE		ARMCORE			438
++hobbit			MACH_HOBBIT		HOBBIT			439
++h7210			MACH_H7210		H7210			440
++pxa_netdcu5		MACH_PXA_NETDCU5	PXA_NETDCU5		441
++acc			MACH_ACC		ACC			442
++esl_sarva		MACH_ESL_SARVA		ESL_SARVA		443
++xm250			MACH_XM250		XM250			444
++t6tc1xb			MACH_T6TC1XB		T6TC1XB			445
++ess710			MACH_ESS710		ESS710			446
++mx3ads			MACH_MX3ADS		MX3ADS			447
++himalaya		MACH_HIMALAYA		HIMALAYA		448
++bolfenk			MACH_BOLFENK		BOLFENK			449
++at91rm9200kr		MACH_AT91RM9200KR	AT91RM9200KR		450
++edb9312			MACH_EDB9312		EDB9312			451
++omap_generic		MACH_OMAP_GENERIC	OMAP_GENERIC		452
++aximx3			MACH_AXIMX3		AXIMX3			453
++eb67xdip		MACH_EB67XDIP		EB67XDIP		454
++webtxs			MACH_WEBTXS		WEBTXS			455
++hawk			MACH_HAWK		HAWK			456
+--- linux-2.4.25/arch/i386/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/i386/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -9,6 +9,7 @@
+ 
+ define_bool CONFIG_UID16 y
+ 
++define_bool CONFIG_GENERIC_ISA_DMA y
+ mainmenu_option next_comment
+ comment 'Code maturity level options'
+ bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL
+--- linux-2.4.25/arch/i386/kernel/Makefile~2.4.25-vrs2.patch	2003-11-28 19:26:19.000000000 +0100
++++ linux-2.4.25/arch/i386/kernel/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -7,8 +7,8 @@
+ #
+ # Note 2! The CFLAGS definitions are now in the main makefile...
+ 
+-.S.o:
+-	$(CC) $(AFLAGS) -traditional -c $< -o $*.o
++USE_STANDARD_AS_RULE := true
++EXTRA_AFLAGS := -traditional
+ 
+ all: kernel.o head.o init_task.o
+ 
+--- linux-2.4.25/arch/i386/kernel/apm.c~2.4.25-vrs2.patch	2003-08-25 13:44:39.000000000 +0200
++++ linux-2.4.25/arch/i386/kernel/apm.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1267,6 +1267,7 @@
+ 		as->suspend_wait = 0;
+ 		as->suspend_result = err;
+ 	}
++	ignore_normal_resume = 1;
+ 	wake_up_interruptible(&apm_suspend_waitqueue);
+ 	return err;
+ }
+@@ -1319,6 +1320,8 @@
+ 		if (ignore_bounce
+ 		    && ((jiffies - last_resume) > bounce_interval))
+ 			ignore_bounce = 0;
++		if (ignore_normal_resume && (event != APM_NORMAL_RESUME))
++			ignore_normal_resume = 0;
+ 
+ 		switch (event) {
+ 		case APM_SYS_STANDBY:
+--- linux-2.4.25/arch/i386/lib/Makefile~2.4.25-vrs2.patch	2001-09-10 16:31:30.000000000 +0200
++++ linux-2.4.25/arch/i386/lib/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -2,8 +2,7 @@
+ # Makefile for i386-specific library files..
+ #
+ 
+-.S.o:
+-	$(CC) $(AFLAGS) -c $< -o $*.o
++USE_STANDARD_AS_RULE := true
+ 
+ L_TARGET = lib.a
+ 
+--- linux-2.4.25/arch/i386/math-emu/Makefile~2.4.25-vrs2.patch	2000-12-29 23:07:20.000000000 +0100
++++ linux-2.4.25/arch/i386/math-emu/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -2,15 +2,15 @@
+ #               Makefile for wm-FPU-emu
+ #
+ 
++USE_STANDARD_AS_RULE := true
++
+ O_TARGET := math.o
+ 
+ #DEBUG	= -DDEBUGGING
+ DEBUG	=
+ PARANOID = -DPARANOID
+ CFLAGS	:= $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin $(MATH_EMULATION)
+-
+-.S.o:
+-	$(CC) $(AFLAGS) $(PARANOID) -c $<
++EXTRA_AFLAGS := $(PARANOID)
+ 
+ # From 'C' language sources:
+ C_OBJS =fpu_entry.o errors.o \
+--- linux-2.4.25/arch/ia64/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/ia64/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -25,6 +25,7 @@
+ define_bool CONFIG_SBUS n
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ choice 'IA-64 processor type' \
+ 	"Itanium		CONFIG_ITANIUM \
+--- linux-2.4.25/arch/m68k/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/m68k/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -6,6 +6,7 @@
+ define_bool CONFIG_UID16 y
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ mainmenu_name "Linux/68k Kernel Configuration"
+ 
+--- linux-2.4.25/arch/mips/config.in~2.4.25-vrs2.patch	2002-11-29 00:53:09.000000000 +0100
++++ linux-2.4.25/arch/mips/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -5,5 +5,6 @@
+ define_bool CONFIG_MIPS y
+ define_bool CONFIG_MIPS32 y
+ define_bool CONFIG_MIPS64 n
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ source arch/mips/config-shared.in
+--- linux-2.4.25/arch/parisc/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/parisc/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -9,6 +9,7 @@
+ define_bool CONFIG_UID16 n
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ mainmenu_option next_comment
+ comment 'Code maturity level options'
+--- linux-2.4.25/arch/ppc/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/ppc/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -6,6 +6,7 @@
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
+ define_bool CONFIG_HAVE_DEC_LOCK y
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ mainmenu_name "Linux/PowerPC Kernel Configuration"
+ 
+--- linux-2.4.25/arch/sh/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/sh/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -9,6 +9,7 @@
+ define_bool CONFIG_UID16 y
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ mainmenu_option next_comment
+ comment 'Code maturity level options'
+--- linux-2.4.25/arch/sparc/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:30.000000000 +0100
++++ linux-2.4.25/arch/sparc/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -6,6 +6,7 @@
+ 
+ define_bool CONFIG_UID16 y
+ define_bool CONFIG_HIGHMEM y
++define_bool CONFIG_GENERIC_ISA_DMA y
+ 
+ mainmenu_option next_comment
+ comment 'Code maturity level options'
+--- linux-2.4.25/arch/sparc64/config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/arch/sparc64/config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -41,6 +41,7 @@
+ define_bool CONFIG_HAVE_DEC_LOCK y
+ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+ define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
++define_bool CONFIG_GENERIC_ISA_DMA y
+ define_bool CONFIG_ISA n
+ define_bool CONFIG_ISAPNP n
+ define_bool CONFIG_EISA n
+--- linux-2.4.25/drivers/Makefile~2.4.25-vrs2.patch	2003-11-28 19:26:19.000000000 +0100
++++ linux-2.4.25/drivers/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -8,9 +8,9 @@
+ 
+ mod-subdirs :=	dio hil mtd sbus video macintosh usb input telephony ide \
+ 		message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
+-		fc4 net/hamradio i2c acpi bluetooth usb/gadget
++		fc4 net/hamradio i2c l3 acpi bluetooth serial usb/gadget
+ 
+-subdir-y :=	parport char block net sound misc media cdrom hotplug
++subdir-y :=	parport serial char block net sound misc media cdrom hotplug pld
+ subdir-m :=	$(subdir-y)
+ 
+ 
+@@ -45,8 +45,12 @@
+ # CONFIG_HAMRADIO can be set without CONFIG_NETDEVICE being set  -- ch
+ subdir-$(CONFIG_HAMRADIO)	+= net/hamradio
+ subdir-$(CONFIG_I2C)		+= i2c
++subdir-$(CONFIG_L3)		+= l3
+ subdir-$(CONFIG_ACPI_BOOT)	+= acpi
+ 
+ subdir-$(CONFIG_BLUEZ)		+= bluetooth
++subdir-$(CONFIG_SSI)		+= ssi
++
++subdir-$(CONFIG_ARCH_AT91RM9200)+= at91
+ 
+ include $(TOPDIR)/Rules.make
+--- linux-2.4.25/drivers/acorn/char/i2c.c~2.4.25-vrs2.patch	2004-01-05 14:53:56.000000000 +0100
++++ linux-2.4.25/drivers/acorn/char/i2c.c	2004-03-31 17:15:09.000000000 +0200
+@@ -166,7 +166,6 @@
+ 		break;
+ 
+ 	case RTC_RD_TIME:
+-		memset(&rtctm, 0, sizeof(struct rtc_time));
+ 		get_rtc_time(&rtc_raw, &year);
+ 		rtctm.tm_sec  = rtc_raw.secs;
+ 		rtctm.tm_min  = rtc_raw.mins;
+--- linux-2.4.25/drivers/acorn/net/ether1.c~2.4.25-vrs2.patch	2003-08-25 13:44:40.000000000 +0200
++++ linux-2.4.25/drivers/acorn/net/ether1.c	2004-03-31 17:15:09.000000000 +0200
+@@ -80,7 +80,7 @@
+ #define BUS_16 16
+ #define BUS_8  8
+ 
+-static const card_ids __init ether1_cids[] = {
++static card_ids __initdata ether1_cids[] = {
+ 	{ MANU_ACORN, PROD_ACORN_ETHER1 },
+ 	{ 0xffff, 0xffff }
+ };
+--- linux-2.4.25/drivers/acorn/net/ether3.c~2.4.25-vrs2.patch	2003-08-25 13:44:40.000000000 +0200
++++ linux-2.4.25/drivers/acorn/net/ether3.c	2004-03-31 17:15:09.000000000 +0200
+@@ -75,7 +75,7 @@
+ #include "ether3.h"
+ 
+ static unsigned int net_debug = NET_DEBUG;
+-static const card_ids __init ether3_cids[] = {
++static card_ids __initdata ether3_cids[] = {
+ 	{ MANU_ANT2, PROD_ANT_ETHER3 },
+ 	{ MANU_ANT,  PROD_ANT_ETHER3 },
+ 	{ MANU_ANT,  PROD_ANT_ETHERB },
+--- linux-2.4.25/drivers/acorn/net/etherh.c~2.4.25-vrs2.patch	2003-08-25 13:44:40.000000000 +0200
++++ linux-2.4.25/drivers/acorn/net/etherh.c	2004-03-31 17:15:09.000000000 +0200
+@@ -57,7 +57,7 @@
+ 
+ static unsigned int net_debug = NET_DEBUG;
+ 
+-static const card_ids __init etherh_cids[] = {
++static card_ids __initdata etherh_cids[] = {
+ 	{ MANU_ANT, PROD_ANT_ETHERM      },
+ 	{ MANU_I3,  PROD_I3_ETHERLAN500  },
+ 	{ MANU_I3,  PROD_I3_ETHERLAN600  },
+--- linux-2.4.25/drivers/acorn/scsi/cumana_1.c~2.4.25-vrs2.patch	2001-09-14 00:21:32.000000000 +0200
++++ linux-2.4.25/drivers/acorn/scsi/cumana_1.c	2004-03-31 17:15:09.000000000 +0200
+@@ -153,20 +153,20 @@
+         ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
+         outb(0x00, instance->io_port - 577);
+ 
+-	if (instance->irq != IRQ_NONE)
++	if (instance->irq != SCSI_IRQ_NONE)
+ 	    if (request_irq(instance->irq, do_cumanascsi_intr, SA_INTERRUPT, "CumanaSCSI-1", NULL)) {
+ 		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+ 		    instance->host_no, instance->irq);
+-		instance->irq = IRQ_NONE;
++		instance->irq = SCSI_IRQ_NONE;
+ 	    }
+ 
+-	if (instance->irq == IRQ_NONE) {
++	if (instance->irq == SCSI_IRQ_NONE) {
+ 	    printk("scsi%d: interrupts not enabled. for better interactive performance,\n", instance->host_no);
+ 	    printk("scsi%d: please jumper the board for a free IRQ.\n", instance->host_no);
+ 	}
+ 
+ 	printk("scsi%d: at port %lX irq", instance->host_no, instance->io_port);
+-	if (instance->irq == IRQ_NONE)
++	if (instance->irq == SCSI_IRQ_NONE)
+ 	    printk ("s disabled");
+ 	else
+ 	    printk (" %d", instance->irq);
+@@ -185,7 +185,7 @@
+ {
+ 	int i;
+ 
+-	if (shpnt->irq != IRQ_NONE)
++	if (shpnt->irq != SCSI_IRQ_NONE)
+ 		free_irq (shpnt->irq, NULL);
+ 	if (shpnt->io_port)
+ 		release_region (shpnt->io_port, shpnt->n_io_port);
+--- linux-2.4.25/drivers/acorn/scsi/ecoscsi.c~2.4.25-vrs2.patch	2002-08-03 02:39:43.000000000 +0200
++++ linux-2.4.25/drivers/acorn/scsi/ecoscsi.c	2004-03-31 17:15:09.000000000 +0200
+@@ -106,7 +106,7 @@
+     instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+     instance->io_port = 0x80ce8000;
+     instance->n_io_port = 144;
+-    instance->irq = IRQ_NONE;
++    instance->irq = SCSI_IRQ_NONE;
+ 
+     if (check_region (instance->io_port, instance->n_io_port)) {
+ 	scsi_unregister (instance);
+@@ -130,20 +130,20 @@
+ 	return 0;
+     }
+ 
+-    if (instance->irq != IRQ_NONE)
++    if (instance->irq != SCSI_IRQ_NONE)
+ 	if (request_irq(instance->irq, do_ecoscsi_intr, SA_INTERRUPT, "ecoscsi", NULL)) {
+ 	    printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+ 	    instance->host_no, instance->irq);
+-	    instance->irq = IRQ_NONE;
++	    instance->irq = SCSI_IRQ_NONE;
+ 	}
+ 
+-    if (instance->irq != IRQ_NONE) {
++    if (instance->irq != SCSI_IRQ_NONE) {
+   	printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
+ 	printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
+     }
+ 
+     printk("scsi%d: at port %X irq", instance->host_no, instance->io_port);
+-    if (instance->irq == IRQ_NONE)
++    if (instance->irq == SCSI_IRQ_NONE)
+ 	printk ("s disabled");
+     else
+         printk (" %d", instance->irq);
+@@ -157,7 +157,7 @@
+ 
+ int ecoscsi_release (struct Scsi_Host *shpnt)
+ {
+-	if (shpnt->irq != IRQ_NONE)
++	if (shpnt->irq != SCSI_IRQ_NONE)
+ 		free_irq (shpnt->irq, NULL);
+ 	if (shpnt->io_port)
+ 		release_region (shpnt->io_port, shpnt->n_io_port);
+--- linux-2.4.25/drivers/acorn/scsi/oak.c~2.4.25-vrs2.patch	2001-10-11 18:04:57.000000000 +0200
++++ linux-2.4.25/drivers/acorn/scsi/oak.c	2004-03-31 17:15:09.000000000 +0200
+@@ -97,7 +97,7 @@
+ };
+ 
+ #define OAK_ADDRESS(card) (ecard_address((card), ECARD_MEMC, 0))
+-#define OAK_IRQ(card)	  (IRQ_NONE)
++#define OAK_IRQ(card)	  (SCSI_IRQ_NONE)
+ /*
+  * Function : int oakscsi_detect(Scsi_Host_Template * tpnt)
+  *
+@@ -136,20 +136,20 @@
+ 	instance->n_io_port = 255;
+ 	request_region (instance->io_port, instance->n_io_port, "Oak SCSI");
+ 
+-	if (instance->irq != IRQ_NONE)
++	if (instance->irq != SCSI_IRQ_NONE)
+ 	    if (request_irq(instance->irq, do_oakscsi_intr, SA_INTERRUPT, "Oak SCSI", NULL)) {
+ 		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+ 		    instance->host_no, instance->irq);
+-		instance->irq = IRQ_NONE;
++		instance->irq = SCSI_IRQ_NONE;
+ 	    }
+ 
+-	if (instance->irq != IRQ_NONE) {
++	if (instance->irq != SCSI_IRQ_NONE) {
+ 	    printk("scsi%d: eek! Interrupts enabled, but I don't think\n", instance->host_no);
+ 	    printk("scsi%d: that the board had an interrupt!\n", instance->host_no);
+ 	}
+ 
+ 	printk("scsi%d: at port %lX irq", instance->host_no, instance->io_port);
+-	if (instance->irq == IRQ_NONE)
++	if (instance->irq == SCSI_IRQ_NONE)
+ 	    printk ("s disabled");
+ 	else
+ 	    printk (" %d", instance->irq);
+@@ -172,7 +172,7 @@
+ {
+ 	int i;
+ 
+-	if (shpnt->irq != IRQ_NONE)
++	if (shpnt->irq != SCSI_IRQ_NONE)
+ 		free_irq (shpnt->irq, NULL);
+ 	if (shpnt->io_port)
+ 		release_region (shpnt->io_port, shpnt->n_io_port);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,23 @@
++#
++# Makefile for the AT91RM9200-specific Linux kernel device drivers.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (not a .c file).
++
++O_TARGET := at91drv.o
++
++subdir-y :=	serial net watchdog rtc usb i2c spi mtd
++subdir-m :=	$(subdir-y)
++
++obj-$(CONFIG_SERIAL_AT91)		+= serial/at91serial.o
++obj-$(CONFIG_AT91_ETHER)		+= net/at91net.o
++obj-$(CONFIG_AT91_WATCHDOG)		+= watchdog/at91wdt.o
++obj-$(CONFIG_AT91_RTC)			+= rtc/at91rtc.o
++obj-$(CONFIG_USB)			+= usb/at91usb.o
++obj-$(CONFIG_I2C_AT91)			+= i2c/at91i2c.o
++obj-$(CONFIG_AT91_SPIDEV)		+= spi/at91spi.o
++obj-$(CONFIG_MTD_AT91_DATAFLASH)	+= spi/at91spi.o mtd/at91mtd.o
++obj-$(CONFIG_MTD_AT91_SMARTMEDIA)	+= mtd/at91mtd.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/i2c/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,15 @@
++# File: drivers/at91/i2c/Makefile
++#
++# Makefile for the Atmel AT91RM9200 I2C (TWI) device drivers
++#
++
++O_TARGET := at91i2c.o
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++obj-$(CONFIG_I2C_AT91) += at91_i2c.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/i2c/at91_i2c.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,257 @@
++/*
++    i2c Support for Atmel's AT91RM9200 Two-Wire Interface
++
++    (c) Rick Bronson
++
++    Borrowed heavily from original work by:
++    Copyright (c) 2000 Philip Edelbrock <phil@stimpy.netroedge.com>
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++
++*/
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++
++#include <asm/arch/AT91RM9200_TWI.h>
++#include <asm/arch/pio.h>
++#include "at91_i2c.h"
++
++#define DBG(x...) do {\
++	if (debug > 0) \
++		printk(KERN_DEBUG "i2c:" x); \
++	} while(0)
++
++int debug = 0;
++
++static struct at91_i2c_local *at91_i2c_device;
++
++/*
++ * Poll the i2c status register until the specified bit is set.
++ * Returns 0 if timed out (100 msec)
++ */
++static short at91_poll_status(AT91PS_TWI twi, unsigned long bit) {
++	int loop_cntr = 10000;
++	do {
++		udelay(10);
++	} while (!(twi->TWI_SR & bit) && (--loop_cntr > 0));
++
++	return (loop_cntr > 0);
++}
++
++/*
++ * Generic i2c master transfer entrypoint
++ */
++static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
++{
++	struct at91_i2c_local *device = (struct at91_i2c_local *) adap->data;
++	AT91PS_TWI twi = (AT91PS_TWI) device->base_addr;
++
++	struct i2c_msg *pmsg;
++	int length;
++	unsigned char *buf;
++
++	/*
++	 * i2c_smbus_xfer_emulated() in drivers/i2c/i2c-core.c states:
++	 * "... In the case of writing, we need to use only one message;
++	 * when reading, we need two..."
++	 */
++
++	pmsg = msgs;		/* look at 1st message, it contains the address/command */
++	if (num >= 1 && num <= 2) {
++		DBG("xfer: doing %s %d bytes to 0x%02x - %d messages\n",
++		    pmsg->flags & I2C_M_RD ? "read" : "write",
++		    pmsg->len, pmsg->buf[0], num);
++
++		/* Set the TWI Master Mode Register */
++		twi->TWI_MMR = (pmsg->addr << 16) | (pmsg->len << 8)
++			| ((pmsg + 1)->flags & I2C_M_RD ? AT91C_TWI_MREAD : 0);
++
++		/* Set TWI Internal Address Register with first messages data field */
++		if (pmsg->len == 1)
++			twi->TWI_IADR = pmsg->buf[0];
++		else if (pmsg->len == 2)
++			twi->TWI_IADR = pmsg->buf[0] << 8 | pmsg->buf[1];
++		else			/* must be 3 */
++			twi->TWI_IADR =  pmsg->buf[0] << 16 | pmsg->buf[1] << 8 | pmsg->buf[2];
++
++		/* 1st message contains the address/command */
++		if (num > 1)
++			pmsg++;		/* go to real message */
++
++		length = pmsg->len;
++		buf = pmsg->buf;
++		if (length && buf) {	/* sanity check */
++			if (pmsg->flags & I2C_M_RD) {
++				twi->TWI_CR = AT91C_TWI_START;
++				while (length--) {
++					if (!length)
++						twi->TWI_CR = AT91C_TWI_STOP;
++					/* Wait until transfer is finished */
++					if (!at91_poll_status(twi, AT91C_TWI_RXRDY)) {
++						printk(KERN_ERR "at91_i2c: timeout 1\n");
++						return 0;
++					}
++					*buf++ = twi->TWI_RHR;
++				}
++				if (!at91_poll_status(twi, AT91C_TWI_TXCOMP)) {
++					printk(KERN_ERR "at91_i2c: timeout 2\n");
++					return 0;
++				}
++			} else {
++				twi->TWI_CR = AT91C_TWI_START;
++				while (length--) {
++					twi->TWI_THR = *buf++;
++					if (!length)
++						twi->TWI_CR = AT91C_TWI_STOP;
++					if (!at91_poll_status(twi, AT91C_TWI_TXRDY)) {
++						printk(KERN_ERR "at91_i2c: timeout 3\n");
++						return 0;
++					}
++				}
++				/* Wait until transfer is finished */
++				if (!at91_poll_status(twi, AT91C_TWI_TXCOMP)) {
++					printk(KERN_ERR "at91_i2c: timeout 4\n");
++					return 0;
++				}
++			}
++		}
++		DBG("transfer complete\n");
++		return num;
++	}
++	else {
++		printk(KERN_ERR "at91_i2c: unexpected number of messages: %d\n", num);
++		return 0;
++	}
++}
++
++/*
++ * Return list of supported functionality
++ */
++static u32 at91_func(struct i2c_adapter *adapter)
++{
++	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE
++		| I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA
++		| I2C_FUNC_SMBUS_BLOCK_DATA;
++}
++
++/*
++ * Open
++ */
++static void at91_inc(struct i2c_adapter *adapter)
++{
++	MOD_INC_USE_COUNT;
++}
++
++/*
++ * Close
++ */
++static void at91_dec(struct i2c_adapter *adapter)
++{
++	MOD_DEC_USE_COUNT;
++}
++
++/* For now, we only handle combined mode (smbus) */
++static struct i2c_algorithm at91_algorithm = {
++	name:"at91 i2c",
++	id:I2C_ALGO_SMBUS,
++	master_xfer:at91_xfer,
++	functionality:at91_func,
++};
++
++/*
++ * Main initialization routine
++ */
++static int __init i2c_at91_init(void)
++{
++	AT91PS_TWI twi = (AT91PS_TWI) AT91C_VA_BASE_TWI;
++	struct at91_i2c_local *device;
++	int rc;
++
++	AT91_CfgPIO_TWI();
++	AT91_SYS->PMC_PCER = 1 << AT91C_ID_TWI;		/* enable peripheral clock */
++
++	twi->TWI_IDR = 0x3ff;				/* Disable all interrupts */
++	twi->TWI_CR = AT91C_TWI_SWRST;			/* Reset peripheral */
++	twi->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS;	/* Set Master mode */
++
++	/* Here, CKDIV = 1 and CHDIV=CLDIV  ==> CLDIV = CHDIV = 1/4*((Fmclk/FTWI) -6) */
++	twi->TWI_CWGR = AT91C_TWI_CKDIV1 | AT91C_TWI_CLDIV3 | (AT91C_TWI_CLDIV3 << 8);
++
++	device = (struct at91_i2c_local *) kmalloc(sizeof(struct at91_i2c_local), GFP_KERNEL);
++	if (device == NULL) {
++		printk(KERN_ERR "at91_i2c: can't allocate inteface!\n");
++		return -ENOMEM;
++	}
++	memset(device, 0, sizeof(struct at91_i2c_local));
++	at91_i2c_device = device;
++
++	sprintf(device->adapter.name, "AT91RM9200");
++	device->adapter.data = (void *) device;
++	device->adapter.id = I2C_ALGO_SMBUS;
++	device->adapter.algo = &at91_algorithm;
++	device->adapter.algo_data = NULL;
++	device->adapter.inc_use = at91_inc;
++	device->adapter.dec_use = at91_dec;
++	device->adapter.client_register = NULL;
++	device->adapter.client_unregister = NULL;
++	device->base_addr = AT91C_VA_BASE_TWI;
++
++	rc = i2c_add_adapter(&device->adapter);
++	if (rc) {
++		printk(KERN_ERR "at91_i2c: Adapter %s registration failed\n", device->adapter.name);
++		device->adapter.data = NULL;
++		kfree(device);
++	}
++	else
++		printk(KERN_INFO "Found AT91 i2c\n");
++	return rc;
++}
++
++/*
++ * Clean up routine
++ */
++static void __exit i2c_at91_cleanup(void)
++{
++	struct at91_i2c_local *device = at91_i2c_device;
++	int rc;
++
++	rc = i2c_del_adapter(&device->adapter);
++	device->adapter.data = NULL;
++	kfree(device);
++	
++	AT91_SYS->PMC_PCDR = 1 << AT91C_ID_TWI;		/* disable peripheral clock */
++
++	/* We aren't that prepared to deal with this... */
++	if (rc)
++		printk(KERN_ERR "at91_i2c: i2c_del_adapter failed (%i), that's bad!\n", rc);
++}
++
++module_init(i2c_at91_init);
++module_exit(i2c_at91_cleanup);
++
++MODULE_AUTHOR("Rick Bronson");
++MODULE_DESCRIPTION("I2C driver for Atmel AT91RM9200");
++MODULE_LICENSE("GPL");
++MODULE_PARM(debug, "i");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/i2c/at91_i2c.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,43 @@
++/*
++    i2c Support for Atmel's AT91RM9200 Two-Wire Interface
++
++    (c) Rick Bronson
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++*/
++
++#ifndef AT91_I2C_H
++#define AT91_I2C_H
++
++#define AT91C_TWI_CLOCK		100000
++#define AT91C_TWI_SCLOCK	(10 * AT91C_MASTER_CLOCK / AT91C_TWI_CLOCK)
++#define AT91C_TWI_CKDIV1	(2 << 16)	/* TWI clock divider.  NOTE: see Errata #22 */
++
++#if (AT91C_TWI_SCLOCK % 10) >= 5
++#define AT91C_TWI_CLDIV2 ((AT91C_TWI_SCLOCK / 10) - 5)
++#else
++#define AT91C_TWI_CLDIV2 ((AT91C_TWI_SCLOCK / 10) - 6)
++#endif
++#define AT91C_TWI_CLDIV3 ((AT91C_TWI_CLDIV2 + (4 - AT91C_TWI_CLDIV2 % 4)) >> 2)
++
++#define AT91C_EEPROM_I2C_ADDRESS        (0x50 << 16)
++
++/* Physical interface */
++struct at91_i2c_local {
++	struct i2c_adapter adapter;
++	unsigned long base_addr;
++};
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/mtd/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,19 @@
++# File: drivers/at91/mtd/Makefile
++#
++# Makefile for the Atmel AT91RM9200 MTD devices.
++#   Includes: NAND flash (SmartMedia) & DataFlash
++#
++
++O_TARGET := at91mtd.o
++
++export-objs :=
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++obj-$(CONFIG_MTD_AT91_DATAFLASH) += at91_dataflash.o
++obj-$(CONFIG_MTD_AT91_SMARTMEDIA) += at91_nand.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/mtd/at91_dataflash.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,495 @@
++/*
++ * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/arch/AT91RM9200_SPI.h>
++#include <asm/arch/pio.h>
++#include "at91_dataflash.h"
++#include "../spi/at91_spi.h"
++
++#undef DEBUG_DATAFLASH
++
++/* Detected DataFlash devices */
++static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
++static int nr_devices = 0;
++
++/* ......................................................................... */
++
++#ifdef CONFIG_MTD_PARTITIONS
++
++static struct mtd_partition *mtd_parts = 0;
++static int mtd_parts_nr = 0;
++
++#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
++
++static struct mtd_partition static_partitions[] =
++{
++	{
++		name:		"bootloader",
++		offset:		0,
++		size:		64 * 1024,		/* 64 Kb */
++		mask_flags:	MTD_WRITEABLE		/* read-only */
++	},
++	{
++		name:		"kernel",
++		offset:		MTDPART_OFS_NXTBLK,
++		size:		768 *1024,		/* 768 Kb */
++	},
++	{
++		name:		"filesystem",
++		offset:		MTDPART_OFS_NXTBLK,
++		size:		MTDPART_SIZ_FULL,
++	}
++};
++
++int parse_cmdline_partitions(struct mtd_info *master,
++		struct mtd_partition **pparts, const char *mtd_id);
++
++#endif
++
++/* ......................................................................... */
++
++/* Allocate a single SPI transfer descriptor.  We're assuming that if multiple
++   SPI transfers occur at the same time, spi_access_bus() will serialize them.
++   If this is not valid, then either (i) each dataflash 'priv' structure
++   needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
++   another mechanism.   */
++struct spi_transfer_list* spi_transfer_desc;
++
++/*
++ * Perform a SPI transfer to access the DataFlash device.
++ */
++int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
++		char* txnext, int txnext_len, char* rxnext, int rxnext_len)
++{
++	struct spi_transfer_list* list = spi_transfer_desc;
++
++	list->tx[0] = tx;	list->txlen[0] = tx_len;
++	list->rx[0] = rx;	list->rxlen[0] = rx_len;
++
++	list->tx[1] = txnext; 	list->txlen[1] = txnext_len;
++	list->rx[1] = rxnext;	list->rxlen[1] = rxnext_len;
++
++	list->nr_transfers = nr;
++
++	return spi_transfer(list);
++}
++
++/* ......................................................................... */
++
++/*
++ * Poll the DataFlash device until it is READY.
++ */
++void at91_dataflash_waitready(void)
++{
++	char* command = kmalloc(2, GFP_KERNEL);
++
++	if (!command)
++		return;
++
++	do {
++		command[0] = OP_READ_STATUS;
++		command[1] = 0;
++
++		do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
++	} while ((command[1] & 0x80) == 0);
++
++	kfree(command);
++}
++
++/*
++ * Return the status of the DataFlash device.
++ */
++unsigned short at91_dataflash_status(void)
++{
++	unsigned short status;
++	char* command = kmalloc(2, GFP_KERNEL);
++
++	if (!command)
++		return 0;
++
++	command[0] = OP_READ_STATUS;
++	command[1] = 0;
++
++	do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
++	status = command[1];
++
++	kfree(command);
++	return status;
++}
++
++/* ......................................................................... */
++
++/*
++ * Erase a block of flash.
++ */
++int at91_dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
++	unsigned int pageaddr;
++	char* command;
++
++#ifdef DEBUG_DATAFLASH
++	printk("dataflash_erase: addr=%i len=%i\n", instr->addr, instr->len);
++#endif
++
++	/* Sanity checks */
++	if (instr->addr + instr->len > mtd->size)
++		return -EINVAL;
++	if ((instr->len != mtd->erasesize) || (instr->len != priv->page_size))
++		return -EINVAL;
++	if ((instr->addr % priv->page_size) != 0)
++		return -EINVAL;
++
++	command = kmalloc(4, GFP_KERNEL);
++	if (!command)
++		return -ENOMEM;
++
++	/* Calculate flash page address */
++	pageaddr = (instr->addr / priv->page_size) << priv->page_offset;
++
++	command[0] = OP_ERASE_PAGE;
++	command[1] = (pageaddr & 0x00FF0000) >> 16;
++	command[2] = (pageaddr & 0x0000FF00) >> 8;
++	command[3] = 0;
++#ifdef DEBUG_DATAFLASH
++	printk("ERASE: (%x) %x %x %x [%i]\n", command[0], command[1], command[2], command[3], pageaddr);
++#endif
++
++	/* Send command to SPI device */
++	spi_access_bus(priv->spi);
++	do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
++
++	at91_dataflash_waitready();	/* poll status until ready */
++	spi_release_bus(priv->spi);
++
++	kfree(command);
++
++	/* Inform MTD subsystem that erase is complete */
++	instr->state = MTD_ERASE_DONE;
++	if (instr->callback)
++		instr->callback(instr);
++
++	return 0;
++}
++
++/*
++ * Read from the DataFlash device.
++ *   from   : Start offset in flash device
++ *   len    : Amount to read
++ *   retlen : About of data actually read
++ *   buf    : Buffer containing the data
++ */
++int at91_dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
++{
++	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
++	unsigned int addr;
++	char* command;
++
++#ifdef DEBUG_DATAFLASH
++	printk("dataflash_read: %lli .. %lli\n", from, from+len);
++#endif
++
++	*retlen = 0;
++
++	/* Sanity checks */
++	if (!len)
++		return 0;
++	if (from + len > mtd->size)
++		return -EINVAL;
++
++	/* Calculate flash page/byte address */
++	addr = (((unsigned)from / priv->page_size) << priv->page_offset) + ((unsigned)from % priv->page_size);
++
++	command = kmalloc(8, GFP_KERNEL);
++	if (!command)
++		return -ENOMEM;
++
++	command[0] = OP_READ_CONTINUOUS;
++	command[1] = (addr & 0x00FF0000) >> 16;
++	command[2] = (addr & 0x0000FF00) >> 8;
++	command[3] = (addr & 0x000000FF);
++#ifdef DEBUG_DATAFLASH
++	printk("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
++#endif
++
++	/* Send command to SPI device */
++	spi_access_bus(priv->spi);
++	do_spi_transfer(2, command, 8, command, 8, buf, len, buf, len);
++	spi_release_bus(priv->spi);
++
++	*retlen = len;
++	kfree(command);
++	return 0;
++}
++
++/*
++ * Write to the DataFlash device.
++ *   to     : Start offset in flash device
++ *   len    : Amount to write
++ *   retlen : Amount of data actually written
++ *   buf    : Buffer containing the data
++ */
++int at91_dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
++{
++	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
++	unsigned int pageaddr, addr, offset, writelen;
++	size_t remaining;
++	char *writebuf;
++	unsigned short status;
++	int res = 0;
++	char* command;
++
++#ifdef DEBUG_DATAFLASH
++	printk("dataflash_write: %lli .. %lli\n", to, to+len);
++#endif
++
++	*retlen = 0;
++
++	/* Sanity checks */
++	if (!len)
++		return 0;
++	if (to + len > mtd->size)
++		return -EINVAL;
++
++	command = kmalloc(4, GFP_KERNEL);
++	if (!command)
++		return -ENOMEM;
++
++	pageaddr = ((unsigned)to / priv->page_size);
++	offset = ((unsigned)to % priv->page_size);
++	if (offset + len > priv->page_size)
++		writelen = priv->page_size - offset;
++	else
++		writelen = len;
++	writebuf = buf;
++	remaining = len;
++
++	/* Gain access to the SPI bus */
++	spi_access_bus(priv->spi);
++
++	while (remaining > 0) {
++#ifdef DEBUG_DATAFLASH
++		printk("write @ %i:%i len=%i\n", pageaddr, offset, writelen);
++#endif
++
++		/* (1) Transfer to Buffer1 */
++		if (writelen != priv->page_size) {
++			addr = pageaddr << priv->page_offset;
++			command[0] = OP_TRANSFER_BUF1;
++			command[1] = (addr & 0x00FF0000) >> 16;
++			command[2] = (addr & 0x0000FF00) >> 8;
++			command[3] = 0;
++#ifdef DEBUG_DATAFLASH
++			printk("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
++#endif
++			do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
++			at91_dataflash_waitready();
++		}
++
++		/* (2) Program via Buffer1 */
++		addr = (pageaddr << priv->page_offset) + offset;
++		command[0] = OP_PROGRAM_VIA_BUF1;
++		command[1] = (addr & 0x00FF0000) >> 16;
++		command[2] = (addr & 0x0000FF00) >> 8;
++		command[3] = (addr & 0x000000FF);
++#ifdef DEBUG_DATAFLASH
++		printk("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
++#endif
++		do_spi_transfer(2, command, 4, command, 4, writebuf, writelen, writebuf, writelen);
++		at91_dataflash_waitready();
++
++		/* (3) Compare to Buffer1 */
++		addr = pageaddr << priv->page_offset;
++		command[0] = OP_COMPARE_BUF1;
++		command[1] = (addr & 0x00FF0000) >> 16;
++		command[2] = (addr & 0x0000FF00) >> 8;
++		command[3] = 0;
++#ifdef DEBUG_DATAFLASH
++		printk("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
++#endif
++		do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
++		at91_dataflash_waitready();
++
++		/* Get result of the compare operation */
++		status = at91_dataflash_status();
++		if ((status & 0x40) == 1) {
++			printk("at91_dataflash: Write error on page %i\n", pageaddr);
++			remaining = 0;
++			res = -EIO;
++		}
++
++		remaining = remaining - writelen;
++		pageaddr++;
++		offset = 0;
++		writebuf += writelen;
++		*retlen += writelen;
++
++		if (remaining > priv->page_size)
++			writelen = priv->page_size;
++		else
++			writelen = remaining;
++	}
++
++	/* Release SPI bus */
++	spi_release_bus(priv->spi);
++
++	kfree(command);
++	return res;
++}
++
++/* ......................................................................... */
++
++/*
++ * Initialize and register DataFlash device with MTD subsystem.
++ */
++int add_dataflash(int channel, char *name, int size, int pagesize, int pageoffset)
++{
++	struct mtd_info *device;
++	struct dataflash_local *priv;
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++	char mtdID[14];
++#endif
++
++	if (nr_devices >= DATAFLASH_MAX_DEVICES) {
++		printk(KERN_ERR "at91_dataflash: Too many devices detected\n");
++		return 0;
++	}
++
++	device = (struct mtd_info *) kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
++	if (!device)
++		return -ENOMEM;
++	memset(device, 0, sizeof(struct mtd_info));
++
++	device->name = name;
++	device->size = size;
++	device->erasesize = pagesize;
++	device->module = THIS_MODULE;
++	device->type = MTD_NORFLASH;
++	device->flags = MTD_CAP_NORFLASH;
++	device->erase = at91_dataflash_erase;
++	device->read = at91_dataflash_read;
++	device->write = at91_dataflash_write;
++
++	priv = (struct dataflash_local *) kmalloc(sizeof(struct dataflash_local), GFP_KERNEL);
++	if (!priv) {
++		kfree(device);
++		return -ENOMEM;
++	}
++	memset(priv, 0, sizeof(struct dataflash_local));
++
++	priv->spi = channel;
++	priv->page_size = pagesize;
++	priv->page_offset = pageoffset;
++	device->priv = priv;
++
++	mtd_devices[nr_devices] = device;
++	nr_devices++;
++	printk("at91_dataflash: %s detected [spi%i] (%i bytes)\n", name, channel, size);
++
++#ifdef CONFIG_MTD_PARTITIONS
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++	sprintf(mtdID, "dataflash%i", nr_devices-1);
++	mtd_parts_nr = parse_cmdline_partitions(device, &mtd_parts, mtdID);
++#endif
++	if (mtd_parts_nr <= 0) {
++		mtd_parts = static_partitions;
++		mtd_parts_nr = NB_OF(static_partitions);
++	}
++
++	return add_mtd_partitions(device, mtd_parts, mtd_parts_nr);
++#else
++	return add_mtd_device(device);
++#endif
++}
++
++/*
++ * Detect and initialize DataFlash device connected to specified SPI channel.
++ */
++int at91_dataflash_detect(int channel)
++{
++	int res = 0;
++	unsigned short status;
++
++	spi_access_bus(channel);
++	status = at91_dataflash_status();
++	if (status != 0xff) {			/* no dataflash device there */
++		switch (status & 0x3c) {
++			case 0x2c:	/* 1 0 1 1 */
++				res = add_dataflash(channel, "Atmel AT45DB161B", 4096*528, 528, 10);
++				break;
++			case 0x34:	/* 1 1 0 1 */
++				res = add_dataflash(channel, "Atmel AT45DB321B", 8192*528, 528, 10);
++				break;
++			case 0x3c:	/* 1 1 1 1 */
++				res = add_dataflash(channel, "Atmel AT45DB642", 8192*1056, 1056, 11);
++				break;
++			default:
++				printk(KERN_ERR "at91_dataflash: Unknown device (%x)\n", status & 0x3c);
++		}
++	}
++	spi_release_bus(channel);
++
++	return res;
++}
++
++int __init at91_dataflash_init(void)
++{
++	spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL);
++	if (!spi_transfer_desc)
++		return -ENOMEM;
++
++	/* DataFlash (SPI chip select 0) */
++	at91_dataflash_detect(0);
++
++#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
++	/* DataFlash card (SPI chip select 3) */
++	AT91_CfgPIO_DataFlashCard();
++	at91_dataflash_detect(3);
++#endif
++
++	return 0;
++}
++
++void __exit at91_dataflash_exit(void)
++{
++	int i;
++
++	for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
++		if (mtd_devices[i]) {
++#ifdef CONFIG_MTD_PARTITIONS
++			del_mtd_partitions(mtd_devices[i]);
++#else
++			del_mtd_device(mtd_devices[i]);
++#endif
++			kfree(mtd_devices[i]->priv);
++			kfree(mtd_devices[i]);
++		}
++	}
++	nr_devices = 0;
++	kfree(spi_transfer_desc);
++}
++
++
++EXPORT_NO_SYMBOLS;
++
++module_init(at91_dataflash_init);
++module_exit(at91_dataflash_exit);
++
++MODULE_LICENSE("GPL")
++MODULE_AUTHOR("Andrew Victor")
++MODULE_DESCRIPTION("DataFlash driver for Atmel AT91RM9200")
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/mtd/at91_dataflash.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,42 @@
++/*
++ * Atmel DataFlash driver for the Atmel AT91RM9200 (Thunder)
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#ifndef AT91_DATAFLASH_H
++#define AT91_DATAFLASH_H
++
++#define DATAFLASH_MAX_DEVICES	4	/* max number of dataflash devices */
++
++#define OP_READ_CONTINUOUS	0xE8
++#define OP_READ_PAGE		0xD2
++#define OP_READ_BUFFER1		0xD4
++#define OP_READ_BUFFER2		0xD6
++#define OP_READ_STATUS		0xD7
++
++#define OP_ERASE_PAGE		0x81
++#define OP_ERASE_BLOCK		0x50
++
++#define OP_TRANSFER_BUF1	0x53
++#define OP_TRANSFER_BUF2	0x55
++#define OP_COMPARE_BUF1		0x60
++#define OP_COMPARE_BUF2		0x61
++
++#define OP_PROGRAM_VIA_BUF1	0x82
++#define OP_PROGRAM_VIA_BUF2	0x85
++
++struct dataflash_local
++{
++	int spi;			/* SPI chip-select number */
++
++	unsigned int page_size;		/* number of bytes per page */
++	unsigned short page_offset;	/* page offset in flash address */
++};
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/mtd/at91_nand.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,328 @@
++/*
++ * drivers/at91/mtd/at91_nand.c
++ *
++ *  Copyright (c) 2003 Rick Bronson
++ *
++ *  Derived from drivers/mtd/nand/autcpu12.c
++ *	 Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
++ *
++ *  Derived from drivers/mtd/spia.c
++ *	 Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <asm/io.h>
++#include <asm/arch/hardware.h>
++#include <asm/sizes.h>
++
++#include <asm/arch/pio.h>
++#include "at91_nand.h"
++
++/*
++ * MTD structure for AT91 board
++ */
++static struct mtd_info *at91_mtd = NULL;
++static struct nand_chip *my_nand_chip = NULL;
++
++static int at91_fio_base;
++
++#ifdef CONFIG_MTD_PARTITIONS
++
++/*
++ * Define partitions for flash devices
++ */
++
++static struct mtd_partition partition_info32k[] = {
++	{ name: "AT91 NAND partition 1, kernel",
++	  offset:  0,
++	  size:   1 * SZ_1M },
++	{ name: "AT91 NAND partition 2, filesystem",
++	  offset:  1 * SZ_1M,
++	  size:   16 * SZ_1M },
++	{ name: "AT91 NAND partition 3a, storage",
++	  offset: (1 * SZ_1M) + (16 * SZ_1M),
++	  size:   1 * SZ_1M },
++	{ name: "AT91 NAND partition 3b, storage",
++	  offset: (2 * SZ_1M) + (16 * SZ_1M),
++	  size:   1 * SZ_1M },
++	{ name: "AT91 NAND partition 3c, storage",
++	  offset: (3 * SZ_1M) + (16 * SZ_1M),
++	  size:   1 * SZ_1M },
++	{ name: "AT91 NAND partition 3d, storage",
++	  offset: (4 * SZ_1M) + (16 * SZ_1M),
++	  size:   1 * SZ_1M },
++};
++
++static struct mtd_partition partition_info64k[] = {
++	{ name: "AT91 NAND partition 1, kernel",
++	  offset:  0,
++	  size:   1 * SZ_1M },
++	{ name: "AT91 NAND partition 2, filesystem",
++	  offset:  1 * SZ_1M,
++	  size:   16 * SZ_1M },
++	{ name: "AT91 NAND partition 3, storage",
++	  offset: (1 * SZ_1M) + (16 * SZ_1M),
++	  size:   47 * SZ_1M },
++};
++
++#endif
++
++/*
++ * Hardware specific access to control-lines
++ */
++static void at91_hwcontrol(int cmd)
++{
++	struct nand_chip *my_nand = my_nand_chip;
++	switch(cmd)
++	{
++	case NAND_CTL_SETCLE:
++		my_nand->IO_ADDR_W = at91_fio_base + AT91_SMART_MEDIA_CLE;
++		break;
++	case NAND_CTL_CLRCLE:
++		my_nand->IO_ADDR_W = at91_fio_base;
++		break;
++	case NAND_CTL_SETALE:
++		my_nand->IO_ADDR_W = at91_fio_base + AT91_SMART_MEDIA_ALE;
++		break;
++	case NAND_CTL_CLRALE:
++		my_nand->IO_ADDR_W = at91_fio_base;
++		break;
++	case NAND_CTL_SETNCE:
++		break;
++	case NAND_CTL_CLRNCE:
++		break;
++	}
++}
++
++/*
++ * Send command to NAND device
++ */
++static void at91_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
++{
++	register struct nand_chip *my_nand = mtd->priv;
++
++	/* Begin command latch cycle */
++	register unsigned long NAND_IO_ADDR = my_nand->IO_ADDR_W + AT91_SMART_MEDIA_CLE;
++
++	/*
++	 * Write out the command to the device.
++	 */
++	if (command != NAND_CMD_SEQIN)
++		writeb (command, NAND_IO_ADDR);
++	else {
++		if (mtd->oobblock == 256 && column >= 256) {
++			column -= 256;
++			writeb (NAND_CMD_RESET, NAND_IO_ADDR);
++			writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
++			writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
++		}
++		else
++			if (mtd->oobblock == 512 && column >= 256) {
++				if (column < 512) {
++					column -= 256;
++					writeb (NAND_CMD_READ1, NAND_IO_ADDR);
++					writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
++				} else {
++					column -= 512;
++					writeb (NAND_CMD_READOOB, NAND_IO_ADDR);
++					writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
++				}
++			} else {
++				writeb (NAND_CMD_READ0, NAND_IO_ADDR);
++				writeb (NAND_CMD_SEQIN, NAND_IO_ADDR);
++			}
++	}
++
++	/* Set ALE and clear CLE to start address cycle */
++	NAND_IO_ADDR = at91_fio_base;
++
++	if (column != -1 || page_addr != -1)
++		NAND_IO_ADDR += AT91_SMART_MEDIA_ALE;
++
++	/* Serially input address */
++	if (column != -1)
++		writeb (column, NAND_IO_ADDR);
++	if (page_addr != -1) {
++		writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR);
++		writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR);
++		/* One more address cycle for higher density devices */
++		if (mtd->size & 0x0c000000) {
++			writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR);
++		}
++	}
++
++	/* wait until command is processed */
++	while (!my_nand->dev_ready())
++		;
++}
++
++/*
++ * Read the Device Ready pin.
++ */
++static int at91_device_ready(void)
++{
++	return AT91_PIO_SmartMedia_RDY();
++}
++/*
++ * Main initialization routine
++ */
++static int __init at91_init (void)
++{
++	struct nand_chip *my_nand;
++	int err = 0;
++
++	/* Allocate memory for MTD device structure and private data */
++	at91_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), GFP_KERNEL);
++	if (!at91_mtd) {
++		printk ("Unable to allocate AT91 NAND MTD device structure.\n");
++		err = -ENOMEM;
++		goto out;
++	}
++
++	/* map physical adress */
++	at91_fio_base = (unsigned long) ioremap(AT91_SMARTMEDIA_BASE, SZ_8M);
++	if(!at91_fio_base) {
++		printk("ioremap AT91 NAND failed\n");
++		err = -EIO;
++		goto out_mtd;
++	}
++
++	/* Get pointer to private data */
++	my_nand_chip = my_nand = (struct nand_chip *) (&at91_mtd[1]);
++
++	/* Initialize structures */
++	memset((char *) at91_mtd, 0, sizeof(struct mtd_info));
++	memset((char *) my_nand, 0, sizeof(struct nand_chip));
++
++	/* Link the private data with the MTD structure */
++	at91_mtd->priv = my_nand;
++
++	/* Set address of NAND IO lines */
++	my_nand->IO_ADDR_R = at91_fio_base;
++	my_nand->IO_ADDR_W = at91_fio_base;
++	my_nand->hwcontrol = at91_hwcontrol;
++	my_nand->dev_ready = at91_device_ready;
++	my_nand->cmdfunc = at91_nand_command;	/* we need our own */
++	my_nand->eccmode = NAND_ECC_SOFT;	/* enable ECC */
++	/* 20 us command delay time */
++	my_nand->chip_delay = 20;
++
++	/* Setup Smart Media, first enable the address range of CS3 */
++	AT91_SYS->EBI_CSA |= AT91C_EBI_CS3A_SMC_SmartMedia;
++	/* set the bus interface characteristics based on
++	   tDS Data Set up Time 30 - ns
++	   tDH Data Hold Time 20 - ns
++	   tALS ALE Set up Time 20 - ns
++	   16ns at 60 MHz ~= 3  */
++#define AT91C_SM_ID_RWH	(5 << 28)		/* orig = 5 */
++#define AT91C_SM_RWH	(1 << 28)		/* orig = 1 */
++#define AT91C_SM_RWS	(0 << 24)		/* orig = 0 */
++#define AT91C_SM_TDF	(1 << 8)		/* orig = 1 */
++#define AT91C_SM_NWS	(5)			/* orig = 3 */
++	AT91_SYS->EBI_SMC2_CSR[3] = ( AT91C_SM_RWH | AT91C_SM_RWS |
++					 AT91C_SMC2_ACSS_STANDARD |
++					 AT91C_SMC2_DBW_8 | AT91C_SM_TDF |
++					 AT91C_SMC2_WSEN | AT91C_SM_NWS);
++
++	AT91_CfgPIO_SmartMedia();
++
++	if (AT91_PIO_SmartMedia_CardDetect())
++		printk ("No ");
++	printk ("SmartMedia card inserted.\n");
++
++	/* Scan to find existance of the device */
++	if (nand_scan (at91_mtd)) {
++		err = -ENXIO;
++		goto out_ior;
++	}
++
++	/* Allocate memory for internal data buffer */
++	my_nand->data_buf = kmalloc (sizeof(u_char) * (at91_mtd->oobblock + at91_mtd->oobsize), GFP_KERNEL);
++	if (!my_nand->data_buf) {
++		printk ("Unable to allocate AT91 NAND data buffer.\n");
++		err = -ENOMEM;
++		goto out_ior;
++	}
++
++	/* Allocate memory for internal data buffer */
++	my_nand->data_cache = kmalloc (sizeof(u_char) * (at91_mtd->oobblock + at91_mtd->oobsize), GFP_KERNEL);
++	if (!my_nand->data_cache) {
++		printk ("Unable to allocate AT91 NAND data cache.\n");
++		err = -ENOMEM;
++		goto out_buf;
++	}
++	my_nand->cache_page = -1;
++
++#ifdef CONFIG_MTD_PARTITIONS
++	/* Register the partitions */
++	switch(at91_mtd->size)
++	{
++	case SZ_32M:
++		err = add_mtd_partitions(at91_mtd, partition_info32k,
++				ARRAY_SIZE (partition_info32k));
++		break;
++	case SZ_64M:
++		err = add_mtd_partitions(at91_mtd, partition_info64k,
++				ARRAY_SIZE (partition_info64k));
++		break;
++	default:
++		printk ("Unsupported SmartMedia device\n");
++		err = -ENXIO;
++		goto out_cac;
++	}
++#else
++	err = add_mtd_device(at91_mtd);
++#endif
++	goto out;
++
++ out_cac:
++	kfree (my_nand->data_cache);
++ out_buf:
++	kfree (my_nand->data_buf);
++ out_ior:
++	iounmap((void *)at91_fio_base);
++ out_mtd:
++	kfree (at91_mtd);
++ out:
++	return err;
++}
++
++/*
++ * Clean up routine
++ */
++static void __exit at91_cleanup (void)
++{
++	struct nand_chip *my_nand = (struct nand_chip *) &at91_mtd[1];
++
++	/* Unregister partitions */
++	del_mtd_partitions(at91_mtd);
++
++	/* Unregister the device */
++	del_mtd_device (at91_mtd);
++
++	/* Free internal data buffers */
++	kfree (my_nand->data_buf);
++	kfree (my_nand->data_cache);
++
++	/* unmap physical adress */
++	iounmap((void *)at91_fio_base);
++
++	/* Free the MTD device structure */
++	kfree (at91_mtd);
++}
++
++module_init(at91_init);
++module_exit(at91_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Rick Bronson");
++MODULE_DESCRIPTION("Glue layer for SmartMediaCard on ATMEL AT91RM9200");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/mtd/at91_nand.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,27 @@
++/*
++ * AT91RM9200 specific NAND (SmartMedia) defines
++ *
++ * (c) 2003 Rick Bronson
++ *
++ * 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 __AT91_NAND_H
++#define __AT91_NAND_H
++
++#define AT91_SMART_MEDIA_ALE (1 << 22)  /* our ALE is AD22 */
++#define AT91_SMART_MEDIA_CLE (1 << 21)  /* our CLE is AD21 */
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/net/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,15 @@
++# File: drivers/at91/net/Makefile
++#
++# Makefile for the Atmel AT91RM9200 ethernet device drivers
++#
++
++O_TARGET := at91net.o
++
++obj-y   :=
++obj-m   :=
++obj-n   :=
++obj-	:=
++
++obj-$(CONFIG_AT91_ETHER) += at91_ether.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/net/at91_ether.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,877 @@
++/*
++ * Ethernet driver for the Atmel AT91RM9200 (Thunder)
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc.
++ * Initial version by Rick Bronson 01/11/2003
++ *
++ * Intel LXT971A PHY support by Christopher Bahns & David Knickerbocker
++ *   (Polaroid 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.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/config.h>
++#include <linux/mii.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++#include <linux/pci.h>
++#include <linux/crc32.h>
++#include <asm/uaccess.h>
++#include <linux/ethtool.h>
++
++#include <asm/arch/AT91RM9200_EMAC.h>
++#include <asm/arch/pio.h>
++#include "at91_ether.h"
++
++static struct net_device at91_dev;
++
++/* ........................... PHY INTERFACE ........................... */
++
++/*
++ * Enable the MDIO bit in MAC control register
++ * When not called from an interrupt-handler, access to the PHY must be
++ *  protected by a spinlock.
++ */
++static void enable_mdi(AT91PS_EMAC regs)
++{
++	regs->EMAC_CTL |= AT91C_EMAC_MPE;	/* enable management port */
++}
++
++/*
++ * Disable the MDIO bit in the MAC control register
++ */
++static void disable_mdi(AT91PS_EMAC regs)
++{
++	regs->EMAC_CTL &= ~AT91C_EMAC_MPE;	/* disable management port */
++}
++
++/*
++ * Write value to the a PHY register
++ * Note: MDI interface is assumed to already have been enabled.
++ */
++static void write_phy(AT91PS_EMAC regs, unsigned char phy_addr, unsigned char address, unsigned int value)
++{
++	regs->EMAC_MAN = (AT91C_EMAC_HIGH | AT91C_EMAC_CODE_802_3 | AT91C_EMAC_RW_W
++		| ((phy_addr & 0x1f) << 23) | (address << 18)) + (value & 0xffff);
++
++	/* Wait until IDLE bit in Network Status register is cleared */
++	// TODO: Enforce some maximum loop-count?
++	while (!(regs->EMAC_SR & AT91C_EMAC_IDLE)) { barrier(); }
++}
++
++/*
++ * Read value stored in a PHY register.
++ * Note: MDI interface is assumed to already have been enabled.
++ */
++static void read_phy(AT91PS_EMAC regs, unsigned char phy_addr, unsigned char address, unsigned int *value)
++{
++	regs->EMAC_MAN = AT91C_EMAC_HIGH | AT91C_EMAC_CODE_802_3 | AT91C_EMAC_RW_R
++		| ((phy_addr & 0x1f) << 23) | (address << 18);
++
++	/* Wait until IDLE bit in Network Status register is cleared */
++	// TODO: Enforce some maximum loop-count?
++	while (!(regs->EMAC_SR & AT91C_EMAC_IDLE)) { barrier(); }
++
++	*value = (regs->EMAC_MAN & 0x0000ffff);
++}
++
++/* ........................... PHY MANAGEMENT .......................... */
++
++/*
++ * Access the PHY to determine the current Link speed and Mode, and update the
++ * MAC accordingly.
++ * If no link or auto-negotiation is busy, then no changes are made.
++ * Returns:  0 : OK
++ *          -1 : No link
++ *          -2 : AutoNegotiation still in progress
++ */
++static int update_linkspeed(struct net_device *dev, AT91PS_EMAC regs) {
++	unsigned int bmsr, bmcr, lpa, mac_cfg;
++	unsigned int speed, duplex;
++
++	/* Link status is latched, so read twice to get current value */
++	read_phy(regs, 0, MII_BMSR, &bmsr);
++	read_phy(regs, 0, MII_BMSR, &bmsr);
++	if (!(bmsr & BMSR_LSTATUS)) return -1;			/* no link */
++
++	read_phy(regs, 0, MII_BMCR, &bmcr);
++	if (bmcr & BMCR_ANENABLE) {				/* AutoNegotiation is enabled */
++		if (!(bmsr & BMSR_ANEGCOMPLETE)) return -2;	/* auto-negotitation in progress */
++
++		read_phy(regs, 0, MII_LPA, &lpa);
++		if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100;
++		else speed = SPEED_10;
++		if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL;
++		else duplex = DUPLEX_HALF;
++	} else {
++		speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
++		duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
++	}
++
++	/* Update the MAC */
++	mac_cfg = regs->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
++	if (speed == SPEED_100) {
++		if (duplex == DUPLEX_FULL)		/* 100 Full Duplex */
++			regs->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;
++		else					/* 100 Half Duplex */
++			regs->EMAC_CFG = mac_cfg | AT91C_EMAC_SPD;
++	} else {
++		if (duplex == DUPLEX_FULL)		/* 10 Full Duplex */
++			regs->EMAC_CFG = mac_cfg | AT91C_EMAC_FD;
++		else					/* 10 Half Duplex */
++			regs->EMAC_CFG = mac_cfg;
++	}
++
++	printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
++	return 0;
++}
++
++/*
++ * Handle interrupts from the PHY
++ */
++static void at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct net_device *dev = (struct net_device *) dev_id;
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	AT91PS_EMAC emac = (AT91PS_EMAC) dev->base_addr;
++	int status;
++	unsigned int phy;
++
++	enable_mdi(emac);
++	if (lp->phy_type == MII_DM9161_ID)
++		read_phy(emac, 0, MII_DSINTR_REG, &phy);	/* ack interrupt in Davicom PHY */
++	else if (lp->phy_type == MII_LXT971A_ID)
++		read_phy(emac, 0, MII_ISINTS_REG, &phy);	/* ack interrupt in Intel PHY */
++		
++	status = AT91_SYS->PIOC_ISR;		/* acknowledge interrupt in PIO */
++
++	status = update_linkspeed(dev, emac);
++	if (status == -1) {			/* link is down */
++		netif_carrier_off(dev);
++		printk(KERN_INFO "%s: Link down.\n", dev->name);
++	} else if (status == -2) {		/* auto-negotiation in progress */
++		/* Do nothing - another interrupt generated when negotiation complete */
++	} else {				/* link is operational */
++		netif_carrier_on(dev);
++	}
++	disable_mdi(emac);
++}
++
++/*
++ * Initialize and enable the PHY interrupt when link-state changes
++ */
++static void enable_phyirq(struct net_device *dev, AT91PS_EMAC regs)
++{
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	unsigned int dsintr, status;
++
++	// TODO: Check error code.  Really need a generic PIO (interrupt)
++	// layer since we're really only interested in the PC4 (DK) or PC2 (CSB337) line.
++	(void) request_irq(AT91C_ID_PIOC, at91ether_phy_interrupt, 0, dev->name, dev);
++
++	status = AT91_SYS->PIOC_ISR;		/* clear any pending PIO interrupts */
++#ifdef CONFIG_MACH_CSB337
++	AT91_SYS->PIOC_IER = AT91C_PIO_PC2;	/* Enable interrupt */
++#else
++	AT91_SYS->PIOC_IER = AT91C_PIO_PC4;	/* Enable interrupt */
++#endif
++
++	spin_lock_irq(&lp->lock);
++	enable_mdi(regs);
++		
++	if (lp->phy_type == MII_DM9161_ID) {		/* for Davicom PHY */
++		read_phy(regs, 0, MII_DSINTR_REG, &dsintr);
++		dsintr = dsintr & ~0xf00;		/* clear bits 8..11 */
++		write_phy(regs, 0, MII_DSINTR_REG, dsintr);
++	}
++	else if (lp->phy_type == MII_LXT971A_ID) {	/* for Intel PHY */
++		read_phy(regs, 0, MII_ISINTE_REG, &dsintr);
++		dsintr = dsintr | 0xf2;			/* set bits 1, 4..7 */
++		write_phy(regs, 0, MII_ISINTE_REG, dsintr);
++	}
++		
++	disable_mdi(regs);
++	spin_unlock_irq(&lp->lock);
++}
++
++/*
++ * Disable the PHY interrupt
++ */
++static void disable_phyirq(struct net_device *dev, AT91PS_EMAC regs)
++{
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	unsigned int dsintr;
++
++	spin_lock_irq(&lp->lock);
++	enable_mdi(regs);
++
++	if (lp->phy_type == MII_DM9161_ID) {		/* for Davicom PHY */
++		read_phy(regs, 0, MII_DSINTR_REG, &dsintr);
++		dsintr = dsintr | 0xf00;			/* set bits 8..11 */
++		write_phy(regs, 0, MII_DSINTR_REG, dsintr);
++	}
++	else if (lp->phy_type == MII_LXT971A_ID) {	/* for Intel PHY */
++		read_phy(regs, 0, MII_ISINTE_REG, &dsintr);
++		dsintr = dsintr & ~0xf2;			/* clear bits 1, 4..7 */
++		write_phy(regs, 0, MII_ISINTE_REG, dsintr);
++	}
++
++	disable_mdi(regs);
++	spin_unlock_irq(&lp->lock);
++
++#ifdef CONFIG_MACH_CSB337
++	AT91_SYS->PIOC_IDR = AT91C_PIO_PC2;		/* Disable interrupt */
++#else
++	AT91_SYS->PIOC_IDR = AT91C_PIO_PC4;		/* Disable interrupt */
++#endif
++	free_irq(AT91C_ID_PIOC, dev);			/* Free interrupt handler */
++}
++
++/*
++ * Perform a software reset of the PHY.
++ */
++static void reset_phy(struct net_device *dev, AT91PS_EMAC regs)
++{
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	unsigned int bmcr;
++
++	spin_lock_irq(&lp->lock);
++	enable_mdi(regs);
++
++	/* Perform PHY reset */
++	write_phy(regs, 0, MII_BMCR, BMCR_RESET);
++
++	/* Wait until PHY reset is complete */
++	do {
++		read_phy(regs, 0, MII_BMCR, &bmcr);
++	} while (!(bmcr && BMCR_RESET));
++
++	disable_mdi(regs);
++	spin_unlock_irq(&lp->lock);
++}
++
++
++/* ......................... ADDRESS MANAGEMENT ........................ */
++
++/*
++ * Set the ethernet MAC address in dev->dev_addr
++ */
++static void get_mac_address(struct net_device *dev) {
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++	char addr[6];
++	unsigned int hi, lo;
++
++	/* Check if bootloader set address in Specific-Address 1 */
++	hi = regs->EMAC_SA1H;
++	lo = regs->EMAC_SA1L;
++	addr[0] = (lo & 0xff);
++	addr[1] = (lo & 0xff00) >> 8;
++	addr[2] = (lo & 0xff0000) >> 16;
++	addr[3] = (lo & 0xff000000) >> 24;
++	addr[4] = (hi & 0xff);
++	addr[5] = (hi & 0xff00) >> 8;
++
++	if (is_valid_ether_addr(addr)) {
++		memcpy(dev->dev_addr, &addr, 6);
++		return;
++	}
++
++	/* Check if bootloader set address in Specific-Address 2 */
++	hi = regs->EMAC_SA2H;
++	lo = regs->EMAC_SA2L;
++	addr[0] = (lo & 0xff);
++	addr[1] = (lo & 0xff00) >> 8;
++	addr[2] = (lo & 0xff0000) >> 16;
++	addr[3] = (lo & 0xff000000) >> 24;
++	addr[4] = (hi & 0xff);
++	addr[5] = (hi & 0xff00) >> 8;
++
++	if (is_valid_ether_addr(addr)) {
++		memcpy(dev->dev_addr, &addr, 6);
++		return;
++	}
++}
++
++/*
++ * Program the hardware MAC address from dev->dev_addr.
++ */
++static void update_mac_address(struct net_device *dev)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++
++	regs->EMAC_SA1L = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]);
++	regs->EMAC_SA1H = (dev->dev_addr[5] << 8) | (dev->dev_addr[4]);
++}
++
++#ifdef AT91_ETHER_ADDR_CONFIGURABLE
++/*
++ * Store the new hardware address in dev->dev_addr, and update the MAC.
++ */
++static int set_mac_address(struct net_device *dev, void* addr)
++{
++	struct sockaddr *address = addr;
++
++	if (!is_valid_ether_addr(address->sa_data))
++		return -EADDRNOTAVAIL;
++
++	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
++	update_mac_address(dev);
++
++	printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
++		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
++		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
++
++	return 0;
++}
++#endif
++
++/*
++ * Add multicast addresses to the internal multicast-hash table.
++ */
++static void at91ether_sethashtable(struct net_device *dev, AT91PS_EMAC regs)
++{
++	struct dev_mc_list *curr;
++	unsigned char mc_filter[2];
++	unsigned int i, bitnr;
++
++	mc_filter[0] = mc_filter[1] = 0;
++
++	curr = dev->mc_list;
++	for (i = 0; i < dev->mc_count; i++, curr = curr->next) {
++		if (!curr) break;	/* unexpected end of list */
++
++		bitnr = ether_crc(ETH_ALEN, curr->dmi_addr) >> 26;
++		mc_filter[bitnr >> 5] |= 1 << (bitnr & 31);
++	}
++
++	regs->EMAC_HSH = mc_filter[1];
++	regs->EMAC_HSL = mc_filter[0];
++}
++
++/*
++ * Enable/Disable promiscuous and multicast modes.
++ */
++static void at91ether_set_rx_mode(struct net_device *dev)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++
++	if (dev->flags & IFF_PROMISC) {			/* Enable promiscuous mode */
++		regs->EMAC_CFG |= AT91C_EMAC_CAF;
++	} else if (dev->flags & (~IFF_PROMISC)) {	/* Disable promiscuous mode */
++		regs->EMAC_CFG &= ~AT91C_EMAC_CAF;
++	}
++
++	if (dev->flags & IFF_ALLMULTI) {		/* Enable all multicast mode */
++		regs->EMAC_HSH = -1;
++		regs->EMAC_HSL = -1;
++		regs->EMAC_CFG |= AT91C_EMAC_MTI;
++	} else if (dev->mc_count > 0) {			/* Enable specific multicasts */
++		at91ether_sethashtable(dev, regs);
++		regs->EMAC_CFG |= AT91C_EMAC_MTI;
++	} else if (dev->flags & (~IFF_ALLMULTI)) {	/* Disable all multicast mode */
++		regs->EMAC_HSH = 0;
++		regs->EMAC_HSL = 0;
++		regs->EMAC_CFG &= ~AT91C_EMAC_MTI;
++	}
++}
++
++/* ............................... IOCTL ............................... */
++
++static int mdio_read(struct net_device *dev, int phy_id, int location)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++	unsigned int value;
++
++	read_phy(regs, phy_id, location, &value);
++	return value;
++}
++
++static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++
++	write_phy(regs, phy_id, location, value);
++}
++
++/*
++ * ethtool support.
++ */
++static int at91ether_ethtool_ioctl (struct net_device *dev, void *useraddr)
++{
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++	u32 ethcmd;
++	int res = 0;
++
++	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
++		return -EFAULT;
++
++	spin_lock_irq(&lp->lock);
++	enable_mdi(regs);
++
++	switch (ethcmd) {
++	case ETHTOOL_GSET: {
++		struct ethtool_cmd ecmd = { ETHTOOL_GSET };
++		res = mii_ethtool_gset(&lp->mii, &ecmd);
++		if (lp->phy_media == PORT_FIBRE) {		/* override media type since mii.c doesn't know */
++			ecmd.supported = SUPPORTED_FIBRE;
++			ecmd.port = PORT_FIBRE;
++		}
++		if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
++			res = -EFAULT;
++		break;
++	}
++	case ETHTOOL_SSET: {
++		struct ethtool_cmd ecmd;
++		if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
++			res = -EFAULT;
++		else
++			res = mii_ethtool_sset(&lp->mii, &ecmd);
++		break;
++	}
++	case ETHTOOL_NWAY_RST: {
++		res = mii_nway_restart(&lp->mii);
++		break;
++	}
++	case ETHTOOL_GLINK: {
++		struct ethtool_value edata = { ETHTOOL_GLINK };
++		edata.data = mii_link_ok(&lp->mii);
++		if (copy_to_user(useraddr, &edata, sizeof(edata)))
++			res = -EFAULT;
++		break;
++	}
++	default:
++		res = -EOPNOTSUPP;
++	}
++
++	disable_mdi(regs);
++	spin_unlock_irq(&lp->lock);
++
++	return res;
++}
++
++/*
++ * User-space ioctl interface.
++ */
++static int at91ether_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++	switch(cmd) {
++	case SIOCETHTOOL:
++		return at91ether_ethtool_ioctl(dev, (void *) rq->ifr_data);
++	default:
++		return -EOPNOTSUPP;
++	}
++}
++
++/* ................................ MAC ................................ */
++
++/*
++ * Initialize and start the Receiver and Transmit subsystems
++ */
++static void at91ether_start(struct net_device *dev)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	int i;
++	struct recv_desc_bufs *dlist, *dlist_phys;
++
++	dlist = lp->dlist;
++	dlist_phys = lp->dlist_phys;
++
++	for (i = 0; i < MAX_RX_DESCR; i++) {
++		dlist->descriptors[i].addr = (unsigned int) &dlist_phys->recv_buf[i][0];
++		dlist->descriptors[i].size = 0;
++	}
++
++	/* Set the Wrap bit on the last descriptor */
++	dlist->descriptors[i-1].addr |= EMAC_DESC_WRAP;
++
++	/* Reset buffer index */
++	lp->rxBuffIndex = 0;
++
++	/* Program address of descriptor list in Rx Buffer Queue register */
++	regs->EMAC_RBQP = (AT91_REG) dlist_phys;
++
++	/* Enable Receive and Transmit */
++	regs->EMAC_CTL |= (AT91C_EMAC_RE | AT91C_EMAC_TE);
++}
++
++/*
++ * Open the ethernet interface
++ */
++static int at91ether_open(struct net_device *dev)
++{
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++
++        if (!is_valid_ether_addr(dev->dev_addr))
++        	return -EADDRNOTAVAIL;
++
++	AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC;	/* Re-enable Peripheral clock */
++	regs->EMAC_CTL |= AT91C_EMAC_CSR;		/* Clear internal statistics */
++
++	/* Enable PHY interrupt */
++	enable_phyirq(dev, regs);
++
++	/* Enable MAC interrupts */
++	regs->EMAC_IER = AT91C_EMAC_RCOM | AT91C_EMAC_RBNA
++			| AT91C_EMAC_TUND | AT91C_EMAC_RTRY | AT91C_EMAC_TCOM
++			| AT91C_EMAC_ROVR | AT91C_EMAC_HRESP;
++
++	/* Determine current link speed */
++	spin_lock_irq(&lp->lock);
++	enable_mdi(regs);
++	(void) update_linkspeed(dev, regs);
++	disable_mdi(regs);
++	spin_unlock_irq(&lp->lock);
++
++	at91ether_start(dev);
++	netif_start_queue(dev);
++	return 0;
++}
++
++/*
++ * Close the interface
++ */
++static int at91ether_close(struct net_device *dev)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++
++	/* Disable Receiver and Transmitter */
++	regs->EMAC_CTL &= ~(AT91C_EMAC_TE | AT91C_EMAC_RE);
++
++	/* Disable PHY interrupt */
++	disable_phyirq(dev, regs);
++
++	/* Disable MAC interrupts */
++	regs->EMAC_IDR = AT91C_EMAC_RCOM | AT91C_EMAC_RBNA
++			| AT91C_EMAC_TUND | AT91C_EMAC_RTRY | AT91C_EMAC_TCOM
++			| AT91C_EMAC_ROVR | AT91C_EMAC_HRESP;
++
++	netif_stop_queue(dev);
++
++	AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC;	/* Disable Peripheral clock */
++
++	return 0;
++}
++
++/*
++ * Transmit packet.
++ */
++static int at91ether_tx(struct sk_buff *skb, struct net_device *dev)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++
++	if (regs->EMAC_TSR & AT91C_EMAC_BNQ) {
++		netif_stop_queue(dev);
++
++		/* Store packet information (to free when Tx completed) */
++		lp->skb = skb;
++		lp->skb_length = skb->len;
++		lp->skb_physaddr = pci_map_single(NULL, skb->data, skb->len, PCI_DMA_TODEVICE);
++		lp->stats.tx_bytes += skb->len;
++
++		/* Set address of the data in the Transmit Address register */
++		regs->EMAC_TAR = lp->skb_physaddr;
++		/* Set length of the packet in the Transmit Control register */
++		regs->EMAC_TCR = skb->len;
++
++		dev->trans_start = jiffies;
++	} else {
++		printk(KERN_ERR "at91_ether.c: at91ether_tx() called, but device is busy!\n");
++		return 1;	/* if we return anything but zero, dev.c:1055 calls kfree_skb(skb)
++				on this skb, he also reports -ENETDOWN and printk's, so either
++				we free and return(0) or don't free and return 1 */
++	}
++
++	return 0;
++}
++
++/*
++ * Update the current statistics from the internal statistics registers.
++ */
++static struct net_device_stats *at91ether_stats(struct net_device *dev)
++{
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	AT91PS_EMAC regs = (AT91PS_EMAC) dev->base_addr;
++	int ale, lenerr, seqe, lcol, ecol;
++
++	if (netif_running(dev)) {
++		lp->stats.rx_packets += regs->EMAC_OK;			/* Good frames received */
++		ale = regs->EMAC_ALE;
++		lp->stats.rx_frame_errors += ale;			/* Alignment errors */
++		lenerr = regs->EMAC_ELR + regs->EMAC_USF;
++		lp->stats.rx_length_errors += lenerr;			/* Excessive Length or Undersize Frame error */
++		seqe = regs->EMAC_SEQE;
++		lp->stats.rx_crc_errors += seqe;			/* CRC error */
++		lp->stats.rx_fifo_errors += regs->EMAC_DRFC;		/* Receive buffer not available */
++		lp->stats.rx_errors += (ale + lenerr + seqe + regs->EMAC_CDE + regs->EMAC_RJB);
++
++		lp->stats.tx_packets += regs->EMAC_FRA;			/* Frames successfully transmitted */
++		lp->stats.tx_fifo_errors += regs->EMAC_TUE;		/* Transmit FIFO underruns */
++		lp->stats.tx_carrier_errors += regs->EMAC_CSE;		/* Carrier Sense errors */
++		lp->stats.tx_heartbeat_errors += regs->EMAC_SQEE;	/* Heartbeat error */
++
++		lcol = regs->EMAC_LCOL;
++		ecol = regs->EMAC_ECOL;
++		lp->stats.tx_window_errors += lcol;			/* Late collisions */
++		lp->stats.tx_aborted_errors += ecol;			/* 16 collisions */
++
++		lp->stats.collisions += (regs->EMAC_SCOL + regs->EMAC_MCOL + lcol + ecol);
++	}
++	return &lp->stats;
++}
++
++/*
++ * Extract received frame from buffer descriptors and sent to upper layers.
++ * (Called from interrupt context)
++ */
++static void at91ether_rx(struct net_device *dev)
++{
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	struct recv_desc_bufs *dlist;
++	unsigned char *p_recv;
++	struct sk_buff *skb;
++	unsigned int pktlen;
++
++	dlist = lp->dlist;
++	while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) {
++		p_recv = dlist->recv_buf[lp->rxBuffIndex];
++		pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff;	/* Length of frame including FCS */
++		skb = alloc_skb(pktlen + 2, GFP_ATOMIC);
++		if (skb != NULL) {
++			skb_reserve(skb, 2);
++			memcpy(skb_put(skb, pktlen), p_recv, pktlen);
++
++			skb->dev = dev;
++			skb->protocol = eth_type_trans(skb, dev);
++			skb->len = pktlen;
++			dev->last_rx = jiffies;
++			lp->stats.rx_bytes += pktlen;
++			netif_rx(skb);
++		}
++		else {
++			lp->stats.rx_dropped += 1;
++			printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
++		}
++
++		if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST)
++			lp->stats.multicast++;
++
++		dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE;	/* reset ownership bit */
++		if (lp->rxBuffIndex == MAX_RX_DESCR-1)				/* wrap after last buffer */
++			lp->rxBuffIndex = 0;
++		else
++			lp->rxBuffIndex++;
++	}
++}
++
++/*
++ * MAC interrupt handler
++ */
++static void at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct net_device *dev = (struct net_device *) dev_id;
++	struct at91_private *lp = (struct at91_private *) dev->priv;
++	AT91PS_EMAC emac = (AT91PS_EMAC) dev->base_addr;
++	unsigned long intstatus;
++
++	/* MAC Interrupt Status register indicates what interrupts are pending.
++	   It is automatically cleared once read. */
++	intstatus = emac->EMAC_ISR;
++
++	if (intstatus & AT91C_EMAC_RCOM)		/* Receive complete */
++		at91ether_rx(dev);
++
++	if (intstatus & AT91C_EMAC_TCOM) {		/* Transmit complete */
++		/* The TCOM bit is set even if the transmission failed. */
++		if (intstatus & (AT91C_EMAC_TUND | AT91C_EMAC_RTRY))
++			lp->stats.tx_errors += 1;
++
++		dev_kfree_skb_irq(lp->skb);
++		pci_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, PCI_DMA_TODEVICE);
++		netif_wake_queue(dev);
++	}
++
++	if (intstatus & AT91C_EMAC_RBNA)
++		printk("%s: RBNA error\n", dev->name);
++	if (intstatus & AT91C_EMAC_ROVR)
++		printk("%s: ROVR error\n", dev->name);
++}
++
++/*
++ * Initialize the ethernet interface
++ */
++static int at91ether_setup(struct net_device *dev, unsigned long phy_type)
++{
++	struct at91_private *lp;
++	AT91PS_EMAC regs;
++	static int already_initialized = 0;
++	unsigned int val;
++
++	if (already_initialized)
++		return 0;
++
++	dev = init_etherdev(dev, sizeof(struct at91_private));
++	dev->base_addr = AT91C_VA_BASE_EMAC;
++	dev->irq = AT91C_ID_EMAC;
++	SET_MODULE_OWNER(dev);
++
++	/* Install the interrupt handler */
++	if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev))
++		return -EBUSY;
++
++	/* Allocate memory for private data structure */
++	lp = (struct at91_private *) kmalloc(sizeof(struct at91_private), GFP_KERNEL);
++	if (lp == NULL) {
++		free_irq(dev->irq, dev);
++		return -ENOMEM;
++	}
++	memset(lp, 0, sizeof(struct at91_private));
++	dev->priv = lp;
++
++	/* Allocate memory for DMA Receive descriptors */
++	lp->dlist = (struct recv_desc_bufs *) consistent_alloc(GFP_DMA | GFP_KERNEL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys);
++	if (lp->dlist == NULL) {
++		kfree(dev->priv);
++		free_irq(dev->irq, dev);
++		return -ENOMEM;
++	}
++
++	spin_lock_init(&lp->lock);
++
++	ether_setup(dev);
++	dev->open = at91ether_open;
++	dev->stop = at91ether_close;
++	dev->hard_start_xmit = at91ether_tx;
++	dev->get_stats = at91ether_stats;
++	dev->set_multicast_list = at91ether_set_rx_mode;
++	dev->do_ioctl = at91ether_ioctl;
++
++#ifdef AT91_ETHER_ADDR_CONFIGURABLE
++	dev->set_mac_address = set_mac_address;
++#endif
++
++	get_mac_address(dev);		/* Get ethernet address and store it in dev->dev_addr */
++	update_mac_address(dev);	/* Program ethernet address into MAC */
++
++	regs = (AT91PS_EMAC) dev->base_addr;
++	regs->EMAC_CTL = 0;
++
++#ifdef CONFIG_AT91_ETHER_RMII
++	regs->EMAC_CFG = AT91C_EMAC_BIG | AT91C_EMAC_RMII;
++#else
++	regs->EMAC_CFG = AT91C_EMAC_BIG;
++#endif
++	if (phy_type == MII_LXT971A_ID)
++		regs->EMAC_CFG |= AT91C_EMAC_CLK_HCLK_64;	/* MDIO clock = system clock/64 */
++
++	if (phy_type == MII_DM9161_ID) {
++		spin_lock_irq(&lp->lock);
++		enable_mdi(regs);
++
++		read_phy(regs, 0, MII_DSCR_REG, &val);
++		if ((val & (1 << 10)) == 0)			/* DSCR bit 10 is 0 -- fiber mode */
++			lp->phy_media = PORT_FIBRE;
++
++		disable_mdi(regs);
++		spin_unlock_irq(&lp->lock);
++	}
++
++	lp->mii.dev = dev;		/* Support for ethtool */
++	lp->mii.mdio_read = mdio_read;
++	lp->mii.mdio_write = mdio_write;
++	
++	lp->phy_type = phy_type;	/* Type of PHY connected */
++
++	/* Determine current link speed */
++	spin_lock_irq(&lp->lock);
++	enable_mdi(regs);
++	(void) update_linkspeed(dev, regs);
++	disable_mdi(regs);
++	spin_unlock_irq(&lp->lock);
++
++	/* Display ethernet banner */
++	printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n",
++		dev->name, (uint) dev->base_addr, dev->irq,
++		regs->EMAC_CFG & AT91C_EMAC_SPD ? "100-" : "10-",
++		regs->EMAC_CFG & AT91C_EMAC_FD ? "FullDuplex" : "HalfDuplex",
++		dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
++		dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
++	if (phy_type == MII_DM9161_ID)
++		printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)");
++	else if (phy_type == MII_LXT971A_ID)
++		printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name);
++
++	already_initialized = 1;
++	return 0;
++}
++
++/*
++ * Detect MAC and PHY and perform initialization
++ */
++static int at91ether_probe(struct net_device *dev)
++{
++	AT91PS_EMAC regs = (AT91PS_EMAC) AT91C_VA_BASE_EMAC;
++	unsigned int phyid1, phyid2;
++	int detected = -1;
++
++	/* Configure the hardware - RMII vs MII mode */
++#ifdef CONFIG_AT91_ETHER_RMII
++	AT91_CfgPIO_EMAC_RMII();
++#else
++	AT91_CfgPIO_EMAC_MII();
++#endif
++
++	AT91_CfgPIO_EMAC_PHY();				/* Configure PHY interrupt */
++	AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC;	/* Enable Peripheral clock */
++
++	/* Read the PHY ID registers */
++	enable_mdi(regs);
++	read_phy(regs, 0, MII_PHYSID1, &phyid1);
++	read_phy(regs, 0, MII_PHYSID2, &phyid2);
++	disable_mdi(regs);
++
++	/* Davicom 9161: PHY_ID1 = 0x181  PHY_ID2 = B881 */
++	if (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_DM9161_ID) {
++		detected = at91ether_setup(dev, MII_DM9161_ID);
++	}
++	/* Intel LXT971A: PHY_ID1 = 0x13  PHY_ID2 = 78E0 */
++	else if (((phyid1 << 16) | (phyid2 & 0xfff0)) == MII_LXT971A_ID) {
++		detected = at91ether_setup(dev, MII_LXT971A_ID);
++	}
++
++	AT91_SYS->PMC_PCDR = 1 << AT91C_ID_EMAC;	/* Disable Peripheral clock */
++
++	return detected;
++}
++
++static int __init at91ether_init(void)
++{
++	if (!at91ether_probe(&at91_dev))
++		return register_netdev(&at91_dev);
++
++	return -1;
++}
++
++static void __exit at91ether_exit(void)
++{
++	unregister_netdev(&at91_dev);
++}
++
++module_init(at91ether_init)
++module_exit(at91ether_exit)
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver");
++MODULE_AUTHOR("Andrew Victor");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/net/at91_ether.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,81 @@
++/*
++ * Ethernet driver for the Atmel AT91RM9200 (Thunder)
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc.
++ * Initial version by Rick Bronson.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#ifndef AT91_ETHERNET
++#define AT91_ETHERNET
++
++#undef AT91_ETHER_ADDR_CONFIGURABLE	/* MAC address can be changed? */
++
++
++/* Davicom 9161 PHY */
++#define MII_DM9161_ID   0x0181b880
++
++/* Davicom specific registers */
++#define MII_DSCR_REG	16
++#define MII_DSCSR_REG   17
++#define MII_DSINTR_REG  21
++
++/* Intel LXT971A PHY */
++#define MII_LXT971A_ID	0x001378E0
++
++/* Intel specific registers */
++#define MII_ISINTE_REG	18
++#define MII_ISINTS_REG	19
++
++/* ........................................................................ */
++
++#define MAX_RBUFF_SZ	0x600		/* 1518 rounded up */
++#define MAX_RX_DESCR	9		/* max number of receive buffers */
++
++#define EMAC_DESC_DONE	0x00000001	/* bit for if DMA is done */
++#define EMAC_DESC_WRAP	0x00000002	/* bit for wrap */
++
++#define EMAC_BROADCAST	0x80000000	/* broadcast address */
++#define EMAC_MULTICAST	0x40000000	/* multicast address */
++#define EMAC_UNICAST	0x20000000	/* unicast address */
++
++struct rbf_t
++{
++	unsigned int addr;
++	unsigned long size;
++};
++
++struct recv_desc_bufs
++{
++	struct rbf_t descriptors[MAX_RX_DESCR];		/* must be on sizeof (rbf_t) boundary */
++	char recv_buf[MAX_RX_DESCR][MAX_RBUFF_SZ];	/* must be on long boundary */
++};
++
++struct at91_private
++{
++	struct net_device_stats stats;
++	struct mii_if_info mii;			/* ethtool support */
++
++	/* PHY */
++	unsigned long phy_type;			/* type of PHY (PHY_ID) */
++	spinlock_t lock;			/* lock for MDI interface */
++	short phy_media;			/* media interface type */
++
++	/* Transmit */
++	struct sk_buff *skb;			/* holds skb until xmit interrupt completes */
++	dma_addr_t skb_physaddr;		/* phys addr from pci_map_single */
++	int skb_length;				/* saved skb length for pci_unmap_single */
++
++	/* Receive */
++	int rxBuffIndex;			/* index into receive descriptor list */
++	struct recv_desc_bufs *dlist;		/* descriptor list address */
++	struct recv_desc_bufs *dlist_phys;	/* descriptor list physical address */
++};
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/rtc/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,15 @@
++# File: drivers/at91/rtc/Makefile
++#
++# Makefile for the Atmel AT91RM9200 real time clock device drivers
++#
++
++O_TARGET := at91rtc.o
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++obj-$(CONFIG_AT91_RTC) += at91_rtc.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/rtc/at91_rtc.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,441 @@
++/*
++ *	Real Time Clock interface for Linux on Atmel AT91RM9200
++ *
++ *	Copyright (c) 2002 Rick Bronson
++ *
++ *      Based on sa1100-rtc.c by Nils Faerber
++ *	Based on rtc.c by Paul Gortmaker
++ *	Date/time conversion routines taken from arch/arm/kernel/time.c
++ *			by Linus Torvalds and Russell King
++ *		and the GNU C Library
++ *	( ... I love the GPL ... just take what you need! ;)
++ *
++ *	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/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/string.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/proc_fs.h>
++#include <asm/bitops.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <linux/rtc.h>
++
++#define AT91_RTC_FREQ	1
++#define EPOCH		1970
++
++/* Those are the bits from a classic RTC we want to mimic */
++#define AT91_RTC_IRQF	0x80	/* any of the following 3 is active */
++#define AT91_RTC_PF	0x40
++#define AT91_RTC_AF	0x20
++#define AT91_RTC_UF	0x10
++
++#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
++#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
++
++static unsigned long rtc_status = 0;
++static unsigned long rtc_irq_data;
++static unsigned int at91_alarm_year = EPOCH;
++
++static struct fasync_struct *at91_rtc_async_queue;
++static DECLARE_WAIT_QUEUE_HEAD(at91_rtc_wait);
++static DECLARE_WAIT_QUEUE_HEAD(at91_rtc_update);
++static spinlock_t at91_rtc_updlock;	/* some spinlocks for saving/restoring interrupt levels */
++extern spinlock_t at91_rtc_lock;
++
++static const unsigned char days_in_mo[] =
++    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
++
++#define is_leap(year) \
++	((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
++
++static const unsigned short int __mon_yday[2][13] =
++{
++	/* Normal years.  */
++	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
++	/* Leap years.  */
++	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
++};
++
++/*
++ * Returns day since start of the year [0-365]
++ *  (from drivers/char/efirtc.c)
++ */
++static inline int compute_yday(int year, int month, int day)
++{
++	return  __mon_yday[is_leap(year)][month] + day-1;
++}
++
++/*
++ * Set current time and date in RTC
++ */
++static void at91_rtc_settime(struct rtc_time *tval)
++{
++	unsigned long flags;
++
++	/* Stop Time/Calendar from counting */
++	AT91_SYS->RTC_CR |= (AT91C_RTC_UPDCAL | AT91C_RTC_UPDTIM);
++
++	spin_lock_irqsave(&at91_rtc_updlock, flags);	/* stop int's else we wakeup b4 we sleep */
++	AT91_SYS->RTC_IER = AT91C_RTC_ACKUPD;
++	interruptible_sleep_on(&at91_rtc_update);	/* wait for ACKUPD interrupt to hit */
++	spin_unlock_irqrestore(&at91_rtc_updlock, flags);
++	AT91_SYS->RTC_IDR = AT91C_RTC_ACKUPD;
++
++	AT91_SYS->RTC_TIMR = BIN2BCD(tval->tm_sec) << 0
++			| BIN2BCD(tval->tm_min) << 8
++			| BIN2BCD(tval->tm_hour) << 16;
++
++	AT91_SYS->RTC_CALR = BIN2BCD((tval->tm_year + 1900) / 100)	/* century */
++	    		| BIN2BCD(tval->tm_year % 100) << 8	/* year */
++	    		| BIN2BCD(tval->tm_mon + 1) << 16	/* tm_mon starts at zero */
++	    		| BIN2BCD(tval->tm_wday + 1) << 21	/* day of the week [0-6], Sunday=0 */
++			| BIN2BCD(tval->tm_mday) << 24;
++
++	/* Restart Time/Calendar */
++	AT91_SYS->RTC_CR &= ~(AT91C_RTC_UPDCAL | AT91C_RTC_UPDTIM);
++}
++
++/*
++ * Decode time/date into rtc_time structure
++ */
++static void at91_rtc_decodetime(AT91_REG *timereg, AT91_REG *calreg, struct rtc_time *tval)
++{
++	unsigned int time, date;
++
++	do {			/* must read twice in case it changes */
++		time = *timereg;
++		date = *calreg;
++	} while ((time != *timereg) || (date != *calreg));
++
++	tval->tm_sec = BCD2BIN((time & AT91C_RTC_SEC) >> 0);
++	tval->tm_min = BCD2BIN((time & AT91C_RTC_MIN) >> 8);
++	tval->tm_hour = BCD2BIN((time & AT91C_RTC_HOUR) >> 16);
++
++	/* The Calendar Alarm register does not have a field for
++	   the year - so these will return an invalid value.  When an
++	   alarm is set, at91_alarm_year wille store the current year. */
++	tval->tm_year = BCD2BIN(date & AT91C_RTC_CENT) * 100;		/* century */
++	tval->tm_year += BCD2BIN((date & AT91C_RTC_YEAR) >> 8);		/* year */
++
++	tval->tm_wday = BCD2BIN((date & AT91C_RTC_DAY) >> 21) - 1;	/* day of the week [0-6], Sunday=0 */
++	tval->tm_mon = BCD2BIN(((date & AT91C_RTC_MONTH) >> 16) - 1);
++	tval->tm_mday = BCD2BIN((date & AT91C_RTC_DATE) >> 24);
++}
++
++/*
++ * IRQ handler for the RTC
++ */
++static void at91_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned int rtsr = AT91_SYS->RTC_SR & AT91_SYS->RTC_IMR;
++
++	/* update irq data & counter */
++	if (rtsr) {		/* this interrupt is shared!  Is it ours? */
++		if (rtsr & AT91C_RTC_ALARM)
++			rtc_irq_data |= (AT91_RTC_AF | AT91_RTC_IRQF);
++		if (rtsr & AT91C_RTC_SECEV)
++			rtc_irq_data |= (AT91_RTC_UF | AT91_RTC_IRQF);
++		if (rtsr & AT91C_RTC_ACKUPD)
++			wake_up_interruptible(&at91_rtc_update);
++		rtc_irq_data += 0x100;
++		AT91_SYS->RTC_SCCR = rtsr;		/* clear status reg */
++
++		/* wake up waiting process */
++		wake_up_interruptible(&at91_rtc_wait);
++		kill_fasync(&at91_rtc_async_queue, SIGIO, POLL_IN);
++	}
++}
++
++static int at91_rtc_open(struct inode *inode, struct file *file)
++{
++	if (test_and_set_bit(1, &rtc_status))
++		return -EBUSY;
++	rtc_irq_data = 0;
++	return 0;
++}
++
++static int at91_rtc_release(struct inode *inode, struct file *file)
++{
++	rtc_status = 0;
++	return 0;
++}
++
++static int at91_rtc_fasync(int fd, struct file *filp, int on)
++{
++	return fasync_helper(fd, filp, on, &at91_rtc_async_queue);
++}
++
++static unsigned int at91_rtc_poll(struct file *file, poll_table * wait)
++{
++	poll_wait(file, &at91_rtc_wait, wait);
++	return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM;
++}
++
++static ssize_t at91_rtc_read(struct file * file, char *buf, size_t count, loff_t * ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long data;
++	ssize_t retval;
++
++	if (count < sizeof(unsigned long))
++		return -EINVAL;
++
++	add_wait_queue(&at91_rtc_wait, &wait);
++	set_current_state(TASK_INTERRUPTIBLE);
++	for (;;) {
++		spin_lock_irq(&at91_rtc_lock);
++		data = rtc_irq_data;
++		if (data != 0) {
++			rtc_irq_data = 0;
++			break;
++		}
++		spin_unlock_irq(&at91_rtc_lock);
++
++		if (file->f_flags & O_NONBLOCK) {
++			retval = -EAGAIN;
++			goto out;
++		}
++
++		if (signal_pending(current)) {
++			retval = -ERESTARTSYS;
++			goto out;
++		}
++
++		schedule();
++	}
++	spin_unlock_irq(&at91_rtc_lock);
++
++	data -= 0x100;		/* the first IRQ wasn't actually missed */
++	retval = put_user(data, (unsigned long *) buf);
++	if (!retval)
++		retval = sizeof(unsigned long);
++
++out:
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&at91_rtc_wait, &wait);
++	return retval;
++}
++
++/*
++ * Handle commands from user-space
++ */
++static int at91_rtc_ioctl(struct inode *inode, struct file *file,
++			  unsigned int cmd, unsigned long arg)
++{
++	struct rtc_time tm, tm2;
++	int ret = 0;
++
++	spin_lock_irq(&at91_rtc_lock);
++	switch (cmd) {
++	case RTC_AIE_OFF:	/* alarm off */
++		AT91_SYS->RTC_IDR = AT91C_RTC_ALARM;
++		rtc_irq_data = 0;
++		break;
++	case RTC_AIE_ON:	/* alarm on */
++		AT91_SYS->RTC_IER = AT91C_RTC_ALARM;
++		rtc_irq_data = 0;
++		break;
++	case RTC_UIE_OFF:	/* update off */
++		AT91_SYS->RTC_IDR = AT91C_RTC_SECEV;
++		rtc_irq_data = 0;
++		break;
++	case RTC_UIE_ON:	/* update on */
++		AT91_SYS->RTC_IER = AT91C_RTC_SECEV;
++		rtc_irq_data = 0;
++		break;
++	case RTC_PIE_OFF:	/* periodic off */
++		AT91_SYS->RTC_IDR = AT91C_RTC_SECEV;
++		rtc_irq_data = 0;
++		break;
++	case RTC_PIE_ON:	/* periodic on */
++		AT91_SYS->RTC_IER = AT91C_RTC_SECEV;
++		rtc_irq_data = 0;
++		break;
++	case RTC_ALM_READ:	/* read alarm */
++		memset(&tm, 0, sizeof(struct rtc_time));
++		at91_rtc_decodetime(&(AT91_SYS->RTC_TIMALR), &(AT91_SYS->RTC_CALALR), &tm);
++		tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday);
++		tm.tm_year = at91_alarm_year - 1900;
++		ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0;
++		break;
++	case RTC_ALM_SET:	/* set alarm */
++		if (copy_from_user(&tm2, (struct rtc_time *) arg, sizeof(tm2)))
++			ret = -EFAULT;
++		else {
++			at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm);
++			at91_alarm_year = tm.tm_year;
++			if ((unsigned) tm2.tm_hour < 24)	/* do some range checking */
++				tm.tm_hour = tm2.tm_hour;
++			if ((unsigned) tm2.tm_min < 60)
++				tm.tm_min = tm2.tm_min;
++			if ((unsigned) tm2.tm_sec < 60)
++				tm.tm_sec = tm2.tm_sec;
++			AT91_SYS->RTC_TIMALR = BIN2BCD(tm.tm_sec) << 0
++				| BIN2BCD(tm.tm_min) << 8
++				| BIN2BCD(tm.tm_hour) << 16
++				| AT91C_RTC_HOUREN | AT91C_RTC_MINEN
++				| AT91C_RTC_SECEN;
++			AT91_SYS->RTC_CALALR = BIN2BCD(tm.tm_mon + 1) << 16	/* tm_mon starts at zero */
++				| BIN2BCD(tm.tm_mday) << 24
++				| AT91C_RTC_DATEEN | AT91C_RTC_MONTHEN;
++		}
++		break;
++	case RTC_RD_TIME:	/* read time */
++		memset(&tm, 0, sizeof(struct rtc_time));
++		at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm);
++		tm.tm_yday = compute_yday(tm.tm_year, tm.tm_mon, tm.tm_mday);
++		tm.tm_year = tm.tm_year - 1900;
++		ret = copy_to_user((void *) arg, &tm, sizeof(tm)) ? -EFAULT : 0;
++		break;
++	case RTC_SET_TIME:	/* set time */
++		if (!capable(CAP_SYS_TIME))
++			ret = -EACCES;
++		else {
++			if (copy_from_user(&tm, (struct rtc_time *) arg, sizeof(tm)))
++				ret = -EFAULT;
++			else {
++				int tm_year = tm.tm_year + 1900;
++				if (tm_year < EPOCH
++				    || (unsigned) tm.tm_mon >= 12
++				    || tm.tm_mday < 1
++				    || tm.tm_mday > (days_in_mo[tm.tm_mon] + (tm.tm_mon == 1 && is_leap(tm_year)))
++				    || (unsigned) tm.tm_hour >= 24
++				    || (unsigned) tm.tm_min >= 60
++				    || (unsigned) tm.tm_sec >= 60)
++					ret = -EINVAL;
++				else
++					at91_rtc_settime(&tm);
++			}
++		}
++		break;
++	case RTC_IRQP_READ:	/* read periodic alarm frequency */
++		ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
++		break;
++	case RTC_IRQP_SET:	/* set periodic alarm frequency */
++		if (arg != AT91_RTC_FREQ)
++			ret = -EINVAL;
++		break;
++	case RTC_EPOCH_READ:	/* read epoch */
++		ret = put_user(EPOCH, (unsigned long *) arg);
++		break;
++	default:
++		ret = -EINVAL;
++		break;
++	}
++	spin_unlock_irq(&at91_rtc_lock);
++	return ret;
++}
++
++/*
++ * Provide RTC information in /proc/driver/rtc
++ */
++static int at91_rtc_read_proc(char *page, char **start, off_t off,
++			      int count, int *eof, void *data)
++{
++	char *p = page;
++	int len;
++	struct rtc_time tm;
++
++	at91_rtc_decodetime(&(AT91_SYS->RTC_TIMR), &(AT91_SYS->RTC_CALR), &tm);
++	p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n"
++			"rtc_date\t: %04d-%02d-%02d\n"
++			"rtc_epoch\t: %04d\n",
++			tm.tm_hour, tm.tm_min, tm.tm_sec,
++			tm.tm_year, tm.tm_mon + 1, tm.tm_mday, EPOCH);
++	at91_rtc_decodetime(&(AT91_SYS->RTC_TIMALR), &(AT91_SYS->RTC_CALALR), &tm);
++	p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n"
++			"alrm_date\t: %04d-%02d-%02d\n",
++			tm.tm_hour, tm.tm_min, tm.tm_sec,
++			at91_alarm_year, tm.tm_mon + 1, tm.tm_mday);
++	p += sprintf(p, "alarm_IRQ\t: %s\n", (AT91_SYS->RTC_IMR & AT91C_RTC_ALARM) ? "yes" : "no");
++	p += sprintf(p, "update_IRQ\t: %s\n", (AT91_SYS->RTC_IMR & AT91C_RTC_ACKUPD) ? "yes" : "no");
++	p += sprintf(p, "periodic_IRQ\t: %s\n", (AT91_SYS->RTC_IMR & AT91C_RTC_SECEV) ? "yes" : "no");
++	p += sprintf(p, "periodic_freq\t: %ld\n", (unsigned long) AT91_RTC_FREQ);
++
++	len = (p - page) - off;
++	if (len < 0)
++		len = 0;
++
++	*eof = (len <= count) ? 1 : 0;
++	*start = page + off;
++
++	return len;
++}
++
++static struct file_operations at91_rtc_fops = {
++	owner:THIS_MODULE,
++	llseek:no_llseek,
++	read:at91_rtc_read,
++	poll:at91_rtc_poll,
++	ioctl:at91_rtc_ioctl,
++	open:at91_rtc_open,
++	release:at91_rtc_release,
++	fasync:at91_rtc_fasync,
++};
++
++static struct miscdevice at91_rtc_miscdev = {
++	minor:RTC_MINOR,
++	name:"rtc",
++	fops:&at91_rtc_fops,
++};
++
++/*
++ * Initialize and install RTC driver
++ */
++static int __init at91_rtc_init(void)
++{
++	int ret;
++
++	AT91_SYS->RTC_CR = 0;
++	AT91_SYS->RTC_MR = 0;	/* put in 24 hour format */
++	/* Disable all interrupts */
++	AT91_SYS->RTC_IDR = AT91C_RTC_ACKUPD | AT91C_RTC_ALARM | AT91C_RTC_SECEV | AT91C_RTC_TIMEV | AT91C_RTC_CALEV;
++
++	spin_lock_init(&at91_rtc_updlock);
++	spin_lock_init(&at91_rtc_lock);
++
++	misc_register(&at91_rtc_miscdev);
++	create_proc_read_entry("driver/rtc", 0, 0, at91_rtc_read_proc, NULL);
++	ret = request_irq(AT91C_ID_SYS, at91_rtc_interrupt, SA_SHIRQ,
++			"at91_rtc", &rtc_status);
++	if (ret) {
++		printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n", AT91C_ID_SYS);
++		remove_proc_entry("driver/rtc", NULL);
++		misc_deregister(&at91_rtc_miscdev);
++		return ret;
++	}
++
++	printk(KERN_INFO "AT91 Real Time Clock driver\n");
++	return 0;
++}
++
++/*
++ * Disable and remove the RTC driver
++ */
++static void __exit at91_rtc_exit(void)
++{
++	/* Disable all interrupts */
++	AT91_SYS->RTC_IDR = AT91C_RTC_ACKUPD | AT91C_RTC_ALARM | AT91C_RTC_SECEV | AT91C_RTC_TIMEV | AT91C_RTC_CALEV;
++	free_irq(AT91C_ID_SYS, &rtc_status);
++
++	rtc_status = 0;
++	remove_proc_entry("driver/rtc", NULL);
++	misc_deregister(&at91_rtc_miscdev);
++}
++
++module_init(at91_rtc_init);
++module_exit(at91_rtc_exit);
++
++MODULE_AUTHOR("Rick Bronson");
++MODULE_DESCRIPTION("AT91 Realtime Clock Driver (AT91_RTC)");
++MODULE_LICENSE("GPL");
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/serial/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,15 @@
++# File: drivers/at91/serial/Makefile
++#
++# Makefile for the Atmel AT91RM9200 serial and console device drivers
++#
++
++O_TARGET := at91serial.o
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/serial/at91_serial.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,870 @@
++/*
++ *  linux/drivers/char/at91_serial.c
++ *
++ *  Driver for Atmel AT91RM9200 Serial ports
++ *
++ *  Copyright (c) Rick Bronson
++ *
++ *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/ioport.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++
++#include <asm/arch/AT91RM9200_USART.h>
++#include <asm/mach/serial_at91rm9200.h>
++#include <asm/arch/pio.h>
++
++
++#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++
++#define SERIAL_AT91_MAJOR	TTY_MAJOR
++#define CALLOUT_AT91_MAJOR	TTYAUX_MAJOR
++#define MINOR_START		64
++
++#define AT91C_VA_BASE_DBGU	((unsigned long) &(AT91_SYS->DBGU_CR))
++#define AT91_ISR_PASS_LIMIT	256
++
++#define UART_PUT_CR(port,v)	((AT91PS_USART)(port)->membase)->US_CR = v
++#define UART_GET_MR(port)	((AT91PS_USART)(port)->membase)->US_MR
++#define UART_PUT_MR(port,v)	((AT91PS_USART)(port)->membase)->US_MR = v
++#define UART_PUT_IER(port,v)	((AT91PS_USART)(port)->membase)->US_IER = v
++#define UART_PUT_IDR(port,v)	((AT91PS_USART)(port)->membase)->US_IDR = v
++#define UART_GET_IMR(port)	((AT91PS_USART)(port)->membase)->US_IMR
++#define UART_GET_CSR(port)	((AT91PS_USART)(port)->membase)->US_CSR
++#define UART_GET_CHAR(port)	((AT91PS_USART)(port)->membase)->US_RHR
++#define UART_PUT_CHAR(port,v)	((AT91PS_USART)(port)->membase)->US_THR = v
++#define UART_GET_BRGR(port)	((AT91PS_USART)(port)->membase)->US_BRGR
++#define UART_PUT_BRGR(port,v)	((AT91PS_USART)(port)->membase)->US_BRGR = v
++#define UART_PUT_RTOR(port,v)	((AT91PS_USART)(port)->membase)->US_RTOR = v
++
++// #define UART_GET_CR(port)	((AT91PS_USART)(port)->membase)->US_CR		// is write-only
++
++ /* PDC registers */
++#define UART_PUT_PTCR(port,v)	((AT91PS_USART)(port)->membase)->US_PTCR = v
++#define UART_PUT_RPR(port,v)	((AT91PS_USART)(port)->membase)->US_RPR = v
++#define UART_PUT_RCR(port,v)	((AT91PS_USART)(port)->membase)->US_RCR = v
++#define UART_GET_RCR(port)	((AT91PS_USART)(port)->membase)->US_RCR
++#define UART_PUT_RNPR(port,v)	((AT91PS_USART)(port)->membase)->US_RNPR = v
++#define UART_PUT_RNCR(port,v)	((AT91PS_USART)(port)->membase)->US_RNCR = v
++
++static struct tty_driver normal, callout;
++static struct tty_struct *at91_table[AT91C_NR_UART];
++static struct termios *at91_termios[AT91C_NR_UART], *at91_termios_locked[AT91C_NR_UART];
++
++const int at91_serialmap[AT91C_NR_UART] = AT91C_UART_MAP;
++
++static int (*at91_open)(struct uart_port *);
++static void (*at91_close)(struct uart_port *);
++
++#ifdef SUPPORT_SYSRQ
++static struct console at91_console;
++#endif
++
++/*
++ * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
++ */
++static u_int at91_tx_empty(struct uart_port *port)
++{
++	return UART_GET_CSR(port) & AT91C_US_TXEMPTY ? TIOCSER_TEMT : 0;
++}
++
++/*
++ * Set state of the modem control output lines
++ */
++static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
++{
++	unsigned int control = 0;
++
++	if (mctrl & TIOCM_RTS)
++		control |= AT91C_US_RTSEN;
++	else
++		control |= AT91C_US_RTSDIS;
++
++	if (mctrl & TIOCM_DTR)
++		control |= AT91C_US_DTREN;
++	else
++		control |=  AT91C_US_DTRDIS;
++
++	UART_PUT_CR(port,control);
++}
++
++/*
++ * Get state of the modem control input lines
++ */
++static u_int at91_get_mctrl(struct uart_port *port)
++{
++	unsigned int status, ret = 0;
++
++	status = UART_GET_CSR(port);
++	if (status & AT91C_US_DCD)
++		ret |= TIOCM_CD;
++	if (status & AT91C_US_CTS)
++		ret |= TIOCM_CTS;
++	if (status & AT91C_US_DSR)
++		ret |= TIOCM_DSR;
++	if (status & AT91C_US_RI)
++		ret |= TIOCM_RI;
++
++	return ret;
++}
++
++/*
++ * Stop transmitting.
++ */
++static void at91_stop_tx(struct uart_port *port, u_int from_tty)
++{
++	UART_PUT_IDR(port, AT91C_US_TXRDY);
++	port->read_status_mask &= ~AT91C_US_TXRDY;
++}
++
++/*
++ * Start transmitting.
++ */
++static void at91_start_tx(struct uart_port *port, u_int from_tty)
++{
++	unsigned long flags;
++
++	local_irq_save(flags);
++	port->read_status_mask |= AT91C_US_TXRDY;
++	UART_PUT_IER(port, AT91C_US_TXRDY);
++	local_irq_restore(flags);
++}
++
++/*
++ * Stop receiving - port is in process of being closed.
++ */
++static void at91_stop_rx(struct uart_port *port)
++{
++	UART_PUT_IDR(port, AT91C_US_RXRDY);
++}
++
++/*
++ * Enable modem status interrupts
++ */
++static void at91_enable_ms(struct uart_port *port)
++{
++	UART_PUT_IER(port, AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | AT91C_US_CTSIC);
++}
++
++/*
++ * Control the transmission of a break signal
++ */
++static void at91_break_ctl(struct uart_port *port, int break_state)
++{
++	if (break_state != 0)
++		UART_PUT_CR(port, AT91C_US_STTBRK);	/* start break */
++	else
++		UART_PUT_CR(port, AT91C_US_STPBRK);	/* stop break */
++}
++
++/*
++ * Characters received (called from interrupt handler)
++ */
++static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs)
++{
++	struct uart_info *info = port->info;
++	struct tty_struct *tty = info->tty;
++	unsigned int status, ch, flg, ignored = 0;
++
++	status = UART_GET_CSR(port);
++	while (status & (AT91C_US_RXRDY)) {
++		ch = UART_GET_CHAR(port);
++
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++		port->icount.rx++;
++
++		flg = TTY_NORMAL;
++
++		/*
++		 * note that the error handling code is
++		 * out of the main execution path
++		 */
++		if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE))
++			goto handle_error;
++
++		if (uart_handle_sysrq_char(port, ch, regs))
++			goto ignore_char;
++
++	error_return:
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++	ignore_char:
++		status = UART_GET_CSR(port);
++	}
++out:
++	tty_flip_buffer_push(tty);
++	return;
++
++handle_error:
++	if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE))
++		UART_PUT_CR(port, AT91C_US_RSTSTA);  /* clear error */
++	if (status & (AT91C_US_PARE))
++		port->icount.parity++;
++	else if (status & (AT91C_US_FRAME))
++		port->icount.frame++;
++	if (status & (AT91C_US_OVRE))
++		port->icount.overrun++;
++
++	if (status & port->ignore_status_mask) {
++		if (++ignored > 100)
++			goto out;
++		goto ignore_char;
++	}
++
++	status &= port->read_status_mask;
++
++	UART_PUT_CR(port, AT91C_US_RSTSTA);  /* clear error */
++	if (status & AT91C_US_PARE)
++		flg = TTY_PARITY;
++	else if (status & AT91C_US_FRAME)
++		flg = TTY_FRAME;
++
++	if (status & AT91C_US_OVRE) {
++		/*
++		 * overrun does *not* affect the character
++		 * we read from the FIFO
++		 */
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++		ch = 0;
++		flg = TTY_OVERRUN;
++	}
++#ifdef SUPPORT_SYSRQ
++	port->sysrq = 0;
++#endif
++	goto error_return;
++}
++
++/*
++ * Transmit characters (called from interrupt handler)
++ */
++static void at91_tx_chars(struct uart_port *port)
++{
++	struct circ_buf *xmit = &port->info->xmit;
++
++	if (port->x_char) {
++		UART_PUT_CHAR(port, port->x_char);
++		port->icount.tx++;
++		port->x_char = 0;
++		return;
++	}
++	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
++		at91_stop_tx(port, 0);
++		return;
++	}
++
++	while (UART_GET_CSR(port) & AT91C_US_TXRDY) {
++		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
++		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++		port->icount.tx++;
++		if (uart_circ_empty(xmit))
++			break;
++	}
++
++	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++		uart_write_wakeup(port);
++
++	if (uart_circ_empty(xmit))
++		at91_stop_tx(port, 0);
++}
++
++/*
++ * Interrupt handler
++ */
++static void at91_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct uart_port *port = dev_id;
++	unsigned int status, pending, pass_counter = 0;
++
++	status = UART_GET_CSR(port);
++	pending = status & port->read_status_mask;
++	if (pending) {
++		do {
++			if (pending & AT91C_US_RXRDY)
++				at91_rx_chars(port, regs);
++
++			/* Clear the relevent break bits */
++			if (pending & AT91C_US_RXBRK) {
++				UART_PUT_CR(port, AT91C_US_RSTSTA);
++				port->icount.brk++;
++#ifdef SUPPORT_SYSRQ
++				if (port->line == at91_console.index && !port->sysrq) {
++					port->sysrq = jiffies + HZ*5;
++				}
++#endif
++			}
++
++			// TODO: All reads to CSR will clear these interrupts!
++			if (pending & AT91C_US_RIIC) port->icount.rng++;
++			if (pending & AT91C_US_DSRIC) port->icount.dsr++;
++			if (pending & AT91C_US_DCDIC) {
++				port->icount.dcd++;
++				uart_handle_dcd_change(port, status & AT91C_US_DCD);
++			}
++			if (pending & AT91C_US_CTSIC) {
++				port->icount.cts++;
++				uart_handle_cts_change(port, status & AT91C_US_CTS);
++			}
++			if (pending & (AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | AT91C_US_CTSIC))
++				wake_up_interruptible(&port->info->delta_msr_wait);
++
++			if (pending & AT91C_US_TXRDY)
++				at91_tx_chars(port);
++			if (pass_counter++ > AT91_ISR_PASS_LIMIT)
++				break;
++
++			status = UART_GET_CSR(port);
++			pending = status & port->read_status_mask;
++		} while (pending);
++	}
++}
++
++/*
++ * Perform initialization and enable port for reception
++ */
++static int at91_startup(struct uart_port *port)
++{
++	int retval;
++
++	/*
++	 * Allocate the IRQ
++	 */
++	retval = request_irq(port->irq, at91_interrupt, SA_SHIRQ, "at91_serial", port);
++	if (retval) {
++		printk("at91_serial: at91_startup - Can't get irq\n");
++		return retval;
++	}
++	/*
++	 * If there is a specific "open" function (to register
++	 * control line interrupts)
++	 */
++	if (at91_open) {
++		retval = at91_open(port);
++		if (retval) {
++			free_irq(port->irq, port);
++			return retval;
++		}
++	}
++
++	/* Enable peripheral clock if required */
++	if (port->irq != AT91C_ID_SYS)
++		AT91_SYS->PMC_PCER = 1 << port->irq;
++
++	port->read_status_mask = AT91C_US_RXRDY | AT91C_US_TXRDY | AT91C_US_OVRE
++			| AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_RXBRK;
++	/*
++	 * Finally, clear and enable interrupts
++	 */
++	UART_PUT_IDR(port, -1);
++	UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN);  /* enable xmit & rcvr */
++	UART_PUT_IER(port, AT91C_US_RXRDY);  /* do receive only */
++	return 0;
++}
++
++/*
++ * Disable the port
++ */
++static void at91_shutdown(struct uart_port *port)
++{
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(port->irq, port);
++
++	/*
++	 * If there is a specific "close" function (to unregister
++	 * control line interrupts)
++	 */
++	if (at91_close)
++		at91_close(port);
++
++	/*
++	 * Disable all interrupts, port and break condition.
++	 */
++	UART_PUT_CR(port, AT91C_US_RSTSTA);
++	UART_PUT_IDR(port, -1);
++
++	/* Disable peripheral clock if required */
++	if (port->irq != AT91C_ID_SYS)
++		AT91_SYS->PMC_PCDR = 1 << port->irq;
++}
++
++static struct uart_ops at91_pops;		/* forward declaration */
++
++/*
++ * Change the port parameters
++ */
++static void at91_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
++{
++	unsigned long flags;
++	unsigned int mode, imr;
++
++	/* Get current mode register */
++	mode = UART_GET_MR(port) & ~(AT91C_US_CHRL | AT91C_US_NBSTOP | AT91C_US_PAR);
++
++	/* byte size */
++	switch (cflag & CSIZE) {
++	case CS5:
++		mode |= AT91C_US_CHRL_5_BITS;
++		break;
++	case CS6:
++		mode |= AT91C_US_CHRL_6_BITS;
++		break;
++	case CS7:
++		mode |= AT91C_US_CHRL_7_BITS;
++		break;
++	default:
++		mode |= AT91C_US_CHRL_8_BITS;
++		break;
++	}
++
++	/* stop bits */
++	if (cflag & CSTOPB)
++		mode |= AT91C_US_NBSTOP_2_BIT;
++
++	/* parity */
++	if (cflag & PARENB) {
++		if (cflag & CMSPAR) {			/* Mark or Space parity */
++			if (cflag & PARODD)
++				mode |= AT91C_US_PAR_MARK;
++			else
++				mode |= AT91C_US_PAR_SPACE;
++		}
++		else if (cflag & PARODD)
++			mode |= AT91C_US_PAR_ODD;
++		else
++			mode |= AT91C_US_PAR_EVEN;
++	}
++	else
++		mode |= AT91C_US_PAR_NONE;
++
++	port->read_status_mask |= AT91C_US_OVRE;
++	if (iflag & INPCK)
++		port->read_status_mask |= AT91C_US_FRAME | AT91C_US_PARE;
++	if (iflag & (BRKINT | PARMRK))
++		port->read_status_mask |= AT91C_US_RXBRK;
++
++	/*
++	 * Characters to ignore
++	 */
++	port->ignore_status_mask = 0;
++	if (iflag & IGNPAR)
++		port->ignore_status_mask |= (AT91C_US_FRAME | AT91C_US_PARE);
++	if (iflag & IGNBRK) {
++		port->ignore_status_mask |= AT91C_US_RXBRK;
++		/*
++		 * If we're ignoring parity and break indicators,
++		 * ignore overruns too (for real raw support).
++		 */
++		if (iflag & IGNPAR)
++			port->ignore_status_mask |= AT91C_US_OVRE;
++	}
++
++	// TODO: Ignore all characters if CREAD is set.
++
++	/* first, disable interrupts and drain transmitter */
++	local_irq_save(flags);
++	imr = UART_GET_IMR(port);	/* get interrupt mask */
++	UART_PUT_IDR(port, -1);		/* disable all interrupts */
++	local_irq_restore(flags);
++	while (!(UART_GET_CSR(port) & AT91C_US_TXEMPTY)) { barrier(); }
++
++	/* disable receiver and transmitter */
++	UART_PUT_CR(port, AT91C_US_TXDIS | AT91C_US_RXDIS);
++
++	/* set the parity, stop bits and data size */
++	UART_PUT_MR(port, mode);
++
++	/* set the baud rate */
++	UART_PUT_BRGR(port, quot);
++	UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN);
++
++	/* restore interrupts */
++	UART_PUT_IER(port, imr);
++
++	/* CTS flow-control and modem-status interrupts */
++	if (UART_ENABLE_MS(uart, cflag))
++		at91_pops.enable_ms(uart);
++}
++
++/*
++ * Return string describing the specified port
++ */
++static const char *at91_type(struct uart_port *port)
++{
++	return port->type == PORT_AT91RM9200 ? "AT91_SERIAL" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'.
++ */
++static void at91_release_port(struct uart_port *port)
++{
++	release_mem_region(port->mapbase,
++		port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'.
++ */
++static int at91_request_port(struct uart_port *port)
++{
++	return request_mem_region(port->mapbase,
++		port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K,
++		"at91_serial") != NULL ? 0 : -EBUSY;
++
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void at91_config_port(struct uart_port *port, int flags)
++{
++	if (flags & UART_CONFIG_TYPE) {
++		port->type = PORT_AT91RM9200;
++		at91_request_port(port);
++	}
++}
++
++/*
++ * Verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int at91_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++	int ret = 0;
++	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91RM9200)
++		ret = -EINVAL;
++	if (port->irq != ser->irq)
++		ret = -EINVAL;
++	if (ser->io_type != SERIAL_IO_MEM)
++		ret = -EINVAL;
++	if (port->uartclk / 16 != ser->baud_base)
++		ret = -EINVAL;
++	if ((void *)port->mapbase != ser->iomem_base)
++		ret = -EINVAL;
++	if (port->iobase != ser->port)
++		ret = -EINVAL;
++	if (ser->hub6 != 0)
++		ret = -EINVAL;
++	return ret;
++}
++
++static struct uart_ops at91_pops = {
++	tx_empty:	at91_tx_empty,
++	set_mctrl:	at91_set_mctrl,
++	get_mctrl:	at91_get_mctrl,
++	stop_tx:	at91_stop_tx,
++	start_tx:	at91_start_tx,
++	stop_rx:	at91_stop_rx,
++	enable_ms:	at91_enable_ms,
++	break_ctl:	at91_break_ctl,
++	startup:	at91_startup,
++	shutdown:	at91_shutdown,
++	change_speed:	at91_change_speed,
++	type:		at91_type,
++	release_port:	at91_release_port,
++	request_port:	at91_request_port,
++	config_port:	at91_config_port,
++	verify_port:	at91_verify_port,
++};
++
++static struct uart_port at91_ports[AT91C_NR_UART];
++
++void __init at91_init_ports(void)
++{
++	static int first = 1;
++	int i;
++
++	if (!first)
++		return;
++	first = 0;
++
++	for (i = 0; i < AT91C_NR_UART; i++) {
++		at91_ports[i].iotype	= SERIAL_IO_MEM;
++		at91_ports[i].flags     = ASYNC_BOOT_AUTOCONF;
++		at91_ports[i].uartclk   = AT91C_MASTER_CLOCK;
++		at91_ports[i].ops	= &at91_pops;
++		at91_ports[i].fifosize  = 1;
++		at91_ports[i].line	= i;
++ 	}
++}
++
++void __init at91_register_uart_fns(struct at91rm9200_port_fns *fns)
++{
++	if (fns->enable_ms)
++		at91_pops.enable_ms = fns->enable_ms;
++	if (fns->get_mctrl)
++		at91_pops.get_mctrl = fns->get_mctrl;
++	if (fns->set_mctrl)
++		at91_pops.set_mctrl = fns->set_mctrl;
++	at91_open          = fns->open;
++	at91_close         = fns->close;
++	at91_pops.pm       = fns->pm;
++	at91_pops.set_wake = fns->set_wake;
++}
++
++/*
++ * Setup ports.
++ */
++void __init at91_register_uart(int idx, int port)
++{
++	if ((idx < 0) || (idx >= AT91C_NR_UART)) {
++		printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx);
++		return;
++	}
++
++	switch (port) {
++	case 0:
++		at91_ports[idx].membase = (void *) AT91C_VA_BASE_US0;
++		at91_ports[idx].mapbase = AT91C_VA_BASE_US0;
++		at91_ports[idx].irq     = AT91C_ID_US0;
++		AT91_CfgPIO_USART0();
++		break;
++	case 1:
++		at91_ports[idx].membase = (void *) AT91C_VA_BASE_US1;
++		at91_ports[idx].mapbase = AT91C_VA_BASE_US1;
++		at91_ports[idx].irq     = AT91C_ID_US1;
++		AT91_CfgPIO_USART1();
++		break;
++	case 2:
++		at91_ports[idx].membase = (void *) AT91C_VA_BASE_US2;
++		at91_ports[idx].mapbase = AT91C_VA_BASE_US2;
++		at91_ports[idx].irq     = AT91C_ID_US2;
++		AT91_CfgPIO_USART2();
++		break;
++	case 3:
++		at91_ports[idx].membase = (void *) AT91C_VA_BASE_US3;
++		at91_ports[idx].mapbase = AT91C_VA_BASE_US3;
++		at91_ports[idx].irq     = AT91C_ID_US3;
++		AT91_CfgPIO_USART3();
++		break;
++	case 4:
++		at91_ports[idx].membase = (void *) AT91C_VA_BASE_DBGU;
++		at91_ports[idx].mapbase = AT91C_VA_BASE_DBGU;
++		at91_ports[idx].irq     = AT91C_ID_SYS;
++		AT91_CfgPIO_DBGU();
++		break;
++	default:
++		printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port);
++	}
++}
++
++#ifdef CONFIG_SERIAL_AT91_CONSOLE
++
++/*
++ * Interrupts are disabled on entering
++ */
++static void at91_console_write(struct console *co, const char *s, u_int count)
++{
++	struct uart_port *port = at91_ports + co->index;
++	unsigned int status, i, imr;
++
++	/*
++	 *	First, save IMR and then disable interrupts
++	 */
++	imr = UART_GET_IMR(port);	/* get interrupt mask */
++	UART_PUT_IDR(port, AT91C_US_RXRDY | AT91C_US_TXRDY);
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++) {
++		do {
++			status = UART_GET_CSR(port);
++		} while (!(status & AT91C_US_TXRDY));
++		UART_PUT_CHAR(port, s[i]);
++		if (s[i] == '\n') {
++			do {
++				status = UART_GET_CSR(port);
++			} while (!(status & AT91C_US_TXRDY));
++			UART_PUT_CHAR(port, '\r');
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore IMR
++	 */
++	do {
++		status = UART_GET_CSR(port);
++	} while (status & AT91C_US_TXRDY);
++	UART_PUT_IER(port, imr);	/* set interrupts back the way they were */
++}
++
++static kdev_t at91_console_device(struct console *co)
++{
++	return MKDEV(SERIAL_AT91_MAJOR, MINOR_START + co->index);
++}
++
++/*
++ * If the port was already initialised (eg, by a boot loader), try to determine
++ * the current setup.
++ */
++static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++	unsigned int mr, quot;
++
++// TODO: CR is a write-only register
++//	unsigned int cr;
++//
++//	cr = UART_GET_CR(port) & (AT91C_US_RXEN | AT91C_US_TXEN);
++//	if (cr == (AT91C_US_RXEN | AT91C_US_TXEN)) {
++//		/* ok, the port was enabled */
++//
++//		mr = UART_GET_MR(port) & AT91C_US_PAR;
++//
++//		*parity = 'n';
++//		if (mr == AT91C_US_PAR_EVEN)
++//			*parity = 'e';
++//		else if (mr == AT91C_US_PAR_ODD)
++//			*parity = 'o';
++//	}
++
++	mr = UART_GET_MR(port) & AT91C_US_CHRL;
++	if (mr == AT91C_US_CHRL_8_BITS)
++		*bits = 8;
++	else
++		*bits = 7;
++
++	quot = UART_GET_BRGR(port);
++	*baud = port->uartclk / (16 * (quot));
++}
++
++static int __init at91_console_setup(struct console *co, char *options)
++{
++	struct uart_port *port;
++	int baud = AT91C_CONSOLE_DEFAULT_BAUDRATE;
++	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.
++	 */
++	port = uart_get_console(at91_ports, AT91C_NR_UART, co);
++
++	// TODO: The console port should be initialized, and clock enabled if
++	//  we're not relying on the bootloader to do it.
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++	else
++		at91_console_get_options(port, &baud, &parity, &bits);
++
++	return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct console at91_console = {
++	name:		"ttyS",
++	write:		at91_console_write,
++	device:		at91_console_device,
++	setup:		at91_console_setup,
++	flags:		CON_PRINTBUFFER,
++	index:		AT91C_CONSOLE,
++};
++
++#define AT91_CONSOLE_DEVICE	&at91_console
++
++void __init at91_console_init(void)
++{
++	at91_init_ports();
++	register_console(&at91_console);
++}
++
++#else
++#define AT91_CONSOLE_DEVICE	NULL
++#endif
++
++static struct uart_driver at91_reg = {
++	owner:			THIS_MODULE,
++	normal_major:		SERIAL_AT91_MAJOR,
++#ifdef CONFIG_DEVFS_FS
++	normal_name:		"ttyS%d",
++	callout_name:		"cua%d",
++#else
++	normal_name:		"ttyS",
++	callout_name:		"cua",
++#endif
++	normal_driver:		&normal,
++	callout_major:		CALLOUT_AT91_MAJOR,
++	callout_driver:		&callout,
++	table:			at91_table,
++	termios:		at91_termios,
++	termios_locked:		at91_termios_locked,
++	minor:			MINOR_START,
++	nr:			AT91C_NR_UART,
++	cons:			AT91_CONSOLE_DEVICE,
++};
++
++static int __init at91_serial_init(void)
++{
++	int ret, i;
++
++	at91_init_ports();
++
++	ret = uart_register_driver(&at91_reg);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < AT91C_NR_UART; i++) {
++		if (at91_serialmap[i] >= 0)
++			uart_add_one_port(&at91_reg, &at91_ports[i]);
++	}
++
++	return 0;
++}
++
++static void __exit at91_serial_exit(void)
++{
++	int i;
++
++	for (i = 0; i < AT91C_NR_UART; i++) {
++ 		if (at91_serialmap[i] >= 0)
++			uart_remove_one_port(&at91_reg, &at91_ports[i]);
++  	}
++
++	uart_unregister_driver(&at91_reg);
++}
++
++module_init(at91_serial_init);
++module_exit(at91_serial_exit);
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_AUTHOR("Rick Bronson");
++MODULE_DESCRIPTION("AT91 generic serial port driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/spi/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,17 @@
++# File: drivers/at91/spi/Makefile
++#
++# Makefile for the Atmel AT91RM9200 SPI device drivers
++#
++
++O_TARGET := at91spi.o
++
++export-objs := at91_spi.o
++
++obj-y	:= at91_spi.o
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++obj-$(CONFIG_AT91_SPIDEV) += at91_spidev.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/spi/at91_spi.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,275 @@
++/*
++ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200 (Thunder)
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/semaphore.h>
++#include <linux/pci.h>
++#include <linux/sched.h>
++#include <linux/completion.h>
++
++#include <asm/arch/AT91RM9200_SPI.h>
++#include <asm/arch/pio.h>
++#include "at91_spi.h"
++
++#undef DEBUG_SPI
++
++static struct spi_local spi_dev[NR_SPI_DEVICES];	/* state of the SPI devices */
++static int spi_enabled = 0;
++static struct semaphore spi_lock;			/* protect access to SPI bus */
++static int current_device = -1;				/* currently selected SPI device */
++
++DECLARE_COMPLETION(transfer_complete);
++
++/* SPI controller device */
++AT91PS_SPI controller = (AT91PS_SPI) AT91C_VA_BASE_SPI;
++
++/* ......................................................................... */
++
++/*
++ * Access and enable the SPI bus.
++ * This MUST be called before any transfers are performed.
++ */
++void spi_access_bus(short device)
++{
++	/* Ensure that requested device is valid */
++	if ((device < 0) || (device >= NR_SPI_DEVICES))
++		panic("at91_spi: spi_access_bus called with invalid device");
++
++	if (spi_enabled == 0) {
++		AT91_SYS->PMC_PCER = 1 << AT91C_ID_SPI;	/* Enable Peripheral clock */
++		controller->SPI_CR = AT91C_SPI_SPIEN;	/* Enable SPI */
++#ifdef DEBUG_SPI
++		printk("SPI on\n");
++#endif
++	}
++	MOD_INC_USE_COUNT;
++	spi_enabled++;
++
++	/* Lock the SPI bus */
++	down(&spi_lock);
++	current_device = device;
++
++	/* Enable PIO */
++	if (!spi_dev[device].pio_enabled) {
++		switch (device) {
++			case 0: AT91_CfgPIO_SPI_CS0();
++			case 1: AT91_CfgPIO_SPI_CS1();
++			case 2: AT91_CfgPIO_SPI_CS2();
++			case 3: AT91_CfgPIO_SPI_CS3();
++		}
++		spi_dev[device].pio_enabled = 1;
++#ifdef DEBUG_SPI
++		printk("SPI CS%i enabled\n", device);
++#endif
++	}
++
++	/* Configure SPI bus for device */
++	controller->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | (spi_dev[device].pcs << 16);
++}
++
++/*
++ * Relinquish control of the SPI bus.
++ */
++void spi_release_bus(short device)
++{
++	if (device != current_device)
++		panic("at91_spi: spi_release called with invalid device");
++
++	/* Release the SPI bus */
++	current_device = -1;
++	up(&spi_lock);
++
++	spi_enabled--;
++	MOD_DEC_USE_COUNT;
++	if (spi_enabled == 0) {
++		controller->SPI_CR = AT91C_SPI_SPIDIS;	/* Disable SPI */
++		AT91_SYS->PMC_PCER = 1 << AT91C_ID_SPI;	/* Disable Peripheral clock */
++#ifdef DEBUG_SPI
++		printk("SPI off\n");
++#endif
++	}
++}
++
++/*
++ * Perform a data transfer over the SPI bus
++ */
++int spi_transfer(struct spi_transfer_list* list)
++{
++	struct spi_local *device = (struct spi_local *) &spi_dev[current_device];
++
++	if (!list)
++		panic("at91_spi: spi_transfer called with NULL transfer list");
++	if (current_device == -1)
++		panic("at91_spi: spi_transfer called without acquiring bus");
++
++#ifdef DEBUG_SPI
++	printk("SPI transfer start [%i]\n", list->nr_transfers);
++#endif
++
++	/* Store transfer list */
++	device->xfers = list;
++	list->curr = 0;
++
++	/* Assume there must be at least one transfer */
++	device->tx = pci_map_single(NULL, list->tx[0], list->txlen[0], PCI_DMA_TODEVICE);
++	device->rx = pci_map_single(NULL, list->rx[0], list->rxlen[0], PCI_DMA_FROMDEVICE);
++
++	/* Program PDC registers */
++	controller->SPI_TPR = device->tx;
++	controller->SPI_RPR = device->rx;
++	controller->SPI_TCR = list->txlen[0];
++	controller->SPI_RCR = list->rxlen[0];
++
++	/* Is there a second transfer? */
++	if (list->nr_transfers > 1) {
++		device->txnext = pci_map_single(NULL, list->tx[1], list->txlen[1], PCI_DMA_TODEVICE);
++		device->rxnext = pci_map_single(NULL, list->rx[1], list->rxlen[1], PCI_DMA_FROMDEVICE);
++
++		/* Program Next PDC registers */
++		controller->SPI_TNPR = device->txnext;
++		controller->SPI_RNPR = device->rxnext;
++		controller->SPI_TNCR = list->txlen[1];
++		controller->SPI_RNCR = list->rxlen[1];
++	}
++	else {
++		device->txnext = 0;
++		device->rxnext = 0;
++		controller->SPI_TNCR = 0;
++		controller->SPI_RNCR = 0;
++	}
++
++	// TODO: If we are doing consecutive transfers (at high speed, or
++	//   small buffers), then it might be worth modifying the 'Delay between
++	//   Consecutive Transfers' in the CSR registers.
++	//   This is an issue if we cannot chain the next buffer fast enough
++	//   in the interrupt handler.
++
++	/* Enable transmitter and receiver */
++	controller->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
++
++	controller->SPI_IER = AT91C_SPI_SPENDRX;	/* enable buffer complete interrupt */
++	wait_for_completion(&transfer_complete);
++
++#ifdef DEBUG_SPI
++	printk("SPI transfer end\n");
++#endif
++
++	return 0;
++}
++
++/* ......................................................................... */
++
++/*
++ * Handle interrupts from the SPI controller.
++ */
++void spi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++ 	unsigned int status;
++	struct spi_local *device = (struct spi_local *) &spi_dev[current_device];
++	struct spi_transfer_list *list = device->xfers;
++
++#ifdef DEBUG_SPI
++	printk("SPI interrupt %i\n", current_device);
++#endif
++
++	if (!list)
++		panic("at91_spi: spi_interrupt with a NULL transfer list");
++
++       	status = controller->SPI_SR & controller->SPI_IMR;	/* read status */
++
++	pci_unmap_single(NULL, device->tx, list->txlen[list->curr], PCI_DMA_TODEVICE);
++	pci_unmap_single(NULL, device->rx, list->rxlen[list->curr], PCI_DMA_FROMDEVICE);
++
++	device->tx = device->txnext;	/* move next transfer to current transfer */
++	device->rx = device->rxnext;
++
++	list->curr = list->curr + 1;
++	if (list->curr == list->nr_transfers) {		/* all transfers complete */
++		controller->SPI_IDR = AT91C_SPI_SPENDRX;	/* disable interrupt */
++
++		/* Disable transmitter and receiver */
++		controller->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
++
++		device->xfers = NULL;
++		complete(&transfer_complete);
++	}
++	else if (list->curr+1 == list->nr_transfers) {	/* no more next transfers */
++		device->txnext = 0;
++		device->rxnext = 0;
++		controller->SPI_TNCR = 0;
++		controller->SPI_RNCR = 0;
++	}
++	else {
++		int i = (list->curr)+1;
++
++		device->txnext = pci_map_single(NULL, list->tx[i], list->txlen[i], PCI_DMA_TODEVICE);
++		device->rxnext = pci_map_single(NULL, list->rx[i], list->rxlen[i], PCI_DMA_FROMDEVICE);
++		controller->SPI_TNPR = device->txnext;
++		controller->SPI_RNPR = device->rxnext;
++		controller->SPI_TNCR = list->txlen[i];
++		controller->SPI_RNCR = list->rxlen[i];
++	}
++}
++
++/* ......................................................................... */
++
++/*
++ * Initialize the SPI controller
++ */
++static int __init at91_spi_init(void)
++{
++	init_MUTEX(&spi_lock);
++
++	AT91_CfgPIO_SPI();
++
++	controller->SPI_CR = AT91C_SPI_SWRST;	/* software reset of SPI controller */
++
++	/* Set Chip Select registers to good defaults */
++	controller->SPI_CSR0 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8);
++	controller->SPI_CSR1 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8);
++	controller->SPI_CSR2 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8);
++	controller->SPI_CSR3 = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | (16 << 16) | (DEFAULT_SPI_BAUD << 8);
++
++	controller->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
++
++	memset(&spi_dev, 0, sizeof(spi_dev));
++	spi_dev[0].pcs = 0xE;
++	spi_dev[1].pcs = 0xD;
++	spi_dev[2].pcs = 0xB;
++	spi_dev[3].pcs = 0x7;
++
++	if (request_irq(AT91C_ID_SPI, spi_interrupt, 0, "spi", NULL))
++		return -EBUSY;
++
++	controller->SPI_CR = AT91C_SPI_SPIEN;		/* Enable SPI */
++
++	return 0;
++}
++
++static void at91_spi_exit(void)
++{
++	controller->SPI_CR = AT91C_SPI_SPIDIS;		/* Disable SPI */
++
++	free_irq(AT91C_ID_SPI, 0);
++}
++
++
++EXPORT_SYMBOL(spi_access_bus);
++EXPORT_SYMBOL(spi_release_bus);
++EXPORT_SYMBOL(spi_transfer);
++
++module_init(at91_spi_init);
++module_exit(at91_spi_exit);
++
++MODULE_LICENSE("GPL")
++MODULE_AUTHOR("Andrew Victor")
++MODULE_DESCRIPTION("SPI driver for Atmel AT91RM9200")
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/spi/at91_spi.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,56 @@
++/*
++ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#ifndef AT91_SPI_H
++#define AT91_SPI_H
++
++/* Maximum number of buffers in a single SPI transfer.
++ *  DataFlash uses maximum of 2
++ *  spidev interface supports up to 8.
++ */
++#define MAX_SPI_TRANSFERS	8
++
++#define NR_SPI_DEVICES  	4	/* number of devices on SPI bus */
++
++#define DATAFLASH_CLK		6000000
++#define DEFAULT_SPI_BAUD	AT91C_MASTER_CLOCK / (2 * DATAFLASH_CLK)
++
++#define SPI_MAJOR		153	/* registered device number */
++
++/*
++ * Describes the buffers for a SPI transfer.
++ * A transmit & receive buffer must be specified for each transfer
++ */
++struct spi_transfer_list {
++	void* tx[MAX_SPI_TRANSFERS];	/* transmit */
++	int txlen[MAX_SPI_TRANSFERS];
++	void* rx[MAX_SPI_TRANSFERS];	/* receive */
++	int rxlen[MAX_SPI_TRANSFERS];
++	int nr_transfers;		/* number of transfers */
++	int curr;			/* current transfer */
++};
++
++struct spi_local {
++	unsigned int pcs;		/* Peripheral Chip Select value */
++	short pio_enabled;		/* has PIO been enabled? */
++
++	struct spi_transfer_list *xfers;	/* current transfer list */
++	dma_addr_t tx, rx;		/* DMA address for current transfer */
++	dma_addr_t txnext, rxnext;	/* DMA address for next transfer */
++};
++
++
++/* Exported functions */
++extern void spi_access_bus(short device);
++extern void spi_release_bus(short device);
++extern int spi_transfer(struct spi_transfer_list* list);
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/spi/at91_spidev.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,226 @@
++/*
++ * User-space interface to the SPI bus on Atmel AT91RM9200
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * Based on SPI driver by Rick Bronson
++ *
++ * 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/config.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/iobuf.h>
++#include <linux/highmem.h>
++
++#ifdef CONFIG_DEVFS_FS
++#include <linux/devfs_fs_kernel.h>
++#endif
++
++#include "at91_spi.h"
++
++#undef DEBUG_SPIDEV
++
++#ifdef CONFIG_DEVFS_FS
++static devfs_handle_t devfs_handle = NULL;
++static devfs_handle_t devfs_spi[NR_SPI_DEVICES];
++#endif
++
++/* ......................................................................... */
++
++/*
++ * Read or Write to SPI bus.
++ */
++static ssize_t spidev_rd_wr(struct file *file, char *buf, size_t count, loff_t *offset)
++{
++	unsigned int spi_device = (unsigned int) file->private_data;
++	struct kiobuf *iobuf;
++	unsigned int ofs, pagelen;
++	int res, i;
++
++	struct spi_transfer_list* list = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL);
++	if (!list)
++		return -ENOMEM;
++
++	res = alloc_kiovec(1, &iobuf);
++	if (res) {
++		kfree(list);
++		return res;
++	}
++
++	res = map_user_kiobuf(READ, iobuf, (unsigned long) buf, count);
++	if (res) {
++		free_kiovec(1, &iobuf);
++		kfree(list);
++		return res;
++	}
++
++	/* More pages than transfer slots in spi_transfer_list */
++	if (iobuf->nr_pages >= MAX_SPI_TRANSFERS) {
++		unmap_kiobuf(iobuf);
++		free_kiovec(1, &iobuf);
++		kfree(list);
++		return -EFBIG;
++	}
++
++#ifdef DEBUG_SPIDEV
++	printk("spidev_rd_rw: %i %i\n", count, iobuf->nr_pages);
++#endif
++
++	/* Set default return value = transfer length */
++	res = count;
++
++	/*
++	 * At this point, the virtual area buf[0] .. buf[count-1] will have
++	 * corresponding pages mapped in the physical memory and locked until
++	 * we unmap the kiobuf.  The pages cannot be swapped out or moved
++	 * around.
++	 */
++	ofs = iobuf->offset;
++	pagelen = PAGE_SIZE - iobuf->offset;
++	if (count < pagelen)
++		pagelen = count;
++
++	for (i = 0; i < iobuf->nr_pages; i++) {
++		list->tx[i] = list->rx[i] = page_address(iobuf->maplist[i]) + ofs;
++		list->txlen[i] = list->rxlen[i] = pagelen;
++
++#ifdef DEBUG_SPIDEV
++		printk("  %i: %x  (%i)\n", i, list->tx[i], list->txlen[i]);
++#endif
++
++		ofs = 0;	/* all subsequent transfers start at beginning of a page */
++		count = count - pagelen;
++		pagelen = (count < PAGE_SIZE) ? count : PAGE_SIZE;
++	}
++	list->nr_transfers = iobuf->nr_pages;
++
++	/* Perform transfer on SPI bus */
++	spi_access_bus(spi_device);
++	spi_transfer(list);
++	spi_release_bus(spi_device);
++
++	unmap_kiobuf(iobuf);
++	free_kiovec(1, &iobuf);
++	kfree(list);
++
++	return res;
++}
++
++int spidev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++	int spi_device = MINOR(inode->i_rdev);
++
++	if (spi_device >= NR_SPI_DEVICES)
++		return -ENODEV;
++
++	// TODO: This interface can be used to configure the SPI bus.
++	// Configurable options could include: Speed, Clock Polarity, Clock Phase
++
++	switch(cmd) {
++		default:
++			return -ENOIOCTLCMD;
++	}
++}
++
++/*
++ * Open the SPI device
++ */
++int spidev_open(struct inode *inode, struct file *file)
++{
++	unsigned int spi_device = MINOR(inode->i_rdev);
++
++	if (spi_device >= NR_SPI_DEVICES)
++		return -ENODEV;
++
++	MOD_INC_USE_COUNT;
++
++	/*
++	 * 'private_data' is actually a pointer, but we overload it with the
++	 * value we want to store.
++	 */
++	(unsigned int) file->private_data = spi_device;
++
++	return 0;
++}
++
++/*
++ * Close the SPI device
++ */
++static int spidev_close(struct inode *inode, struct file *file)
++{
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++/* ......................................................................... */
++
++static struct file_operations spidev_fops = {
++	owner:		THIS_MODULE,
++	llseek:		no_llseek,
++	read:		spidev_rd_wr,
++	write:		spidev_rd_wr,
++	ioctl:		spidev_ioctl,
++	open:		spidev_open,
++	release:	spidev_close,
++};
++
++/*
++ * Install the SPI /dev interface driver
++ */
++static int __init at91_spidev_init(void)
++{
++	int i;
++	char name[3];
++
++#ifdef CONFIG_DEVFS_FS
++	if (devfs_register_chrdev(SPI_MAJOR, "spi", &spidev_fops)) {
++#else
++	if (register_chrdev(SPI_MAJOR, "spi", &spidev_fops)) {
++#endif
++		printk(KERN_ERR "at91_spidev: Unable to get major %d for SPI bus\n", SPI_MAJOR);
++		return -EIO;
++	}
++
++#ifdef CONFIG_DEVFS_FS
++	devfs_handle = devfs_mk_dir(NULL, "spi", NULL);
++
++	for (i = 0; i < NR_SPI_DEVICES; i++) {
++		sprintf (name, "%d", i);
++		devfs_spi[i] = devfs_register (devfs_handle, name,
++			DEVFS_FL_DEFAULT, SPI_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR,
++			&spidev_fops, NULL);
++	}
++#endif
++	printk(KERN_INFO "AT91 SPI driver loaded\n");
++
++	return 0;
++}
++
++/*
++ * Remove the SPI /dev interface driver
++ */
++static void at91_spidev_exit(void)
++{
++#ifdef CONFIG_DEVFS_FS
++	devfs_unregister(devfs_handle);
++	if (devfs_unregister_chrdev(SPI_MAJOR, "spi")) {
++#else
++	if (unregister_chrdev(SPI_MAJOR,"spi")) {
++#endif
++		printk(KERN_ERR "at91_spidev: Unable to release major %d for SPI bus\n", SPI_MAJOR);
++		return;
++	}
++}
++
++module_init(at91_spidev_init);
++module_exit(at91_spidev_exit);
++
++MODULE_LICENSE("GPL")
++MODULE_AUTHOR("Andrew Victor")
++MODULE_DESCRIPTION("SPI /dev interface for Atmel AT91RM9200")
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/usb/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,17 @@
++# File: drivers/at91/usb/Makefile
++#
++# Makefile for the Atmel AT91RM9200 USB device drivers
++#
++
++O_TARGET := at91usb.o
++
++export-objs :=
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++obj-$(CONFIG_USB_OHCI_AT91) += at91_usb-ohci.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/usb/at91_usb-ohci.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,81 @@
++/*
++ *  linux/drivers/at91/usb/at91_usb_ohci-at91.c
++ *
++ *  (c) Rick Bronson
++ *
++ *  The outline of this code was taken from Brad Parkers <brad@heeltoe.com>
++ *  original OHCI driver modifications, and reworked into a cleaner form
++ *  by Russell King <rmk@arm.linux.org.uk>.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/usb.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++
++#include <asm/arch/AT91RM9200_UHP.h>
++
++/*
++  NOTE:
++  The following is so that we don't have to include usb-ohci.h or pci.h as the
++  usb-ohci.c driver needs these routines even when the architecture
++  has no PCI bus...
++*/
++
++extern int __devinit hc_add_ohci(struct pci_dev *dev, int irq, void *membase,
++	    unsigned long flags, void *ohci, const char *name,
++	    const char *slot_name);
++extern void hc_remove_ohci(void *ohci);
++
++static void *at91_ohci;
++AT91PS_UHP ohci_regs;
++
++static int __init at91_ohci_init(void)
++{
++	int ret;
++
++	ohci_regs = ioremap(AT91_UHP_BASE, SZ_4K);
++	if (!ohci_regs) {
++		printk(KERN_ERR "at91_usb-ohci: ioremap failed\n");
++		return -EIO;
++	}
++
++	/* Now, enable the USB clock */
++	AT91_SYS->PMC_SCER = AT91C_PMC_UHP;	/* enable system clock */
++	AT91_SYS->PMC_PCER = 1 << AT91C_ID_UHP;	/* enable peripheral clock */
++
++	/* Take Hc out of reset */
++	ohci_regs->UHP_HcControl = 2 << 6;
++
++	/* Initialise the generic OHCI driver. */
++	ret = hc_add_ohci((struct pci_dev *) 1, AT91C_ID_UHP,
++			  (void *)ohci_regs, 0, &at91_ohci,
++			  "usb-ohci", "at91");
++	if (ret)
++		iounmap(ohci_regs);
++
++	return ret;
++}
++
++static void __exit at91_ohci_exit(void)
++{
++	hc_remove_ohci(at91_ohci);
++
++	/* Force UHP_Hc to reset */
++	ohci_regs->UHP_HcControl = 0;
++
++	 /* Stop the USB clock. */
++	AT91_SYS->PMC_SCDR = AT91C_PMC_UHP;	/* disable system clock */
++	AT91_SYS->PMC_PCDR = 1 << AT91C_ID_UHP;	/* disable peripheral clock */
++
++	iounmap(ohci_regs);
++}
++
++module_init(at91_ohci_init);
++module_exit(at91_ohci_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/watchdog/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,15 @@
++# File: drivers/at91/watchdog/Makefile
++#
++# Makefile for the Atmel AT91RM9200 watchdog device driver
++#
++
++O_TARGET := at91wdt.o
++
++obj-y	:=
++obj-m	:=
++obj-n	:=
++obj-	:=
++
++obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/at91/watchdog/at91_wdt.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,193 @@
++/*
++ * Watchdog driver for Atmel AT91RM9200 (Thunder)
++ *
++ * (c) SAN People (Pty) Ltd
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version
++ * 2 of the License, or (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <asm/uaccess.h>
++#include <linux/init.h>
++
++#define WDT_DEFAULT_TIME 5	/* 5 seconds */
++#define WDT_MAX_TIME 256	/* 256 seconds */
++
++static int at91wdt_time = WDT_DEFAULT_TIME;
++static int at91wdt_busy;
++
++/* ......................................................................... */
++
++/*
++ * Disable the watchdog.
++ */
++void at91_wdt_stop(void)
++{
++	AT91_SYS->ST_WDMR = AT91C_ST_EXTEN;
++}
++
++/*
++ * Enable and reset the watchdog.
++ */
++void at91_wdt_start(void)
++{
++	AT91_SYS->ST_WDMR = AT91C_ST_EXTEN | AT91C_ST_RSTEN | (((65536 * at91wdt_time) >> 8) & AT91C_ST_WDV);
++	AT91_SYS->ST_CR = AT91C_ST_WDRST;
++}
++
++/* ......................................................................... */
++
++/*
++ * Watchdog device is opened, and watchdog starts running.
++ */
++static int at91_wdt_open(struct inode *inode, struct file *file)
++{
++	if (test_and_set_bit(1, &at91wdt_busy))
++		return -EBUSY;
++	MOD_INC_USE_COUNT;
++
++	/*
++	 * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
++	 *
++	 * Since WDV is a 16-bit counter, the maximum period is
++	 * 65536 / 0.256 = 256 seconds.
++	 */
++
++	at91_wdt_start();
++	return 0;
++}
++
++/*
++ * Close the watchdog device.
++ * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
++ *  disabled.
++ */
++static int at91_wdt_close(struct inode *inode, struct file *file)
++{
++#ifndef CONFIG_WATCHDOG_NOWAYOUT
++	/* Disable the watchdog when file is closed */
++	at91_wdt_stop();
++#endif
++
++	at91wdt_busy = 0;
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++/*
++ * Handle commands from user-space.
++ */
++static int at91_wdt_ioctl(struct inode *inode, struct file *file,
++		unsigned int cmd, unsigned long arg)
++{
++	unsigned int new_value;
++	static struct watchdog_info info = {
++		identity: "at91 watchdog",
++		options:  WDIOF_SETTIMEOUT,
++	};
++
++	switch(cmd) {
++		case WDIOC_KEEPALIVE:
++			AT91_SYS->ST_CR = AT91C_ST_WDRST;	/* Pat the watchdog */
++			return 0;
++
++		case WDIOC_GETSUPPORT:
++			return copy_to_user((struct watchdog_info *)arg, &info, sizeof(info));
++
++		case WDIOC_SETTIMEOUT:
++			if (get_user(new_value, (int *)arg))
++				return -EFAULT;
++			if ((new_value <= 0) || (new_value > WDT_MAX_TIME))
++				return -EINVAL;
++
++			/* Restart watchdog with new time */
++			at91wdt_time = new_value;
++			at91_wdt_start();
++
++			/* Return current value */
++			return put_user(at91wdt_time, (int *)arg);
++
++		case WDIOC_GETTIMEOUT:
++			return put_user(at91wdt_time, (int *)arg);
++
++		case WDIOC_GETSTATUS:
++			return put_user(0, (int *)arg);
++
++		case WDIOC_SETOPTIONS:
++			if (get_user(new_value, (int *)arg))
++				return -EFAULT;
++			if (new_value & WDIOS_DISABLECARD)
++				at91_wdt_stop();
++			if (new_value & WDIOS_ENABLECARD)
++				at91_wdt_start();
++			return 0;
++
++		default:
++			return -ENOIOCTLCMD;
++	}
++}
++
++/*
++ * Pat the watchdog whenever device is written to.
++ */
++static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
++{
++	/*  Can't seek (pwrite) on this device  */
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++
++	if (len) {
++		AT91_SYS->ST_CR = AT91C_ST_WDRST;	/* Pat the watchdog */
++		return len;
++	}
++
++	return 0;
++}
++
++/* ......................................................................... */
++
++static struct file_operations at91wdt_fops =
++{
++	.owner		= THIS_MODULE,
++	.ioctl		= at91_wdt_ioctl,
++	.open		= at91_wdt_open,
++	.release	= at91_wdt_close,
++	.write		= at91_wdt_write,
++};
++
++static struct miscdevice at91wdt_miscdev =
++{
++	.minor		= WATCHDOG_MINOR,
++	.name		= "watchdog",
++	.fops		= &at91wdt_fops,
++};
++
++static int __init at91_wdt_init(void)
++{
++	int res;
++
++	res = misc_register(&at91wdt_miscdev);
++	if (res)
++		return res;
++
++	printk("AT91 Watchdog Timer enabled (%d seconds)\n", WDT_DEFAULT_TIME);
++	return 0;
++}
++
++static void __exit at91_wdt_exit(void)
++{
++	misc_deregister(&at91wdt_miscdev);
++}
++
++module_init(at91_wdt_init);
++module_exit(at91_wdt_exit);
++
++MODULE_LICENSE("GPL")
++MODULE_AUTHOR("Andrew Victor")
++MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200")
+--- linux-2.4.25/drivers/block/Makefile~2.4.25-vrs2.patch	2003-06-13 16:51:32.000000000 +0200
++++ linux-2.4.25/drivers/block/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -27,11 +27,17 @@
+ obj-$(CONFIG_BLK_DEV_PS2)	+= ps2esdi.o
+ obj-$(CONFIG_BLK_DEV_XD)	+= xd.o
+ obj-$(CONFIG_BLK_CPQ_DA)	+= cpqarray.o
+-obj-$(CONFIG_BLK_CPQ_CISS_DA)  += cciss.o
++obj-$(CONFIG_BLK_CPQ_CISS_DA)	+= cciss.o
+ obj-$(CONFIG_BLK_DEV_DAC960)	+= DAC960.o
+ obj-$(CONFIG_BLK_DEV_UMEM)	+= umem.o
+ obj-$(CONFIG_BLK_DEV_NBD)	+= nbd.o
+ 
+ subdir-$(CONFIG_PARIDE) += paride
+ 
++ifeq ($(CONFIG_ARCH_ACORN),y)
++mod-subdirs	+= ../acorn/block
++subdir-y	+= ../acorn/block
++obj-y		+= ../acorn/block/acorn-block.o
++endif
++
+ include $(TOPDIR)/Rules.make
+--- linux-2.4.25/drivers/block/ll_rw_blk.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/block/ll_rw_blk.c	2004-03-31 17:15:09.000000000 +0200
+@@ -32,6 +32,19 @@
+ #include <linux/slab.h>
+ #include <linux/module.h>
+ 
++/* Maybe something to cleanup in 2.3?
++ * We shouldn't touch 0x3f2 on machines which don't have a PC floppy controller
++ * - it may contain something else which could cause a system hang.  This is
++ * now selected by a configuration option, but maybe it ought to be in the
++ * floppy code itself? - rmk
++ */
++#if defined(__i386__) || (defined(__arm__) && defined(CONFIG_ARCH_ACORN))
++#define FLOPPY_BOOT_DISABLE
++#endif
++#ifdef CONFIG_BLK_DEV_FD
++#undef FLOPPY_BOOT_DISABLE
++#endif
++
+ /*
+  * MAC Floppy IWM hooks
+  */
+@@ -524,7 +537,7 @@
+ 	elevator_init(&q->elevator, ELEVATOR_LINUS);
+ 	blk_init_free_list(q);
+ 	q->request_fn     	= rfn;
+-	q->back_merge_fn       	= ll_back_merge_fn;
++	q->back_merge_fn	= ll_back_merge_fn;
+ 	q->front_merge_fn      	= ll_front_merge_fn;
+ 	q->merge_requests_fn	= ll_merge_requests_fn;
+ 	q->make_request_fn	= __make_request;
+@@ -1540,7 +1553,7 @@
+ 	mfm_init();
+ #endif
+ #ifdef CONFIG_PARIDE
+-	{ extern void paride_init(void); paride_init(); };
++	{ extern void paride_init(void); paride_init(); }
+ #endif
+ #ifdef CONFIG_MAC_FLOPPY
+ 	swim3_init();
+@@ -1554,12 +1567,14 @@
+ #ifdef CONFIG_ATARI_FLOPPY
+ 	atari_floppy_init();
+ #endif
++#ifdef CONFIG_BLK_DEV_FD1772
++	fd1772_init();
++#endif
+ #ifdef CONFIG_BLK_DEV_FD
+ 	floppy_init();
+-#else
+-#if defined(__i386__)	/* Do we even need this? */
+-	outb_p(0xc, 0x3f2);
+ #endif
++#ifdef FLOPPY_BOOT_DISABLE
++	outb_p(0xc, 0x3f2);
+ #endif
+ #ifdef CONFIG_CDU31A
+ 	cdu31a_init();
+@@ -1617,7 +1632,7 @@
+ 	jsfd_init();
+ #endif
+ 	return 0;
+-};
++}
+ 
+ EXPORT_SYMBOL(io_request_lock);
+ EXPORT_SYMBOL(end_that_request_first);
+--- linux-2.4.25/drivers/cdrom/cdrom.c~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/cdrom/cdrom.c	2004-03-31 17:15:09.000000000 +0200
+@@ -246,8 +246,8 @@
+ #define CD_DVD		0x80
+ 
+ /* Define this to remove _all_ the debugging messages */
+-/* #define ERRLOGMASK CD_NOTHING */
+-#define ERRLOGMASK (CD_WARNING)
++#define ERRLOGMASK CD_NOTHING
++/* #define ERRLOGMASK (CD_WARNING) */
+ /* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */
+ /* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */
+ 
+--- linux-2.4.25/drivers/char/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/char/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -20,10 +20,10 @@
+    if [ "$CONFIG_IA64" = "y" ]; then
+       bool '  Support for serial port described by EFI HCDP table' CONFIG_SERIAL_HCDP
+    fi
+-   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+-      tristate '   Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL
+-      tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL
+-   fi
++fi
++if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
++   dep_tristate '   Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL $CONFIG_SERIAL
++   dep_tristate '   Dual serial port support' CONFIG_DUALSP_SERIAL $CONFIG_SERIAL
+ fi
+ dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
+ if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
+@@ -132,18 +132,6 @@
+ 	 bool '  SGI SN2 IOC4 serial port support' CONFIG_SGI_IOC4_SERIAL
+       fi
+    fi
+-fi
+-if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then
+-   tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232
+-fi
+-if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
+-   bool 'DC21285 serial port support' CONFIG_SERIAL_21285
+-   if [ "$CONFIG_SERIAL_21285" = "y" ]; then
+-      if [ "$CONFIG_OBSOLETE" = "y" ]; then
+-         bool '  Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD
+-      fi
+-      bool '  Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE
+-   fi
+    if [ "$CONFIG_PARISC" = "y" ]; then
+      bool '  PDC software console support' CONFIG_PDC_CONSOLE
+    fi
+@@ -168,6 +156,16 @@
+ if [ "$CONFIG_CPU_VR41XX" = "y" ]; then
+    bool 'NEC VR4100 series Keyboard Interface Unit Support ' CONFIG_VR41XX_KIU
+ fi
++if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
++  tristate 'AT91RM9200 SPI device interface' CONFIG_AT91_SPIDEV
++fi
++
++source drivers/serial/Config.in
++
++if [ "$CONFIG_ARCH_ANAKIN" = "y" ]; then
++   tristate 'Anakin touchscreen support' CONFIG_TOUCHSCREEN_ANAKIN
++fi
++
+ bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
+ if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+    int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256
+@@ -190,6 +188,12 @@
+ 
+ source drivers/i2c/Config.in
+ 
++if [ "$CONFIG_I2C" != "n" ]; then
++    dep_tristate '  DS1307 RTC' CONFIG_I2C_DS1307 $CONFIG_I2C
++fi
++
++source drivers/l3/Config.in
++
+ mainmenu_option next_comment
+ comment 'Mice'
+ tristate 'Bus Mouse Support' CONFIG_BUSMOUSE
+@@ -245,11 +249,13 @@
+    tristate '  ALi M7101 PMU Watchdog Timer' CONFIG_ALIM7101_WDT
+    tristate '  AMD "Elan" SC520 Watchdog Timer' CONFIG_SC520_WDT
+    tristate '  Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
+-   if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
+-      tristate '  DC21285 watchdog' CONFIG_21285_WATCHDOG
+-      if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
+-         tristate '  NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG
+-      fi
++   if [ "$CONFIG_ARM" = "y" ]; then
++      dep_tristate '  DC21285 watchdog' CONFIG_21285_WATCHDOG $CONFIG_FOOTBRIDGE
++      dep_tristate '  NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG $CONFIG_ARCH_NETWINDER
++      dep_tristate '  SA1100 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_SA1100
++      dep_tristate '  EPXA watchdog' CONFIG_EPXA_WATCHDOG $CONFIG_ARCH_CAMELOT
++      dep_tristate '  Omaha watchdog' CONFIG_OMAHA_WATCHDOG $CONFIG_ARCH_OMAHA
++      dep_tristate '  AT91RM9200 watchdog' CONFIG_AT91_WATCHDOG $CONFIG_ARCH_AT91RM9200
+    fi
+    tristate '  Eurotech CPU-1220/1410 Watchdog Timer' CONFIG_EUROTECH_WDT
+    tristate '  IB700 SBC Watchdog Timer' CONFIG_IB700_WDT
+@@ -326,6 +332,15 @@
+ if [ "$CONFIG_TOSHIBA_RBTX4927" = "y" -o "$CONFIG_TOSHIBA_JMR3927" = "y" ]; then
+    tristate 'Dallas DS1742 RTC support' CONFIG_DS1742
+ fi
++if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
++   tristate 'SA1100 Real Time Clock' CONFIG_SA1100_RTC
++fi
++if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then
++   tristate 'Omaha Real Time Clock' CONFIG_OMAHA_RTC
++fi
++if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
++   tristate 'AT91RM9200 Real Time Clock' CONFIG_AT91_RTC
++fi
+ 
+ tristate 'Double Talk PC internal speech card support' CONFIG_DTLK
+ tristate 'Siemens R3964 line discipline' CONFIG_R3964
+--- linux-2.4.25/drivers/char/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/char/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -29,7 +29,7 @@
+ 
+ mod-subdirs	:=	joystick ftape drm drm-4.0 pcmcia
+ 
+-list-multi	:=	
++list-multi	:=
+ 
+ KEYMAP   =defkeymap.o
+ KEYBD    =pc_keyb.o
+@@ -106,11 +106,39 @@
+ endif
+ 
+ ifeq ($(ARCH),arm)
+-  ifneq ($(CONFIG_PC_KEYMAP),y)
+-    KEYMAP   =
++  KEYMAP     :=
++  KEYBD      :=
++  ifeq ($(CONFIG_PC_KEYMAP),y)
++    KEYMAP   := defkeymap.o
+   endif
+-  ifneq ($(CONFIG_PC_KEYB),y)
+-    KEYBD    =
++  ifeq ($(CONFIG_PC_KEYB),y)
++    KEYBD    += pc_keyb.o
++  endif
++  ifeq ($(CONFIG_KMI_KEYB),y)
++    KEYBD    += amba_kmi_keyb.o
++  endif
++  ifeq ($(CONFIG_SA1111),y)
++    KEYBD    += sa1111_keyb.o
++  endif
++  ifeq ($(CONFIG_ARCH_EDB7211),y)
++    KEYBD    += edb7211_keyb.o
++  endif
++  ifeq ($(CONFIG_ARCH_AUTCPU12),y)
++    KEYMAP   := defkeymap.o
++    KEYBD    += clps711x_keyb.o
++  endif
++  ifeq ($(CONFIG_SA1100_GRAPHICSCLIENT),y)
++    KEYMAP    = gckeymap.o
++    KEYBD    += gc_keyb.o
++  endif
++  ifeq ($(CONFIG_SA1100_CERF_CPLD),y)
++    KEYBD    += cerf_keyb.o
++  endif
++  ifeq ($(CONFIG_ARCH_FORTUNET),y)
++    KEYMAP   := defkeymap.o
++  endif
++  ifeq ($(CONFIG_ARCH_GUIDEA07),y)
++    KEYMAP   := defkeymap.o
+   endif
+ endif
+ 
+@@ -172,11 +200,9 @@
+ obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
+ obj-$(CONFIG_SERIAL) += $(SERIAL)
+ obj-$(CONFIG_SERIAL_HCDP) += hcdp_serial.o
+-obj-$(CONFIG_SERIAL_21285) += serial_21285.o
+-obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
+-obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o
+ obj-$(CONFIG_TS_AU1X00_ADS7846) += au1000_ts.o
+ obj-$(CONFIG_SERIAL_DEC) += decserial.o
++obj-$(CONFIG_TOUCHSCREEN_ANAKIN) += anakin_ts.o
+ 
+ ifndef CONFIG_SUN_KEYBOARD
+   obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD)
+@@ -253,6 +279,8 @@
+ obj-$(CONFIG_SGI_DS1286) += ds1286.o
+ obj-$(CONFIG_MIPS_RTC) += mips_rtc.o
+ obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
++obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o
++obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o
+ ifeq ($(CONFIG_PPC),)
+   obj-$(CONFIG_NVRAM) += nvram.o
+ endif
+@@ -291,6 +319,7 @@
+ obj-$(CONFIG_NWFLASH) += nwflash.o
+ obj-$(CONFIG_SCx200) += scx200.o
+ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
++obj-$(CONFIG_SA1100_CONSUS) += consusbutton.o
+ 
+ # Only one watchdog can succeed. We probe the hardware watchdog
+ # drivers first, then the softdog driver.  This means if your hardware
+@@ -319,16 +348,28 @@
+ obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
+ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
+ obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
++obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
++obj-$(CONFIG_EPXA_WATCHDOG) += epxa_wdt.o
++obj-$(CONFIG_OMAHA_WATCHDOG) += omaha_wdt.o
+ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+ obj-$(CONFIG_AMD7XX_TCO) += amd7xx_tco.o
+ obj-$(CONFIG_INDYDOG) += indydog.o
+ obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+ 
++# I2C char devices
++obj-$(CONFIG_I2C_DS1307) += ds1307.o
++
+ subdir-$(CONFIG_MWAVE) += mwave
+ ifeq ($(CONFIG_MWAVE),y)
+   obj-y += mwave/mwave.o
+ endif
+ 
++ifeq ($(CONFIG_ARCH_ACORN),y)
++mod-subdirs	+= ../acorn/char
++subdir-y	+= ../acorn/char
++obj-y		+= ../acorn/char/acorn-char.o
++endif
++
+ subdir-$(CONFIG_IPMI_HANDLER) += ipmi
+ ifeq ($(CONFIG_IPMI_HANDLER),y)
+   obj-y += ipmi/ipmi.o
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/amba_kmi_keyb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,999 @@
++/*
++ *  linux/drivers/char/amba_kmi_keyb.c
++ *
++ *  AMBA Keyboard and Mouse Interface Driver
++ *
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  This keyboard driver drives a PS/2 keyboard and mouse connected
++ *  to the KMI interfaces.  The KMI interfaces are nothing more than
++ *  a uart; there is no inteligence in them to do keycode translation.
++ *  We leave all that up to the keyboard itself.
++ *
++ *	   FIXES:
++ *		 dirk.uffmann@nokia.com:  enabled PS/2 reconnection
++ */
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>	/* for in_interrupt */
++#include <linux/timer.h>
++#include <linux/init.h>
++#include <linux/delay.h>	/* for udelay */
++#include <linux/kbd_kern.h>	/* for keyboard_tasklet */
++#include <linux/kbd_ll.h>
++
++#include <asm/io.h>
++#include <asm/hardware/amba_kmi.h>
++#include <asm/mach/amba_kmi.h>
++#include <asm/keyboard.h>
++
++//#define DEBUG(s) printk s
++#define DEBUG(s) do { } while (0)
++
++#define CONFIG_AMBA_PS2_RECONNECT
++
++#define KMI_BASE	(kmi->base)
++
++#define KMI_RESET		0x00
++#define KMI_RESET_POR		0x01
++#define KMI_RESET_DONE		0x02
++
++#define KMI_NO_ACK		0xffff
++
++#define PS2_O_RESET		0xff
++#define PS2_O_RESEND		0xfe
++#define PS2_O_DISABLE		0xf5
++#define PS2_O_ENABLE		0xf4
++#define PS2_O_ECHO		0xee
++
++/*
++ * Keyboard
++ */
++#define PS2_O_SET_DEFAULT	0xf6
++#define PS2_O_SET_RATE_DELAY	0xf3
++#define PS2_O_SET_SCANSET	0xf0
++#define PS2_O_INDICATORS	0xed
++
++/*
++ * Mouse
++ */
++#define PS2_O_SET_SAMPLE	0xf3
++#define PS2_O_SET_STREAM	0xea
++#define PS2_O_SET_RES		0xe8
++#define PS2_O_SET_SCALE21	0xe7
++#define PS2_O_SET_SCALE11	0xe6
++#define PS2_O_REQ_STATUS	0xe9
++
++/*
++ * Responses
++ */
++#define PS2_I_RESEND		0xfe
++#define PS2_I_DIAGFAIL		0xfc
++#define PS2_I_ACK		0xfa
++#define PS2_I_BREAK		0xf0
++#define PS2_I_ECHO		0xee
++#define PS2_I_BAT_OK		0xaa
++
++static char *kmi_type[] = { "Keyboard", "Mouse" };
++
++static struct kmi_info *kmi_keyb;
++static struct kmi_info *kmi_mouse;
++
++static inline void __kmi_send(struct kmi_info *kmi, u_int val)
++{
++	u_int status;
++
++	do {
++		status = __raw_readb(KMISTAT);
++	} while (!(status & KMISTAT_TXEMPTY));
++
++	kmi->resend_count += 1;
++	__raw_writeb(val, KMIDATA);
++}
++
++static void kmi_send(struct kmi_info *kmi, u_int val)
++{
++	kmi->last_tx = val;
++	kmi->resend_count = -1;
++	__kmi_send(kmi, val);
++}
++
++static u_int kmi_send_and_wait(struct kmi_info *kmi, u_int val, u_int timeo)
++{
++	DECLARE_WAITQUEUE(wait, current);
++
++	if (kmi->present == 0)
++		return KMI_NO_ACK;
++
++	kmi->res = KMI_NO_ACK;
++	kmi->last_tx = val;
++	kmi->resend_count = -1;
++
++	if (current->pid != 0 && !in_interrupt()) {
++		add_wait_queue(&kmi->wait_q, &wait);
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		__kmi_send(kmi, val);
++		schedule_timeout(timeo);
++		current->state = TASK_RUNNING;
++		remove_wait_queue(&kmi->wait_q, &wait);
++	} else {
++		int i;
++
++		__kmi_send(kmi, val);
++		for (i = 0; i < 1000; i++) {
++			if (kmi->res != KMI_NO_ACK)
++				break;
++			udelay(100);
++		}
++	}
++
++	return kmi->res;
++}
++
++/*
++ * This lot should probably be separated into a separate file...
++ */
++#ifdef CONFIG_KMI_MOUSE
++
++#include <linux/fs.h>		/* for struct file_ops */
++#include <linux/poll.h> 	/* for poll_table */
++#include <linux/miscdevice.h>	/* for struct miscdev */
++#include <linux/random.h>	/* for add_mouse_randomness */
++#include <linux/slab.h> 	/* for kmalloc */
++#include <linux/smp_lock.h>	/* for {un,}lock_kernel */
++#include <linux/spinlock.h>
++
++#include <asm/uaccess.h>
++
++#define BUF_SZ	2048
++
++static spinlock_t kmi_mouse_lock;
++static int kmi_mouse_count;
++static struct queue {
++	u_int			head;
++	u_int			tail;
++	struct fasync_struct	*fasync;
++	unsigned char		buf[BUF_SZ];
++} *queue;
++
++#define queue_empty() (queue->head == queue->tail)
++
++static u_char get_from_queue(void)
++{
++	unsigned long flags;
++	u_char res;
++
++	spin_lock_irqsave(&kmi_mouse_lock, flags);
++	res = queue->buf[queue->tail];
++	queue->tail = (queue->tail + 1) & (BUF_SZ-1);
++	spin_unlock_irqrestore(&kmi_mouse_lock, flags);
++
++	return res;
++}
++
++static ssize_t
++kmi_mouse_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++	ssize_t i = count;
++
++	if (queue_empty()) {
++		int ret;
++
++		if (file->f_flags & O_NONBLOCK)
++			return -EAGAIN;
++		ret = wait_event_interruptible(kmi_mouse->wait_q, !queue_empty());
++		if (ret)
++			return ret;
++	}
++	while (i > 0 && !queue_empty()) {
++		u_char c;
++		c = get_from_queue();
++		put_user(c, buf++);
++		i--;
++	}
++	if (count - i)
++		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
++	return count - i;
++}
++
++static ssize_t
++kmi_mouse_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
++{
++	ssize_t retval = 0;
++
++	if (count > 32)
++		count = 32;
++
++	do {
++		char c;
++		get_user(c, buf++);
++		kmi_send_and_wait(kmi_mouse, c, HZ);
++		retval++;
++	} while (--count);
++
++	if (retval)
++		file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
++
++	return retval;
++}
++
++static unsigned int
++kmi_mouse_poll(struct file *file, poll_table *wait)
++{
++	poll_wait(file, &kmi_mouse->wait_q, wait);
++	return (!queue_empty()) ? POLLIN | POLLRDNORM : 0;
++}
++
++static int
++kmi_mouse_release(struct inode *inode, struct file *file)
++{
++	lock_kernel();
++	fasync_helper(-1, file, 0, &queue->fasync);
++	if (--kmi_mouse_count == 0)
++		kmi_send_and_wait(kmi_mouse, PS2_O_DISABLE, HZ);
++	unlock_kernel();
++	return 0;
++}
++
++static int
++kmi_mouse_open(struct inode *inode, struct file *file)
++{
++	if (kmi_mouse_count++)
++		return 0;
++	queue->head = queue->tail = 0;
++	kmi_send_and_wait(kmi_mouse, PS2_O_ENABLE, HZ);
++	return 0;
++}
++
++static int
++kmi_mouse_fasync(int fd, struct file *filp, int on)
++{
++	int retval = fasync_helper(fd, filp, on, &queue->fasync);
++	if (retval > 0)
++		retval = 0;
++	return retval;
++}
++
++static struct file_operations ps_fops = {
++	read:		kmi_mouse_read,
++	write:		kmi_mouse_write,
++	poll:		kmi_mouse_poll,
++	open:		kmi_mouse_open,
++	release:	kmi_mouse_release,
++	fasync: 	kmi_mouse_fasync,
++};
++
++static struct miscdevice ps_mouse = {
++	minor:		PSMOUSE_MINOR,
++	name:		"psaux",
++	fops:		&ps_fops,
++};
++
++static u_char kmi_mse_init_string[] = {
++	PS2_O_DISABLE,
++	PS2_O_SET_SAMPLE, 100,
++	PS2_O_SET_RES, 3,
++	PS2_O_SET_SCALE21
++};
++
++/*
++ * The "normal" mouse scancode processing
++ */
++static void kmi_mse_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs)
++{
++	u_int head;
++
++	add_mouse_randomness(val);
++
++#ifdef CONFIG_AMBA_PS2_RECONNECT
++	/* Try to detect a hot-plug event on the PS/2 mouse port */
++	switch (kmi->hotplug_state) {
++	case 0:
++		/* Maybe we lost contact... */
++		if (val == PS2_I_BAT_OK) {
++			kmi->hotplug_state++;
++			DEBUG(("%s: Saw 0xAA. Going to hotplug state %d\n", kmi->name, kmi->hotplug_state));
++		}
++		break;
++
++	case 1:
++		/* Again, maybe (but only maybe) we lost contact... */
++		if (val == 0) {
++			kmi->hotplug_state++;
++			kmi_send(kmi, PS2_O_REQ_STATUS);
++			DEBUG(("%s: Got 0xAA 0x00. Sent Status Request\n", kmi->name));
++		} else {
++			kmi->hotplug_state = 0;
++			DEBUG(("%s: No 0x00 followed 0xAA. No reconnect.\n", kmi->name));
++		}
++		break;
++
++	case 2:
++		/* Eat up acknowledge */
++		if (val == PS2_I_ACK)
++			kmi->hotplug_state++;
++		else {
++			kmi->hotplug_state = 0;
++			DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));
++		}
++		break;
++
++	case 3:
++		/* check if data reporting is still enabled, then no POR has happend */
++		kmi->reconnect = !(val & 1<<5);
++		DEBUG(("%s: Data reporting disabled?: (%d)\n", kmi->name, kmi->reconnect));
++		kmi->hotplug_state++;
++		DEBUG(("%s: Going to hotplug state %d\n", kmi->name, kmi->hotplug_state));
++		break;
++
++	case 4:
++		/* Eat up one status byte */
++		kmi->hotplug_state++;
++		DEBUG(("%s: Going to hotplug state %d\n", kmi->name, kmi->hotplug_state));
++		break;
++
++	case 5:
++		/* Eat up another status byte */
++		if (kmi->reconnect) {
++			kmi->config_num = 0;
++			kmi_send(kmi, kmi_mse_init_string[kmi->config_num]);
++			kmi->config_num++;
++			kmi->hotplug_state++;
++			DEBUG(("%s: Sending byte %d of PS/2 init string.\n", kmi->name, kmi->config_num));
++		} else {
++			kmi->hotplug_state = 0;
++			DEBUG(("%s: False Alarm...\n", kmi->name));
++		}
++		break;
++
++	case 6:
++		if (val == PS2_I_ACK && kmi->config_num < sizeof(kmi_mse_init_string)) {
++			kmi_send(kmi, kmi_mse_init_string[kmi->config_num]);
++			kmi->config_num++;
++			DEBUG(("%s: Sending byte %d of PS/2 init string.\n", kmi->name, kmi->config_num));
++		} else {
++			if (val == PS2_I_ACK) {
++				DEBUG(("%s: Now enable the mouse again...\n", kmi->name));
++				queue->head = queue->tail = 0;
++				kmi_send(kmi, PS2_O_ENABLE);
++				kmi->hotplug_state++;
++			} else {
++				kmi->hotplug_state = 0;
++				DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));
++			}
++		}
++		break;
++
++	case 7:
++		/* Eat up last acknowledge from enable */
++		if (val == PS2_I_ACK)
++			printk(KERN_ERR "%s: reconnected\n", kmi->name);
++		else
++			DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));
++
++		kmi->hotplug_state = 0;
++		break;
++
++	} /* switch (kmi->hotplug_state) */
++
++	/* while inside hotplug mechanism, don't misinterpret values */
++	if (kmi->hotplug_state > 2)
++		return;
++#endif
++
++	/* We are waiting for the mouse to respond to a kmi_send_and_wait() */
++	if (kmi->res == KMI_NO_ACK) {
++		if (val == PS2_I_RESEND) {
++			if (kmi->resend_count < 5)
++				__kmi_send(kmi, kmi->last_tx);
++			else {
++				printk(KERN_ERR "%s: too many resends\n", kmi->name);
++				return;
++			}
++		}
++
++		if (val == PS2_I_ACK) {
++			kmi->res = val;
++			wake_up(&kmi->wait_q);
++		}
++		return;
++	}
++
++	/* The mouse autonomously send new data, so wake up mouse_read() */
++	if (queue) {
++		head = queue->head;
++		queue->buf[head] = val;
++		head = (head + 1) & (BUF_SZ - 1);
++		if (head != queue->tail) {
++			queue->head = head;
++			kill_fasync(&queue->fasync, SIGIO, POLL_IN);
++			wake_up_interruptible(&kmi->wait_q);
++		}
++	}
++}
++
++static int kmi_init_mouse(struct kmi_info *kmi)
++{
++	u_int ret, i;
++
++	if (kmi->present) {
++		kmi->rx = kmi_mse_intr;
++
++		for (i = 0; i < sizeof(kmi_mse_init_string); i++) {
++			ret = kmi_send_and_wait(kmi, kmi_mse_init_string[i], HZ);
++			if (ret != PS2_I_ACK)
++				printk("%s: didn't get ack (0x%2.2x)\n",
++					kmi->name, ret);
++		}
++	}
++
++	queue = kmalloc(sizeof(*queue), GFP_KERNEL);
++	if (queue) {
++		memset(queue, 0, sizeof(*queue));
++		misc_register(&ps_mouse);
++		ret = 0;
++	} else
++		ret = -ENOMEM;
++
++	return ret;
++}
++#endif /* CONFIG_KMI_MOUSE */
++
++/*
++ * The "program" we send to the keyboard to set it up how we want it:
++ *  - default typematic delays
++ *  - scancode set 1
++ */
++static u_char kmi_kbd_init_string[] = {
++	PS2_O_DISABLE,
++	PS2_O_SET_DEFAULT,
++	PS2_O_SET_SCANSET, 0x01,
++	PS2_O_ENABLE
++};
++
++static void kmi_kbd_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs);
++
++static int __kmi_init_keyboard(struct kmi_info *kmi)
++{
++	u_int ret, i;
++
++	if (!kmi->present)
++		return 0;
++
++	kmi->rx = kmi_kbd_intr;
++
++	for (i = 0; i < sizeof(kmi_kbd_init_string); i++) {
++		ret = kmi_send_and_wait(kmi, kmi_kbd_init_string[i], HZ);
++		if (ret != PS2_I_ACK)
++			printk("%s: didn't ack (0x%2.2x)\n",
++				kmi->name, ret);
++	}
++
++	return 0;
++}
++
++static void kmi_kbd_init_tasklet(unsigned long k)
++{
++	struct kmi_info *kmi = (struct kmi_info *)k;
++	__kmi_init_keyboard(kmi);
++}
++
++static DECLARE_TASKLET_DISABLED(kmikbd_init_tasklet, kmi_kbd_init_tasklet, 0);
++
++/*
++ * The "normal" keyboard scancode processing
++ */
++static void kmi_kbd_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs)
++{
++#ifdef CONFIG_AMBA_PS2_RECONNECT
++	/* Try to detect a hot-plug event on the PS/2 keyboard port */
++	switch (kmi->hotplug_state) {
++	case 0:
++		/* Maybe we lost contact... */
++		if (val == PS2_I_BAT_OK) {
++			kmi_send(kmi, PS2_O_SET_SCANSET);
++			kmi->hotplug_state++;
++			DEBUG(("%s: Saw 0xAA. Going to hotplug state %d\n", kmi->name, kmi->hotplug_state));
++		}
++		break;
++
++	case 1:
++		/* Eat up acknowledge */
++		if (val == PS2_I_ACK) {
++			/* Request scan code set: '2' if POR has happend, '1' is false alarm */
++			kmi_send(kmi, 0);
++			kmi->hotplug_state++;
++		}
++		else {
++			kmi->hotplug_state = 0;
++			DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));
++		}
++		break;
++
++	case 2:
++		/* Eat up acknowledge */
++		if (val == PS2_I_ACK)
++			kmi->hotplug_state++;
++		else {
++			kmi->hotplug_state = 0;
++			DEBUG(("%s: didn't get ack (0x%2.2x)\n", kmi->name, val));
++		}
++		break;
++
++	case 3:
++		kmi->hotplug_state = 0;
++		if (val == 2) {
++			DEBUG(("%s: POR detected. Scan code is: (%d)\n", kmi->name, val));
++			kmi->present = 1;
++			tasklet_schedule(&kmikbd_init_tasklet);
++			printk(KERN_ERR "%s: reconnected\n", kmi->name);
++			return;
++		}
++		else
++			DEBUG(("%s: False Alarm...\n", kmi->name));
++		break;
++
++	} /* switch (kmi->hotplug_state) */
++#endif
++
++	if (val == PS2_I_DIAGFAIL) {
++		printk(KERN_ERR "%s: diagnostic failed\n", kmi->name);
++		return;
++	}
++
++	/* We are waiting for the keyboard to respond to a kmi_send_and_wait() */
++	if (kmi->res == KMI_NO_ACK) {
++		if (val == PS2_I_RESEND) {
++			if (kmi->resend_count < 5)
++				__kmi_send(kmi, kmi->last_tx);
++			else {
++				printk(KERN_ERR "%s: too many resends\n", kmi->name);
++				return;
++			}
++		}
++
++		if (val >= 0xee) {
++			kmi->res = val;
++			wake_up(&kmi->wait_q);
++		}
++		return;
++	}
++
++#ifdef CONFIG_VT
++	kbd_pt_regs = regs;
++	handle_scancode(val, !(val & 0x80));
++	tasklet_schedule(&keyboard_tasklet);
++#endif
++}
++
++static void kmi_intr(int nr, void *devid, struct pt_regs *regs)
++{
++	struct kmi_info *kmi = devid;
++	u_int status = __raw_readb(KMIIR);
++
++	if (status & KMIIR_RXINTR) {
++		u_int val = __raw_readb(KMIDATA);
++
++		if (kmi->rx)
++			kmi->rx(kmi, val, regs);
++	}
++}
++
++static int kmi_init_keyboard(struct kmi_info *kmi)
++{
++	kmikbd_init_tasklet.data = (unsigned long)kmi;
++	tasklet_enable(&kmikbd_init_tasklet);
++
++	return __kmi_init_keyboard(kmi);
++}
++
++/*
++ * Reset interrupt handler
++ */
++static void __init
++kmi_reset_intr(struct kmi_info *kmi, u_int val, struct pt_regs *regs)
++{
++	if (kmi->state == KMI_RESET) {
++		if (val == PS2_I_ACK)
++			kmi->state = KMI_RESET_POR;
++		else {
++			val = KMI_NO_ACK;
++			goto finished;
++		}
++	} else if (kmi->state == KMI_RESET_POR) {
++finished:
++		kmi->res = val;
++		kmi->state = KMI_RESET_DONE;
++		kmi->rx = NULL;
++		wake_up(&kmi->wait_q);
++	}
++}
++
++/*
++ * Reset the device plugged into this interface
++ */
++static int __init kmi_reset(struct kmi_info *kmi)
++{
++	u_int res;
++	int ret = 0;
++
++	kmi->state = KMI_RESET;
++	kmi->rx = kmi_reset_intr;
++	res = kmi_send_and_wait(kmi, PS2_O_RESET, HZ);
++	kmi->rx = NULL;
++
++	if (res != PS2_I_BAT_OK) {
++		printk(KERN_ERR "%s: reset failed; ", kmi->name);
++		if (kmi->res != KMI_NO_ACK)
++			printk("code 0x%2.2x\n", kmi->res);
++		else
++			printk("no ack\n");
++		ret = -EINVAL;
++	}
++	return ret;
++}
++
++static int __init kmi_init_one_interface(struct kmi_info *kmi)
++{
++	u_int stat;
++	int ret = -ENODEV;
++
++	init_waitqueue_head(&kmi->wait_q);
++
++	printk(KERN_INFO "%s at 0x%8.8x on irq %d (%s)\n", kmi->name,
++		kmi->base, kmi->irq, kmi_type[kmi->type]);
++
++	/*
++	 * Initialise the KMI interface
++	 */
++	__raw_writeb(kmi->divisor, KMICLKDIV);
++	__raw_writeb(KMICR_EN, KMICR);
++
++	/*
++	 * Check that the data and clock lines are OK.
++	 */
++	stat = __raw_readb(KMISTAT);
++	if ((stat & (KMISTAT_IC|KMISTAT_ID)) != (KMISTAT_IC|KMISTAT_ID)) {
++		printk(KERN_ERR "%s: %s%s%sline%s stuck low\n", kmi->name,
++			(stat & KMISTAT_IC) ? "" : "clock ",
++			(stat & (KMISTAT_IC | KMISTAT_ID)) ? "" : "and ",
++			(stat & KMISTAT_ID) ? "" : "data ",
++			(stat & (KMISTAT_IC | KMISTAT_ID)) ? "" : "s");
++		goto bad;
++	}
++
++	/*
++	 * Claim the appropriate interrupts
++	 */
++	ret = request_irq(kmi->irq, kmi_intr, 0, kmi->name, kmi);
++	if (ret)
++		goto bad;
++
++	/*
++	 * Enable the receive interrupt, and reset the device.
++	 */
++	__raw_writeb(KMICR_EN | KMICR_RXINTREN, KMICR);
++	kmi->present = 1;
++	kmi->present = kmi_reset(kmi) == 0;
++
++	switch (kmi->type) {
++	case KMI_KEYBOARD:
++		ret = kmi_init_keyboard(kmi);
++		break;
++
++#ifdef CONFIG_KMI_MOUSE
++	case KMI_MOUSE:
++		ret = kmi_init_mouse(kmi);
++		break;
++#endif
++	}
++
++	return ret;
++
++bad:
++	/*
++	 * Oh dear, the interface was bad, disable it.
++	 */
++	__raw_writeb(0, KMICR);
++	return ret;
++}
++
++#ifdef CONFIG_VT
++/*
++ * The fragment between #ifdef above and #endif * CONFIG_VT *
++ * is from the pc_keyb.c driver.  It is not copyrighted under the
++ * above notice.  This code is by various authors; please see
++ * drivers/char/pc_keyb.c for further information.
++ */
++
++/*
++ * Translation of escaped scancodes to keycodes.
++ * This is now user-settable.
++ * The keycodes 1-88,96-111,119 are fairly standard, and
++ * should probably not be changed - changing might confuse X.
++ * X also interprets scancode 0x5d (KEY_Begin).
++ *
++ * For 1-88 keycode equals scancode.
++ */
++
++#define E0_KPENTER 96
++#define E0_RCTRL   97
++#define E0_KPSLASH 98
++#define E0_PRSCR   99
++#define E0_RALT    100
++#define E0_BREAK   101	/* (control-pause) */
++#define E0_HOME    102
++#define E0_UP	   103
++#define E0_PGUP    104
++#define E0_LEFT    105
++#define E0_RIGHT   106
++#define E0_END	   107
++#define E0_DOWN    108
++#define E0_PGDN    109
++#define E0_INS	   110
++#define E0_DEL	   111
++
++#define E1_PAUSE   119
++
++/* BTC */
++#define E0_MACRO   112
++/* LK450 */
++#define E0_F13	   113
++#define E0_F14	   114
++#define E0_HELP    115
++#define E0_DO	   116
++#define E0_F17	   117
++#define E0_KPMINPLUS 118
++/*
++ * My OmniKey generates e0 4c for  the "OMNI" key and the
++ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
++ */
++#define E0_OK	124
++/*
++ * New microsoft keyboard is rumoured to have
++ * e0 5b (left window button), e0 5c (right window button),
++ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
++ * [or: Windows_L, Windows_R, TaskMan]
++ */
++#define E0_MSLW 125
++#define E0_MSRW 126
++#define E0_MSTM 127
++
++static u_char e0_keys[128] = {
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	E0_KPENTER,	E0_RCTRL,	0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		E0_KPSLASH,	0,		E0_PRSCR,
++	E0_RALT,	0,		0,		0,
++	0,		E0_F13, 	E0_F14, 	E0_HELP,
++	E0_DO,		E0_F17, 	0,		0,
++	0,		0,		E0_BREAK,	E0_HOME,
++	E0_UP,		E0_PGUP,	0,		E0_LEFT,
++	E0_OK,		E0_RIGHT,	E0_KPMINPLUS,	E0_END,
++	E0_DOWN,	E0_PGDN,	E0_INS, 	E0_DEL,
++	0,		0,		0,		0,
++	0,		0,		0,		E0_MSLW,
++	E0_MSRW,	E0_MSTM,	0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		E0_MACRO,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0,
++	0,		0,		0,		0
++};
++
++#ifdef CONFIG_MAGIC_SYSRQ
++u_char kmi_kbd_sysrq_xlate[128] =
++	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
++	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
++	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
++	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
++	"\206\207\210\211\212\000\000789-456+1" 	/* 0x40 - 0x4f */
++	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
++	"\r\000/";					/* 0x60 - 0x6f */
++#endif
++
++int kmi_kbd_setkeycode(u_int scancode, u_int keycode)
++{
++	if (scancode < 128 || scancode > 255 || keycode > 127)
++		return -EINVAL;
++	e0_keys[scancode - 128] = keycode;
++	return 0;
++}
++
++int kmi_kbd_getkeycode(u_int scancode)
++{
++	if (scancode < 128 || scancode > 255)
++		return -EINVAL;
++	return e0_keys[scancode - 128];
++}
++	        
++int kmi_kbd_translate(u_char scancode, u_char *keycode, char raw_mode)
++{
++	static int prev_scancode = 0;
++
++	/* special prefix scancodes.. */
++	if (scancode == 0xe0 || scancode == 0xe1) {
++		prev_scancode = scancode;
++		return 0;
++	}
++
++	/* 0xff is sent by a few keyboards, ignore it.	0x00 is error */
++	if (scancode == 0x00 || scancode == 0xff) {
++		prev_scancode = 0;
++		return 0;
++	}
++
++	scancode &= 0x7f;
++
++	if (prev_scancode) {
++		int old_scancode = prev_scancode;
++
++		prev_scancode = 0;
++		switch (old_scancode) {
++		case 0xe0:
++			/*
++			 * The keyboard maintains its own internal caps lock
++			 * and num lock status.  In caps lock mode, E0 AA
++			 * precedes make code and E0 2A follows break code.
++			 * In numlock mode, E0 2A precedes make code, and
++			 * E0 AA follows break code.  We do our own book-
++			 * keeping, so we will just ignore these.
++			 *
++			 * For my keyboard there is no caps lock mode, but
++			 * there are both Shift-L and Shift-R modes. The
++			 * former mode generates E0 2A / E0 AA pairs, the
++			 * latter E0 B6 / E0 36 pairs.	So, we should also
++			 * ignore the latter. - aeb@cwi.nl
++			 */
++			if  (scancode == 0x2a || scancode == 0x36)
++				return 0;
++			if (e0_keys[scancode])
++				*keycode = e0_keys[scancode];
++			else {
++				if (!raw_mode)
++					printk(KERN_INFO "kbd: unknown "
++						"scancode e0 %02x\n",
++						scancode);
++				return 0;
++			}
++			break;
++
++		case 0xe1:
++			if (scancode == 0x1d)
++				prev_scancode = 0x100;
++			else {
++				if (!raw_mode)
++					printk(KERN_INFO "kbd: unknown "
++						"scancode e1 %02x\n",
++						scancode);
++				return 0;
++			}
++			break;
++
++		case 0x100:
++			if (scancode == 0x45)
++				*keycode = E1_PAUSE;
++			else {
++				if (!raw_mode)
++					printk(KERN_INFO "kbd: unknown "
++						"scan code e1 1d %02x\n",
++						scancode);
++				return 0;
++			}
++			break;
++		}
++	} else
++		*keycode = scancode;
++	return 1;
++}
++
++char kmi_kbd_unexpected_up(u_char keycode)
++{
++	return 0x80;
++}
++
++void kmi_kbd_leds(u_char leds)
++{
++	struct kmi_info *kmi = kmi_keyb;
++	u_int ret;
++
++	if (kmi) {
++		ret = kmi_send_and_wait(kmi, PS2_O_INDICATORS, HZ);
++		if (ret != KMI_NO_ACK)
++			ret = kmi_send_and_wait(kmi, leds, HZ);
++		if (ret == KMI_NO_ACK)
++			kmi->present = 0;
++	}
++}
++
++int __init kmi_kbd_init(void)
++{
++	int  ret = -ENODEV;
++
++	if (kmi_keyb) {
++		strcpy(kmi_keyb->name, "kmikbd");
++		ret = kmi_init_one_interface(kmi_keyb);
++	}
++
++	if (ret == 0) {
++		k_setkeycode	= kmi_kbd_setkeycode;
++		k_getkeycode	= kmi_kbd_getkeycode;
++		k_translate	= kmi_kbd_translate;
++		k_unexpected_up = kmi_kbd_unexpected_up;
++		k_leds		= kmi_kbd_leds;
++#ifdef CONFIG_MAGIC_SYSRQ
++		k_sysrq_xlate	= kmi_kbd_sysrq_xlate;
++		k_sysrq_key	= 0x54;
++#endif
++	}
++
++	return ret;
++}
++
++#endif /* CONFIG_VT */
++
++int register_kmi(struct kmi_info *kmi)
++{
++	struct kmi_info **kmip = NULL;
++	int ret;
++
++	if (kmi->type == KMI_KEYBOARD)
++		kmip = &kmi_keyb;
++	else if (kmi->type == KMI_MOUSE)
++		kmip = &kmi_mouse;
++
++	ret = -EINVAL;
++	if (kmip) {
++		ret = -EBUSY;
++		if (!*kmip) {
++			*kmip = kmi;
++			ret = 0;
++		}
++	}
++
++	return ret;
++}
++
++#ifdef CONFIG_KMI_MOUSE
++static int __init kmi_init(void)
++{
++	int  ret = -ENODEV;
++
++	if (kmi_mouse) {
++		strcpy(kmi_mouse->name, "kmimouse");
++		ret = kmi_init_one_interface(kmi_mouse);
++	}
++
++	return ret;
++}
++
++__initcall(kmi_init);
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/anakin_ts.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ *  linux/drivers/char/anakin_ts.c
++ *
++ *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Changelog:
++ *   18-Apr-2001 TTC	Created
++ *   23-Oct-2001 dwmw2	Cleanup
++ */
++
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/wait.h>
++#include <linux/fs.h>
++#include <linux/sched.h>
++#include <linux/poll.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <linux/compiler.h>
++#include <linux/interrupt.h>
++
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++
++/*
++ * TSBUF_SIZE must be a power of two
++ */
++#define ANAKIN_TS_MINOR	16
++#define TSBUF_SIZE	256
++#define NEXT(index)	(((index) + 1) & (TSBUF_SIZE - 1))
++
++static unsigned short buffer[TSBUF_SIZE][4];
++static int head, tail;
++static DECLARE_WAIT_QUEUE_HEAD(queue);
++static DECLARE_MUTEX(open_sem);
++static spinlock_t tailptr_lock = SPIN_LOCK_UNLOCKED;
++static struct fasync_struct *fasync;
++
++/*
++ * Interrupt handler and standard file operations
++ */
++static void
++anakin_ts_handler(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned int status = __raw_readl(IO_BASE + IO_CONTROLLER + 0x24);
++
++	/*
++	 * iPAQ format (u16 pressure, x, y, millisecs)
++	 */
++	switch (status >> 20 & 3) {
++	case 0:
++		return;
++	case 2:
++		buffer[head][0] = 0;
++		break;
++	default:
++		buffer[head][0] = 0x7f;
++	}
++
++	if (unlikely((volatile int)tail == NEXT(head))) {
++		/* Run out of space in the buffer. Move the tail pointer */
++		spin_lock(&tailptr_lock);
++
++		if ((volatile int)tail == NEXT(head)) {
++			tail = NEXT(NEXT(head));
++		}
++		spin_unlock(&tailptr_lock);
++	}
++
++	buffer[head][1] = status >> 2 & 0xff;
++	buffer[head][2] = status >> 12 & 0xff;
++	buffer[head][3] = jiffies;
++	mb();
++	head = NEXT(head);
++
++	wake_up_interruptible(&queue);
++	kill_fasync(&fasync, SIGIO, POLL_IN);
++
++}
++
++static ssize_t
++anakin_ts_read(struct file *filp, char *buf, size_t count, loff_t *l)
++{
++	unsigned short data[4];
++	ssize_t written = 0;
++
++	if (head == tail) {
++		if (filp->f_flags & O_NONBLOCK)
++			return -EAGAIN;
++		if (wait_event_interruptible(queue, (volatile int)head != (volatile int)tail))
++			return -ERESTARTSYS;
++	}
++
++	while ((volatile int)head != (volatile int)tail && count >= sizeof data) {
++		/* Copy the data out with the spinlock held, so the 
++		   interrupt can't fill the buffer and move the tail 
++		   pointer while we're doing it */
++		spin_lock_irq(&tailptr_lock);
++
++		memcpy(data, buffer[tail], sizeof data);
++		tail = NEXT(tail);
++
++		spin_unlock_irq(&tailptr_lock);
++
++		if (copy_to_user(buf, data, sizeof data))
++			return -EFAULT;
++		count -= sizeof data;
++		buf += sizeof data;
++		written += sizeof data;
++	}
++	return written ? written : -EINVAL;
++}
++
++static unsigned int
++anakin_ts_poll(struct file *filp, poll_table *wait)
++{
++	poll_wait(filp, &queue, wait);
++	return head != tail ? POLLIN | POLLRDNORM : 0;
++}
++
++static int
++anakin_ts_ioctl(struct inode *inode, struct file *filp,
++		unsigned int cmd, unsigned long arg)
++{
++	/*
++	 * Future ioctl goes here
++	 */
++	return 0;
++}
++
++static int
++anakin_ts_open(struct inode *inode, struct file *filp)
++{
++	if (down_trylock(&open_sem))
++		return -EBUSY;
++	return 0;
++}
++
++static int
++anakin_ts_fasync(int fd, struct file *filp, int on)
++{
++	return fasync_helper(fd, filp, on, &fasync);
++}
++
++static int
++anakin_ts_release(struct inode *inode, struct file *filp)
++{
++	anakin_ts_fasync(-1, filp, 0);
++	up(&open_sem);
++	return 0;
++}
++
++static struct file_operations anakin_ts_fops = {
++	owner:		THIS_MODULE,
++	read:		anakin_ts_read,
++	poll:		anakin_ts_poll,
++	ioctl:		anakin_ts_ioctl,
++	open:		anakin_ts_open,
++	release:	anakin_ts_release,
++	fasync:		anakin_ts_fasync,
++};
++
++static struct miscdevice anakin_ts_miscdev = {
++        ANAKIN_TS_MINOR,
++        "anakin_ts",
++        &anakin_ts_fops
++};
++
++/*
++ * Initialization and exit routines
++ */
++int __init
++anakin_ts_init(void)
++{
++	int retval;
++
++	if ((retval = request_irq(IRQ_TOUCHSCREEN, anakin_ts_handler,
++			SA_INTERRUPT, "anakin_ts", 0))) {
++		printk(KERN_WARNING "anakin_ts: failed to get IRQ\n");
++		return retval;
++	}
++	__raw_writel(1, IO_BASE + IO_CONTROLLER + 8);
++	misc_register(&anakin_ts_miscdev);
++
++	printk(KERN_NOTICE "Anakin touchscreen driver initialised\n");
++
++	return 0;
++}
++
++void __exit
++anakin_ts_exit(void)
++{
++	__raw_writel(0, IO_BASE + IO_CONTROLLER + 8);
++	free_irq(IRQ_TOUCHSCREEN, 0);
++	misc_deregister(&anakin_ts_miscdev);
++}
++
++module_init(anakin_ts_init);
++module_exit(anakin_ts_exit);
++
++MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");
++MODULE_DESCRIPTION("Anakin touchscreen driver");
++MODULE_SUPPORTED_DEVICE("touchscreen/anakin");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/cerf_keyb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,380 @@
++/*
++   cerf_keyb.c: This is the end. Daniel is writing a device driver!!!
++*/
++#include <linux/config.h>
++
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/mm.h>
++#include <linux/signal.h>
++#include <linux/init.h>
++#include <linux/kbd_ll.h>
++#include <linux/delay.h>
++#include <linux/random.h>
++#include <linux/poll.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/kbd_kern.h>
++#include <linux/smp_lock.h>
++#include <linux/timer.h>
++
++#include <asm/keyboard.h>
++#include <asm/bitops.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++
++#include <asm/io.h>
++
++#define KBD_REPORT_UNKN
++
++#define KBD_REPORT_ERR			/* Report keyboard errors */
++#define KBD_REPORT_UNKN                 /* Report unknown scan codes */
++#define KBD_REPORT_TIMEOUTS		/* Report keyboard timeouts */
++#define KBD_NO_DATA         (-1)        /* No data */
++#define KBD_REPEAT_START    (0x20)
++#define KBD_REPEAT_CONTINUE (0x05)
++#define KBD_KEY_DOWN_MAX    (0x10)
++#define UINT_LEN            (20)
++#define SC_LIM              (69)
++#define KBD_ROWS            (5)
++#define KBD_COLUMNS         (8)
++
++#define KBD_KEYUP           (0x80)
++#define KBD_MODESCAN        (0x7f)
++#define KBD_CAPSSCAN        (0x3a)
++#define KBD_SHIFTSCAN       (0x2a)
++#define KBD_NUMCURSCAN      (0x7c)
++#define KBD_CTRLSCAN        (0x1d)
++#define KBD_ALTSCAN         (0x38)
++
++#define KBD_UP_OFF          (0)
++#define KBD_UP_ON           (1)
++#define KBD_DOWN            (2)
++#define KBD_DOWN_HOLD       (3)
++
++
++
++static unsigned char handle_kbd_event(void);
++static unsigned char kbd_read_input(void);
++static void column_set(unsigned int column);
++static int scancodes(unsigned char codeval[KBD_ROWS][KBD_COLUMNS]);
++
++static spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
++static struct timer_list kbd_timer;
++
++static short mode_ena = 0;
++static short numcur_ena = 0;
++static short shift_ena = 0;
++
++#define E0_KPENTER 96
++#define E0_RCTRL   97
++#define E0_KPSLASH 98
++#define E0_PRSCR   99
++#define E0_RALT    100
++#define E0_BREAK   101  /* (control-pause) */
++#define E0_HOME    102
++#define E0_UP      103
++#define E0_PGUP    104
++#define E0_LEFT    105
++#define E0_RIGHT   106
++#define E0_END     107
++#define E0_DOWN    108
++#define E0_PGDN    109
++#define E0_INS     110
++#define E0_DEL     111
++#define E1_PAUSE   119
++#define E0_MACRO   112
++#define E0_F13     113
++#define E0_F14     114
++#define E0_HELP    115
++#define E0_DO      116
++#define E0_F17     117
++#define E0_KPMINPLUS 118
++#define E0_OK      124
++#define E0_MSLW    125
++#define E0_MSRW    126
++#define E0_MSTM    127
++
++static unsigned char e0_keys[128] = {
++  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x00-0x07 */
++  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x08-0x0f */
++  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x10-0x17 */
++  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,             /* 0x18-0x1f */
++  0, 0, 0, 0, 0, 0, 0, 0,                       	/* 0x20-0x27 */
++  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x28-0x2f */
++  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,             /* 0x30-0x37 */
++  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,       /* 0x38-0x3f */
++  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,       /* 0x40-0x47 */
++  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
++  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,       /* 0x50-0x57 */
++  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,           /* 0x58-0x5f */
++  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x60-0x67 */
++  0, 0, 0, 0, 0, 0, 0, E0_MACRO,                      /* 0x68-0x6f */
++  0, 0, 0, 0, 0, 0, 0, 0,                             /* 0x70-0x77 */
++  0, 0, 0, 0, 0, 0, 0, 0                              /* 0x78-0x7f */
++};
++
++static unsigned char cerf_normal_map[KBD_ROWS][KBD_COLUMNS] = {
++   {KBD_ALTSCAN, KBD_MODESCAN, 0x1e, 0x30, 0x2e, 0x20, 0x00, 0x00},
++   {0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x00},
++   {0x26, 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x00},
++   {0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x00},
++   {0x2c, KBD_SHIFTSCAN, KBD_CTRLSCAN, 0x39, KBD_NUMCURSCAN, 0x2b, 0x1c, 0x00}
++};
++
++static unsigned char cerf_mode_map[KBD_ROWS][KBD_COLUMNS] = {
++   {0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00},
++   {0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00}, //
++   {0x0d, 0x0c, 0x37, 0x35, 0x0d, 0x48, 0x28, 0x00},
++   {0x01, 0x33, 0x34, 0x00, 0x4b, 0x27, 0x4d, 0x00}, //
++   {0x0f, 0x00, KBD_CAPSSCAN, 0x0e, 0x00, 0x50, 0x00, 0x00}
++};
++
++static unsigned char cerf_numcur_map[KBD_ROWS][KBD_COLUMNS] = {
++   {0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x00, 0x00},
++   {0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00},
++   {0x0d, 0x0c, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00},
++   {0x00, 0x00, 0x00, 0x00, 0x4b, 0x00, 0x4d, 0x00},
++   {0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00}
++};
++
++static void column_set(unsigned int column)
++{
++   if (column < 0)
++   {
++      CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_A, 0xFF, 0xFF);
++      CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_B, 0xFF, 0xFF);
++   }
++   else
++   {
++      if(column < 4)
++      {
++         CERF_PDA_CPLD_Set(CERF_PDA_CPLD_KEYPAD_A, 1 << (column % 4), 0xFF);
++         CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_B, 0xFF, 0xFF);
++      }
++      else
++      {
++         CERF_PDA_CPLD_UnSet(CERF_PDA_CPLD_KEYPAD_A, 0xFF, 0xFF);
++         CERF_PDA_CPLD_Set(CERF_PDA_CPLD_KEYPAD_B, 1 << (column % 4), 0xFF);
++      }
++   }
++}
++
++static int scancodes(unsigned char codeval[KBD_ROWS][KBD_COLUMNS])
++{
++   int i, j;
++
++   for(i = 0; i < KBD_COLUMNS; i++)
++   {
++      column_set(i);
++      udelay(50);
++      for(j = 0; j < KBD_ROWS; j++)
++      {
++         if(mode_ena)
++            codeval[j][i] = (GPLR & (1 << (20 + j)))?(cerf_mode_map[j][i]?cerf_mode_map[j][i]:cerf_normal_map[j][i]):0;
++         else if(numcur_ena)
++            codeval[j][i] = (GPLR & (1 << (20 + j)))?(cerf_numcur_map[j][i]?cerf_numcur_map[j][i]:cerf_normal_map[j][i]):0;
++         else
++            codeval[j][i] = (GPLR & (1 << (20 + j)))?cerf_normal_map[j][i]:0;
++      }
++   }
++   column_set(-1);
++
++   return 0;
++}
++
++static unsigned char kbd_read_input(void)
++{
++   int i, j, k, l;
++   unsigned char prev;
++   static unsigned char count = 0;
++
++   static unsigned char oldcodes[KBD_ROWS][KBD_COLUMNS]={{0,0,0,0,0,0,0,0},
++                                                         {0,0,0,0,0,0,0,0},
++                                                         {0,0,0,0,0,0,0,0},
++                                                         {0,0,0,0,0,0,0,0},
++                                                         {0,0,0,0,0,0,0,0}};
++   unsigned char inputcode[KBD_ROWS][KBD_COLUMNS];
++
++   memset(inputcode, 0, sizeof(unsigned char) * (KBD_ROWS * KBD_COLUMNS));
++   scancodes(inputcode);
++
++   for(i = 0; i < KBD_COLUMNS; i++)
++   {
++      for(j = 0; j < KBD_ROWS; j++)
++      {
++//         if(oldcodes[j][i] == 0xe0)
++//            oldcodes[j][i] =
++         if(oldcodes[j][i] != inputcode[j][i])
++         {
++            // Value of the key before entering this function
++            prev = oldcodes[j][i];
++
++            // KEYUP
++            if(inputcode[j][i] == 0 && oldcodes[j][i] != 0 && !(oldcodes[j][i] & KBD_KEYUP))
++            {
++               oldcodes[j][i] |= KBD_KEYUP;
++
++               if(mode_ena == KBD_UP_ON)
++                  mode_ena = KBD_UP_OFF;
++               if(prev == KBD_MODESCAN)
++                  if(mode_ena == KBD_DOWN_HOLD)
++                     mode_ena = KBD_UP_OFF;
++                  else if(mode_ena == KBD_DOWN)
++                     mode_ena = KBD_UP_ON;
++               if(mode_ena == KBD_DOWN)
++                  mode_ena = KBD_DOWN_HOLD;
++            }
++            // RESET KEYUP
++            else if(oldcodes[j][i] & KBD_KEYUP)
++               oldcodes[j][i] = 0;
++            // KEY DOWN
++            else
++            {
++               oldcodes[j][i] = inputcode[j][i];
++
++               // Parse out mode modifiers before the keyboard interpreter can touch them
++  	       if(inputcode[j][i] == KBD_MODESCAN)
++               {
++                  if(!mode_ena)
++                     mode_ena = KBD_DOWN;
++                  continue;
++               }
++               if(inputcode[j][i] == KBD_NUMCURSCAN)
++               {
++                  numcur_ena = numcur_ena?0:1;
++                  continue;
++               }
++            }
++            //printk("Modified: (%#x,%#x), ipv:%#x, To: (%#.2x), From: (%#.2x), Flags:%d,%d,%d\r\n", j, i, inputcode[j][i], oldcodes[j][i], prev, mode_ena, shift_ena, numcur_ena);
++            return oldcodes[j][i];
++         }
++      }
++   }
++
++   return (unsigned char)(KBD_NO_DATA);
++}
++
++int cerf_kbd_translate(unsigned char scancode, unsigned char *keycode,
++		    char raw_mode)
++{
++	static int prev_scancode;
++
++	if (scancode == 0xe0 || scancode == 0xe1) {
++		prev_scancode = scancode;
++		return 0;
++	}
++
++	if (scancode == 0x00 || scancode == 0xff) {
++		prev_scancode = 0;
++		return 0;
++	}
++
++	scancode &= 0x7f;
++
++	if (prev_scancode) {
++	  if (prev_scancode != 0xe0) {
++	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
++		  prev_scancode = 0x100;
++		  return 0;
++	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
++		  prev_scancode = 0;
++	      } else {
++#ifdef KBD_REPORT_UNKN
++		  if (!raw_mode)
++		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
++#endif
++		  prev_scancode = 0;
++		  return 0;
++	      }
++	  } else {
++	      prev_scancode = 0;
++	      if (scancode == 0x2a || scancode == 0x36)
++		return 0;
++	      else {
++#ifdef KBD_REPORT_UNKN
++		  if (!raw_mode)
++		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
++			   scancode);
++#endif
++		  return 0;
++	      }
++	  }
++ 	} else
++	  *keycode = scancode;
++ 	return 1;
++}
++
++static inline void handle_keyboard_event(unsigned char scancode)
++{
++   if(scancode != (unsigned char)(KBD_NO_DATA))
++   {
++#ifdef CONFIG_VT
++      handle_scancode(scancode, !(scancode & KBD_KEYUP));
++#endif
++      tasklet_schedule(&keyboard_tasklet);
++   }
++}
++
++static unsigned char handle_kbd_event(void)
++{
++   unsigned char scancode;
++
++   scancode = kbd_read_input();
++   handle_keyboard_event(scancode);
++
++   return 0;
++}
++
++/* Handle the automatic interrupts handled by the timer */
++static void keyboard_interrupt(unsigned long foo)
++{
++   spin_lock_irq(&kbd_controller_lock);
++   handle_kbd_event();
++   spin_unlock_irq(&kbd_controller_lock);
++
++   kbd_timer.expires = 8 + jiffies;
++   kbd_timer.data = 0x00000000;
++   kbd_timer.function = (void(*)(unsigned long))&keyboard_interrupt;
++
++   add_timer(&kbd_timer);
++}
++
++void cerf_leds(unsigned char leds)
++{
++}
++char cerf_unexpected_up(unsigned char keycode)
++{
++return 0;
++}
++int cerf_getkeycode(unsigned int scancode)
++{
++return 0;
++}
++int cerf_setkeycode(unsigned int scancode, unsigned int keycode)
++{
++return 0;
++}
++
++void cerf_kbd_init_hw(void)
++{
++   printk("Starting Cerf PDA Keyboard Driver... ");
++
++   k_setkeycode	= cerf_setkeycode;
++   k_getkeycode    = cerf_getkeycode;
++   k_translate     = cerf_kbd_translate;
++   k_unexpected_up = cerf_unexpected_up;
++   k_leds          = cerf_leds;
++
++   GPDR &= ~(GPIO_GPIO(20) | GPIO_GPIO(21) | GPIO_GPIO(22) | GPIO_GPIO(23) | GPIO_GPIO(24));
++   kbd_timer.expires = 40 + jiffies;
++   kbd_timer.data = 0x00000000;
++   kbd_timer.function = (void(*)(unsigned long))&keyboard_interrupt;
++
++   add_timer(&kbd_timer);
++
++   printk("Done\r\n");
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/clps711x_keyb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,547 @@
++/*
++ * drivers/char/clps711x_keyb.c
++ *
++ * Copyright (C) 2001 Thomas Gleixner <gleixner@autronix.de>
++ *
++ * based on drivers/edb7211_keyb.c, which is copyright (C) 2000 Bluemug Inc.
++ * 
++ * Keyboard driver for ARM Linux on EP7xxx and CS89712 processors
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation. See the file COPYING 
++ * in the main directory of this archive for more details.
++ *
++ *
++ * Hardware: 
++ *
++ * matrix scan keyboards based on EP7209,7211,7212,7312 and CS89712 
++ * on chip keyboard scanner.		
++ * Adaption for different machines is done in init function.
++ *
++ * Basic Function:
++ *
++ * Basicly the driver is interrupt driven. It sets all column drivers	
++ * high. If any key is pressed, a interrupt occures. Now a seperate scan of
++ * each column is done. This scan is timer based, because we use a keyboard 
++ * interface with decoupling capacitors (neccecary if you want to survive 
++ * EMC compliance tests). Always one line is set high. When next timer event 
++ * occures the scan data on port A are valid. This makes also sure, that no
++ * spurious keys are scanned. The kbd int on these CPU's is not deglitched!
++ * After scanning all columns, we switch back to int mode, if no key is
++ * pressed. If any is pressed we reschedule the scan within a programmable
++ * delay. If we would switch back to interrupt mode as long as a key is pressed,
++ * we come right back to the interrupt, because the int. is level triggered !
++ * The timer based scan of the seperate columns can also be done in one
++ * timer event (set fastscan to 1).
++ *
++ * Summary:
++ * The design of this keyboard controller chip is stupid at all !
++ *
++ * Matrix translation:
++ * The matrix translation table is based on standard XT scancodes. Maybe
++ * you have to adjust the KEYISPRINTABLE macro if you set other codes.
++ *
++ * HandyKey:
++ *
++ * On small matrix keyboards you don't have enough keys for operation.
++ * The intention was to implement a operation mode as it's used on handys.
++ * You can rotate trough four scancode levels and produce e.g. with a 4x3
++ * matrix 4*3*4 = 48 different keycodes. That's basicly enough for editing
++ * filenames or things like that. The HandyKey function takes care about 
++ * nonprintable keys like cursors, backspace, del ...
++ * If a key is pressed and is a printable keycode, the code is put to the
++ * main keyboard handler and a cursor left is applied. If you press the same
++ * key again, the current character is deleted and the next level character
++ * is applied. (e.g. 1, a, b, c, 1 ....). If you press a different key, the
++ * driver applies cursor right, before processing the new key.
++ * The autocomplete feature moves the cursor right, if you do not press a
++ * key within a programmable time.
++ * If HandyKey is off, the keyboard behaviour is that of a standard keyboard
++ * HandyKey can be en/disabled from userspace with the proc/keyboard entry
++ * 
++ * proc/keyboard:
++ * 
++ * Read access gives back the actual state of the HandyKey function	
++ *	h:0	Disabled
++ *	h:1	Enabled
++ * Write access has two functions. Changing the HandyKey mode and applying
++ * a different scancode translation table.
++ * Syntax is: 	h:0	disable Handykey
++ *		h:1	enabled Handykey
++ *		t:array[256] of bytes	Transfer translation table	
++ */
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/ptrace.h>
++#include <linux/signal.h>
++#include <linux/timer.h>
++#include <linux/tqueue.h>
++#include <linux/random.h>
++#include <linux/ctype.h>
++#include <linux/init.h>
++#include <linux/kbd_ll.h>
++#include <linux/kbd_kern.h>
++#include <linux/delay.h>
++#include <linux/proc_fs.h>
++
++#include <asm/bitops.h>
++#include <asm/keyboard.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/uaccess.h>
++
++#include <asm/io.h>
++#include <asm/system.h>
++
++void clps711x_kbd_init_hw(void);
++
++/*
++ * Values for the keyboard column scan control register.
++ */
++#define KBSC_HI	    0x0	    /*   All driven high */
++#define KBSC_LO	    0x1	    /*   All driven low */
++#define KBSC_X	    0x2	    /*   All high impedance */
++#define KBSC_COL0   0x8	    /*   Column 0 high, others high impedance */
++#define KBSC_COL1   0x9	    /*   Column 1 high, others high impedance */
++#define KBSC_COL2   0xa	    /*   Column 2 high, others high impedance */
++#define KBSC_COL3   0xb	    /*   Column 3 high, others high impedance */
++#define KBSC_COL4   0xc	    /*   Column 4 high, others high impedance */
++#define KBSC_COL5   0xd	    /*   Column 5 high, others high impedance */
++#define KBSC_COL6   0xe	    /*   Column 6 high, others high impedance */
++#define KBSC_COL7   0xf	    /*   Column 7 high, others high impedance */
++
++/*
++* Keycodes for cursor left/right and delete (used by HandyKey)	
++*/
++#define KEYCODE_CLEFT	0x4b
++#define KEYCODE_CRIGHT  0x4d
++#define KEYCODE_DEL	0x53
++#define KEYISPRINTABLE(code) ( (code > 0x01 && code < 0x37 && code != 0x1c \
++				 && code != 0x0e) || code == 0x39) 
++
++/* Simple translation table for the SysRq keys */
++#ifdef CONFIG_MAGIC_SYSRQ
++unsigned char clps711x_kbd_sysrq_xlate[128] =
++	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
++	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
++	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
++	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
++	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
++	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
++	"\r\000/";					/* 0x60 - 0x6f */
++#endif
++
++/* 
++ * This table maps row/column keyboard matrix positions to XT scancodes.
++ * It's a default table, which can be overriden by writing to proc/keyboard 
++ */
++#ifdef CONFIG_ARCH_AUTCPU12
++static unsigned char autcpu12_scancode[256] = 
++{
++/*  Column: 
++  Row       0     1     2     3     4     5     6     7   */
++/* A0 */  0x08, 0x09, 0x0a, 0x0e, 0x05, 0x06, 0x00, 0x00,
++/* A1 */  0x07, 0x53, 0x02, 0x03, 0x04, 0x0f, 0x00, 0x00,
++/* A2 */  0x0c, 0x0b, 0x33, 0x1c, 0xff, 0x4b, 0x00, 0x00,
++/* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
++/* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++
++/* A0 */  0x1e, 0x20, 0x22, 0x0e, 0x24, 0x32, 0x00, 0x00,
++/* A1 */  0x19, 0x53, 0x1f, 0x2f, 0x15, 0x0f, 0x00, 0x00,
++/* A2 */  0x0c, 0x39, 0x34, 0x1c, 0xff, 0x4b, 0x00, 0x00,
++/* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
++/* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++
++/* A0 */  0x30, 0x12, 0x23, 0x0e, 0x25, 0x31, 0x00, 0x00,
++/* A1 */  0x10, 0x53, 0x14, 0x11, 0x2c, 0x0f, 0x00, 0x00,
++/* A2 */  0x0c, 0x0b, 0x27, 0x1c, 0xff, 0x4b, 0x00, 0x00,
++/* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
++/* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++
++/* A0 */  0x2e, 0x21, 0x17, 0x0e, 0x26, 0x18, 0x00, 0x00,
++/* A1 */  0x13, 0x53, 0x16, 0x2D, 0x04, 0x0f, 0x00, 0x00,
++/* A2 */  0x0c, 0x39, 0x35, 0x1c, 0xff, 0x4b, 0x00, 0x00,
++/* A3 */  0x48, 0x50, 0x4d, 0x3b, 0x3c, 0x3d, 0x00, 0x00,
++/* A4 */  0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++};
++#endif
++
++static int keys[8];
++static int new_keys[8];
++static int previous_keys[8];
++
++static int fastscan;
++static int scan_interval;
++static int scan_delay;
++static int last_column; 
++static int key_is_pressed;
++
++static unsigned char *act_scancode;
++
++static struct kbd_handy_key {
++	int		ena;
++	int		code;
++	int		shift;
++	int		autocomplete;
++	unsigned long 	expires;
++	unsigned long	delay;
++	unsigned char 	left;
++	unsigned char	right;
++	unsigned char   del;
++} khandy;
++
++static struct tq_struct kbd_process_task;
++static struct timer_list clps711x_kbd_timer;
++static struct timer_list clps711x_kbdhandy_timer;
++static struct proc_dir_entry *clps711x_keyboard_proc_entry = NULL;
++
++/*
++ * Translate a raw keycode to an XT keyboard scancode.
++ */
++static int clps711x_translate(unsigned char scancode, unsigned char *keycode,
++		 		 char raw_mode)
++{
++	*keycode = act_scancode[scancode];
++	return 1;
++}
++
++/*
++* Initialize handykey structure
++* clear code, clear shift
++* scan scancode for cursor right/left and delete
++*/
++static void clps711x_handykey_init(void) {
++
++	int	i;
++
++	khandy.ena = 0;
++	khandy.code = 0;
++	khandy.shift = 0;
++	khandy.autocomplete = 0;
++	for(i = 0; i < 64; i++) {
++		switch(act_scancode[i]) {
++			case KEYCODE_CLEFT: 	khandy.left = i; break;	
++			case KEYCODE_CRIGHT: 	khandy.right = i; break;	
++			case KEYCODE_DEL: 	khandy.del = i; break;
++		}
++	}	
++} 
++
++/*
++* Check for handy key and process it	
++*/
++void inline clps711x_checkhandy(int col, int row) {
++
++	int scode, down;
++	unsigned char kcode;
++	
++	scode = (row<<3) + col;
++	down  = keys[col]>>row & 0x01;
++	kcode = act_scancode[scode];
++	
++	if (!khandy.ena) {
++		if (khandy.code) {			
++			handle_scancode(khandy.right,1);
++			handle_scancode(khandy.right,0);
++		}
++		khandy.code = 0;
++		khandy.shift = 0;
++		khandy.autocomplete = 0;
++	}
++
++	if(!kcode)
++		return;
++
++	if (!down || !khandy.ena) {
++		if (khandy.ena && KEYISPRINTABLE(act_scancode[scode]))
++			khandy.autocomplete = 1;
++		else
++			handle_scancode(scode + khandy.shift, down);
++		return;	
++	}
++	
++	khandy.autocomplete = 0;
++	if (KEYISPRINTABLE(kcode)) {
++		if (khandy.code) {	
++			if(khandy.code == (scode|0x100)) {
++				handle_scancode(khandy.del,1);
++				handle_scancode(khandy.del,0);
++				khandy.shift = khandy.shift < 3*64 ? khandy.shift + 64 : 0 ;
++			} else {
++				handle_scancode(khandy.right,1);
++				handle_scancode(khandy.right,0);
++				khandy.shift = 0;
++			}			
++		}
++		handle_scancode(scode + khandy.shift, 1);
++		handle_scancode(scode + khandy.shift, 0);
++		khandy.code = scode | 0x100;
++		handle_scancode(khandy.left,1);
++		handle_scancode(khandy.left,0);
++	} else {
++		if (khandy.code) {
++			khandy.code = 0;
++			handle_scancode(khandy.right,1);
++			handle_scancode(khandy.right,0);
++		}
++		khandy.shift = 0;
++		handle_scancode(scode, down);
++	}
++}
++
++
++/*
++ * Process the new key data 
++ */
++static void clps711x_kbd_process(void* data)
++{
++	int col,row,res;
++
++	for (col = 0; col < 8; col++) {
++		if (( res = previous_keys[col] ^ keys[col]) == 0) 		
++			continue;
++		for(row = 0; row < 8; row++) {
++			if ( ((res >> row) & 0x01) != 0) 
++				clps711x_checkhandy(col,row);	
++		}				
++	}
++	/* Update the state variables. */
++	memcpy(previous_keys, keys, 8 * sizeof(int));
++
++	/* reschedule, if autocomplete pending */
++	if (khandy.autocomplete) {
++		khandy.expires = jiffies + khandy.delay;
++		mod_timer(&clps711x_kbdhandy_timer,khandy.expires);
++	}
++
++}
++
++static char clps711x_unexpected_up(unsigned char scancode)
++{
++	return 0200;
++}
++
++/*
++* Handle timer event, for autocomplete function
++* Reschedule keyboard process task
++*/
++static void clps711x_kbdhandy_timeout(unsigned long data) 
++{
++	if(khandy.autocomplete) {
++		khandy.code = 0;
++		khandy.shift = 0;
++		khandy.autocomplete = 0;
++		handle_scancode(khandy.right,1);
++		handle_scancode(khandy.right,0);
++	}
++}
++
++/*
++* Handle timer event, while in pollmode
++*/
++static void clps711x_kbd_timeout(unsigned long data)
++{
++	int i;
++	unsigned long flags;
++	/* 
++	* read bits of actual column or all columns in fastscan-mode
++	*/
++	for (i = 0; i < 8; i++) {
++		new_keys[last_column - KBSC_COL0] = clps_readb(PADR) & 0xff;
++		key_is_pressed |= new_keys[last_column - KBSC_COL0];
++		last_column = last_column < KBSC_COL7 ? last_column + 1 : KBSC_COL0;
++		local_irq_save(flags);
++		clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) 
++				| last_column, SYSCON1);
++		local_irq_restore(flags);
++		/*
++		* For fastscan, apply a short delay to settle scanlines
++		* else break and wait for next timeout
++		*/
++		if (fastscan)
++			udelay(5);	
++		else
++			break;
++	}
++
++	if (key_is_pressed)
++		khandy.autocomplete = 0;
++
++	/*
++	* switch to interupt mode, if all columns scanned and no key pressed
++	* else reschedule scan
++	*/
++	if (last_column == KBSC_COL0) {
++		if (!key_is_pressed) {
++			local_irq_save(flags);
++			clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK)
++					 | KBSC_HI, SYSCON1);
++			local_irq_restore(flags);
++			clps_writel(0,KBDEOI);	
++			enable_irq(IRQ_KBDINT);
++		} else {
++			clps711x_kbd_timer.expires = jiffies + scan_interval;
++			add_timer(&clps711x_kbd_timer);
++		}		
++		key_is_pressed = 0;
++		memcpy(keys, new_keys, 8 * sizeof(int));
++		for (i = 0; i < 8; i++) {
++			if (previous_keys[i] != keys[i]) {
++				queue_task(&kbd_process_task, &tq_timer);
++				return;
++			}
++		}
++	} else {
++		clps711x_kbd_timer.expires = jiffies + scan_delay;
++		add_timer(&clps711x_kbd_timer);
++	}
++}
++
++/*
++* Keyboard interrupt, change to scheduling mode
++*/
++static void clps711x_kbd_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++
++#ifdef CONFIG_VT
++	kbd_pt_regs = regs;
++#endif
++	disable_irq(IRQ_KBDINT);
++	khandy.autocomplete = 0;
++	clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK)
++		 | KBSC_COL0, SYSCON1);
++	clps711x_kbd_timer.expires = jiffies + scan_delay;
++	add_timer(&clps711x_kbd_timer);
++}
++
++
++static int clps711x_kbd_proc_keyboard_read(char *page, char **start, off_t off,
++		int count, int *eof, void *data)
++{
++	if (count < 2) 
++		return -EINVAL;
++
++	return sprintf(page,"h:%d\n",khandy.ena);
++}
++
++static int clps711x_kbd_proc_keyboard_write(struct file *file, const char *buffer, 
++		unsigned long count, void *data)
++{
++	unsigned char buf[260];
++
++	if (count < 3|| count > 258)
++		return -EINVAL;
++	if (copy_from_user(buf, buffer, count)) 
++		return -EFAULT;
++	if (buf[1] != ':')
++		return -EINVAL;
++			
++	if (buf[0] == 'h') {
++		switch (buf[2]) {
++			case '0':
++			case '1':
++			case '2': khandy.ena = buf[2]-'0'; return count;	
++		}
++	}	
++		
++	if (buf[0] == 't' && count == 258) {
++		memcpy(act_scancode,buf+2,256);
++		/* rescan cursor left/right and del */ 
++		clps711x_handykey_init();
++		return count;
++	}
++	
++	return -EINVAL;
++}
++
++
++/*
++ * Initialize the keyboard hardware. 
++ * Set all columns high
++ * Install interrupt handler
++ *
++ * Machine dependent parameters:
++ *
++ * fastscan: 		0 = timer based scan for each column
++ *			1 = full scan is done in one timer event
++ * scan_delay:		time between column scans 
++ * 			setup even if you use fastscan (leeds to timer mode)
++ * scan_interval:	time between full scans
++ * handy.delay:		timeout before last entry get's automatically valid
++ * 
++ */
++void __init clps711x_kbd_init_hw(void)
++{
++
++	/*
++	* put here  machine dependent init stuff 
++	*/
++	if (machine_is_autcpu12()) {
++		fastscan = 0;
++		scan_interval = 50*HZ/1000;
++		scan_delay = 20*HZ/1000;
++		khandy.delay = 750*HZ/1000;
++		act_scancode = autcpu12_scancode;
++	} else {
++		printk("No initialization, keyboard killed\n");
++		return;
++	}
++
++	last_column = KBSC_COL0;
++	key_is_pressed = 0;
++
++	clps711x_handykey_init();
++
++	/* Register the /proc entry */
++	clps711x_keyboard_proc_entry = create_proc_entry("keyboard", 0444,
++		&proc_root);
++	if (clps711x_keyboard_proc_entry == NULL)
++	    	printk("Couldn't create the /proc entry for the keyboard\n");
++	else {
++		clps711x_keyboard_proc_entry->read_proc = 
++			&clps711x_kbd_proc_keyboard_read;
++		clps711x_keyboard_proc_entry->write_proc = 
++			&clps711x_kbd_proc_keyboard_write;
++	}
++
++	/* Initialize the matrix processing task. */
++	k_translate	= clps711x_translate;
++	k_unexpected_up	= clps711x_unexpected_up;
++	kbd_process_task.routine = clps711x_kbd_process;
++	kbd_process_task.data = 0;
++	
++	/* Setup the timer for keyboard polling, after kbd int */
++	init_timer(&clps711x_kbd_timer);
++	clps711x_kbd_timer.function = clps711x_kbd_timeout;
++	clps711x_kbd_timer.data = 0;
++	init_timer(&clps711x_kbdhandy_timer);
++	clps711x_kbdhandy_timer.function = clps711x_kbdhandy_timeout;
++	clps711x_kbdhandy_timer.data = 1;
++
++	/* Initialise scan hardware, request int */
++	clps_writel( (clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK)
++		 | KBSC_HI, SYSCON1);
++	request_irq(IRQ_KBDINT, clps711x_kbd_int, 0,"keyboard", NULL);
++
++	printk("clps711x keyboard init done\n");
++
++}
+--- linux-2.4.25/drivers/char/console.c~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/char/console.c	2004-03-31 17:15:09.000000000 +0200
+@@ -72,8 +72,14 @@
+  *
+  * Removed console_lock, enabled interrupts across all console operations
+  * 13 March 2001, Andrew Morton
++ *
++ * Split out con_write_ctrl_* functions from do_con_write & changed
++ * vc_state to function pointer
++ * by Russell King <rmk@arm.linux.org.uk>, July 1998
+  */
+ 
++#define CONSOLE_WIP
++
+ #include <linux/module.h>
+ #include <linux/sched.h>
+ #include <linux/tty.h>
+@@ -228,7 +234,7 @@
+ static inline unsigned short *screenpos(int currcons, int offset, int viewed)
+ {
+ 	unsigned short *p;
+-	
++
+ 	if (!viewed)
+ 		p = (unsigned short *)(origin + offset);
+ 	else if (!sw->con_screen_pos)
+@@ -729,7 +735,7 @@
+ 		else {
+ 			unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
+ 			if (!p) {
+-				for (i = first; i < currcons; i++)
++				for (i = first; i< currcons; i++)
+ 					if (newscreens[i])
+ 						kfree(newscreens[i]);
+ 				return -ENOMEM;
+@@ -847,7 +853,7 @@
+ /* the default colour table, for VGA+ colour systems */
+ int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
+     0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
+-int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
++int default_grn[] = {0x00,0x00,0xaa,0xaa,0x00,0x00,0xaa,0xaa,
+     0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
+ int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
+     0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+@@ -1393,6 +1399,19 @@
+ 	need_wrap = 0;
+ }
+ 
++static int con_write_ctrl_ESnormal(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESesc(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESnonstd(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESpalette(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESsquare(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESgetpars(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESgotpars(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESpercent(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESfunckey(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_EShash(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESsetG0(int, struct tty_struct *, unsigned int);
++static int con_write_ctrl_ESsetG1(int, struct tty_struct *, unsigned int);
++
+ enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+ 	EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
+ 	ESpalette };
+@@ -1402,7 +1421,7 @@
+ {
+ 	top		= 0;
+ 	bottom		= video_num_lines;
+-	vc_state	= ESnormal;
++	vc_state	= con_write_ctrl_ESnormal;
+ 	ques		= 0;
+ 	translate	= set_translate(LAT1_MAP,currcons);
+ 	G0_charset	= LAT1_MAP;
+@@ -1500,328 +1519,426 @@
+ 		disp_ctrl = 0;
+ 		return;
+ 	case 24: case 26:
+-		vc_state = ESnormal;
++		vc_state = con_write_ctrl_ESnormal;
+ 		return;
+ 	case 27:
+-		vc_state = ESesc;
++		vc_state = con_write_ctrl_ESesc;
+ 		return;
+ 	case 127:
+ 		del(currcons);
+ 		return;
+ 	case 128+27:
+-		vc_state = ESsquare;
++		vc_state = con_write_ctrl_ESsquare;
+ 		return;
+ 	}
+-	switch(vc_state) {
+-	case ESesc:
+-		vc_state = ESnormal;
+-		switch (c) {
+-		case '[':
+-			vc_state = ESsquare;
+-			return;
+-		case ']':
+-			vc_state = ESnonstd;
+-			return;
+-		case '%':
+-			vc_state = ESpercent;
+-			return;
+-		case 'E':
+-			cr(currcons);
+-			lf(currcons);
+-			return;
+-		case 'M':
+-			ri(currcons);
+-			return;
+-		case 'D':
+-			lf(currcons);
+-			return;
+-		case 'H':
+-			tab_stop[x >> 5] |= (1 << (x & 31));
+-			return;
+-		case 'Z':
+-			respond_ID(tty);
+-			return;
+-		case '7':
+-			save_cur(currcons);
+-			return;
+-		case '8':
+-			restore_cur(currcons);
+-			return;
+-		case '(':
+-			vc_state = ESsetG0;
+-			return;
+-		case ')':
+-			vc_state = ESsetG1;
+-			return;
+-		case '#':
+-			vc_state = EShash;
+-			return;
+-		case 'c':
+-			reset_terminal(currcons,1);
+-			return;
+-		case '>':  /* Numeric keypad */
+-			clr_kbd(kbdapplic);
+-			return;
+-		case '=':  /* Appl. keypad */
+-			set_kbd(kbdapplic);
+-			return;
++	vc_state(currcons, tty, c);
++}
++
++static int con_write_utf(int currcons, int c)
++{
++	unsigned int chr;
++
++	/* Combine UTF-8 into Unicode */
++	/* Incomplete characters silently ignored */
++	if (c < 0x80) {
++		utf_count = 0;
++		return c;
++	}
++
++	if (utf_count > 0 && (c & 0xc0) == 0x80) {
++		chr = (utf_char << 6) | (c & 0x3f);
++		utf_count--;
++		if (utf_count == 0)
++			return chr;
++	} else {
++		unsigned int count;
++		if ((c & 0xe0) == 0xc0) {
++			count = 1;
++			chr = (c & 0x1f);
++		} else if ((c & 0xf0) == 0xe0) {
++			count = 2;
++			chr = (c & 0x0f);
++		} else if ((c & 0xf8) == 0xf0) {
++			count = 3;
++			chr = (c & 0x07);
++		} else if ((c & 0xfc) == 0xf8) {
++			count = 4;
++			chr = (c & 0x03);
++		} else if ((c & 0xfe) == 0xfc) {
++			count = 5;
++			chr = (c & 0x01);
++		} else {
++			count = 0;
++			chr = 0;
+ 		}
+-		return;
+-	case ESnonstd:
+-		if (c=='P') {   /* palette escape sequence */
+-			for (npar=0; npar<NPAR; npar++)
+-				par[npar] = 0 ;
+-			npar = 0 ;
+-			vc_state = ESpalette;
+-			return;
+-		} else if (c=='R') {   /* reset palette */
+-			reset_palette(currcons);
+-			vc_state = ESnormal;
+-		} else
+-			vc_state = ESnormal;
+-		return;
+-	case ESpalette:
+-		if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
+-			par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
+-			if (npar==7) {
+-				int i = par[0]*3, j = 1;
+-				palette[i] = 16*par[j++];
+-				palette[i++] += par[j++];
+-				palette[i] = 16*par[j++];
+-				palette[i++] += par[j++];
+-				palette[i] = 16*par[j++];
+-				palette[i] += par[j];
+-				set_palette(currcons);
+-				vc_state = ESnormal;
+-			}
+-		} else
+-			vc_state = ESnormal;
+-		return;
+-	case ESsquare:
+-		for(npar = 0 ; npar < NPAR ; npar++)
+-			par[npar] = 0;
+-		npar = 0;
+-		vc_state = ESgetpars;
+-		if (c == '[') { /* Function key */
+-			vc_state=ESfunckey;
+-			return;
++		utf_count = count;
++	}
++
++	utf_char = chr;
++	return -1;
++}
++
++static int con_write_ctrl_ESnormal(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	return 0;
++}
++
++static int con_write_ctrl_ESesc(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	vc_state = con_write_ctrl_ESnormal;
++	switch (c) {
++	case '[':
++		vc_state = con_write_ctrl_ESsquare;
++		break;
++	case ']':
++		vc_state = con_write_ctrl_ESnonstd;
++		break;
++	case '%':
++		vc_state = con_write_ctrl_ESpercent;
++		break;
++	case 'E':
++		cr(currcons);
++		lf(currcons);
++		break;
++	case 'M':
++		ri(currcons);
++		break;
++	case 'D':
++		lf(currcons);
++		break;
++	case 'H':
++		tab_stop[x >> 5] |= (1 << (x & 31));
++		break;
++	case 'Z':
++		respond_ID(tty);
++		break;
++	case '7':
++		save_cur(currcons);
++		break;
++	case '8':
++		restore_cur(currcons);
++		return 1;
++	case '(':
++		vc_state = con_write_ctrl_ESsetG0;
++		break;
++	case ')':
++		vc_state = con_write_ctrl_ESsetG1;
++		break;
++	case '#':
++		vc_state = con_write_ctrl_EShash;
++		break;
++	case 'c':
++		reset_terminal(currcons,1);
++		return 1;
++	case '>':  /* Numeric keypad */
++		clr_kbd(kbdapplic);
++		break;
++	case '=':  /* Appl. keypad */
++		set_kbd(kbdapplic);
++	 	break;
++	}
++	return 0;
++}
++
++static int con_write_ctrl_ESnonstd(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	switch (c) {
++	case 'P': /* palette escape sequence */
++		for (npar=0; npar<NPAR; npar++)
++			par[npar] = 0 ;
++		npar = 0 ;
++		vc_state = con_write_ctrl_ESpalette;
++		break;
++	case 'R': /* reset palette */
++		reset_palette (currcons);
++	default:
++		vc_state = con_write_ctrl_ESnormal;
++	}
++	return 0;
++}
++
++static int con_write_ctrl_ESpalette(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
++		par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
++		if (npar==7) {
++			int i = par[0]*3, j = 1;
++			palette[i] = 16*par[j++];
++			palette[i++] += par[j++];
++			palette[i] = 16*par[j++];
++			palette[i++] += par[j++];
++			palette[i] = 16*par[j++];
++			palette[i] += par[j];
++			set_palette(currcons);
++			vc_state = con_write_ctrl_ESnormal;
+ 		}
+-		ques = (c=='?');
+-		if (ques)
+-			return;
+-	case ESgetpars:
+-		if (c==';' && npar<NPAR-1) {
+-			npar++;
+-			return;
+-		} else if (c>='0' && c<='9') {
+-			par[npar] *= 10;
+-			par[npar] += c-'0';
+-			return;
+-		} else vc_state=ESgotpars;
+-	case ESgotpars:
+-		vc_state = ESnormal;
+-		switch(c) {
+-		case 'h':
+-			set_mode(currcons,1);
+-			return;
+-		case 'l':
+-			set_mode(currcons,0);
+-			return;
+-		case 'c':
+-			if (ques) {
+-				if (par[0])
+-					cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
+-				else
+-					cursor_type = CUR_DEFAULT;
+-				return;
+-			}
+-			break;
+-		case 'm':
+-			if (ques) {
+-				clear_selection();
+-				if (par[0])
+-					complement_mask = par[0]<<8 | par[1];
+-				else
+-					complement_mask = s_complement_mask;
+-				return;
+-			}
+-			break;
+-		case 'n':
+-			if (!ques) {
+-				if (par[0] == 5)
+-					status_report(tty);
+-				else if (par[0] == 6)
+-					cursor_report(currcons,tty);
+-			}
+-			return;
++	} else
++		vc_state = con_write_ctrl_ESnormal;
++	return 0;
++}
++
++static int con_write_ctrl_ESsquare(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	for(npar = 0 ; npar < NPAR ; npar++)
++		par[npar] = 0;
++	npar = 0;
++	vc_state = con_write_ctrl_ESgetpars;
++	if (c == '[') { /* Function key */
++		vc_state = con_write_ctrl_ESfunckey;
++		return 0;
++	}
++	ques = (c=='?');
++	if (ques)
++		return 0;
++	return con_write_ctrl_ESgetpars(currcons, tty, c);
++}
++
++static int con_write_ctrl_ESgetpars(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	if (c==';' && npar<NPAR-1) {
++		npar++;
++		return 0;
++	} else if (c>='0' && c<='9') {
++		par[npar] *= 10;
++		par[npar] += c-'0';
++		return 0;
++	} else vc_state = con_write_ctrl_ESgotpars;
++	return con_write_ctrl_ESgotpars(currcons, tty, c);
++}
++
++static int con_write_ctrl_ESgotpars(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	vc_state = con_write_ctrl_ESnormal;
++	switch(c) {
++	case 'h':
++		set_mode(currcons,1);
++		return 0;
++	case 'l':
++		set_mode(currcons,0);
++		return 0;
++	case 'c':
++		if (ques) {
++			if (par[0])
++				cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
++			else
++				cursor_type = CUR_DEFAULT;
++			return 0;
+ 		}
++		break;
++	case 'm':
+ 		if (ques) {
+-			ques = 0;
+-			return;
++			clear_selection();
++			if (par[0])
++				complement_mask = par[0]<<8 | par[1];
++			else
++				complement_mask = s_complement_mask;
++			return 0;
+ 		}
+-		switch(c) {
+-		case 'G': case '`':
+-			if (par[0]) par[0]--;
+-			gotoxy(currcons,par[0],y);
+-			return;
+-		case 'A':
+-			if (!par[0]) par[0]++;
+-			gotoxy(currcons,x,y-par[0]);
+-			return;
+-		case 'B': case 'e':
+-			if (!par[0]) par[0]++;
+-			gotoxy(currcons,x,y+par[0]);
+-			return;
+-		case 'C': case 'a':
+-			if (!par[0]) par[0]++;
+-			gotoxy(currcons,x+par[0],y);
+-			return;
+-		case 'D':
+-			if (!par[0]) par[0]++;
+-			gotoxy(currcons,x-par[0],y);
+-			return;
+-		case 'E':
+-			if (!par[0]) par[0]++;
+-			gotoxy(currcons,0,y+par[0]);
+-			return;
+-		case 'F':
+-			if (!par[0]) par[0]++;
+-			gotoxy(currcons,0,y-par[0]);
+-			return;
+-		case 'd':
+-			if (par[0]) par[0]--;
+-			gotoxay(currcons,x,par[0]);
+-			return;
+-		case 'H': case 'f':
+-			if (par[0]) par[0]--;
+-			if (par[1]) par[1]--;
+-			gotoxay(currcons,par[1],par[0]);
+-			return;
+-		case 'J':
+-			csi_J(currcons,par[0]);
+-			return;
+-		case 'K':
+-			csi_K(currcons,par[0]);
+-			return;
+-		case 'L':
+-			csi_L(currcons,par[0]);
+-			return;
+-		case 'M':
+-			csi_M(currcons,par[0]);
+-			return;
+-		case 'P':
+-			csi_P(currcons,par[0]);
+-			return;
+-		case 'c':
+-			if (!par[0])
+-				respond_ID(tty);
+-			return;
+-		case 'g':
+-			if (!par[0])
+-				tab_stop[x >> 5] &= ~(1 << (x & 31));
+-			else if (par[0] == 3) {
+-				tab_stop[0] =
+-					tab_stop[1] =
+-					tab_stop[2] =
+-					tab_stop[3] =
+-					tab_stop[4] = 0;
+-			}
+-			return;
+-		case 'm':
+-			csi_m(currcons);
+-			return;
+-		case 'q': /* DECLL - but only 3 leds */
+-			/* map 0,1,2,3 to 0,1,2,4 */
+-			if (par[0] < 4)
+-				setledstate(kbd_table + currcons,
+-					    (par[0] < 3) ? par[0] : 4);
+-			return;
+-		case 'r':
+-			if (!par[0])
+-				par[0]++;
+-			if (!par[1])
+-				par[1] = video_num_lines;
+-			/* Minimum allowed region is 2 lines */
+-			if (par[0] < par[1] &&
+-			    par[1] <= video_num_lines) {
+-				top=par[0]-1;
+-				bottom=par[1];
+-				gotoxay(currcons,0,0);
+-			}
+-			return;
+-		case 's':
+-			save_cur(currcons);
+-			return;
+-		case 'u':
+-			restore_cur(currcons);
+-			return;
+-		case 'X':
+-			csi_X(currcons, par[0]);
+-			return;
+-		case '@':
+-			csi_at(currcons,par[0]);
+-			return;
+-		case ']': /* setterm functions */
+-			setterm_command(currcons);
+-			return;
++		break;
++	case 'n':
++		if (!ques) {
++			if (par[0] == 5)
++				status_report(tty);
++			else if (par[0] == 6)
++				cursor_report(currcons,tty);
+ 		}
+-		return;
+-	case ESpercent:
+-		vc_state = ESnormal;
+-		switch (c) {
+-		case '@':  /* defined in ISO 2022 */
+-			utf = 0;
+-			return;
+-		case 'G':  /* prelim official escape code */
+-		case '8':  /* retained for compatibility */
+-			utf = 1;
+-			return;
++		return 0;
++	}
++	if (ques) {
++		ques = 0;
++		return 0;
++	}
++	switch(c) {
++	case 'G': case '`':
++		if (par[0]) par[0]--;
++		gotoxy(currcons,par[0],y);
++		break;
++	case 'A':
++		if (!par[0]) par[0]++;
++		gotoxy(currcons,x,y-par[0]);
++		break;
++	case 'B': case 'e':
++		if (!par[0]) par[0]++;
++		gotoxy(currcons,x,y+par[0]);
++		break;
++	case 'C': case 'a':
++		if (!par[0]) par[0]++;
++		gotoxy(currcons,x+par[0],y);
++		break;
++	case 'D':
++		if (!par[0]) par[0]++;
++		gotoxy(currcons,x-par[0],y);
++		break;
++	case 'E':
++		if (!par[0]) par[0]++;
++		gotoxy(currcons,0,y+par[0]);
++		break;
++	case 'F':
++		if (!par[0]) par[0]++;
++		gotoxy(currcons,0,y-par[0]);
++		break;
++	case 'd':
++		if (par[0]) par[0]--;
++		gotoxay(currcons,x,par[0]);
++		break;
++	case 'H': case 'f':
++		if (par[0]) par[0]--;
++		if (par[1]) par[1]--;
++		gotoxay(currcons,par[1],par[0]);
++		break;
++	case 'J':
++		csi_J(currcons,par[0]);
++		break;
++	case 'K':
++		csi_K(currcons,par[0]);
++		break;
++	case 'L':
++		csi_L(currcons,par[0]);
++		break;
++	case 'M':
++		csi_M(currcons,par[0]);
++		break;
++	case 'P':
++		csi_P(currcons,par[0]);
++		break;
++	case 'c':
++		if (!par[0])
++			respond_ID(tty);
++		break;
++	case 'g':
++		if (!par[0])
++			tab_stop[x >> 5] &= ~(1 << (x & 31));
++		else if (par[0] == 3) {
++			tab_stop[0] =
++			tab_stop[1] =
++			tab_stop[2] =
++			tab_stop[3] =
++			tab_stop[4] = 0;
+ 		}
+-		return;
+-	case ESfunckey:
+-		vc_state = ESnormal;
+-		return;
+-	case EShash:
+-		vc_state = ESnormal;
+-		if (c == '8') {
+-			/* DEC screen alignment test. kludge :-) */
+-			video_erase_char =
+-				(video_erase_char & 0xff00) | 'E';
+-			csi_J(currcons, 2);
+-			video_erase_char =
+-				(video_erase_char & 0xff00) | ' ';
+-			do_update_region(currcons, origin, screenbuf_size/2);
++		break;
++	case 'm':
++		csi_m(currcons);
++		return 1;
++	case 'q': /* DECLL - but only 3 leds */
++		/* map 0,1,2,3 to 0,1,2,4 */
++		if (par[0] < 4)
++		  setledstate(kbd_table + currcons,
++			      (par[0] < 3) ? par[0] : 4);
++		break;
++	case 'r':
++		if (!par[0])
++			par[0]++;
++		if (!par[1])
++			par[1] = video_num_lines;
++		/* Minimum allowed region is 2 lines */
++		if (par[0] < par[1] &&
++		    par[1] <= video_num_lines) {
++			top=par[0]-1;
++			bottom=par[1];
++			gotoxay(currcons,0,0);
+ 		}
+-		return;
+-	case ESsetG0:
+-		if (c == '0')
+-			G0_charset = GRAF_MAP;
+-		else if (c == 'B')
+-			G0_charset = LAT1_MAP;
+-		else if (c == 'U')
+-			G0_charset = IBMPC_MAP;
+-		else if (c == 'K')
+-			G0_charset = USER_MAP;
+-		if (charset == 0)
+-			translate = set_translate(G0_charset,currcons);
+-		vc_state = ESnormal;
+-		return;
+-	case ESsetG1:
+-		if (c == '0')
+-			G1_charset = GRAF_MAP;
+-		else if (c == 'B')
+-			G1_charset = LAT1_MAP;
+-		else if (c == 'U')
+-			G1_charset = IBMPC_MAP;
+-		else if (c == 'K')
+-			G1_charset = USER_MAP;
+-		if (charset == 1)
+-			translate = set_translate(G1_charset,currcons);
+-		vc_state = ESnormal;
+-		return;
+-	default:
+-		vc_state = ESnormal;
++		break;
++	case 's':
++		save_cur(currcons);
++		break;
++	case 'u':
++		restore_cur(currcons);
++		return 1;
++	case 'X':
++		csi_X(currcons, par[0]);
++		break;
++	case '@':
++		csi_at(currcons,par[0]);
++		break;
++	case ']': /* setterm functions */
++		setterm_command(currcons);
++		break;
++	}
++	return 0;
++}
++
++static int con_write_ctrl_ESpercent(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	vc_state = con_write_ctrl_ESnormal;
++	switch (c) {
++	case '@':  /* defined in ISO 2022 */
++		utf = 0;
++		break;
++	case 'G':  /* prelim official escape code */
++	case '8':  /* retained for compatibility */
++		utf = 1;
++		break;
++	}
++	return 0;
++}
++
++static int con_write_ctrl_ESfunckey(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	vc_state = con_write_ctrl_ESnormal;
++	return 0;
++}
++
++static int con_write_ctrl_EShash(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	vc_state = con_write_ctrl_ESnormal;
++	if (c == '8') {
++		/* DEC screen alignment test. kludge :-) */
++		video_erase_char =
++			(video_erase_char & 0xff00) | 'E';
++		csi_J(currcons, 2);
++		video_erase_char =
++			(video_erase_char & 0xff00) | ' ';
++		do_update_region(currcons, origin, screenbuf_size/2);
++	}
++	return 0;
++}
++
++static int con_write_ctrl_ESsetG0(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	switch (c) {
++	case '0':
++		G0_charset = GRAF_MAP;
++		break;
++	case 'B':
++		G0_charset = LAT1_MAP;
++		break;
++	case 'U':
++		G0_charset = IBMPC_MAP;
++		break;
++	case 'K':
++		G0_charset = USER_MAP;
++		break;
++	}
++	if (charset == 0) {
++		translate = set_translate(G0_charset,currcons);
++		return 1;
++	}
++	vc_state = con_write_ctrl_ESnormal;
++	return 0;
++}
++
++static int con_write_ctrl_ESsetG1(int currcons, struct tty_struct *tty, unsigned int c)
++{
++	switch (c) {
++	case '0':
++		G1_charset = GRAF_MAP;
++		break;
++	case 'B':
++		G1_charset = LAT1_MAP;
++		break;
++	case 'U':
++		G1_charset = IBMPC_MAP;
++		break;
++	case 'K':
++		G1_charset = USER_MAP;
++		break;
++	}
++	if (charset == 1) {
++		translate = set_translate(G1_charset,currcons);
++		return 1;
+ 	}
++	vc_state = con_write_ctrl_ESnormal;
++	return 0;
+ }
+ 
+ /* This is a temporary buffer used to prepare a tty console write
+@@ -1855,7 +1972,7 @@
+ 	unsigned long draw_from = 0, draw_to = 0;
+ 	struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
+ 	u16 himask, charmask;
+-	const unsigned char *orig_buf = NULL;
++	const unsigned char *orig_buf;
+ 	int orig_count;
+ 
+ 	if (in_interrupt())
+@@ -1913,42 +2030,12 @@
+ 		count--;
+ 
+ 		if (utf) {
+-		    /* Combine UTF-8 into Unicode */
+-		    /* Incomplete characters silently ignored */
+-		    if(c > 0x7f) {
+-			if (utf_count > 0 && (c & 0xc0) == 0x80) {
+-				utf_char = (utf_char << 6) | (c & 0x3f);
+-				utf_count--;
+-				if (utf_count == 0)
+-				    tc = c = utf_char;
+-				else continue;
+-			} else {
+-				if ((c & 0xe0) == 0xc0) {
+-				    utf_count = 1;
+-				    utf_char = (c & 0x1f);
+-				} else if ((c & 0xf0) == 0xe0) {
+-				    utf_count = 2;
+-				    utf_char = (c & 0x0f);
+-				} else if ((c & 0xf8) == 0xf0) {
+-				    utf_count = 3;
+-				    utf_char = (c & 0x07);
+-				} else if ((c & 0xfc) == 0xf8) {
+-				    utf_count = 4;
+-				    utf_char = (c & 0x03);
+-				} else if ((c & 0xfe) == 0xfc) {
+-				    utf_count = 5;
+-				    utf_char = (c & 0x01);
+-				} else
+-				    utf_count = 0;
++			tc = con_write_utf(currcons, c);
++			if (tc < 0)
+ 				continue;
+-			      }
+-		    } else {
+-		      tc = c;
+-		      utf_count = 0;
+-		    }
+-		} else {	/* no utf */
+-		  tc = translate[toggle_meta ? (c|0x80) : c];
+-		}
++			c = tc;
++		} else	/* no utf */
++			tc = translate[toggle_meta ? (c|0x80) : c];
+ 
+                 /* If the original code was a control character we
+                  * only allow a glyph to be displayed if the code is
+@@ -1966,7 +2053,7 @@
+                         && (c != 127 || disp_ctrl)
+ 			&& (c != 128+27);
+ 
+-		if (vc_state == ESnormal && ok) {
++		if (vc_state == con_write_ctrl_ESnormal && ok) {
+ 			/* Now try to find out how to display it */
+ 			tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
+ 			if ( tc == -4 ) {
+@@ -2112,7 +2199,7 @@
+ 	if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
+ 		currcons = kmsg_redirect - 1;
+ 
+-	/* read `x' only after setting currecons properly (otherwise
++	/* read `x' only after setting currcons properly (otherwise
+ 	   the `x' macro will read the x of the foreground console). */
+ 	myx = x;
+ 
+@@ -2475,8 +2562,8 @@
+ 	console_driver.init_termios = tty_std_termios;
+ 	console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
+ 	/* Tell tty_register_driver() to skip consoles because they are
+-	 * registered before kmalloc() is ready. We'll patch them in later. 
+-	 * See comments at console_init(); see also con_init_devfs(). 
++	 * registered before kmalloc() is ready. We'll patch them in later.
++	 * See comments at console_init(); see also con_init_devfs().
+ 	 */
+ 	console_driver.flags |= TTY_DRIVER_NO_DEVFS;
+ 	console_driver.refcount = &console_refcount;
+@@ -2719,7 +2806,7 @@
+ 
+ 	if (console_blank_hook && console_blank_hook(1))
+ 		return;
+-    	if (vesa_blank_mode)
++	if (vesa_blank_mode)
+ 		sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);
+ }
+ 
+@@ -2893,7 +2980,7 @@
+ 		if (!op->height) {		/* Need to guess font height [compat] */
+ 			int h, i;
+ 			u8 *charmap = op->data, tmp;
+-			
++
+ 			/* If from KDFONTOP ioctl, don't allow things which can be done in userland,
+ 			   so that we can get rid of this soon */
+ 			if (!(op->flags & KD_FONT_FLAG_OLD))
+@@ -2940,18 +3027,18 @@
+ 	op->data = old_op.data;
+ 	if (!rc && !set) {
+ 		int c = (op->width+7)/8 * 32 * op->charcount;
+-		
++
+ 		if (op->data && op->charcount > old_op.charcount)
+ 			rc = -ENOSPC;
+ 		if (!(op->flags & KD_FONT_FLAG_OLD)) {
+-			if (op->width > old_op.width || 
++			if (op->width > old_op.width ||
+ 			    op->height > old_op.height)
+ 				rc = -ENOSPC;
+ 		} else {
+ 			if (op->width != 8)
+ 				rc = -EIO;
+ 			else if ((old_op.height && op->height > old_op.height) ||
+-			         op->height > 32)
++				 op->height > 32)
+ 				rc = -ENOSPC;
+ 		}
+ 		if (!rc && op->data && copy_to_user(op->data, temp, c))
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/ds1307.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,604 @@
++/*
++ * ds1307.c
++ *
++ * Device driver for Dallas Semiconductor's Real Time Controller DS1307.
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/version.h>
++
++#include <linux/kernel.h>
++#include <linux/poll.h>
++#include <linux/i2c.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/rtc.h>
++#include <linux/string.h>
++#include <linux/miscdevice.h>
++#include <linux/proc_fs.h>
++
++#include "ds1307.h"
++
++#define DEBUG 0
++
++#if DEBUG
++static unsigned int rtc_debug = DEBUG;
++#else
++#define rtc_debug 0	/* gcc will remove all the debug code for us */
++#endif
++
++static unsigned short slave_address = DS1307_I2C_SLAVE_ADDR;
++
++struct i2c_driver ds1307_driver;
++struct i2c_client *ds1307_i2c_client = 0;
++
++static unsigned short ignore[] = { I2C_CLIENT_END };
++static unsigned short normal_addr[] = { DS1307_I2C_SLAVE_ADDR, I2C_CLIENT_END };
++
++static struct i2c_client_address_data addr_data = {
++	normal_i2c:		normal_addr,
++	normal_i2c_range:	ignore,
++	probe:			ignore,
++	probe_range:		ignore,
++	ignore: 		ignore,
++	ignore_range:		ignore,
++	force:			ignore,
++};
++
++static int ds1307_rtc_ioctl( struct inode *, struct file *, unsigned int, unsigned long);
++static int ds1307_rtc_open(struct inode *inode, struct file *file);
++static int ds1307_rtc_release(struct inode *inode, struct file *file);
++
++static struct file_operations rtc_fops = {
++	owner:		THIS_MODULE,
++	ioctl:		ds1307_rtc_ioctl,
++	open:		ds1307_rtc_open,
++	release:	ds1307_rtc_release,
++};
++
++static struct miscdevice ds1307_rtc_miscdev = {
++	RTC_MINOR,
++	"rtc",
++	&rtc_fops
++};
++
++static int ds1307_probe(struct i2c_adapter *adap);
++static int ds1307_detach(struct i2c_client *client);
++static int ds1307_command(struct i2c_client *client, unsigned int cmd, void *arg);
++
++struct i2c_driver ds1307_driver = {
++	name:		"DS1307",
++	id:		I2C_DRIVERID_DS1307,
++	flags:		I2C_DF_NOTIFY,
++	attach_adapter: ds1307_probe,
++	detach_client:	ds1307_detach,
++	command:	ds1307_command
++};
++
++static spinlock_t ds1307_rtc_lock = SPIN_LOCK_UNLOCKED;
++
++#define DAT(x) ((unsigned int)((x)->data)) /* keep the control register info */
++
++static int
++ds1307_readram( char *buf, int len)
++{
++	unsigned long	flags;
++	unsigned char ad[1] = { 0 };
++	int ret;
++	struct i2c_msg msgs[2] = {
++		{ ds1307_i2c_client->addr  , 0,        1, ad  },
++		{ ds1307_i2c_client->addr  , I2C_M_RD, len, buf } };
++
++	spin_lock_irqsave(&ds1307_rtc_lock, flags);
++	ret = i2c_transfer(ds1307_i2c_client->adapter, msgs, 2);
++	spin_unlock_irqrestore(&ds1307_rtc_lock,flags);
++
++	return ret;
++}
++
++static void
++ds1307_dumpram( void)
++{
++	unsigned char buf[DS1307_RAM_SIZE];
++	int ret;
++
++	ret = ds1307_readram( buf, DS1307_RAM_SIZE);
++
++	if( ret > 0)
++	{
++		int i;
++		for( i=0; i<DS1307_RAM_SIZE; i++)
++		{
++			printk ("%02X ", buf[i]);
++			if( (i%8) == 7) printk ("\n");
++		}
++		printk ("\n");
++	}
++}
++
++static void
++ds1307_enable_clock( int enable)
++{
++	unsigned char buf[2], ad[1] = { 0 };
++	struct i2c_msg msgs[2] = {
++		{ ds1307_i2c_client->addr	, 0,	    1, ad  },
++		{ ds1307_i2c_client->addr	, I2C_M_RD, 1, buf }
++	};
++	unsigned char ctrl_info;
++	int ret;
++
++	if( enable)
++		ctrl_info = SQW_ENABLE | RATE_32768HZ;
++	else
++		ctrl_info = SQW_DISABLE;
++	ds1307_command(ds1307_i2c_client, DS1307_SETCTRL, &ctrl_info);
++
++	/* read addr 0 (Clock-Halt bit and second counter */
++	ret = i2c_transfer(ds1307_i2c_client->adapter, msgs, 2);
++
++	if( enable)
++		buf[1] = buf[0] & ~CLOCK_HALT; /* clear Clock-Halt bit */
++	else
++		buf[1] = buf[0] | CLOCK_HALT; /* set Clock-Halt bit */
++	buf[0] = 0;	/* control register address on DS1307 */
++
++	ret = i2c_master_send(ds1307_i2c_client, (char *)buf, 2);
++}
++
++static int
++ds1307_attach(struct i2c_adapter *adap, int addr, unsigned short flags,int kind)
++{
++	struct i2c_client *c;
++	unsigned char buf[1], ad[1] = { 7 };
++	struct i2c_msg msgs[2] = {
++		{ addr	, 0,	    1, ad  },
++		{ addr	, I2C_M_RD, 1, buf }
++	};
++	int ret;
++
++	c = (struct i2c_client *)kmalloc(sizeof(*c), GFP_KERNEL);
++	if (!c)
++		return -ENOMEM;
++
++	strcpy(c->name, "DS1307");
++	c->id		= ds1307_driver.id;
++	c->flags	= 0;
++	c->addr 	= addr;
++	c->adapter	= adap;
++	c->driver	= &ds1307_driver;
++	c->data 	= NULL;
++
++	ret = i2c_transfer(c->adapter, msgs, 2);
++
++	if ( ret == 2 )
++	{
++		DAT(c) = buf[0];
++	}
++	else
++		printk ("ds1307_attach(): i2c_transfer() returned %d.\n",ret);
++
++	ds1307_i2c_client = c;
++	ds1307_enable_clock( 1);
++
++	return i2c_attach_client(c);
++}
++
++static int
++ds1307_probe(struct i2c_adapter *adap)
++{
++	return i2c_probe(adap, &addr_data, ds1307_attach);
++}
++
++static int
++ds1307_detach(struct i2c_client *client)
++{
++	i2c_detach_client(client);
++	ds1307_enable_clock( 0);
++
++	return 0;
++}
++
++static void
++ds1307_convert_to_time( struct rtc_time *dt, char *buf)
++{
++	dt->tm_sec = BCD_TO_BIN(buf[0]);
++	dt->tm_min = BCD_TO_BIN(buf[1]);
++
++	if ( TWELVE_HOUR_MODE(buf[2]) )
++	{
++		dt->tm_hour = HOURS_12(buf[2]);
++		if (HOURS_AP(buf[2])) /* PM */
++		{
++			dt->tm_hour += 12;
++		}
++	}
++	else /* 24-hour-mode */
++	{
++		dt->tm_hour = HOURS_24(buf[2]);
++	}
++
++	dt->tm_mday = BCD_TO_BIN(buf[4]);
++	/* dt->tm_mon is zero-based */
++	dt->tm_mon = BCD_TO_BIN(buf[5]) - 1;
++	/* year is 1900 + dt->tm_year */
++	dt->tm_year = BCD_TO_BIN(buf[6]) + 100;
++
++	if( rtc_debug > 2)
++	{
++		printk("ds1307_get_datetime: year = %d\n", dt->tm_year);
++		printk("ds1307_get_datetime: mon  = %d\n", dt->tm_mon);
++		printk("ds1307_get_datetime: mday = %d\n", dt->tm_mday);
++		printk("ds1307_get_datetime: hour = %d\n", dt->tm_hour);
++		printk("ds1307_get_datetime: min  = %d\n", dt->tm_min);
++		printk("ds1307_get_datetime: sec  = %d\n", dt->tm_sec);
++	}
++}
++
++static int
++ds1307_get_datetime(struct i2c_client *client, struct rtc_time *dt)
++{
++	unsigned char buf[7], addr[1] = { 0 };
++	struct i2c_msg msgs[2] = {
++		{ client->addr, 0,	  1, addr },
++		{ client->addr, I2C_M_RD, 7, buf  }
++	};
++	int ret = -EIO;
++
++	memset(buf, 0, sizeof(buf));
++
++	ret = i2c_transfer(client->adapter, msgs, 2);
++
++	if (ret == 2) {
++		ds1307_convert_to_time( dt, buf);
++		ret = 0;
++	}
++	else
++		printk("ds1307_get_datetime(), i2c_transfer() returned %d\n",ret);
++
++	return ret;
++}
++
++static int
++ds1307_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo)
++{
++	unsigned char buf[8];
++	int ret, len = 4;
++
++	if( rtc_debug > 2)
++	{
++		printk("ds1307_set_datetime: tm_year = %d\n", dt->tm_year);
++		printk("ds1307_set_datetime: tm_mon  = %d\n", dt->tm_mon);
++		printk("ds1307_set_datetime: tm_mday = %d\n", dt->tm_mday);
++		printk("ds1307_set_datetime: tm_hour = %d\n", dt->tm_hour);
++		printk("ds1307_set_datetime: tm_min  = %d\n", dt->tm_min);
++		printk("ds1307_set_datetime: tm_sec  = %d\n", dt->tm_sec);
++	}
++
++	buf[0] = 0;	/* register address on DS1307 */
++	buf[1] = (BIN_TO_BCD(dt->tm_sec));
++	buf[2] = (BIN_TO_BCD(dt->tm_min));
++	buf[3] = (BIN_TO_BCD(dt->tm_hour));
++
++	if (datetoo) {
++		len = 8;
++		/* we skip buf[4] as we don't use day-of-week. */
++		buf[5] = (BIN_TO_BCD(dt->tm_mday));
++		buf[6] = (BIN_TO_BCD(dt->tm_mon + 1));
++		/* The year only ranges from 0-99, we are being passed an offset from 1900,
++		 * and the chip calulates leap years based on 2000, thus we adjust by 100.
++		 */
++		buf[7] = (BIN_TO_BCD(dt->tm_year - 100));
++	}
++	ret = i2c_master_send(client, (char *)buf, len);
++	if (ret == len)
++		ret = 0;
++	else
++		printk("ds1307_set_datetime(), i2c_master_send() returned %d\n",ret);
++
++
++	return ret;
++}
++
++static int
++ds1307_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
++{
++	*ctrl = DAT(client);
++
++	return 0;
++}
++
++static int
++ds1307_set_ctrl(struct i2c_client *client, unsigned char *cinfo)
++{
++	unsigned char buf[2];
++	int ret;
++
++
++	buf[0] = 7;	/* control register address on DS1307 */
++	buf[1] = *cinfo;
++	/* save the control reg info in the client data field so that get_ctrl
++	 * function doesn't have to do an I2C transfer to get it.
++	 */
++	DAT(client) = buf[1];
++
++	ret = i2c_master_send(client, (char *)buf, 2);
++
++	return ret;
++}
++
++static int
++ds1307_read_mem(struct i2c_client *client, struct rtc_mem *mem)
++{
++	unsigned char addr[1];
++	struct i2c_msg msgs[2] = {
++		{ client->addr, 0,	  1, addr },
++		{ client->addr, I2C_M_RD, mem->nr, mem->data }
++	};
++
++	if ( (mem->loc < DS1307_RAM_ADDR_START) ||
++	     ((mem->loc + mem->nr -1) > DS1307_RAM_ADDR_END) )
++		return -EINVAL;
++
++	addr[0] = mem->loc;
++
++	return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
++}
++
++static int
++ds1307_write_mem(struct i2c_client *client, struct rtc_mem *mem)
++{
++	unsigned char addr[1];
++	struct i2c_msg msgs[2] = {
++		{ client->addr, 0, 1, addr },
++		{ client->addr, 0, mem->nr, mem->data }
++	};
++
++	if ( (mem->loc < DS1307_RAM_ADDR_START) ||
++	     ((mem->loc + mem->nr -1) > DS1307_RAM_ADDR_END) )
++		return -EINVAL;
++
++	addr[0] = mem->loc;
++
++	return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
++}
++
++static int
++ds1307_command(struct i2c_client *client, unsigned int cmd, void *arg)
++{
++	switch (cmd) {
++	case DS1307_GETDATETIME:
++		return ds1307_get_datetime(client, arg);
++
++	case DS1307_SETTIME:
++		return ds1307_set_datetime(client, arg, 0);
++
++	case DS1307_SETDATETIME:
++		return ds1307_set_datetime(client, arg, 1);
++
++	case DS1307_GETCTRL:
++		return ds1307_get_ctrl(client, arg);
++
++	case DS1307_SETCTRL:
++		return ds1307_set_ctrl(client, arg);
++
++	case DS1307_MEM_READ:
++		return ds1307_read_mem(client, arg);
++
++	case DS1307_MEM_WRITE:
++		return ds1307_write_mem(client, arg);
++
++	default:
++		return -EINVAL;
++	}
++}
++
++static int
++ds1307_rtc_open(struct inode *inode, struct file *file)
++{
++	return 0;
++}
++
++static int
++ds1307_rtc_release(struct inode *inode, struct file *file)
++{
++	return 0;
++}
++
++static int
++ds1307_rtc_ioctl( struct inode *inode, struct file *file,
++		unsigned int cmd, unsigned long arg)
++{
++	unsigned long	flags;
++	struct rtc_time wtime;
++	int status = 0;
++
++	switch (cmd) {
++		default:
++		case RTC_UIE_ON:
++		case RTC_UIE_OFF:
++		case RTC_PIE_ON:
++		case RTC_PIE_OFF:
++		case RTC_AIE_ON:
++		case RTC_AIE_OFF:
++		case RTC_ALM_SET:
++		case RTC_ALM_READ:
++		case RTC_IRQP_READ:
++		case RTC_IRQP_SET:
++		case RTC_EPOCH_READ:
++		case RTC_EPOCH_SET:
++		case RTC_WKALM_SET:
++		case RTC_WKALM_RD:
++			status = -EINVAL;
++			break;
++
++		case RTC_RD_TIME:
++			spin_lock_irqsave(&ds1307_rtc_lock, flags);
++			ds1307_command( ds1307_i2c_client, DS1307_GETDATETIME, &wtime);
++			spin_unlock_irqrestore(&ds1307_rtc_lock,flags);
++
++			if( copy_to_user((void *)arg, &wtime, sizeof (struct rtc_time)))
++				status = -EFAULT;
++			break;
++
++		case RTC_SET_TIME:
++			if (!capable(CAP_SYS_TIME))
++			{
++				status = -EACCES;
++				break;
++			}
++
++			if (copy_from_user(&wtime, (struct rtc_time *)arg, sizeof(struct rtc_time)) )
++			{
++				status = -EFAULT;
++				break;
++			}
++
++			spin_lock_irqsave(&ds1307_rtc_lock, flags);
++			ds1307_command( ds1307_i2c_client, DS1307_SETDATETIME, &wtime);
++			spin_unlock_irqrestore(&ds1307_rtc_lock,flags);
++			break;
++	}
++
++	return status;
++}
++
++static char *
++ds1307_mon2str( unsigned int mon)
++{
++	char *mon2str[12] = {
++	  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
++	  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
++	};
++	if( mon > 11) return "error";
++	else return mon2str[ mon];
++}
++
++static int ds1307_rtc_proc_output( char *buf)
++{
++#define CHECK(ctrl,bit) ((ctrl & bit) ? "yes" : "no")
++	unsigned char ram[DS1307_RAM_SIZE];
++	int ret;
++
++	char *p = buf;
++
++	ret = ds1307_readram( ram, DS1307_RAM_SIZE);
++	if( ret > 0)
++	{
++		int i;
++		struct rtc_time dt;
++		char text[9];
++
++		p += sprintf(p, "DS1307 (64x8 Serial Real Time Clock)\n");
++
++		ds1307_convert_to_time( &dt, ram);
++		p += sprintf(p, "Date/Time	     : %02d-%s-%04d %02d:%02d:%02d\n",
++			dt.tm_mday, ds1307_mon2str(dt.tm_mon), dt.tm_year + 1900,
++			dt.tm_hour, dt.tm_min, dt.tm_sec);
++
++		p += sprintf(p, "Clock halted	     : %s\n", CHECK(ram[0],0x80));
++		p += sprintf(p, "24h mode	     : %s\n", CHECK(ram[2],0x40));
++		p += sprintf(p, "Square wave enabled : %s\n", CHECK(ram[7],0x10));
++		p += sprintf(p, "Freq		     : ");
++
++		switch( ram[7] & 0x03)
++		{
++			case RATE_1HZ:
++				p += sprintf(p, "1Hz\n");
++				break;
++			case RATE_4096HZ:
++				p += sprintf(p, "4.096kHz\n");
++				break;
++			case RATE_8192HZ:
++				p += sprintf(p, "8.192kHz\n");
++				break;
++			case RATE_32768HZ:
++			default:
++				p += sprintf(p, "32.768kHz\n");
++				break;
++
++		}
++
++		p += sprintf(p, "RAM dump:\n");
++		text[8]='\0';
++		for( i=0; i<DS1307_RAM_SIZE; i++)
++		{
++			p += sprintf(p, "%02X ", ram[i]);
++
++			if( (ram[i] < 32) || (ram[i]>126)) ram[i]='.';
++			text[i%8] = ram[i];
++			if( (i%8) == 7) p += sprintf(p, "%s\n",text);
++		}
++		p += sprintf(p, "\n");
++	}
++	else
++	{
++		p += sprintf(p, "Failed to read RTC memory!\n");
++	}
++
++	return	p - buf;
++}
++
++static int ds1307_rtc_read_proc(char *page, char **start, off_t off,
++		int count, int *eof, void *data)
++{
++	int len = ds1307_rtc_proc_output (page);
++	if (len <= off+count) *eof = 1;
++	*start = page + off;
++	len -= off;
++	if (len>count) len = count;
++	if (len<0) len = 0;
++	return len;
++}
++
++static __init int ds1307_init(void)
++{
++	int retval=0;
++
++	if( slave_address != 0xffff)
++	{
++		normal_addr[0] = slave_address;
++	}
++
++	if( normal_addr[0] == 0xffff)
++	{
++		printk(KERN_ERR"I2C: Invalid slave address for DS1307 RTC (%#x)\n",
++			normal_addr[0]);
++		return -EINVAL;
++	}
++
++	retval = i2c_add_driver(&ds1307_driver);
++
++	if (retval==0)
++	{
++		misc_register (&ds1307_rtc_miscdev);
++		create_proc_read_entry (PROC_DS1307_NAME, 0, 0, ds1307_rtc_read_proc, NULL);
++		printk("I2C: DS1307 RTC driver successfully loaded\n");
++
++		if( rtc_debug) ds1307_dumpram();
++	}
++	return retval;
++}
++
++static __exit void ds1307_exit(void)
++{
++	remove_proc_entry (PROC_DS1307_NAME, NULL);
++	misc_deregister(&ds1307_rtc_miscdev);
++	i2c_del_driver(&ds1307_driver);
++}
++
++module_init(ds1307_init);
++module_exit(ds1307_exit);
++
++MODULE_PARM (slave_address, "i");
++MODULE_PARM_DESC (slave_address, "I2C slave address for DS1307 RTC.");
++
++MODULE_AUTHOR ("Intrinsyc Software Inc.");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/ds1307.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,58 @@
++/*
++ * ds1307.h
++ *
++ * Copyright (C) 2002 Intrinsyc Software Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#ifndef DS1307_H
++#define DS1307_H
++
++#if defined(CONFIG_PXA_EMERSON_SBC) || defined(CONFIG_PXA_CERF_BOARD) || defined(CONFIG_MACH_CSB337)
++	#define DS1307_I2C_SLAVE_ADDR	0x68
++#else
++	#define DS1307_I2C_SLAVE_ADDR	0xffff
++#endif
++
++#define DS1307_RAM_ADDR_START	0x08
++#define DS1307_RAM_ADDR_END	0x3F
++#define DS1307_RAM_SIZE 0x40
++
++#define PROC_DS1307_NAME	"driver/ds1307"
++
++struct rtc_mem {
++	unsigned int	loc;
++	unsigned int	nr;
++	unsigned char	*data;
++};
++
++#define DS1307_GETDATETIME	0
++#define DS1307_SETTIME		1
++#define DS1307_SETDATETIME	2
++#define DS1307_GETCTRL		3
++#define DS1307_SETCTRL		4
++#define DS1307_MEM_READ		5
++#define DS1307_MEM_WRITE	6
++
++#define SQW_ENABLE	0x10	/* Square Wave Enable */
++#define SQW_DISABLE	0x00	/* Square Wave disable */
++
++#define RATE_32768HZ	0x03	/* Rate Select 32.768KHz */
++#define RATE_8192HZ	0x02	/* Rate Select 8.192KHz */
++#define RATE_4096HZ	0x01	/* Rate Select 4.096KHz */
++#define RATE_1HZ	0x00	/* Rate Select 1Hz */
++
++#define CLOCK_HALT	0x80	/* Clock Halt */
++
++#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
++#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
++
++#define TWELVE_HOUR_MODE(n)	(((n)>>6)&1)
++#define HOURS_AP(n)		(((n)>>5)&1)
++#define HOURS_12(n)		BCD_TO_BIN((n)&0x1F)
++#define HOURS_24(n)		BCD_TO_BIN((n)&0x3F)
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/edb7211_keyb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,335 @@
++/*
++ * drivers/char/edb7211_keyb.c
++ *
++ * Copyright (C) 2000 Blue Mug, Inc.  All Rights Reserved.
++ *
++ * EDB7211 Keyboard driver for ARM Linux.
++ *
++ * The EP7211 keyboard hardware only supports generating interrupts for 64 keys.
++ * The EBD7211's keyboard has 84 keys. Therefore we need to poll for keys,
++ * instead of waiting for interrupts.
++ *
++ * In a real-world hardware situation, this would be a bad thing. It would
++ * kill power management.
++ */
++
++#include <linux/config.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/ptrace.h>
++#include <linux/signal.h>
++#include <linux/timer.h>
++#include <linux/tqueue.h>
++#include <linux/random.h>
++#include <linux/ctype.h>
++#include <linux/init.h>
++#include <linux/kbd_ll.h>
++#include <linux/kbd_kern.h>
++#include <linux/delay.h>
++
++#include <asm/bitops.h>
++#include <asm/keyboard.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++
++#include <asm/io.h>
++#include <asm/system.h>
++
++
++/*
++ * The number of jiffies between keyboard scans.
++ */
++#define KEYBOARD_SCAN_INTERVAL	5
++
++/*
++ * Values for the keyboard column scan control register.
++ */
++#define KBSC_HI	    0x0	    /*   All driven high */
++#define KBSC_LO	    0x1	    /*   All driven low */
++#define KBSC_X	    0x2	    /*   All high impedance */
++#define KBSC_COL0   0x8	    /*   Column 0 high, others high impedance */
++#define KBSC_COL1   0x9	    /*   Column 1 high, others high impedance */
++#define KBSC_COL2   0xa	    /*   Column 2 high, others high impedance */
++#define KBSC_COL3   0xb	    /*   Column 3 high, others high impedance */
++#define KBSC_COL4   0xc	    /*   Column 4 high, others high impedance */
++#define KBSC_COL5   0xd	    /*   Column 5 high, others high impedance */
++#define KBSC_COL6   0xe	    /*   Column 6 high, others high impedance */
++#define KBSC_COL7   0xf	    /*   Column 7 high, others high impedance */
++
++
++/* XXX: Figure out what these values should be... */
++/* Simple translation table for the SysRq keys */
++#ifdef CONFIG_MAGIC_SYSRQ
++unsigned char edb7211_kbd_sysrq_xlate[128] =
++	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
++	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
++	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
++	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
++	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
++	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
++	"\r\000/";					/* 0x60 - 0x6f */
++#endif
++
++/* 
++ * Row/column to scancode mappings.
++ *
++ * This table maps row/column keyboard matrix positions to XT scancodes.
++ * 
++ * The port A rows come first, followed by the extended rows.
++ */
++static unsigned char colrow_2_scancode[128] = 
++{
++/*  Column: 
++  Row       0     1     2     3     4     5     6     7   */
++/* A0 */  0x01, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x40, 0x41,
++/* A1 */  0x02, 0x07, 0x06, 0x05, 0x04, 0x03, 0x08, 0x09,
++/* A2 */  0x0f, 0x14, 0x13, 0x12, 0x11, 0x10, 0x15, 0x16,
++/* A3 */  0x3a, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x23, 0x24,
++/* A4 */  0x29, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x31, 0x32,
++/* A5 */  0x39, 0x35, 0x6F, 0x52, 0x00, 0x6B, 0x34, 0x33,
++/* A6 */  0x6A, 0x27, 0x28, 0x00, 0x1c, 0x6D, 0x26, 0x25,
++/* A7 */  0x67, 0x19, 0x1a, 0x1b, 0x2b, 0x68, 0x18, 0x17,
++/* E0 */  0x6C, 0x0c, 0x0d, 0x0e, 0x00, 0x66, 0x0b, 0x0a,
++/* E1 */  0x69, 0x44, 0x45, 0x37, 0x46, 0x77, 0x43, 0x42,
++/* E2 */  0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* E3 */  0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* E4 */  0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* E5 */  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* E6 */  0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* E7 */  0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++};
++
++/*
++ * A bitfield array which contains the state of the keyboard after the last
++ * scan. A bit set in this array corresponds to a key down. Only the lower
++ * 16 bits of each array element are used.
++ */
++static unsigned long previous_keys[8];
++static unsigned long keys[8];
++
++
++/* This will be set to a non-zero value if a key was found to be pressed
++ * in the last scan. */
++static int key_is_pressed;
++
++static struct tq_struct kbd_process_task;
++static struct timer_list edb7211_kbd_timer;
++
++/*
++ * External methods.
++ */
++void edb7211_kbd_init_hw(void);
++
++/* 
++ * Internal methods.
++ */
++static int edb7211_kbd_scan_matrix(u_long* keys);
++static void edb7211_kbd_timeout(unsigned long data);
++static void edb7211_kbd_process(void* data);
++
++/*
++ * Translate a raw keycode to an XT keyboard scancode.
++ */
++static int
++edb7211_translate(unsigned char scancode, unsigned char *keycode,
++		  char raw_mode)
++{
++	*keycode = colrow_2_scancode[scancode & 0x7f];
++	return 1;
++}
++
++/*
++ * Scan the keyboard matrix; for each key that is pressed, set the
++ * corresponding bit in the bitfield array.
++ *
++ * The parameter is expected to be an array of 8 32-bit values. Only the lower
++ * 16 bits of each value is used. Each value contains the row bits for the
++ * corresponding column.
++ */
++static int
++edb7211_kbd_scan_matrix(u_long* keys)
++{
++	int column, row, key_pressed;
++	unsigned char port_a_data, ext_port_data;
++
++	key_pressed = 0;
++
++	/* Drive all the columns low. */
++	clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_LO, 
++		SYSCON1);
++
++	for (column = 0; column < 8; column++) {
++
++		/* Drive the column high. */
++		clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | 
++			    (KBSC_COL0 + column), SYSCON1);
++
++		/* Read port A and the extended port. */
++		port_a_data = clps_readb(PADR) & 0xff;
++		ext_port_data = __raw_readb(EP7211_VIRT_EXTKBD) & 0xff;
++
++		/* Drive all columns tri-state. */
++		clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_X, 
++			SYSCON1);
++
++		/* Look at each column in port A. */
++		for (row=0; row < 8; row++) {
++			/* If the row's bit is set, set the bit in the bitfield.
++			 * Otherwise, clear it. 
++			 */
++			if (port_a_data & (1 << row)) {
++				keys[column] |= (1 << row); 
++				key_pressed = 1;
++			} else {
++				keys[column] &= ~(1 << row); 
++			}
++		}
++
++		/* Look at each column in the extended port. */
++		for (row=0; row < 8; row++) {
++			/* If the row's bit is set, set the bit in the bitfield.
++			 * Otherwise, clear it. 
++			 */
++			if (ext_port_data & (1 << row)) {
++				keys[column] |= (1 << (row + 8)); 
++				key_pressed = 1;
++			} else {
++				keys[column] &= ~(1 << (row + 8)); 
++			}
++		}
++
++		/* 
++		 * Short delay: The example code for the EDB7211 runs an empty
++		 * loop 256 times. At this rate, there were some spurious keys
++		 * generated. I doubled the delay to let the column drives 
++		 * settle some. 
++		 */
++		for (row=0; row < 512; row++) { }
++	}
++
++	/* If we could use interrupts, we would drive all columns high so 
++	 * that interrupts will be generated on key presses. But we can't,
++	 * so we leave all columns floating. 
++	 */
++	clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_X, 
++		SYSCON1);
++
++	return key_pressed;
++}
++
++/* 
++ * XXX: This is really ugly; this needs to be reworked to have less levels of
++ *   	indentation.
++ */
++static void
++edb7211_kbd_timeout(unsigned long data)
++{
++	/* Schedule the next timer event. */
++	edb7211_kbd_timer.expires = jiffies + KEYBOARD_SCAN_INTERVAL;
++	add_timer(&edb7211_kbd_timer);
++
++	if (edb7211_kbd_scan_matrix(keys) || key_is_pressed) {
++		queue_task(&kbd_process_task, &tq_timer);
++	} else {
++		key_is_pressed = 0;
++	}
++}
++
++/*
++ * Process the keys that have been pressed. 
++ */
++static void
++edb7211_kbd_process(void* data)
++{
++	int i;
++
++	/* First check if any keys have been released. */
++	if (key_is_pressed) {
++		for (i=0; i < 8; i++) {
++			if (previous_keys[i]) {
++				int row;
++
++				for (row=0; row < 16; row++) {
++					if ((previous_keys[i] & (1 << row)) &&
++						!(keys[i] & (1 << row))) {
++						/* Generate the up event. */
++						handle_scancode(
++								(row<<3)+i, 0);
++					}
++				}
++			}
++		}
++	}
++
++	key_is_pressed = 0;
++
++	/* Now scan the keys and send press events. */
++	for (i=0; i < 8; i++) {
++		if (keys[i]) {
++			int row;
++
++			for (row=0; row < 16; row++) {
++				if (keys[i] & (1 << row)) {
++					if (previous_keys[i] & (1 << row)) {
++						/* Generate the hold event. */
++						handle_scancode((row<<3)+i, 1);
++					} else {
++						/* Generate the down event. */
++						handle_scancode((row<<3)+i, 1);
++					}
++
++					key_is_pressed = 1;
++				}
++			}
++		}
++	}
++
++	/* Update the state variables. */
++	memcpy(previous_keys, keys, 8 * sizeof(unsigned long));
++}
++
++static char edb7211_unexpected_up(unsigned char scancode)
++{
++	return 0200;
++}
++
++static void edb7211_leds(unsigned char leds)
++{
++}
++
++/*
++ * Initialize the keyboard hardware. Set the column drives low and
++ * start the timer.
++ */
++void __init
++edb7211_kbd_init_hw(void)
++{
++	k_translate	= edb7211_translate;
++	k_unexpected_up	= edb7211_unexpected_up;
++	k_leds		= edb7211_leds;
++
++	/* 
++	 * If we had the ability to use interrupts, we would want to drive all
++	 * columns high. But we have more keys than can generate interrupts, so
++	 * we leave them floating.
++	 */
++	clps_writel((clps_readl(SYSCON1) & ~SYSCON1_KBDSCANMASK) | KBSC_X, 
++		SYSCON1);
++
++	/* Initialize the matrix processing task. */
++	kbd_process_task.routine = edb7211_kbd_process;
++	kbd_process_task.data = NULL;
++
++	/* Setup the timer to poll the keyboard. */
++	init_timer(&edb7211_kbd_timer);
++	edb7211_kbd_timer.function = edb7211_kbd_timeout;
++	edb7211_kbd_timer.data = (unsigned long)NULL;
++	edb7211_kbd_timer.expires = jiffies + KEYBOARD_SCAN_INTERVAL;
++	add_timer(&edb7211_kbd_timer); 
++}
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/epxa_wdt.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,178 @@
++/*
++ *	Watchdog driver for the Altera Excalibur EPXA1DB
++ *
++ *      (c) Copyright 2003 Krzysztof Marianski <kmarian@konin.lm.pl>
++ *          Based on SA11x0 Watchdog driver by Oleg Drokin <green@crimea.edu>
++ *
++ *	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 material is provided "AS-IS" and at no charge
++ *
++ *	(c) Copyright 2003 Krzysztof Marianski <kmarian@konin.lm.pl>
++ *
++ *      1/08/2003 Initial release
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++
++#define WATCHDOG00_TYPE (volatile unsigned int*)
++#include <asm/arch/watchdog00.h>
++#include <asm/bitops.h>
++
++#define TIMER_MARGIN	30		/* (secs) Default is 30 seconds */
++
++static int margin = TIMER_MARGIN;	/* in seconds */
++static int epxa1wdt_users;
++static unsigned char last_written_byte;
++
++#ifdef CONFIG_WATCHDOG_NOWAYOUT
++static int nowayout=1;
++#else
++static int nowayout=0;
++#endif
++
++#ifdef MODULE
++MODULE_PARM(margin,"i");
++MODULE_PARM(nowayout, "i");
++#endif
++
++/*
++ *	Allow only one person to hold it open
++ */
++
++static int epxa1dog_open(struct inode *inode, struct file *file)
++{
++	if(test_and_set_bit(1,&epxa1wdt_users))
++		return -EBUSY;
++
++	/* Reset the Watchdog, just to be sure we don't set
++	    a value close to actual value of WDOG_COUNT register */
++	*WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_1;
++	*WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_2;
++
++	/* Activate EPXA1DB Watchdog timer */
++	*WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE))= (EXC_INPUT_CLK_FREQUENCY * margin) & WDOG_CR_TRIGGER_MSK;
++
++	last_written_byte = 'V'; //in case user opens it only to ioctl
++	return 0;
++}
++
++static int epxa1dog_release(struct inode *inode, struct file *file)
++{
++	/*
++	 *	Shut off the timer and set lock bit when no special
++	 *	character 'V' was last written
++	 */
++
++	if ((last_written_byte != 'V') && (nowayout)) {
++		*WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE)) |= WDOG_CR_LK_MSK;
++		printk("No special character 'V' was written to Watchdog just before closing it\n");
++		printk("WATCHDOG LOCKED - Reboot expected!!!\n");
++	} else
++		*WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE))=0;
++
++	epxa1wdt_users = 0;
++
++	return 0;
++}
++
++static ssize_t epxa1dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
++{
++	/*  Can't seek (pwrite) on this device  */
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++
++	/* Reset Watchdog timer. */
++	if(len) {
++		*WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_1;
++		*WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_2;
++		last_written_byte = *data;
++		return 1;
++	}
++	return 0;
++}
++
++static int epxa1dog_ioctl(struct inode *inode, struct file *file,
++	unsigned int cmd, unsigned long arg)
++{
++	static struct watchdog_info ident = {
++		identity: "EPXA Watchdog",
++	};
++
++	switch(cmd){
++	default:
++		return -ENOIOCTLCMD;
++	case WDIOC_GETSUPPORT:
++		return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident));
++//	case WDIOC_GETSTATUS: //TODO
++//		return put_user(0,(int *)arg);
++//	case WDIOC_GETBOOTSTATUS: //TODO
++//		return 0;
++	case WDIOC_KEEPALIVE:
++		*WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_1;
++		*WDOG_RELOAD(IO_ADDRESS(EXC_WATCHDOG00_BASE))=WDOG_RELOAD_MAGIC_2;
++		return 0;
++	case WDIOC_SETTIMEOUT:
++		*WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE))= (EXC_INPUT_CLK_FREQUENCY * margin) & WDOG_CR_TRIGGER_MSK;
++		return 0;
++	case WDIOC_GETTIMEOUT:
++		return put_user( ((*WDOG_CR(IO_ADDRESS(EXC_WATCHDOG00_BASE)))/EXC_INPUT_CLK_FREQUENCY), (int*)arg);
++	}
++}
++
++static struct file_operations epxa1dog_fops = {
++	.owner		= THIS_MODULE,
++	.write		= epxa1dog_write,
++	.ioctl		= epxa1dog_ioctl,
++	.open		= epxa1dog_open,
++	.release	= epxa1dog_release,
++};
++
++static struct miscdevice epxa1dog_miscdev=
++{
++	.minor	= WATCHDOG_MINOR,
++	.name	= "EPXA watchdog",
++	.fops	= &epxa1dog_fops
++};
++
++static int __init epxa1dog_init(void)
++{
++	int ret;
++
++	ret = misc_register(&epxa1dog_miscdev);
++
++	if (ret)
++		return ret;
++
++	printk("EPXA Watchdog Timer: timer margin %d sec\n", margin);
++	printk("EPXA Watchdog Timer: no way out is %s\n", nowayout ? "enabled" : "disabled");
++
++	return 0;
++}
++
++static void __exit epxa1dog_exit(void)
++{
++	misc_deregister(&epxa1dog_miscdev);
++}
++
++module_init(epxa1dog_init);
++module_exit(epxa1dog_exit);
++
++MODULE_AUTHOR("Krzysztof Marianski <kmarian@konin.lm.pl>");
++MODULE_DESCRIPTION("EPXA Watchdog Timer");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/gc_kbmap.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,162 @@
++
++
++#define KK_NONE		0x7f
++#define KK_ESC		0x00
++#define KK_F1		0x01
++#define KK_F2		0x02
++#define KK_F3		0x03
++#define KK_F4		0x04
++#define KK_F5		0x05
++#define KK_F6		0x06
++#define KK_F7		0x07
++#define KK_F8		0x08
++#define KK_F9		0x09
++#define KK_F10		0x0a
++#define KK_F11		0x0b
++#define KK_F12		0x0c
++#define KK_PRNT		0x0d
++#define KK_SCRL		0x0e
++#define KK_BRK		0x0f
++#define KK_AGR		0x10
++#define KK_1		0x11
++#define KK_2		0x12
++#define KK_3		0x13
++#define KK_4		0x14
++#define KK_5		0x15
++#define KK_6		0x16
++#define KK_7		0x17
++#define KK_8		0x18
++#define KK_9		0x19
++#define KK_0		0x1a
++#define KK_MINS		0x1b
++#define KK_EQLS		0x1c
++#define KK_BKSP		0x1e
++#define KK_INS		0x1f
++#define KK_HOME		0x20
++#define KK_PGUP		0x21
++#define KK_NUML		0x22
++#define KP_SLH		0x23
++#define KP_STR		0x24
++#define KP_MNS		0x3a
++#define KK_TAB		0x26
++#define KK_Q		0x27
++#define KK_W		0x28
++#define KK_E		0x29
++#define KK_R		0x2a
++#define KK_T		0x2b
++#define KK_Y		0x2c
++#define KK_U		0x2d
++#define KK_I		0x2e
++#define KK_O		0x2f
++#define KK_P		0x30
++#define KK_LSBK		0x31
++#define KK_RSBK		0x32
++#define KK_ENTR		0x47
++#define KK_DEL		0x34
++#define KK_END		0x35
++#define KK_PGDN		0x36
++#define KP_7		0x37
++#define KP_8		0x38
++#define KP_9		0x39
++#define KP_PLS		0x4b
++#define KK_CAPS		0x5d
++#define KK_A		0x3c
++#define KK_S		0x3d
++#define KK_D		0x3e
++#define KK_F		0x3f
++#define KK_G		0x40
++#define KK_H		0x41
++#define KK_J		0x42
++#define KK_K		0x43
++#define KK_L		0x44
++#define KK_SEMI		0x45
++#define KK_SQOT		0x46
++#define KK_HASH		0x1d
++#define KP_4		0x48
++#define KP_5		0x49
++#define KP_6		0x4a
++#define KK_LSFT		0x4c
++#define KK_BSLH		0x33
++#define KK_Z		0x4e
++#define KK_X		0x4f
++#define KK_C		0x50
++#define KK_V		0x51
++#define KK_B		0x52
++#define KK_N		0x53
++#define KK_M		0x54
++#define KK_COMA		0x55
++#define KK_DOT		0x56
++#define KK_FSLH		0x57
++#define KK_RSFT		0x58
++#define KK_UP		0x59
++#define KP_1		0x5a
++#define KP_2		0x5b
++#define KP_3		0x5c
++#define KP_ENT		0x67
++#define KK_LCTL		0x3b
++#define KK_LALT		0x5e
++#define KK_SPCE		0x5f
++#define KK_RALT		0x60
++#define KK_RCTL		0x61
++#define KK_LEFT		0x62
++#define KK_DOWN		0x63
++#define KK_RGHT		0x64
++#define KP_0		0x65
++#define KP_DOT		0x66
++
++static char kbmap[128] = {
++KK_NONE, KK_LALT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_AGR,  KK_BSLH, KK_TAB,  KK_Z,    KK_A,    KK_X,    KK_NONE,
++KK_NONE, KK_NONE, KK_LSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_LCTL, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, 0x21,   KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_ESC,  KK_DEL,  KK_Q,    KK_CAPS, KK_S,    KK_C,    KK_3,
++KK_NONE, KK_1,    KK_NONE, KK_W,    KK_NONE, KK_D,    KK_V,    KK_4,
++KK_NONE, KK_2,    KK_T,    KK_E,    KK_NONE, KK_F,    KK_B,    KK_5,
++KK_NONE, KK_9,    KK_Y,    KK_R,    KK_K,    KK_G,    KK_N,    KK_6,
++KK_NONE, KK_0,    KK_U,    KK_O,    KK_L,    KK_H,    KK_M,    KK_7,
++KK_NONE, KK_MINS, KK_I,    KK_P,    KK_SEMI, KK_J,    KK_COMA, KK_8,
++KK_NONE, KK_EQLS, KK_ENTR, KK_LSBK, KK_BSLH, KK_FSLH, KK_DOT,  KK_NONE,
++KK_NONE, KK_NONE, KK_RSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_BKSP, KK_DOWN, KK_RSBK, KK_UP,   KK_LEFT, KK_SPCE, KK_RGHT,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE};
++
++static char kbmapFN[128] = {
++KK_NONE, KK_LALT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_LSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_LCTL, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE,   0x21, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F3,
++KK_NONE, KK_F1,   KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F4,
++KK_NONE, KK_F2,   KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F5,
++KK_NONE, KK_F9,   KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F6,
++KK_NONE, KK_F10,  KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_F7,
++KK_NONE, KK_NUML, KK_NONE, KK_INS,  KK_PRNT, KK_NONE, KK_NONE, KK_F8,
++KK_NONE, KK_BRK,  KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_RSFT, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_PGDN, KK_SCRL, KK_PGUP, KK_HOME, KK_NONE, KK_END,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE};
++
++static char kbmapNL[128] = {
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KP_9,   KK_NONE, KK_NONE, KP_2,   KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KP_STR, KP_4,   KP_6,   KP_3,   KK_NONE, KP_0,   KP_7,
++KK_NONE, KK_NONE, KP_5,   KP_MNS, KP_PLS, KP_1,   KK_NONE, KP_8,
++KK_NONE, KK_NONE, KP_ENT, KK_NONE, KK_NONE, KP_SLH, KP_DOT, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE,
++KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE, KK_NONE};
++
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/gc_keyb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,1145 @@
++/*
++ * linux/arch/arm/drivers/char/gc_keyb.c
++ *
++ * Copyright 2000 Applied Data Systems
++ *
++ * Keyboard & Smartio driver for GraphicsClient ARM Linux.
++ * Graphics Client is SA1110 based single board computer by
++ *    Applied Data Systems (http://www.applieddata.net)
++ *
++ * Change log:
++ *    7-10/6/01 Thomas Thaele <tthaele@papenmeier.de>
++ *       - Added Keyboard Sniffer on /dev/sio12 <minor = 12>
++ *       - First implementation of PC- compatible Scancodes (thanks to pc_keyb.c)
++ *       3/23/01 Woojung Huh
++ *          Power Management added
++ * 		12/01/00 Woojung Huh
++ * 			Bug fixed
++ * 		11/16/00 Woojung Huh [whuh@applieddata.net]
++ * 			Added smartio device driver on it
++ */
++
++/*
++ * Introduced setkeycode, ketkeycode for the GC+ by Thomas Thaele
++ * <tthaele@papenmeier.de> GC+ now performs like a real PC on the keyboard.
++ * Warning: this code is still beta! PrntScrn and Pause keys are not
++ * completely tested and implemented!!! Keyboard driver can be confused
++ * by hacking like crazy on the keyboard. (hardware problem on serial line?)
++ */
++
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/kbd_ll.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/kbd_kern.h>
++
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/keyboard.h>
++#include <linux/tqueue.h>
++#include <linux/proc_fs.h>
++#include <linux/pm.h>
++
++#define ADS_AVR_IRQ	63
++
++#define	SMARTIO_IOCTL_BASES		's'
++#define	SMARTIO_KPD_TIMEOUT		_IOW(SMARTIO_IOCTL_BASES, 0, int)
++#define	SMARTIO_KPD_SETUP		_IOW(SMARTIO_IOCTL_BASES, 1, short)
++#define	SMARTIO_BL_CONTROL		_IOW(SMARTIO_IOCTL_BASES, 2, char)
++#define	SMARTIO_BL_CONTRAST		_IOW(SMARTIO_IOCTL_BASES, 3, char)
++#define SMARTIO_PORT_CONFIG		_IOW(SMARTIO_IOCTL_BASES, 4, char)
++#define SMARTIO_SNIFFER_TIMEOUT		_IOW(SMARTIO_IOCTL_BASES, 5, long)
++
++
++/* Simple translation table for the SysRq keys */
++
++#ifdef CONFIG_MAGIC_SYSRQ
++unsigned char pckbd_sysrq_xlate[128] =
++	"\000\0331234567890-=\177\t"			/* 0x00 - 0x0f */
++	"qwertyuiop[]\r\000as"				/* 0x10 - 0x1f */
++	"dfghjkl;'`\000\\zxcv"				/* 0x20 - 0x2f */
++	"bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
++	"\206\207\210\211\212\000\000789-456+1"		/* 0x40 - 0x4f */
++	"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
++	"\r\000/";					/* 0x60 - 0x6f */
++#endif
++
++/*
++ * Translation of escaped scancodes to keycodes.
++ * This is now user-settable.
++ * The keycodes 1-88,96-111,119 are fairly standard, and
++ * should probably not be changed - changing might confuse X.
++ * X also interprets scancode 0x5d (KEY_Begin).
++ *
++ * For 1-88 keycode equals scancode.
++ */
++
++#define E0_KPENTER 96
++#define E0_RCTRL   97
++#define E0_KPSLASH 98
++#define E0_PRSCR   99
++#define E0_RALT    100
++#define E0_BREAK   101  /* (control-pause) */
++#define E0_HOME    102
++#define E0_UP      103
++#define E0_PGUP    104
++#define E0_LEFT    105
++#define E0_RIGHT   106
++#define E0_END     107
++#define E0_DOWN    108
++#define E0_PGDN    109
++#define E0_INS     110
++#define E0_DEL     111
++
++#define E1_PAUSE   119
++
++/*
++ * The keycodes below are randomly located in 89-95,112-118,120-127.
++ * They could be thrown away (and all occurrences below replaced by 0),
++ * but that would force many users to use the `setkeycodes' utility, where
++ * they needed not before. It does not matter that there are duplicates, as
++ * long as no duplication occurs for any single keyboard.
++ */
++#define SC_LIM 89
++
++#define FOCUS_PF1 85           /* actual code! */
++#define FOCUS_PF2 89
++#define FOCUS_PF3 90
++#define FOCUS_PF4 91
++#define FOCUS_PF5 92
++#define FOCUS_PF6 93
++#define FOCUS_PF7 94
++#define FOCUS_PF8 95
++#define FOCUS_PF9 120
++#define FOCUS_PF10 121
++#define FOCUS_PF11 122
++#define FOCUS_PF12 123
++
++#define JAP_86     124
++/* tfj@olivia.ping.dk:
++ * The four keys are located over the numeric keypad, and are
++ * labelled A1-A4. It's an rc930 keyboard, from
++ * Regnecentralen/RC International, Now ICL.
++ * Scancodes: 59, 5a, 5b, 5c.
++ */
++#define RGN1 124
++#define RGN2 125
++#define RGN3 126
++#define RGN4 127
++
++static unsigned char high_keys[128 - SC_LIM] = {
++  RGN1, RGN2, RGN3, RGN4, 0, 0, 0,                   /* 0x59-0x5f */
++  0, 0, 0, 0, 0, 0, 0, 0,                            /* 0x60-0x67 */
++  0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,          /* 0x68-0x6f */
++  0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,    /* 0x70-0x77 */
++  FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,        /* 0x78-0x7b */
++  FOCUS_PF8, JAP_86, FOCUS_PF10, 0                   /* 0x7c-0x7f */
++};
++
++/* BTC */
++#define E0_MACRO   112
++/* LK450 */
++#define E0_F13     113
++#define E0_F14     114
++#define E0_HELP    115
++#define E0_DO      116
++#define E0_F17     117
++#define E0_KPMINPLUS 118
++/*
++ * My OmniKey generates e0 4c for  the "OMNI" key and the
++ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
++ */
++#define E0_OK	124
++/*
++ * New microsoft keyboard is rumoured to have
++ * e0 5b (left window button), e0 5c (right window button),
++ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
++ * [or: Windows_L, Windows_R, TaskMan]
++ */
++#define E0_MSLW	125
++#define E0_MSRW	126
++#define E0_MSTM	127
++
++static unsigned char e0_keys[128] = {
++  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x00-0x07 */
++  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x08-0x0f */
++  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x10-0x17 */
++  0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	      /* 0x18-0x1f */
++  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x20-0x27 */
++  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x28-0x2f */
++  0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	      /* 0x30-0x37 */
++  E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	      /* 0x38-0x3f */
++  E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	      /* 0x40-0x47 */
++  E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,/* 0x48-0x4f */
++  E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	      /* 0x50-0x57 */
++  0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	      /* 0x58-0x5f */
++  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x60-0x67 */
++  0, 0, 0, 0, 0, 0, 0, E0_MACRO,		      /* 0x68-0x6f */
++  0, 0, 0, 0, 0, 0, 0, 0,			      /* 0x70-0x77 */
++  0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
++};
++
++int gc_kbd_setkeycode(unsigned int scancode, unsigned int keycode)
++{
++	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
++	  return -EINVAL;
++	if (scancode < 128)
++	  high_keys[scancode - SC_LIM] = keycode;
++	else
++	  e0_keys[scancode - 128] = keycode;
++	return 0;
++}
++
++int gc_kbd_getkeycode(unsigned int scancode)
++{
++	return
++	  (scancode < SC_LIM || scancode > 255) ? -EINVAL :
++	  (scancode < 128) ? high_keys[scancode - SC_LIM] :
++	    e0_keys[scancode - 128];
++}
++
++int gc_kbd_translate(unsigned char scancode, unsigned char *keycode,
++		    char raw_mode)
++{
++	static int prev_scancode;
++
++	/* special prefix scancodes.. */
++	if (scancode == 0xe0 || scancode == 0xe1) {
++		prev_scancode = scancode;
++		return 0;
++	}
++
++	/* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
++	if (scancode == 0x00 || scancode == 0xff) {
++		prev_scancode = 0;
++		return 0;
++	}
++
++	scancode &= 0x7f;
++
++	if (prev_scancode) {
++	  /*
++	   * usually it will be 0xe0, but a Pause key generates
++	   * e1 1d 45 e1 9d c5 when pressed, and nothing when released
++	   */
++	  if (prev_scancode != 0xe0) {
++	      if (prev_scancode == 0xe1 && scancode == 0x1d) {
++		  prev_scancode = 0x100;
++		  return 0;
++	      } else if (prev_scancode == 0x100 && scancode == 0x45) {
++		  *keycode = E1_PAUSE;
++		  prev_scancode = 0;
++	      } else {
++#ifdef KBD_REPORT_UNKN
++		  if (!raw_mode)
++		    printk(KERN_INFO "keyboard: unknown e1 escape sequence\n");
++#endif
++		  prev_scancode = 0;
++		  return 0;
++	      }
++	  } else {
++	      prev_scancode = 0;
++	      /*
++	       *  The keyboard maintains its own internal caps lock and
++	       *  num lock statuses. In caps lock mode E0 AA precedes make
++	       *  code and E0 2A follows break code. In num lock mode,
++	       *  E0 2A precedes make code and E0 AA follows break code.
++	       *  We do our own book-keeping, so we will just ignore these.
++	       */
++	      /*
++	       *  For my keyboard there is no caps lock mode, but there are
++	       *  both Shift-L and Shift-R modes. The former mode generates
++	       *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
++	       *  So, we should also ignore the latter. - aeb@cwi.nl
++	       */
++	      if (scancode == 0x2a || scancode == 0x36)
++		return 0;
++
++	      if (e0_keys[scancode])
++		*keycode = e0_keys[scancode];
++	      else {
++#ifdef KBD_REPORT_UNKN
++		  if (!raw_mode)
++		    printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n",
++			   scancode);
++#endif
++		  return 0;
++	      }
++	  }
++	} else if (scancode >= SC_LIM) {
++	    /* This happens with the FOCUS 9000 keyboard
++	       Its keys PF1..PF12 are reported to generate
++	       55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
++	       Moreover, unless repeated, they do not generate
++	       key-down events, so we have to zero up_flag below */
++	    /* Also, Japanese 86/106 keyboards are reported to
++	       generate 0x73 and 0x7d for \ - and \ | respectively. */
++	    /* Also, some Brazilian keyboard is reported to produce
++	       0x73 and 0x7e for \ ? and KP-dot, respectively. */
++
++	  *keycode = high_keys[scancode - SC_LIM];
++
++	  if (!*keycode) {
++	      if (!raw_mode) {
++#ifdef KBD_REPORT_UNKN
++		  printk(KERN_INFO "keyboard: unrecognized scancode (%02x)"
++			 " - ignored\n", scancode);
++#endif
++	      }
++	      return 0;
++	  }
++ 	} else
++	  *keycode = scancode;
++ 	return 1;
++}
++
++// this table converts the hardware dependent codes of a MF-2 Keyboard to
++// the codes normally comming out of a i8042. This table is 128 Bytes too
++// big, but for stability reasons it should be kept like it is!
++// There is no range checking in the code!
++static int mf_two_kbdmap[256] = {
++	00, 67, 65, 63, 61, 59, 60, 88, 00, 68, 66, 64, 62, 15, 41, 00,
++	00, 56, 42, 00, 29, 16, 02, 00, 00, 00, 44, 31, 30, 17, 03, 00,
++	00, 46, 45, 32, 18, 05, 04, 00, 00, 57, 47, 33, 20, 19, 06, 00,
++	00, 49, 48, 35, 34, 21,  7, 00, 00, 00, 50, 36, 22,  8,  9, 00,
++	00, 51, 37, 23, 24, 11, 10, 00, 00, 52, 53, 38, 39, 25, 12, 00,
++	00, 00, 40, 00, 26, 13, 00, 00, 58, 54, 28, 27, 00, 43, 00, 00,
++	00, 86, 00, 00, 00, 00, 14, 00, 00, 79, 00, 75, 71, 00, 00, 00,
++	82, 83, 80, 76, 77, 72, 01, 69, 87, 78, 81, 74, 55, 73, 70, 00,
++	00, 00, 00, 65, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
++	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
++	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
++	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
++	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
++	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
++	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
++	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 };
++
++
++// some texts displayed by the proc_file_system
++static char *kbd_sniff[2] = { "off", "on" };
++static char *kbd_sniff_mode[2] = { "passive", "active" };
++
++#define PASSIVE 0
++#define ACTIVE  1
++
++// is the sniffer active (1) or inactive (0)
++static int  SNIFFER = 0;
++// do we get a copy (SNIFFMODE = PASSIVE) or do we get the original data (SNIFFMODE = ACTIVE)
++// and have to reinsert the data
++static int  SNIFFMODE = PASSIVE;
++
++// we allow only one process to sniff
++static int sniffer_in_use = 0;
++
++// timeout for the keyboard sniffer -1 = blocking, otherwise timeout in msecs
++static long sniffer_timeout = -1;
++
++// the value we sniffed from the keyboard
++static int sniffed_value;
++
++static char *smartio_version = "1.02 MF-II compatibility patch <tthaele@papenmeier.de>";
++static char *smartio_date = "Aug-27-2001";
++
++static int sio_reset_flag;
++static int kbd_press_flag;
++
++static void send_SSP_msg(unchar *pBuf, int num)
++{
++	ushort	tmp;
++	int		i;
++
++	for (i=0;i<num;i++) {
++		while ((Ser4SSSR & SSSR_TNF) == 0);
++		tmp = pBuf[i];
++		Ser4SSDR = (tmp << 8);
++	}
++
++	// Throw away Echo
++	for (i=0;i<num;i++) {
++		while ((Ser4SSSR & SSSR_RNE) == 0);
++		tmp = Ser4SSDR;
++	}
++}
++
++static unchar ReadSSPByte(void)
++{
++	if (Ser4SSSR & SSSR_ROR) {
++		printk("%s() : Overrun\n", __FUNCTION__);
++		return 0;
++	}
++
++	Ser4SSDR = 0x00;
++
++	while ((Ser4SSSR & SSSR_RNE) == 0);
++
++	return ((unchar) Ser4SSDR);
++}
++
++static ulong read_SSP_response(int num)
++{
++	int		i;
++	ulong	ret;
++
++	// discard leading 0x00 and command echo 0 (command group value)
++	while (ReadSSPByte() == 0);
++	// discard command echo 1 (command code value)
++	ReadSSPByte();
++
++	// data from SMARTIO
++	// It assumes LSB first.
++	// NOTE:Some command uses MSB first order
++	ret = 0;
++	for (i=0;i<num;i++) {
++		ret |= ReadSSPByte() << (8*i);
++	}
++
++	return ret;
++}
++
++typedef	struct	t_SMARTIO_CMD {
++	unchar	Group;
++	unchar	Code;
++	unchar  Opt[2];
++}	SMARTIO_CMD;
++
++static	SMARTIO_CMD RD_INT_CMD = { 0x83, 0x01, { 0x00, 0x00 } };
++static	SMARTIO_CMD RD_KBD_CMD = { 0x83, 0x02, { 0x00, 0x00 } };
++static	SMARTIO_CMD RD_ADC_CMD = { 0x83, 0x28, { 0x00, 0x00 } };
++static	SMARTIO_CMD RD_KPD_CMD = { 0x83, 0x04, { 0x00, 0x00 } };
++
++static	volatile ushort	adc_value;
++static	volatile unchar	kpd_value;
++static	unsigned int	kpd_timeout = 10000;			// 10000 msec
++
++static  ulong kbd_int, kpd_int, adc_int;
++
++static void smartio_interrupt_task(void *data);
++
++static struct tq_struct tq_smartio = {
++		{ NULL,	NULL },		// struct list_head
++		0,			// unsigned long sync
++		smartio_interrupt_task,	// void (*routine)(void *)
++		NULL,			// void *data
++};
++
++DECLARE_WAIT_QUEUE_HEAD(smartio_queue);
++DECLARE_WAIT_QUEUE_HEAD(smartio_adc_queue);
++DECLARE_WAIT_QUEUE_HEAD(smartio_kpd_queue);
++DECLARE_WAIT_QUEUE_HEAD(keyboard_done_queue);
++DECLARE_WAIT_QUEUE_HEAD(sniffer_queue);
++
++static spinlock_t smartio_busy_lock = SPIN_LOCK_UNLOCKED;
++static atomic_t	smartio_busy = ATOMIC_INIT(0);
++
++static int f_five_pressed = 0;
++static int f_seven_pressed = 0;
++//static int e_null_counter = 0;
++//static int f_null_counter = 0;
++//static int keydown = 0;
++static unchar previous_code = 0;
++//static int e0 = 0;
++
++static void smartio_interrupt_task(void *arg)
++{
++	unchar	code;
++	unsigned long flags;
++	unchar  dummy;
++
++	spin_lock_irqsave(&smartio_busy_lock, flags);
++	if (atomic_read(&smartio_busy) == 1) {
++		spin_unlock_irqrestore(&smartio_busy_lock, flags);
++		queue_task(&tq_smartio, &tq_timer);
++	}
++	else {
++		atomic_set(&smartio_busy, 1);
++		spin_unlock_irqrestore(&smartio_busy_lock, flags);
++	}
++
++	/* Read SMARTIO Interrupt Status to check which Interrupt is occurred
++	 * and Clear SMARTIO Interrupt */
++	send_SSP_msg((unchar *) &RD_INT_CMD, 2);
++	code = (unchar) (read_SSP_response(1) & 0xFF);
++
++#ifdef CONFIG_VT
++	if (code  & 0x04) {					// Keyboard Interrupt
++		kbd_int++;
++		/* Read Scan code */
++		send_SSP_msg((unchar *) &RD_KBD_CMD, 2);
++		code = (unchar) (read_SSP_response(1) & 0xFF);
++		dummy = code & 0x80;
++		if ((code == 0xE0) || (code == 0xE1) || (code == 0xF0)) {	// combined code
++			if (code == 0xF0) {
++				if (!previous_code) {
++					code = 0xE0;
++					previous_code = 0xF0;
++				} else {
++					code = mf_two_kbdmap[code & 0x7F] | dummy;
++					previous_code = 0;
++				}
++			} else if (code == 0xE0) {
++				if (previous_code != 0) {
++					code = mf_two_kbdmap[code & 0x7F] | dummy;
++					previous_code = 0;
++				} else previous_code = code;
++			} else {						// 0xE1
++				if (!previous_code) {
++					code = mf_two_kbdmap[code &0x7F] | dummy;
++					previous_code = 0;
++				} else {
++					previous_code = code;
++				}
++			}
++		} else {
++			if (code == 0x03) {
++				f_five_pressed = 1;
++			} else if (code == 0x83) {
++				if (f_five_pressed != 0) {
++					f_five_pressed = 0;
++					code = 0x03;
++				} else if (f_seven_pressed == 0) {
++					f_seven_pressed = 1;
++					code = 2;
++					dummy = 0;
++				} else {
++					f_seven_pressed = 0;
++					code = 2;
++				}
++			}
++			previous_code = 0;
++			code &= 0x7F;
++			code = mf_two_kbdmap[code] | dummy;
++		}
++		sniffed_value = (ushort)code;
++		if (SNIFFER) wake_up_interruptible(&sniffer_queue);
++		if (SNIFFMODE == PASSIVE) {
++			handle_scancode( code, (code & 0x80) ? 0 : 1 );
++			if (code & 0x80) {
++				wake_up_interruptible(&keyboard_done_queue);
++				mdelay(10);		// this makes the whole thing a bit more stable
++							// keyboard handling can be corrupted when hitting
++							// thousands of keys like crazy. kbd_translate might catch up
++							// with irq routine? or there is simply a buffer overflow on
++							// the serial device? somehow it looses some key sequences.
++							// if a break code is lost or coruppted the keyboard starts
++							// to autorepeat like crazy and appears to hang.
++							// this needs further investigations! Thomas
++				kbd_press_flag = 0;
++			}
++			else
++				kbd_press_flag = 1;
++		}
++		code = 0;       // prevent furthermore if ... then to react!
++	}
++#endif
++	// ADC resolution is 10bit (0x000 ~ 0x3FF)
++	if (code & 0x02) {					// ADC Complete Interrupt
++		adc_int++;
++		send_SSP_msg((unchar *) &RD_ADC_CMD, 2);
++		adc_value = (ushort) (read_SSP_response(2) & 0x3FF);
++		wake_up_interruptible(&smartio_adc_queue);
++	}
++
++	if (code & 0x08) { 					// Keypad interrupt
++		kpd_int++;
++		send_SSP_msg((unchar *) &RD_KPD_CMD, 2);
++		kpd_value = (unchar) (read_SSP_response(1) & 0xFF);
++		wake_up_interruptible(&smartio_kpd_queue);
++	}
++
++	spin_lock_irqsave(&smartio_busy_lock, flags);
++	atomic_set(&smartio_busy, 0);
++	spin_unlock_irqrestore(&smartio_busy_lock, flags);
++
++	enable_irq(ADS_AVR_IRQ);
++
++	wake_up_interruptible(&smartio_queue);
++}
++
++static void gc_sio_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++#ifdef CONFIG_VT
++	kbd_pt_regs = regs;
++#endif
++
++	// *NOTE*
++	// ADS SMARTIO interrupt is cleared after reading interrupt status
++	// from smartio.
++	// disable SMARTIO IRQ here and re-enable at samrtio_bh.
++	// 11/13/00 Woojung
++	disable_irq(ADS_AVR_IRQ);
++
++	queue_task(&tq_smartio, &tq_immediate);
++	mark_bh(IMMEDIATE_BH);
++}
++
++char gc_kbd_unexpected_up(unsigned char keycode)
++{
++	return 0;
++}
++
++static inline void gc_sio_init(void)
++{
++	GPDR |= (GPIO_GPIO10 | GPIO_GPIO12 | GPIO_GPIO13); 	// Output
++	GPDR &= ~GPIO_GPIO11;
++
++	// Alternative Function
++	GAFR |= (GPIO_GPIO10 | GPIO_GPIO11 | GPIO_GPIO12 | GPIO_GPIO13);
++
++	Ser4SSCR0 = 0xA707;
++	Ser4SSSR = SSSR_ROR;
++	Ser4SSCR1 = 0x0010;
++	Ser4SSCR0 = 0xA787;
++
++	// Reset SMARTIO
++	ADS_AVR_REG &= 0xFE;
++	mdelay(300);			// 10 mSec
++	ADS_AVR_REG |= 0x01;
++	mdelay(10);			// 10 mSec
++
++}
++
++void __init gc_kbd_init_hw(void)
++{
++	printk (KERN_INFO "Graphics Client keyboard driver v1.0\n");
++
++	k_setkeycode	= gc_kbd_setkeycode;
++	k_getkeycode	= gc_kbd_getkeycode;
++	k_translate	= gc_kbd_translate;
++	k_unexpected_up	= gc_kbd_unexpected_up;
++#ifdef CONFIG_MAGIC_SYSRQ
++	k_sysrq_key	= 0x54;
++	/* sysrq table??? --rmk */
++#endif
++
++	gc_sio_init();
++
++	if (request_irq(ADS_AVR_IRQ,gc_sio_interrupt,0,"smartio", NULL) != 0)
++		printk("Could not allocate SMARTIO IRQ!\n");
++
++	sio_reset_flag = 1;
++}
++
++/* SMARTIO ADC Interface */
++#define SMARTIO_VERSION				0
++#define SMARTIO_PORT_A				1
++#define SMARTIO_PORT_B				2
++#define SMARTIO_PORT_C				3
++#define SMARTIO_PORT_D				4
++#define SMARTIO_SELECT_OPTION			5
++#define SMARTIO_BACKLITE			6
++#define SMARTIO_KEYPAD				7
++#define SMARTIO_ADC				8
++#define	SMARTIO_VEE_PWM				9
++#define SMARTIO_SLEEP				11
++#define SMARTIO_KBD_SNIFFER			12
++
++static	SMARTIO_CMD CONV_ADC_CMD = { 0x80, 0x28, { 0x00, 0x00 } };
++static	SMARTIO_CMD READ_PORT_CMD = { 0x82, 0x00, { 0x00, 0x00 } };
++
++static	SMARTIO_CMD READ_DEVVER_CMD = { 0x82, 0x05, { 0x00, 0x00 } };
++static	SMARTIO_CMD READ_DEVTYPE_CMD = { 0x82, 0x06, { 0x00, 0x00 } };
++static	SMARTIO_CMD READ_FWLEVEL_CMD = { 0x82, 0x07, { 0x00, 0x00 } };
++
++static int lock_smartio(unsigned long *flags)
++{
++	spin_lock_irqsave(&smartio_busy_lock, *flags);
++	if (atomic_read(&smartio_busy) == 1) {
++		spin_unlock_irqrestore(&smartio_busy_lock, *flags);
++		interruptible_sleep_on(&smartio_queue);
++	}
++	else {
++		atomic_set(&smartio_busy, 1);
++		spin_unlock_irqrestore(&smartio_busy_lock, *flags);
++	}
++
++	return 1;
++}
++
++static int unlock_smartio(unsigned long *flags)
++{
++	spin_lock_irqsave(&smartio_busy_lock, *flags);
++	atomic_set(&smartio_busy, 0);
++	spin_unlock_irqrestore(&smartio_busy_lock, *flags);
++
++	return 1;
++}
++
++static ushort read_sio_adc(int channel)
++{
++	unsigned long	flags;
++
++	if ((channel < 0) || (channel > 7))
++		return 0xFFFF;
++
++	CONV_ADC_CMD.Opt[0] = (unchar) channel;
++
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &CONV_ADC_CMD, 3);
++	unlock_smartio(&flags);
++
++	interruptible_sleep_on(&smartio_adc_queue);
++
++	return adc_value & 0x3FF;
++}
++
++static ushort read_sio_port(int port)
++{
++	unsigned long	flags;
++	ushort			ret;
++
++	if ((port < SMARTIO_PORT_B) || (port > SMARTIO_PORT_D))
++		return 0xFFFF;
++
++	READ_PORT_CMD.Code = (unchar) port;
++
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &READ_PORT_CMD, 2);
++	ret = read_SSP_response(1);
++	unlock_smartio(&flags);
++
++	return ret;
++}
++
++static ushort read_sio_kpd(void)
++{
++	long	timeout;
++
++	// kpd_timeout is mSec order
++	// interrupt_sleep_on_timeout is based on 10msec timer tick
++	if (kpd_timeout == -1) {
++		interruptible_sleep_on(&smartio_kpd_queue);
++	}
++	else {
++		timeout = interruptible_sleep_on_timeout(&smartio_kpd_queue,
++								kpd_timeout/10);
++		if (timeout == 0) {
++			// timeout without keypad input
++			return 0xFFFF;
++		}
++	}
++	return kpd_value;
++}
++
++static ushort read_sio_sniff(void)
++{
++        long    timeout;
++
++        // kpd_timeout is mSec order
++        // interrupt_sleep_on_timeout is based on 10msec timer tick
++        if (sniffer_timeout == -1) {
++                interruptible_sleep_on(&sniffer_queue);
++        }
++        else {
++                timeout = interruptible_sleep_on_timeout(&sniffer_queue,
++                                                                sniffer_timeout/10);
++                if (timeout == 0) {
++                        // timeout without keypad input
++                        return -1;
++                }
++        }
++        return (ushort)sniffed_value;
++}
++
++static struct sio_ver {
++	uint	DevVer;
++	uint	DevType;
++	uint	FwLevel;
++};
++
++static ushort read_sio_version(struct sio_ver *ptr)
++{
++	unsigned long	flags;
++	ushort          ret;
++
++	// Read Device Version
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &READ_DEVVER_CMD, 2);
++	ret = read_SSP_response(1);
++	unlock_smartio(&flags);
++	ptr->DevVer = (uint)ret;
++	// Read Device Type
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &READ_DEVTYPE_CMD, 2);
++	ret = read_SSP_response(2);
++	unlock_smartio(&flags);
++	// swap MSB & LSB
++	ret = ((ret & 0xFF) << 8) | ((ret & 0xFF00) >> 8);
++	ptr->DevType = (uint)ret;
++	// Read Firmware Level
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &READ_FWLEVEL_CMD, 2);
++	ret = read_SSP_response(2);
++	unlock_smartio(&flags);
++	// swap MSB & LSB
++	ret = ((ret & 0xFF) << 8) | ((ret & 0xFF00) >> 8);
++	ptr->FwLevel = (uint)ret;
++
++	return 0;
++}
++
++static ssize_t sio_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++	struct inode *inode = file->f_dentry->d_inode;
++	unsigned int minor = MINOR(inode->i_rdev);
++	ushort	*ret = (ushort *)buf;
++
++	switch (minor) {
++	case	SMARTIO_ADC:
++			if ((*ret = read_sio_adc(buf[0])) != 0xFFFF)
++				return sizeof(ushort);					// 2 bytes
++	case	SMARTIO_PORT_B:
++	case	SMARTIO_PORT_C:
++	case	SMARTIO_PORT_D:
++			if ((*ret = read_sio_port(minor)) != 0xFFFF)
++				return sizeof(ushort);
++	case	SMARTIO_VERSION:
++			if ((read_sio_version((struct sio_ver *)buf)) != 0xFFFF)
++				return sizeof(struct sio_ver);
++	case	SMARTIO_KEYPAD:
++			if ((*ret = read_sio_kpd()) != 0xFFFF)
++				return sizeof(ushort);
++	case	SMARTIO_KBD_SNIFFER:
++			if ((*ret = read_sio_sniff()) != (ushort)-1)
++				return 1;
++	default :
++			return -ENXIO;
++	}
++}
++
++static	SMARTIO_CMD WRITE_PORT_CMD = { 0x81, 0x00, { 0x00, 0x00 } };
++static	SMARTIO_CMD SELECT_OPT_CMD = { 0x80, 0x00, { 0x00, 0x00 } };
++static	SMARTIO_CMD CONTROL_BL_CMD = { 0x80, 0x00, { 0x00, 0x00 } };
++static	SMARTIO_CMD CONTRAST_BL_CMD = { 0x80, 0x21, { 0x00, 0x00 } };
++static	SMARTIO_CMD CONTROL_KPD_CMD = { 0x80, 0x27, { 0x00, 0x00 } };
++static	SMARTIO_CMD CONTROL_VEE_CMD = { 0x80, 0x22, { 0x00, 0x00 } };
++
++static ushort write_sio_port(int port, unchar value)
++{
++	unsigned long	flags;
++
++	if ((port < SMARTIO_PORT_B) || (port > SMARTIO_PORT_D))
++		return 0xFFFF;
++
++	WRITE_PORT_CMD.Code = (unchar) port;
++	WRITE_PORT_CMD.Opt[0] = (unchar) value;
++
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &WRITE_PORT_CMD, 3);
++	unlock_smartio(&flags);
++
++	return 0;
++}
++
++static ushort write_sio_select(unchar select)
++{
++	unsigned long	flags;
++
++	if ((select < 1) || (select > 2))
++		return 0xFFFF;
++
++	SELECT_OPT_CMD.Code = (unchar) (select + 0x28);
++
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &SELECT_OPT_CMD, 2);
++	unlock_smartio(&flags);
++
++	return 0;
++}
++
++static ushort control_sio_backlite(int cmd, int value)
++{
++	unsigned long	flags;
++
++	if (cmd == SMARTIO_BL_CONTRAST) {
++		value &= 0xFF;
++		CONTRAST_BL_CMD.Opt[0] = (unchar) value;
++
++		lock_smartio(&flags);
++		send_SSP_msg((unchar *) &CONTRAST_BL_CMD, 3);
++		unlock_smartio(&flags);
++	}
++	else if (cmd == SMARTIO_BL_CONTROL) {
++		if (value == 0x00) {
++			// Backlite OFF
++			CONTROL_BL_CMD.Code = 0x24;
++		}
++		else {
++			// Backlite ON
++			CONTROL_BL_CMD.Code = 0x23;
++		}
++		lock_smartio(&flags);
++		send_SSP_msg((unchar *) &CONTROL_BL_CMD, 2);
++		unlock_smartio(&flags);
++	}
++	else
++		return 0xFFFF;
++
++	return 0;
++}
++
++static ushort control_sio_keypad(int x, int y)
++{
++	unsigned long	flags;
++
++	if ( (x<1) || (x>8) || (y<1) || (y>8)) {
++		return 0xFFFF;
++	}
++
++	CONTROL_KPD_CMD.Opt[0] = (unchar) x;
++	CONTROL_KPD_CMD.Opt[1] = (unchar) y;
++
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &CONTROL_KPD_CMD, 4);
++	unlock_smartio(&flags);
++
++	return 0;
++}
++
++static ushort control_sio_vee(int value)
++{
++	unsigned long	flags;
++
++	value &= 0xFF;
++	CONTROL_VEE_CMD.Opt[0] = (unchar) value;
++
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &CONTROL_VEE_CMD, 3);
++	unlock_smartio(&flags);
++
++	return 0;
++}
++
++static ssize_t sio_write(struct file *file, const char *buf, size_t cont, loff_t *ppos)
++{
++	struct inode *inode = file->f_dentry->d_inode;
++	unsigned int minor = MINOR(inode->i_rdev);
++
++	switch (minor) {
++	case	SMARTIO_PORT_B:
++	case	SMARTIO_PORT_C:
++	case	SMARTIO_PORT_D:
++			if (write_sio_port(minor, buf[0]) != 0xFFFF)
++				return 1;
++	case	SMARTIO_SELECT_OPTION:
++			if (write_sio_select(buf[0]) != 0xFFFF)
++				return 1;
++	case	SMARTIO_BACKLITE:
++			if (control_sio_backlite(SMARTIO_BL_CONTROL, buf[0]) != 0xFFFF)
++				return 1;
++	case	SMARTIO_KEYPAD:
++			if (control_sio_keypad(buf[0], buf[1]) != 0xFFFF)
++				return 2;
++	case	SMARTIO_VEE_PWM:
++			if (control_sio_vee(buf[0]) != 0xFFFF)
++				return 1;
++	case	SMARTIO_KBD_SNIFFER:
++			// here are the scancodes injected
++			handle_scancode((unchar)buf[0], (buf[0] & 0x80) ? 0 : 1);
++			wake_up_interruptible(&keyboard_done_queue);
++			// give some time to process! File IO is a bit faster than manual typing ;-)
++			udelay(10000);
++			return 1;
++	default:
++		return -ENXIO;
++	}
++}
++
++static unsigned int sio_poll(struct file *file, struct poll_table_struct *wait)
++{
++	return 0;
++}
++
++static	SMARTIO_CMD IOCTL_PORT_CMD = { 0x81, 0x00, { 0x00, 0x00 } };
++
++static ushort ioctl_sio_port(int port, unchar value)
++{
++	unsigned long	flags;
++
++	if ((port < SMARTIO_PORT_B) || (port > SMARTIO_PORT_D))
++		return 0xFFFF;
++
++	IOCTL_PORT_CMD.Code = (unchar) port + 0x04;		// 0x05 ~ 0x08
++	if (port == SMARTIO_PORT_B) {
++		// Port B has 4 bits only
++		IOCTL_PORT_CMD.Opt[0] = (unchar) value & 0x0F;
++	}
++	else
++		IOCTL_PORT_CMD.Opt[0] = (unchar) value;
++
++	lock_smartio(&flags);
++	send_SSP_msg((unchar *) &IOCTL_PORT_CMD, 3);
++	unlock_smartio(&flags);
++
++	return 0;
++}
++
++static int sio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++	unsigned int minor = MINOR(inode->i_rdev);
++	unchar	*buf = (unchar *)arg;
++
++	switch (minor) {
++	case	SMARTIO_PORT_B:
++	case	SMARTIO_PORT_C:
++	case	SMARTIO_PORT_D:
++			if (cmd == SMARTIO_PORT_CONFIG) {
++				if (ioctl_sio_port(minor, buf[0]) != 0xFFFF)
++					return 0;
++			}
++			return -EINVAL;
++	case	SMARTIO_SELECT_OPTION:
++			if (write_sio_select(buf[0]) != 0xFFFF) return 0;
++			return -EINVAL;
++	case	SMARTIO_BACKLITE:
++			if (cmd == SMARTIO_BL_CONTROL) {
++				if (control_sio_backlite(SMARTIO_BL_CONTROL, buf[0]) != 0xFFFF) return 0;
++			}
++			else if (cmd == SMARTIO_BL_CONTRAST) {
++				if (control_sio_backlite(SMARTIO_BL_CONTRAST, buf[0]) != 0xFFFF) return 0;
++			}
++			else return -EINVAL;
++	case	SMARTIO_KEYPAD:
++			if (cmd == SMARTIO_KPD_TIMEOUT) {
++				kpd_timeout = *(long*)buf;
++				return 0;
++			}
++			else if (cmd == SMARTIO_KPD_SETUP) {
++				if (control_sio_keypad(buf[0], buf[1]) != 0xFFFF) return 0;
++			}
++			return -EINVAL;
++	case	SMARTIO_VEE_PWM:
++			if (control_sio_vee(buf[0]) != 0xFFFF) return 0;
++			return -EINVAL;
++	case	SMARTIO_KBD_SNIFFER:
++			if (cmd == SMARTIO_SNIFFER_TIMEOUT) {
++				sniffer_timeout = *(long*)buf;
++				if (sniffer_timeout < 0) sniffer_timeout = -1;
++				// the value will be devided by 10 later on
++				if (!sniffer_timeout) sniffer_timeout = 10;
++				return 0;
++			}
++			return -EINVAL;
++	default:
++		return -ENXIO;
++	}
++}
++
++static int sio_open(struct inode *inode, struct file *file)
++{
++        unsigned int minor = MINOR(inode->i_rdev);
++
++	// we open all by default. we only have a special handler for the kbd sniffer
++	switch (minor) {
++		case SMARTIO_KBD_SNIFFER:
++			if (sniffer_in_use) return -EBUSY;
++			sniffer_in_use = 1;
++			SNIFFER = 1;
++			// sniff in active or passive mode
++			if ((file->f_flags & O_RDWR) == O_RDWR) SNIFFMODE = 1; else SNIFFMODE = 0;
++			// do we have a blocking or non blocking sniffer?
++			if ((file->f_flags & O_NONBLOCK) == O_NONBLOCK) sniffer_timeout = 100; else sniffer_timeout = -1;
++			break;
++		default:
++			break;
++	}
++	return 0;
++}
++
++static int sio_close(struct inode *inode, struct file *file)
++{
++        unsigned int minor = MINOR(inode->i_rdev);
++
++	switch (minor) {
++		case SMARTIO_KBD_SNIFFER:
++			SNIFFER = 0;
++			SNIFFMODE = 0;
++			sniffer_in_use = 0;
++			break;
++		default:
++			break;
++	}
++	return 0;
++}
++
++static struct file_operations sio_fops = {
++	read: 		sio_read,
++	write:		sio_write,
++	poll:		sio_poll,
++	ioctl:		sio_ioctl,
++	open:		sio_open,
++	release:	sio_close,
++};
++
++static struct proc_dir_entry *sio_dir, *parent_dir = NULL;
++
++#define	SMARTIO_MAJOR	58
++#define	MAJOR_NR	SMARTIO_MAJOR
++
++#define	PROC_NAME	"sio"
++
++static int sio_read_proc(char *buf, char **start, off_t pos, int count, int *eof, void *data)
++{
++	char	*p = buf;
++
++	p += sprintf(p, "ADS SMARTIO Status: \n");
++	p += sprintf(p, "\t Keyboard Interrupt : %lu\n", kbd_int);
++	p += sprintf(p, "\t Keypad Interrupt : %lu\n", kpd_int);
++	p += sprintf(p, "\t ADC Interrupt : %lu\n", adc_int);
++	p += sprintf(p, "\t Keyboard Sniffer : %s mode : %s\n", kbd_sniff[ SNIFFER ], kbd_sniff_mode [ SNIFFMODE ]);
++
++	return (p-buf);
++}
++
++#ifdef	CONFIG_PM
++static int pm_smartio_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++	switch (rqst) {
++		case	PM_RESUME:
++			gc_sio_init();
++			break;
++		case	PM_SUSPEND:
++			// 4/5/01 Woojung
++			// It checks Keybard received pair of press/release code.
++			// System can sleep before receiving release code
++			if (kbd_press_flag) {
++				interruptible_sleep_on(&keyboard_done_queue);
++			}
++			break;
++	}
++
++	return 0;
++}
++#endif
++
++void __init sio_init(void)
++{
++	if (register_chrdev(MAJOR_NR, "sio", &sio_fops)) {
++		printk("smartio : unable to get major %d\n", MAJOR_NR);
++		return;
++	}
++	else {
++		printk("smartio driver initialized. version %s, date:%s\n",
++				smartio_version, smartio_date);
++
++		if (sio_reset_flag != 1) {
++			gc_sio_init();
++			if (request_irq(ADS_AVR_IRQ, gc_sio_interrupt,0,"sio",NULL) != 0){
++				printk("smartio : Could not allocate IRQ!\n");
++				return;
++			}
++		}
++
++		if ((sio_dir = create_proc_entry(PROC_NAME, 0, parent_dir)) == NULL) {
++			printk("smartio : Unable to create /proc entry\n");
++			return;
++		}
++		else {
++			sio_dir->read_proc = sio_read_proc;
++#ifdef	CONFIG_PM
++			pm_register(PM_SYS_DEV, PM_SYS_KBC, pm_smartio_callback);
++#endif
++		}
++	}
++}
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/gckeymap.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,262 @@
++/* Do not edit this file! It was automatically generated by   */
++/*    loadkeys --mktable defkeymap.map > defkeymap.c          */
++
++#include <linux/types.h>
++#include <linux/keyboard.h>
++#include <linux/kd.h>
++
++u_short plain_map[NR_KEYS] = {
++	0xf200,	0xf01b,	0xf031,	0xf032,	0xf033,	0xf034,	0xf035,	0xf036,
++	0xf037,	0xf038,	0xf039,	0xf030,	0xf02d,	0xf03d,	0xf07f,	0xf009,
++	0xfb71,	0xfb77,	0xfb65,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,
++	0xfb6f,	0xfb70,	0xf05b,	0xf05d,	0xf201,	0xf702,	0xfb61,	0xfb73,
++	0xfb64,	0xfb66,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf03b,
++	0xf027,	0xf060,	0xf700,	0xf05c,	0xfb7a,	0xfb78,	0xfb63,	0xfb76,
++	0xfb62,	0xfb6e,	0xfb6d,	0xf02c,	0xf02e,	0xf02f,	0xf700,	0xf30c,
++	0xf703,	0xf020,	0xf207,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,
++	0xf105,	0xf106,	0xf107,	0xf108,	0xf109,	0xf208,	0xf209,	0xf307,
++	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
++	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf03c,	0xf10a,
++	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
++	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
++	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++};
++
++u_short shift_map[NR_KEYS] = {
++	0xf200,	0xf01b,	0xf021,	0xf040,	0xf023,	0xf024,	0xf025,	0xf05e,
++	0xf026,	0xf02a,	0xf028,	0xf029,	0xf05f,	0xf02b,	0xf07f,	0xf009,
++	0xfb51,	0xfb57,	0xfb45,	0xfb52,	0xfb54,	0xfb59,	0xfb55,	0xfb49,
++	0xfb4f,	0xfb50,	0xf07b,	0xf07d,	0xf201,	0xf702,	0xfb41,	0xfb53,
++	0xfb44,	0xfb46,	0xfb47,	0xfb48,	0xfb4a,	0xfb4b,	0xfb4c,	0xf03a,
++	0xf022,	0xf07e,	0xf700,	0xf07c,	0xfb5a,	0xfb58,	0xfb43,	0xfb56,
++	0xfb42,	0xfb4e,	0xfb4d,	0xf03c,	0xf03e,	0xf03f,	0xf700,	0xf30c,
++	0xf703,	0xf020,	0xf207,	0xf10a,	0xf10b,	0xf10c,	0xf10d,	0xf10e,
++	0xf10f,	0xf110,	0xf111,	0xf112,	0xf113,	0xf213,	0xf203,	0xf307,
++	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
++	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf03e,	0xf10a,
++	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
++	0xf20b,	0xf601,	0xf602,	0xf117,	0xf600,	0xf20a,	0xf115,	0xf116,
++	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++};
++
++u_short altgr_map[NR_KEYS] = {
++	0xf200,	0xf200,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
++	0xf07b,	0xf05b,	0xf05d,	0xf07d,	0xf05c,	0xf200,	0xf200,	0xf200,
++	0xfb71,	0xfb77,	0xf918,	0xfb72,	0xfb74,	0xfb79,	0xfb75,	0xfb69,
++	0xfb6f,	0xfb70,	0xf200,	0xf07e,	0xf201,	0xf702,	0xf914,	0xfb73,
++	0xf917,	0xf919,	0xfb67,	0xfb68,	0xfb6a,	0xfb6b,	0xfb6c,	0xf200,
++	0xf200,	0xf200,	0xf700,	0xf200,	0xfb7a,	0xfb78,	0xf916,	0xfb76,
++	0xf915,	0xfb6e,	0xfb6d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
++	0xf703,	0xf200,	0xf207,	0xf50c,	0xf50d,	0xf50e,	0xf50f,	0xf510,
++	0xf511,	0xf512,	0xf513,	0xf514,	0xf515,	0xf208,	0xf202,	0xf911,
++	0xf912,	0xf913,	0xf30b,	0xf90e,	0xf90f,	0xf910,	0xf30a,	0xf90b,
++	0xf90c,	0xf90d,	0xf90a,	0xf310,	0xf206,	0xf200,	0xf07c,	0xf516,
++	0xf517,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
++	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
++	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++};
++
++u_short ctrl_map[NR_KEYS] = {
++	0xf200,	0xf200,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01d,	0xf01e,
++	0xf01f,	0xf07f,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf008,	0xf200,
++	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,
++	0xf00f,	0xf010,	0xf01b,	0xf01d,	0xf201,	0xf702,	0xf001,	0xf013,
++	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,
++	0xf007,	0xf000,	0xf700,	0xf01c,	0xf01a,	0xf018,	0xf003,	0xf016,
++	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf20e,	0xf07f,	0xf700,	0xf30c,
++	0xf703,	0xf000,	0xf207,	0xf100,	0xf101,	0xf102,	0xf103,	0xf104,
++	0xf105,	0xf106,	0xf107,	0xf108,	0xf109,	0xf208,	0xf204,	0xf307,
++	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
++	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf200,	0xf10a,
++	0xf10b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
++	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
++	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++};
++
++u_short shift_ctrl_map[NR_KEYS] = {
++	0xf200,	0xf200,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,
++	0xf011,	0xf017,	0xf005,	0xf012,	0xf014,	0xf019,	0xf015,	0xf009,
++	0xf00f,	0xf010,	0xf200,	0xf200,	0xf201,	0xf702,	0xf001,	0xf013,
++	0xf004,	0xf006,	0xf007,	0xf008,	0xf00a,	0xf00b,	0xf00c,	0xf200,
++	0xf200,	0xf200,	0xf700,	0xf200,	0xf01a,	0xf018,	0xf003,	0xf016,
++	0xf002,	0xf00e,	0xf00d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
++	0xf703,	0xf200,	0xf207,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf208,	0xf200,	0xf307,
++	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
++	0xf302,	0xf303,	0xf300,	0xf310,	0xf206,	0xf200,	0xf200,	0xf200,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
++	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
++	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++};
++
++u_short alt_map[NR_KEYS] = {
++	0xf200,	0xf81b,	0xf831,	0xf832,	0xf833,	0xf834,	0xf835,	0xf836,
++	0xf837,	0xf838,	0xf839,	0xf830,	0xf82d,	0xf83d,	0xf87f,	0xf809,
++	0xf871,	0xf877,	0xf865,	0xf872,	0xf874,	0xf879,	0xf875,	0xf869,
++	0xf86f,	0xf870,	0xf85b,	0xf85d,	0xf80d,	0xf702,	0xf861,	0xf873,
++	0xf864,	0xf866,	0xf867,	0xf868,	0xf86a,	0xf86b,	0xf86c,	0xf83b,
++	0xf827,	0xf860,	0xf700,	0xf85c,	0xf87a,	0xf878,	0xf863,	0xf876,
++	0xf862,	0xf86e,	0xf86d,	0xf82c,	0xf82e,	0xf82f,	0xf700,	0xf30c,
++	0xf703,	0xf820,	0xf207,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,
++	0xf505,	0xf506,	0xf507,	0xf508,	0xf509,	0xf208,	0xf209,	0xf907,
++	0xf908,	0xf909,	0xf30b,	0xf904,	0xf905,	0xf906,	0xf30a,	0xf901,
++	0xf902,	0xf903,	0xf900,	0xf310,	0xf206,	0xf200,	0xf83c,	0xf50a,
++	0xf50b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf30e,	0xf702,	0xf30d,	0xf01c,	0xf701,	0xf205,	0xf114,	0xf603,
++	0xf118,	0xf210,	0xf211,	0xf117,	0xf600,	0xf119,	0xf115,	0xf116,
++	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++};
++
++u_short ctrl_alt_map[NR_KEYS] = {
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf811,	0xf817,	0xf805,	0xf812,	0xf814,	0xf819,	0xf815,	0xf809,
++	0xf80f,	0xf810,	0xf200,	0xf200,	0xf201,	0xf702,	0xf801,	0xf813,
++	0xf804,	0xf806,	0xf807,	0xf808,	0xf80a,	0xf80b,	0xf80c,	0xf200,
++	0xf200,	0xf200,	0xf700,	0xf200,	0xf81a,	0xf818,	0xf803,	0xf816,
++	0xf802,	0xf80e,	0xf80d,	0xf200,	0xf200,	0xf200,	0xf700,	0xf30c,
++	0xf703,	0xf200,	0xf207,	0xf500,	0xf501,	0xf502,	0xf503,	0xf504,
++	0xf505,	0xf506,	0xf507,	0xf508,	0xf509,	0xf208,	0xf200,	0xf307,
++	0xf308,	0xf309,	0xf30b,	0xf304,	0xf305,	0xf306,	0xf30a,	0xf301,
++	0xf302,	0xf303,	0xf300,	0xf20c,	0xf206,	0xf200,	0xf200,	0xf50a,
++	0xf50b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++	0xf30e,	0xf702,	0xf30d,	0xf200,	0xf701,	0xf205,	0xf114,	0xf603,
++	0xf118,	0xf601,	0xf602,	0xf117,	0xf600,	0xf119,	0xf115,	0xf20c,
++	0xf11a,	0xf10c,	0xf10d,	0xf11b,	0xf11c,	0xf110,	0xf311,	0xf11d,
++	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
++};
++
++ushort *key_maps[MAX_NR_KEYMAPS] = {
++	plain_map, shift_map, altgr_map, 0,
++	ctrl_map, shift_ctrl_map, 0, 0,
++	alt_map, 0, 0, 0,
++	ctrl_alt_map,	0
++};
++
++unsigned int keymap_count = 7;
++
++/*
++ * Philosophy: most people do not define more strings, but they who do
++ * often want quite a lot of string space. So, we statically allocate
++ * the default and allocate dynamically in chunks of 512 bytes.
++ */
++
++char func_buf[] = {
++	'\033', '[', '[', 'A', 0,
++	'\033', '[', '[', 'B', 0,
++	'\033', '[', '[', 'C', 0,
++	'\033', '[', '[', 'D', 0,
++	'\033', '[', '[', 'E', 0,
++	'\033', '[', '1', '7', '~', 0,
++	'\033', '[', '1', '8', '~', 0,
++	'\033', '[', '1', '9', '~', 0,
++	'\033', '[', '2', '0', '~', 0,
++	'\033', '[', '2', '1', '~', 0,
++	'\033', '[', '2', '3', '~', 0,
++	'\033', '[', '2', '4', '~', 0,
++	'\033', '[', '2', '5', '~', 0,
++	'\033', '[', '2', '6', '~', 0,
++	'\033', '[', '2', '8', '~', 0,
++	'\033', '[', '2', '9', '~', 0,
++	'\033', '[', '3', '1', '~', 0,
++	'\033', '[', '3', '2', '~', 0,
++	'\033', '[', '3', '3', '~', 0,
++	'\033', '[', '3', '4', '~', 0,
++	'\033', '[', '1', '~', 0,
++	'\033', '[', '2', '~', 0,
++	'\033', '[', '3', '~', 0,
++	'\033', '[', '4', '~', 0,
++	'\033', '[', '5', '~', 0,
++	'\033', '[', '6', '~', 0,
++	'\033', '[', 'M', 0,
++	'\033', '[', 'P', 0,
++};
++
++char *funcbufptr = func_buf;
++int funcbufsize = sizeof(func_buf);
++int funcbufleft = 0;          /* space left */
++
++char *func_table[MAX_NR_FUNC] = {
++	func_buf + 0,
++	func_buf + 5,
++	func_buf + 10,
++	func_buf + 15,
++	func_buf + 20,
++	func_buf + 25,
++	func_buf + 31,
++	func_buf + 37,
++	func_buf + 43,
++	func_buf + 49,
++	func_buf + 55,
++	func_buf + 61,
++	func_buf + 67,
++	func_buf + 73,
++	func_buf + 79,
++	func_buf + 85,
++	func_buf + 91,
++	func_buf + 97,
++	func_buf + 103,
++	func_buf + 109,
++	func_buf + 115,
++	func_buf + 120,
++	func_buf + 125,
++	func_buf + 130,
++	func_buf + 135,
++	func_buf + 140,
++	func_buf + 145,
++	0,
++	0,
++	func_buf + 149,
++	0,
++};
++
++struct kbdiacr accent_table[MAX_DIACR] = {
++	{'`', 'A', '\300'},	{'`', 'a', '\340'},
++	{'\'', 'A', '\301'},	{'\'', 'a', '\341'},
++	{'^', 'A', '\302'},	{'^', 'a', '\342'},
++	{'~', 'A', '\303'},	{'~', 'a', '\343'},
++	{'"', 'A', '\304'},	{'"', 'a', '\344'},
++	{'O', 'A', '\305'},	{'o', 'a', '\345'},
++	{'0', 'A', '\305'},	{'0', 'a', '\345'},
++	{'A', 'A', '\305'},	{'a', 'a', '\345'},
++	{'A', 'E', '\306'},	{'a', 'e', '\346'},
++	{',', 'C', '\307'},	{',', 'c', '\347'},
++	{'`', 'E', '\310'},	{'`', 'e', '\350'},
++	{'\'', 'E', '\311'},	{'\'', 'e', '\351'},
++	{'^', 'E', '\312'},	{'^', 'e', '\352'},
++	{'"', 'E', '\313'},	{'"', 'e', '\353'},
++	{'`', 'I', '\314'},	{'`', 'i', '\354'},
++	{'\'', 'I', '\315'},	{'\'', 'i', '\355'},
++	{'^', 'I', '\316'},	{'^', 'i', '\356'},
++	{'"', 'I', '\317'},	{'"', 'i', '\357'},
++	{'-', 'D', '\320'},	{'-', 'd', '\360'},
++	{'~', 'N', '\321'},	{'~', 'n', '\361'},
++	{'`', 'O', '\322'},	{'`', 'o', '\362'},
++	{'\'', 'O', '\323'},	{'\'', 'o', '\363'},
++	{'^', 'O', '\324'},	{'^', 'o', '\364'},
++	{'~', 'O', '\325'},	{'~', 'o', '\365'},
++	{'"', 'O', '\326'},	{'"', 'o', '\366'},
++	{'/', 'O', '\330'},	{'/', 'o', '\370'},
++	{'`', 'U', '\331'},	{'`', 'u', '\371'},
++	{'\'', 'U', '\332'},	{'\'', 'u', '\372'},
++	{'^', 'U', '\333'},	{'^', 'u', '\373'},
++	{'"', 'U', '\334'},	{'"', 'u', '\374'},
++	{'\'', 'Y', '\335'},	{'\'', 'y', '\375'},
++	{'T', 'H', '\336'},	{'t', 'h', '\376'},
++	{'s', 's', '\337'},	{'"', 'y', '\377'},
++	{'s', 'z', '\337'},	{'i', 'j', '\377'},
++};
++
++unsigned int accent_table_size = 68;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/gckeymap.map	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,357 @@
++# Default kernel keymap. This uses 7 modifier combinations.
++keymaps 0-2,4-5,8,12
++# Change the above line into
++#	keymaps 0-2,4-6,8,12
++# in case you want the entries
++#	altgr   control keycode  83 = Boot
++#	altgr   control keycode 111 = Boot
++# below.
++#
++# In fact AltGr is used very little, and one more keymap can
++# be saved by mapping AltGr to Alt (and adapting a few entries):
++# keycode 100 = Alt
++#
++keycode   1 = Escape           Escape
++	alt     keycode   1 = Meta_Escape
++keycode   2 = one              exclam
++	alt     keycode   2 = Meta_one
++keycode   3 = two              at               at
++	control	keycode   3 = nul
++	shift	control	keycode   3 = nul
++	alt	keycode   3 = Meta_two
++keycode   4 = three            numbersign
++	control keycode   4 = Escape
++	alt     keycode   4 = Meta_three
++keycode   5 = four             dollar           dollar
++	control keycode   5 = Control_backslash
++	alt     keycode   5 = Meta_four
++keycode   6 = five             percent
++	control keycode   6 = Control_bracketright
++	alt     keycode   6 = Meta_five
++keycode   7 = six              asciicircum
++	control keycode   7 = Control_asciicircum
++	alt     keycode   7 = Meta_six
++keycode   8 = seven            ampersand        braceleft
++	control keycode   8 = Control_underscore
++	alt     keycode   8 = Meta_seven
++keycode   9 = eight            asterisk         bracketleft
++	control keycode   9 = Delete
++	alt     keycode   9 = Meta_eight
++keycode  10 = nine             parenleft        bracketright
++	alt     keycode  10 = Meta_nine
++keycode  11 = zero             parenright       braceright
++	alt     keycode  11 = Meta_zero
++keycode  12 = minus            underscore       backslash
++	control	keycode  12 = Control_underscore
++	shift	control	keycode  12 = Control_underscore
++	alt	keycode  12 = Meta_minus
++keycode  13 = equal            plus
++	alt     keycode  13 = Meta_equal
++keycode  14 = Delete           Delete
++	control keycode  14 = BackSpace
++	alt     keycode  14 = Meta_Delete
++keycode  15 = Tab              Tab
++	alt     keycode  15 = Meta_Tab
++keycode  16 = q
++keycode  17 = w
++keycode  18 = e
++	altgr   keycode  18 = Hex_E
++keycode  19 = r
++keycode  20 = t
++keycode  21 = y
++keycode  22 = u
++keycode  23 = i
++keycode  24 = o
++keycode  25 = p
++keycode  26 = bracketleft      braceleft
++	control keycode  26 = Escape
++	alt     keycode  26 = Meta_bracketleft
++keycode  27 = bracketright     braceright       asciitilde
++	control keycode  27 = Control_bracketright
++	alt     keycode  27 = Meta_bracketright
++keycode  28 = Return
++	alt     keycode  28 = Meta_Control_m
++keycode  29 = Control
++keycode  30 = a
++	altgr   keycode  30 = Hex_A
++keycode  31 = s
++keycode  32 = d
++	altgr   keycode  32 = Hex_D
++keycode  33 = f
++	altgr   keycode  33 = Hex_F
++keycode  34 = g
++keycode  35 = h
++keycode  36 = j
++keycode  37 = k
++keycode  38 = l
++keycode  39 = semicolon        colon
++	alt     keycode  39 = Meta_semicolon
++keycode  40 = apostrophe       quotedbl
++	control keycode  40 = Control_g
++	alt     keycode  40 = Meta_apostrophe
++keycode  41 = grave            asciitilde
++	control keycode  41 = nul
++	alt     keycode  41 = Meta_grave
++keycode  42 = Shift
++keycode  43 = backslash        bar
++	control keycode  43 = Control_backslash
++	alt     keycode  43 = Meta_backslash
++keycode  44 = z
++keycode  45 = x
++keycode  46 = c
++	altgr   keycode  46 = Hex_C
++keycode  47 = v
++keycode  48 = b
++	altgr   keycode  48 = Hex_B
++keycode  49 = n
++keycode  50 = m
++keycode  51 = comma            less
++	alt     keycode  51 = Meta_comma
++keycode  52 = period           greater
++	control keycode  52 = Compose
++	alt     keycode  52 = Meta_period
++keycode  53 = slash            question
++	control keycode  53 = Delete
++	alt     keycode  53 = Meta_slash
++keycode  54 = Shift
++keycode  55 = KP_Multiply
++keycode  56 = Alt
++keycode  57 = space            space
++	control keycode  57 = nul
++	alt     keycode  57 = Meta_space
++keycode  58 = Caps_Lock
++keycode  59 = F1               F11              Console_13
++	control keycode  59 = F1
++	alt     keycode  59 = Console_1
++	control alt     keycode  59 = Console_1
++keycode  60 = F2               F12              Console_14
++	control keycode  60 = F2
++	alt     keycode  60 = Console_2
++	control alt     keycode  60 = Console_2
++keycode  61 = F3               F13              Console_15
++	control keycode  61 = F3
++	alt     keycode  61 = Console_3
++	control alt     keycode  61 = Console_3
++keycode  62 = F4               F14              Console_16
++	control keycode  62 = F4
++	alt     keycode  62 = Console_4
++	control alt     keycode  62 = Console_4
++keycode  63 = F5               F15              Console_17
++	control keycode  63 = F5
++	alt     keycode  63 = Console_5
++	control alt     keycode  63 = Console_5
++keycode  64 = F6               F16              Console_18
++	control keycode  64 = F6
++	alt     keycode  64 = Console_6
++	control alt     keycode  64 = Console_6
++keycode  65 = F7               F17              Console_19
++	control keycode  65 = F7
++	alt     keycode  65 = Console_7
++	control alt     keycode  65 = Console_7
++keycode  66 = F8               F18              Console_20
++	control keycode  66 = F8
++	alt     keycode  66 = Console_8
++	control alt     keycode  66 = Console_8
++keycode  67 = F9               F19              Console_21
++	control keycode  67 = F9
++	alt     keycode  67 = Console_9
++	control alt     keycode  67 = Console_9
++keycode  68 = F10              F20              Console_22
++	control keycode  68 = F10
++	alt     keycode  68 = Console_10
++	control alt     keycode  68 = Console_10
++keycode  69 = Num_Lock
++	shift   keycode  69 = Bare_Num_Lock
++keycode  70 = Scroll_Lock      Show_Memory      Show_Registers
++	control keycode  70 = Show_State
++	alt     keycode  70 = Scroll_Lock
++keycode  71 = KP_7
++	alt     keycode  71 = Ascii_7
++	altgr   keycode  71 = Hex_7
++keycode  72 = KP_8
++	alt     keycode  72 = Ascii_8
++	altgr   keycode  72 = Hex_8
++keycode  73 = KP_9
++	alt     keycode  73 = Ascii_9
++	altgr   keycode  73 = Hex_9
++keycode  74 = KP_Subtract
++keycode  75 = KP_4
++	alt     keycode  75 = Ascii_4
++	altgr   keycode  75 = Hex_4
++keycode  76 = KP_5
++	alt     keycode  76 = Ascii_5
++	altgr   keycode  76 = Hex_5
++keycode  77 = KP_6
++	alt     keycode  77 = Ascii_6
++	altgr   keycode  77 = Hex_6
++keycode  78 = KP_Add
++keycode  79 = KP_1
++	alt     keycode  79 = Ascii_1
++	altgr   keycode  79 = Hex_1
++keycode  80 = KP_2
++	alt     keycode  80 = Ascii_2
++	altgr   keycode  80 = Hex_2
++keycode  81 = KP_3
++	alt     keycode  81 = Ascii_3
++	altgr   keycode  81 = Hex_3
++keycode  82 = KP_0
++	alt     keycode  82 = Ascii_0
++	altgr   keycode  82 = Hex_0
++keycode  83 = KP_Period
++#	altgr   control keycode  83 = Boot
++	control alt     keycode  83 = Boot
++keycode  84 = Last_Console
++keycode  85 =
++keycode  86 = less             greater          bar
++	alt     keycode  86 = Meta_less
++keycode  87 = F11              F11              Console_23
++	control keycode  87 = F11
++	alt     keycode  87 = Console_11
++	control alt     keycode  87 = Console_11
++keycode  88 = F12              F12              Console_24
++	control keycode  88 = F12
++	alt     keycode  88 = Console_12
++	control alt     keycode  88 = Console_12
++keycode  89 =
++keycode  90 =
++keycode  91 =
++keycode  92 =
++keycode  93 =
++keycode  94 =
++keycode  95 =
++keycode  96 = KP_Enter
++keycode  97 = Control
++keycode  98 = KP_Divide
++keycode  99 = Control_backslash
++	control keycode  99 = Control_backslash
++	alt     keycode  99 = Control_backslash
++keycode 100 = AltGr
++keycode 101 = Break
++keycode 102 = Find
++keycode 103 = Up
++keycode 104 = Prior
++	shift   keycode 104 = Scroll_Backward
++keycode 105 = Left
++	alt     keycode 105 = Decr_Console
++keycode 106 = Right
++	alt     keycode 106 = Incr_Console
++keycode 107 = Select
++keycode 108 = Down
++keycode 109 = Next
++	shift   keycode 109 = Scroll_Forward
++keycode 110 = Insert
++keycode 111 = Remove
++#	altgr   control keycode 111 = Boot
++	control alt     keycode 111 = Boot
++keycode 112 = Macro
++keycode 113 = F13
++keycode 114 = F14
++keycode 115 = Help
++keycode 116 = Do
++keycode 117 = F17
++keycode 118 = KP_MinPlus
++keycode 119 = Pause
++keycode 120 =
++keycode 121 =
++keycode 122 =
++keycode 123 =
++keycode 124 =
++keycode 125 =
++keycode 126 =
++keycode 127 =
++string F1 = "\033[[A"
++string F2 = "\033[[B"
++string F3 = "\033[[C"
++string F4 = "\033[[D"
++string F5 = "\033[[E"
++string F6 = "\033[17~"
++string F7 = "\033[18~"
++string F8 = "\033[19~"
++string F9 = "\033[20~"
++string F10 = "\033[21~"
++string F11 = "\033[23~"
++string F12 = "\033[24~"
++string F13 = "\033[25~"
++string F14 = "\033[26~"
++string F15 = "\033[28~"
++string F16 = "\033[29~"
++string F17 = "\033[31~"
++string F18 = "\033[32~"
++string F19 = "\033[33~"
++string F20 = "\033[34~"
++string Find = "\033[1~"
++string Insert = "\033[2~"
++string Remove = "\033[3~"
++string Select = "\033[4~"
++string Prior = "\033[5~"
++string Next = "\033[6~"
++string Macro = "\033[M"
++string Pause = "\033[P"
++compose '`' 'A' to '�'
++compose '`' 'a' to '�'
++compose '\'' 'A' to '�'
++compose '\'' 'a' to '�'
++compose '^' 'A' to '�'
++compose '^' 'a' to '�'
++compose '~' 'A' to '�'
++compose '~' 'a' to '�'
++compose '"' 'A' to '�'
++compose '"' 'a' to '�'
++compose 'O' 'A' to '�'
++compose 'o' 'a' to '�'
++compose '0' 'A' to '�'
++compose '0' 'a' to '�'
++compose 'A' 'A' to '�'
++compose 'a' 'a' to '�'
++compose 'A' 'E' to '�'
++compose 'a' 'e' to '�'
++compose ',' 'C' to '�'
++compose ',' 'c' to '�'
++compose '`' 'E' to '�'
++compose '`' 'e' to '�'
++compose '\'' 'E' to '�'
++compose '\'' 'e' to '�'
++compose '^' 'E' to '�'
++compose '^' 'e' to '�'
++compose '"' 'E' to '�'
++compose '"' 'e' to '�'
++compose '`' 'I' to '�'
++compose '`' 'i' to '�'
++compose '\'' 'I' to '�'
++compose '\'' 'i' to '�'
++compose '^' 'I' to '�'
++compose '^' 'i' to '�'
++compose '"' 'I' to '�'
++compose '"' 'i' to '�'
++compose '-' 'D' to '�'
++compose '-' 'd' to '�'
++compose '~' 'N' to '�'
++compose '~' 'n' to '�'
++compose '`' 'O' to '�'
++compose '`' 'o' to '�'
++compose '\'' 'O' to '�'
++compose '\'' 'o' to '�'
++compose '^' 'O' to '�'
++compose '^' 'o' to '�'
++compose '~' 'O' to '�'
++compose '~' 'o' to '�'
++compose '"' 'O' to '�'
++compose '"' 'o' to '�'
++compose '/' 'O' to '�'
++compose '/' 'o' to '�'
++compose '`' 'U' to '�'
++compose '`' 'u' to '�'
++compose '\'' 'U' to '�'
++compose '\'' 'u' to '�'
++compose '^' 'U' to '�'
++compose '^' 'u' to '�'
++compose '"' 'U' to '�'
++compose '"' 'u' to '�'
++compose '\'' 'Y' to '�'
++compose '\'' 'y' to '�'
++compose 'T' 'H' to '�'
++compose 't' 'h' to '�'
++compose 's' 's' to '�'
++compose '"' 'y' to '�'
++compose 's' 'z' to '�'
++compose 'i' 'j' to '�'
+--- linux-2.4.25/drivers/char/generic_serial.c~2.4.25-vrs2.patch	2002-11-29 00:53:12.000000000 +0100
++++ linux-2.4.25/drivers/char/generic_serial.c	2004-03-31 17:15:09.000000000 +0200
+@@ -883,6 +883,9 @@
+ 		if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
+ 	}
+ 
++	/*
++	 * should be using tty_get_baud_rate() here -- rmk
++	 */
+ 	baudrate = tiosp->c_cflag & CBAUD;
+ 	if (baudrate & CBAUDEX) {
+ 		baudrate &= ~CBAUDEX;
+@@ -957,6 +960,11 @@
+ 	unsigned long flags;
+ 	unsigned long page;
+ 
++	/*
++	 * Do we expect to allocate tmp_buf from an interrupt routine?
++	 * If not, then save_flags() cli() and restore_flags() are
++	 * redundant here and should be replaced by a semaphore. -- rmk
++	 */
+ 	save_flags (flags);
+ 	if (!tmp_buf) {
+ 		page = get_free_page(GFP_KERNEL);
+@@ -976,6 +984,11 @@
+ 	if (port->flags & ASYNC_INITIALIZED)
+ 		return 0;
+ 
++	/*
++	 * Do we expect to allocate xmit_buf from an interrupt routine?
++	 * If not, then save_flags() cli() and restore_flags() are
++	 * redundant here and should be replaced by a semaphore. -- rmk
++	 */
+ 	if (!port->xmit_buf) {
+ 		/* We may sleep in get_free_page() */
+ 		unsigned long tmp;
+@@ -1016,7 +1029,7 @@
+ 	struct serial_struct sio;
+ 
+ 	if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
+-		return(-EFAULT);
++		return -EFAULT;
+ 
+ 	if (!capable(CAP_SYS_ADMIN)) {
+ 		if ((sio.baud_base != port->baud_base) ||
+--- linux-2.4.25/drivers/char/keyboard.c~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/char/keyboard.c	2004-03-31 17:15:09.000000000 +0200
+@@ -14,13 +14,17 @@
+  * `Sticky' modifier keys, 951006.
+  *
+  * 11-11-96: SAK should now work in the raw mode (Martin Mares)
+- * 
++ *
+  * Modified to provide 'generic' keyboard support by Hamish Macdonald
+  * Merge with the m68k keyboard driver and split-off of the PC low-level
+  * parts by Geert Uytterhoeven, May 1997
+  *
+  * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
+  * 30-07-98: Dead keys redone, aeb@cwi.nl.
++ *
++ * 04-04-1998: Added keyboard autorepeat support (some keyboards don't
++ *   autorepeat, and some keyboard changers interfere with keyboard
++ *   autorepeat settings).     - Russell King (rmk@arm.linux.org.uk)
+  */
+ 
+ #include <linux/config.h>
+@@ -30,6 +34,7 @@
+ #include <linux/tty_flip.h>
+ #include <linux/mm.h>
+ #include <linux/string.h>
++#include <linux/timer.h>
+ #include <linux/random.h>
+ #include <linux/init.h>
+ 
+@@ -61,6 +66,14 @@
+ #define KBD_DEFLOCK 0
+ #endif
+ 
++/*
++ * Default autorepeat settings.
++ *  DEFAULT_REPEAT_TIMEOUT is the timeout from the keypress to the first repeat
++ *  DEFAULT_REPEAT_INTERVAL is the timeout between successive repeats
++ */
++#define DEFAULT_REPEAT_TIMEOUT	HZ*300/1000
++#define DEFAULT_REPEAT_INTERVAL	HZ*30/1000
++
+ void (*kbd_ledfunc)(unsigned int led);
+ EXPORT_SYMBOL(handle_scancode);
+ EXPORT_SYMBOL(kbd_ledfunc);
+@@ -82,21 +95,25 @@
+ static unsigned long key_down[256/BITS_PER_LONG];
+ 
+ static int dead_key_next;
+-/* 
++/*
+  * In order to retrieve the shift_state (for the mouse server), either
+- * the variable must be global, or a new procedure must be created to 
++ * the variable must be global, or a new procedure must be created to
+  * return the value. I chose the former way.
+  */
+ int shift_state;
+ static int npadch = -1;			/* -1 or number assembled on pad */
+ static unsigned char diacr;
+ static char rep;			/* flag telling character repeat */
++static int kbd_repeatkeycode= -1;
++static int kbd_repeattimeout = DEFAULT_REPEAT_TIMEOUT;
++static int kbd_repeatinterval= DEFAULT_REPEAT_INTERVAL;
+ struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+ static struct tty_struct **ttytab;
+ static struct kbd_struct * kbd = kbd_table;
+ static struct tty_struct * tty;
+ static unsigned char prev_scancode;
+ 
++static void kbd_processkeycode(unsigned char scancode, char up_flag, int autorepeat);
+ void compute_shiftstate(void);
+ 
+ typedef void (*k_hand)(unsigned char value, char up_flag);
+@@ -163,7 +180,8 @@
+  * string, and in both cases we might assume that it is
+  * in utf-8 already.
+  */
+-void to_utf8(ushort c) {
++void to_utf8(ushort c)
++{
+     if (c < 0x80)
+ 	put_queue(c);			/*  0*******  */
+     else if (c < 0x800) {
+@@ -182,17 +200,23 @@
+  * Translation of escaped scancodes to keycodes.
+  * This is now user-settable (for machines were it makes sense).
+  */
+-
+ int setkeycode(unsigned int scancode, unsigned int keycode)
+ {
+-    return kbd_setkeycode(scancode, keycode);
++	return kbd_setkeycode(scancode, keycode);
+ }
+ 
+ int getkeycode(unsigned int scancode)
+ {
+-    return kbd_getkeycode(scancode);
++	return kbd_getkeycode(scancode);
+ }
+ 
++static void key_callback(unsigned long nr);
++
++static struct timer_list key_autorepeat_timer =
++{
++	function: key_callback
++};
++
+ void handle_scancode(unsigned char scancode, int down)
+ {
+ 	unsigned char keycode;
+@@ -201,6 +225,7 @@
+ 	char have_keycode;
+ 
+ 	pm_access(pm_kbd);
++
+ 	add_keyboard_randomness(scancode | up_flag);
+ 
+ 	tty = ttytab? ttytab[fg_console]: NULL;
+@@ -223,15 +248,15 @@
+ 	if (raw_mode) {
+ 		/*
+ 		 *	The following is a workaround for hardware
+-		 *	which sometimes send the key release event twice 
++		 *	which sometimes send the key release event twice
+ 		 */
+ 		unsigned char next_scancode = scancode|up_flag;
+ 		if (have_keycode && up_flag && next_scancode==prev_scancode) {
+ 			/* unexpected 2nd release event */
+ 		} else {
+-			/* 
++			/*
+ 			 * Only save previous scancode if it was a key-up
+-			 * and had a single-byte scancode.  
++			 * and had a single-byte scancode.
+ 			 */
+ 			if (!have_keycode)
+ 				prev_scancode = 1;
+@@ -256,12 +281,35 @@
+ 	 * return the keycode if in MEDIUMRAW mode.
+ 	 */
+ 
++	kbd_processkeycode(keycode, up_flag, 0);
++
++out:
++	do_poke_blanked_console = 1;
++	schedule_console_callback();
++}
++
++static void
++kbd_processkeycode(unsigned char keycode, char up_flag, int autorepeat)
++{
++	char raw_mode = (kbd->kbdmode == VC_RAW);
++
+ 	if (up_flag) {
+ 		rep = 0;
+ 		if(!test_and_clear_bit(keycode, key_down))
+ 		    up_flag = kbd_unexpected_up(keycode);
+-	} else
++	} else {
+ 		rep = test_and_set_bit(keycode, key_down);
++		/* If the keyboard autorepeated for us, ignore it.
++		 * We do our own autorepeat processing.
++		 */
++		if (rep && !autorepeat)
++			return;
++	}
++
++	if (kbd_repeatkeycode == keycode || !up_flag || raw_mode) {
++		kbd_repeatkeycode = -1;
++		del_timer(&key_autorepeat_timer);
++	}
+ 
+ #ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
+ 	if (keycode == SYSRQ_KEY) {
+@@ -275,6 +323,23 @@
+ 	}
+ #endif
+ 
++	/*
++	 * Calculate the next time when we have to do some autorepeat
++	 * processing.  Note that we do not do autorepeat processing
++	 * while in raw mode but we do do autorepeat processing in
++	 * medium raw mode.
++	 */
++	if (!up_flag && !raw_mode) {
++		kbd_repeatkeycode = keycode;
++		if (vc_kbd_mode(kbd, VC_REPEAT)) {
++			if (rep)
++				key_autorepeat_timer.expires = jiffies + kbd_repeatinterval;
++			else
++				key_autorepeat_timer.expires = jiffies + kbd_repeattimeout;
++			add_timer(&key_autorepeat_timer);
++		}
++	}
++
+ 	if (kbd->kbdmode == VC_MEDIUMRAW) {
+ 		/* soon keycodes will require more than one byte */
+ 		put_queue(keycode + up_flag);
+@@ -343,9 +408,24 @@
+ #endif
+ 		}
+ 	}
++	rep = 0;
+ out:
+-	do_poke_blanked_console = 1;
+-	schedule_console_callback();
++}
++
++/*
++ * This clears the key down arrays when the keyboard is reset.  On
++ * keyboard reset, this must be called before any keycodes are
++ * received.
++ */
++void kbd_reset_kdown(void)
++{
++	int i;
++
++	for (i = 0; i < NR_SHIFT; i++)
++		k_down[i] = 0;
++	for (i = 0; i < SIZE(key_down); i++)
++		key_down[i] = 0;
++	shift_state = 0;
+ }
+ 
+ void put_queue(int ch)
+@@ -453,7 +533,7 @@
+ static void decr_console(void)
+ {
+ 	int i;
+- 
++
+ 	for (i = fg_console-1; i != fg_console; i--) {
+ 		if (i == -1)
+ 			i = MAX_NR_CONSOLES-1;
+@@ -531,7 +611,7 @@
+ {
+ }
+ 
+-static void do_null()
++static void do_null(void)
+ {
+ 	compute_shiftstate();
+ }
+@@ -646,8 +726,8 @@
+ 
+ static void do_pad(unsigned char value, char up_flag)
+ {
+-	static const char *pad_chars = "0123456789+-*/\015,.?()";
+-	static const char *app_map = "pqrstuvwxylSRQMnnmPQ";
++	static const char *pad_chars = "0123456789+-*/\015,.?()#";
++	static const char *app_map = "pqrstuvwxylSRQMnnmPQS";
+ 
+ 	if (up_flag)
+ 		return;		/* no action, if this is a key release */
+@@ -748,9 +828,10 @@
+ 	}
+ }
+ 
+-/* called after returning from RAW mode or when changing consoles -
+-   recompute k_down[] and shift_state from key_down[] */
+-/* maybe called when keymap is undefined, so that shiftkey release is seen */
++/* Called after returning from RAW mode or when changing consoles -
++ * recompute k_down[] and shift_state from key_down[]
++ * Maybe called when keymap is undefined so that shift key release is seen
++ */
+ void compute_shiftstate(void)
+ {
+ 	int i, j, k, sym, val;
+@@ -829,19 +910,22 @@
+ }
+ 
+ /*
+- * The leds display either (i) the status of NumLock, CapsLock, ScrollLock,
+- * or (ii) whatever pattern of lights people want to show using KDSETLED,
+- * or (iii) specified bits of specified words in kernel memory.
++ * The leds display either
++ * (i)   the status of NumLock, CapsLock, ScrollLock, or
++ * (ii)  whatever pattern of lights people want to show using KDSETLED, or
++ * (iii) specified bits of specified words in kernel memory.
+  */
+ 
+ static unsigned char ledstate = 0xff; /* undefined */
+ static unsigned char ledioctl;
+ 
+-unsigned char getledstate(void) {
++unsigned char getledstate(void)
++{
+     return ledstate;
+ }
+ 
+-void setledstate(struct kbd_struct *kbd, unsigned int led) {
++void setledstate(struct kbd_struct *kbd, unsigned int led)
++{
+     if (!(led & ~7)) {
+ 	ledioctl = led;
+ 	kbd->ledmode = LED_SHOW_IOCTL;
+@@ -857,7 +941,8 @@
+ } ledptrs[3];
+ 
+ void register_leds(int console, unsigned int led,
+-		   unsigned int *addr, unsigned int mask) {
++		   unsigned int *addr, unsigned int mask)
++{
+     struct kbd_struct *kbd = kbd_table + console;
+     if (led < 3) {
+ 	ledptrs[led].addr = addr;
+@@ -868,7 +953,8 @@
+ 	kbd->ledmode = LED_SHOW_FLAGS;
+ }
+ 
+-static inline unsigned char getleds(void){
++static inline unsigned char getleds(void)
++{
+     struct kbd_struct *kbd = kbd_table + fg_console;
+     unsigned char leds;
+ 
+@@ -915,6 +1001,19 @@
+ {
+ 	unsigned char leds = getleds();
+ 
++	if (rep && kbd_repeatkeycode != -1) {
++		tty = ttytab? ttytab[fg_console]: NULL;
++		kbd = kbd_table + fg_console;
++
++		/* This prevents the kbd_key routine from being called
++		 * twice, once by this BH, and once by the interrupt
++		 * routine.
++		 */
++		kbd_disable_irq();
++		kbd_processkeycode(kbd_repeatkeycode, 0, 1);
++		kbd_enable_irq();
++	}
++
+ 	if (leds != ledstate) {
+ 		ledstate = leds;
+ 		kbd_leds(leds);
+@@ -937,6 +1036,12 @@
+ 	tasklet_enable(&keyboard_tasklet);
+ }
+ 
++static void key_callback(unsigned long nr)
++{
++	rep = 1;
++	tasklet_schedule(&keyboard_tasklet);
++}
++
+ typedef void (pm_kbd_func) (void);
+ 
+ pm_callback pm_kbd_request_override = NULL;
+@@ -953,7 +1058,7 @@
+ 	kbd0.slockstate = 0;
+ 	kbd0.modeflags = KBD_DEFMODE;
+ 	kbd0.kbdmode = VC_XLATE;
+- 
++
+ 	for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
+ 		kbd_table[i] = kbd0;
+ 
+@@ -963,7 +1068,7 @@
+ 
+ 	tasklet_enable(&keyboard_tasklet);
+ 	tasklet_schedule(&keyboard_tasklet);
+-	
++
+ 	pm_kbd = pm_register(PM_SYS_DEV, PM_SYS_KBC, pm_kbd_request_override);
+ 
+ 	return 0;
+--- linux-2.4.25/drivers/char/mem.c~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/char/mem.c	2004-03-31 17:15:09.000000000 +0200
+@@ -27,9 +27,6 @@
+ #include <asm/io.h>
+ #include <asm/pgalloc.h>
+ 
+-#ifdef CONFIG_I2C
+-extern int i2c_init_all(void);
+-#endif
+ #ifdef CONFIG_FB
+ extern void fbmem_init(void);
+ #endif
+@@ -740,9 +737,6 @@
+ 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
+ 	memory_devfs_register();
+ 	rand_initialize();
+-#ifdef CONFIG_I2C
+-	i2c_init_all();
+-#endif
+ #if defined (CONFIG_FB)
+ 	fbmem_init();
+ #endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/omaha-rtc.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,566 @@
++/*
++ *	(C) ARM Limited 2002.
++ *
++ *	Real Time Clock interface for Linux on Omaha
++ *
++ *	Based on sa1100-rtc.c
++ *
++ *	Copyright (c) 2000 Nils Faerber
++ *
++ *	Based on rtc.c by Paul Gortmaker
++ *	Date/time conversion routines taken from arch/arm/kernel/time.c
++ *			by Linus Torvalds and Russell King
++ *		and the GNU C Library
++ *	( ... I love the GPL ... just take what you need! ;)
++ *
++ *	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.
++ *
++ *	1.00	2001-06-08	Nicolas Pitre <nico@cam.org>
++ *	- added periodic timer capability using OSMR1
++ *	- flag compatibility with other RTC chips
++ *	- permission checks for ioctls
++ *	- major cleanup, partial rewrite
++ *
++ *	0.03	2001-03-07	CIH <cih@coventive.com>
++ *	- Modify the bug setups RTC clock.
++ *
++ *	0.02	2001-02-27	Nils Faerber <nils@@kernelconcepts.de>
++ *	- removed mktime(), added alarm irq clear
++ *
++ *	0.01	2000-10-01	Nils Faerber <nils@@kernelconcepts.de>
++ *	- initial release
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/string.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/proc_fs.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <linux/rtc.h>
++#include <linux/mc146818rtc.h>
++
++#define	DRIVER_VERSION		"1.00"
++
++#define epoch			1970
++
++#define TIMER_FREQ		3686400
++
++#define RTC_DEF_DIVIDER		32768 - 1
++#define RTC_DEF_TRIM		0
++
++/* Those are the bits from a classic RTC we want to mimic */
++#define RTC_IRQF		0x80	/* any of the following 3 is active */
++#define RTC_PF			0x40
++#define RTC_AF			0x20
++#define RTC_UF			0x10
++
++// bitdefs for rtc registers
++#define TICNT_ENABLE	0x80	// Enable tick interrupt
++#define TICNT_PERIOD	0x7F	// Divisor required for 1Hz tick
++#define RTC_ENABLE	0x1	// Enable bit for RTC
++
++static unsigned long rtc_status;
++static unsigned long rtc_irq_data;
++static unsigned long rtc_freq = 1024;
++
++static struct fasync_struct *rtc_async_queue;
++static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
++
++extern spinlock_t rtc_lock;
++
++static const unsigned char days_in_mo[] =
++	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
++
++#define is_leap(year) \
++	((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
++
++// all the alarm and rtc registers
++static volatile unsigned int almsec = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMSEC);
++static volatile unsigned int almmin = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMMIN);
++static volatile unsigned int almhour = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMHOUR);
++static volatile unsigned int almday = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMDAY);
++static volatile unsigned int almmon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMMON);
++static volatile unsigned int almyear = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_ALMYEAR);
++
++static volatile unsigned int bcdsec = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDSEC);
++static volatile unsigned int bcdmin = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDMIN);
++static volatile unsigned int bcdhour = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDHOUR);
++static volatile unsigned int bcdday = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDDAY);
++static volatile unsigned int bcddate = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDDATE);
++static volatile unsigned int bcdmon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDMON);
++static volatile unsigned int bcdyear = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_BCDYEAR);
++
++/*
++ * Converts seconds since 1970-01-01 00:00:00 to Gregorian date.
++ */
++
++static void decodetime (unsigned long t, struct rtc_time *tval)
++{
++	long days, month, year, rem;
++
++	days = t / 86400;
++	rem = t % 86400;
++	tval->tm_hour = rem / 3600;
++	rem %= 3600;
++	tval->tm_min = rem / 60;
++	tval->tm_sec = rem % 60;
++	tval->tm_wday = (4 + days) % 7;
++
++#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
++
++	year = epoch;
++	while (days >= (365 + is_leap(year))) {
++		unsigned long yg = year + days / 365;
++		days -= ((yg - year) * 365
++				+ LEAPS_THRU_END_OF (yg - 1)
++				- LEAPS_THRU_END_OF (year - 1));
++		year = yg;
++	}
++	tval->tm_year = year - 1900;
++	tval->tm_yday = days + 1;
++
++	month = 0;
++	if (days >= 31) {
++		days -= 31;
++		month++;
++		if (days >= (28 + is_leap(year))) {
++			days -= (28 + is_leap(year));
++			month++;
++			while (days >= days_in_mo[month]) {
++				days -= days_in_mo[month];
++				month++;
++			}
++		}
++	}
++	tval->tm_mon = month;
++	tval->tm_mday = days + 1;
++}
++
++// Get alarm time in seconds
++static unsigned long get_alarm_time(void)
++{
++	int sec, min,hour,date,mon,year;
++	
++	// Read data from h/w
++	year = __raw_readb(almyear);
++	mon = __raw_readb(almmon);
++	date = __raw_readb(almday);
++	hour = __raw_readb(almhour);
++	min = __raw_readb(almmin);
++	sec = __raw_readb(almsec);
++	
++	// convert all the data into binary
++	year = BCD_TO_BIN(year);
++	mon = BCD_TO_BIN(mon);
++	date = BCD_TO_BIN(date);
++	hour = BCD_TO_BIN(hour);
++	min = BCD_TO_BIN(min);
++	sec = BCD_TO_BIN(sec);
++		
++	// convert year to 19xx or 20xx as appropriate
++	if (year > 69)
++		year += 1900;
++	else
++		year += 2000;
++		
++	// Now calculate number of seconds since time began...
++	return mktime(year,mon,date,hour,min,sec);	
++}
++
++// Get rtc time in seconds
++static unsigned long get_rtc_time(void)
++{
++	int sec,min,hour,day,date,mon,year;
++	
++	// Read data from h/w
++	year = __raw_readb(bcdyear);
++	mon = __raw_readb(bcdmon);
++	date = __raw_readb(bcdday);
++	day = __raw_readb(bcddate);
++	hour = __raw_readb(bcdhour);
++	min = __raw_readb(bcdmin);
++	sec = __raw_readb(bcdsec);
++	
++	// convert all the data into binary
++	year = BCD_TO_BIN(year);
++	mon = BCD_TO_BIN(mon);
++	date = BCD_TO_BIN(date);
++	day = BCD_TO_BIN(day);
++	hour = BCD_TO_BIN(hour);
++	min = BCD_TO_BIN(min);
++	sec = BCD_TO_BIN(sec);
++	
++	// convert year to 19xx or 20xx as appropriate
++	if (year > 69)
++		year += 1900;
++	else
++		year += 2000;
++
++	// Now calculate number of seconds since time began...
++	return mktime(year,mon,date,hour,min,sec);	
++}
++
++/* Sets time of alarm */
++static void set_alarm_time(struct rtc_time *tval)
++{
++	
++	int sec,min,hour,day,mon,year;
++	 
++	 // Convert data from binary to 8-bit bcd
++	 sec = BIN_TO_BCD(tval->tm_sec);
++	 min = BIN_TO_BCD(tval->tm_min);
++	 hour = BIN_TO_BCD(tval->tm_hour);
++	 day = BIN_TO_BCD(tval->tm_mday);
++	 mon = BIN_TO_BCD(tval->tm_mon);
++		
++	// Year is special
++	year = tval->tm_year;
++	if(year > 1999)
++	 	year -=2000;
++	else	
++		year -=1900;
++	
++	year = BIN_TO_BCD(year);	
++	 
++	 // Write all the registers
++	 __raw_writeb(year,almyear);	 
++	 __raw_writeb(mon,almmon);
++	 __raw_writeb(day,almday);
++	 __raw_writeb(hour,almhour);
++	 __raw_writeb(min,almmin);
++	 __raw_writeb(sec,almsec);
++}
++
++/* Sets time of alarm */
++static void set_rtc_time(struct rtc_time *tval)
++{
++	
++	int sec,min,hour,day,date,mon,year;
++	 
++	// Convert data from binary to 8-bit bcd
++	sec = BIN_TO_BCD(tval->tm_sec);
++	min = BIN_TO_BCD(tval->tm_min);
++	hour = BIN_TO_BCD(tval->tm_hour);
++	day = BIN_TO_BCD(tval->tm_mday);
++	date = BIN_TO_BCD(tval->tm_wday);
++	mon = BIN_TO_BCD(tval->tm_mon);
++	 
++	// Year is special
++	year = tval->tm_year;
++	if(year > 1999)
++	 	year -=2000;
++	else	
++		year -=1900;
++	
++	year = BIN_TO_BCD(year);	
++	
++	 // Write all the registers
++	 __raw_writeb(year,bcdyear);	 
++	 __raw_writeb(mon,bcdmon);
++	 __raw_writeb(date,bcddate);
++	 __raw_writeb(day,bcdday);
++	 __raw_writeb(hour,bcdhour);
++	 __raw_writeb(min,bcdmin);
++	 __raw_writeb(sec,bcdsec);
++}
++
++static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	/* update irq data & counter */
++	rtc_irq_data += 0x100;
++
++	/* wake up waiting process */
++	wake_up_interruptible(&rtc_wait);
++	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
++}
++
++static int rtc_open(struct inode *inode, struct file *file)
++{
++	if (test_and_set_bit (1, &rtc_status))
++		return -EBUSY;
++	MOD_INC_USE_COUNT;
++	rtc_irq_data = 0;
++	return 0;
++}
++
++static int rtc_release(struct inode *inode, struct file *file)
++{
++	rtc_status = 0;
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static int rtc_fasync (int fd, struct file *filp, int on)
++{
++	return fasync_helper (fd, filp, on, &rtc_async_queue);
++}
++
++static unsigned int rtc_poll(struct file *file, poll_table *wait)
++{
++	poll_wait (file, &rtc_wait, wait);
++	return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM;
++}
++
++static loff_t rtc_llseek(struct file *file, loff_t offset, int origin)
++{
++	return -ESPIPE;
++}
++
++ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long data;
++	ssize_t retval;
++
++	if (count < sizeof(unsigned long))
++		return -EINVAL;
++
++	add_wait_queue(&rtc_wait, &wait);
++	set_current_state(TASK_INTERRUPTIBLE);
++	for (;;) {
++		spin_lock_irq (&rtc_lock);
++		data = rtc_irq_data;
++		if (data != 0) {
++			rtc_irq_data = 0;
++			break;
++		}
++		spin_unlock_irq (&rtc_lock);
++
++		if (file->f_flags & O_NONBLOCK) {
++			retval = -EAGAIN;
++			goto out;
++		}
++
++		if (signal_pending(current)) {
++			retval = -ERESTARTSYS;
++			goto out;
++		}
++
++		schedule();
++	}
++
++	spin_unlock_irq (&rtc_lock);
++
++	data -= 0x100;	/* the first IRQ wasn't actually missed */
++
++	retval = put_user(data, (unsigned long *)buf);
++	if (!retval)
++		retval = sizeof(unsigned long);
++
++out:
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&rtc_wait, &wait);
++	return retval;
++}
++
++static int rtc_ioctl(struct inode *inode, struct file *file,
++		     unsigned int cmd, unsigned long arg)
++{
++	volatile unsigned int rtcalm = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_RTCALM);
++	volatile unsigned int ticnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TICINT);
++	
++	struct rtc_time tm, tm2;
++	switch (cmd) {
++	case RTC_AIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		__raw_writel(0,rtcalm);
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_AIE_ON:
++		spin_lock_irq(&rtc_lock);
++		__raw_writel(0x7F,rtcalm);
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_UIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		__raw_writel(~TICNT_ENABLE,ticnt);
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_UIE_ON:
++		spin_lock_irq(&rtc_lock);
++		__raw_writel(TICNT_ENABLE|TICNT_PERIOD,ticnt);
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_PIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		// Periodic int not available
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_PIE_ON:
++		spin_lock_irq(&rtc_lock);
++		// Periodic int not available
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_ALM_READ:
++		decodetime(get_alarm_time(),&tm);
++		break;
++	case RTC_ALM_SET:
++		if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2)))
++			return -EFAULT;
++		decodetime(get_rtc_time(),&tm);
++		if ((unsigned)tm2.tm_hour < 24)
++			tm.tm_hour = tm2.tm_hour;
++		if ((unsigned)tm2.tm_min < 60)
++			tm.tm_min = tm2.tm_min;
++		if ((unsigned)tm2.tm_sec < 60)
++			tm.tm_sec = tm2.tm_sec;
++		
++		// Munge (as per sa1100)
++		tm.tm_year+=1900;
++		tm.tm_mon+=1;	
++		
++		// Set the alarm
++		set_alarm_time(&tm);
++		return 0;
++	case RTC_RD_TIME:
++		decodetime (get_rtc_time(), &tm);
++		break;
++	case RTC_SET_TIME:
++		if (!capable(CAP_SYS_TIME))
++			return -EACCES;
++		if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm)))
++			return -EFAULT;	
++		tm.tm_year += 1900;
++		if (tm.tm_year < epoch || (unsigned)tm.tm_mon >= 12 ||
++		    tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] +
++				(tm.tm_mon == 1 && is_leap(tm.tm_year))) ||
++		    (unsigned)tm.tm_hour >= 24 ||
++		    (unsigned)tm.tm_min >= 60 ||
++		    (unsigned)tm.tm_sec >= 60)
++			return -EINVAL;
++		tm.tm_mon +=1;	// wierd: same as sa1100 though (gets month wrong otherwise!)
++		set_rtc_time(&tm);
++		return 0;
++	case RTC_IRQP_READ:
++		return put_user(rtc_freq, (unsigned long *)arg);
++	case RTC_IRQP_SET:
++		if (arg < 1 || arg > TIMER_FREQ)
++			        return -EINVAL;
++		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
++			        return -EACCES;
++		rtc_freq = arg;
++		return 0;
++	case RTC_EPOCH_READ:
++		return put_user (epoch, (unsigned long *)arg);
++	default:
++		return -EINVAL;
++	}
++	return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0;
++}
++
++static struct file_operations rtc_fops = {
++	.owner		= THIS_MODULE,
++	.llseek		= rtc_llseek,
++	.read		= rtc_read,
++	.poll		= rtc_poll,
++	.ioctl		= rtc_ioctl,
++	.open		= rtc_open,
++	.release	= rtc_release,
++	.fasync		= rtc_fasync,
++};
++
++static struct miscdevice omahartc_miscdev = {
++	.minor		= RTC_MINOR,
++	.name		= "rtc",
++	.fops		= &rtc_fops,
++};
++
++static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++	char *p = page;
++	int len;
++	struct rtc_time tm;
++
++	decodetime (get_rtc_time(), &tm);
++	p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n"
++			"rtc_date\t: %04d-%02d-%02d\n"
++			"rtc_epoch\t: %04d\n",
++			tm.tm_hour, tm.tm_min, tm.tm_sec,
++			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch);
++	decodetime (get_alarm_time(), &tm);
++	p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n"
++			"alrm_date\t: %04d-%02d-%02d\n",
++			tm.tm_hour, tm.tm_min, tm.tm_sec,
++			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
++	p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq);
++
++	len = (p - page) - off;
++	if (len < 0)
++		len = 0;
++
++	*eof = (len <= count) ? 1 : 0;
++	*start = page + off;
++
++	return len;
++}
++
++static int __init rtc_init(void)
++{
++	volatile unsigned int ticnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_TICINT);
++	volatile unsigned int rtccon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_RTCCON);
++	int ret;
++
++	misc_register (&omahartc_miscdev);
++	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);
++	
++	// Enable RTC
++	__raw_writel(RTC_ENABLE,rtccon);
++	
++	// Acquire 1Hz timer
++	ret = request_irq (OMAHA_INT_TICK, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL);
++	if (ret) {
++		printk (KERN_ERR "rtc: IRQ %d already in use.\n", OMAHA_INT_TICK);
++		goto IRQ_TICK_failed;
++	}
++
++	// Acquire RTC (Alarm interrupt)
++	ret = request_irq (OMAHA_INT_RTC, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL);
++	if (ret) {
++		printk (KERN_ERR "rtc: IRQ %d already in use.\n", OMAHA_INT_RTC);
++		goto IRQ_RTC_failed;
++	}
++
++	printk (KERN_INFO "Omaha Real Time Clock driver v" DRIVER_VERSION "\n");
++
++	// Program tick interrupt divisor to generate real 1Hz clock and enable the interrupt
++	__raw_writeb(TICNT_ENABLE|TICNT_PERIOD,ticnt);	
++
++	return 0;
++
++IRQ_TICK_failed:
++	free_irq (OMAHA_INT_TICK, NULL);
++IRQ_RTC_failed:
++	free_irq(OMAHA_INT_RTC, NULL);
++	remove_proc_entry ("driver/rtc", NULL);
++	misc_deregister (&omahartc_miscdev);
++	return ret;
++}
++
++static void __exit rtc_exit(void)
++{
++	free_irq (OMAHA_INT_TICK, NULL);
++	remove_proc_entry ("driver/rtc", NULL);
++	misc_deregister (&omahartc_miscdev);
++}
++
++module_init(rtc_init);
++module_exit(rtc_exit);
++
++MODULE_AUTHOR("ARM Limited <support@arm.com>");
++MODULE_DESCRIPTION("Omaha Realtime Clock Driver (RTC)");
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/omaha_wdt.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,193 @@
++/*
++ *	Watchdog driver for the Omaha
++ *	(C) ARM Limited 2002.
++ *
++ *	Based on sa1100_wdt.c
++ *
++ *      (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
++ *          Based on SoftDog driver by Alan Cox <alan@redhat.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.
++ *
++ *	Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
++ *	warranty for any of this software. This material is provided
++ *	"AS-IS" and at no charge.
++ *
++ *	(c) Copyright 2000           Oleg Drokin <green@crimea.edu>
++ *
++ *      27/11/2000 Initial release
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/hardware.h>
++#include <asm/bitops.h>
++
++#define TIMER_MARGIN	8		/* (secs) Default is 1 minute */
++#define WT_TPS		7812		/* Watchdog ticks per second. */
++#define WT_ENABLE	0x21		// Enable bits for watchdog
++#define WT_CLKSEL_128	0x18		// Select 1/128 divider
++
++static int omaha_margin = TIMER_MARGIN;	/* in seconds */
++static int omahawdt_users;
++static int pre_margin;
++#ifdef MODULE
++MODULE_PARM(omaha_margin,"i");
++#endif
++
++/*
++ *	Allow only one person to hold it open
++ */
++
++static int omahadog_open(struct inode *inode, struct file *file)
++{
++	volatile unsigned int wtcon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCON);
++	volatile unsigned int wtdat = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTDAT);
++	volatile unsigned int wtcnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCNT);
++	unsigned int tmp;
++
++	if(test_and_set_bit(1,&omahawdt_users))
++		return -EBUSY;
++	MOD_INC_USE_COUNT;
++	/* Activate omaha Watchdog timer */
++	
++	/* Assume that uhal has set up pre-scaler according
++	 * to the system clock frequency (don't change it!)
++	 * 
++	 * Ie. all counting occurs at 1MHz / 128 = 7812.5Hz
++	 *
++	 * Since we have 16-bit counter, maximum period is
++	 * 65536/7812.5	= 8.338608 seconds!
++	 */
++	 
++	pre_margin = WT_TPS * omaha_margin;
++	
++	// Set count to the maximum
++	__raw_writel(pre_margin,wtcnt);
++	
++	// Set the clock division factor
++	tmp = __raw_readl(wtcon);
++	tmp |= WT_CLKSEL_128;
++	__raw_writel(tmp,wtcon);	
++	
++	// Program an initial count into WTDAT
++	__raw_writel(0x8000,wtdat);
++	
++	// enable the watchdog
++	tmp = __raw_readl(wtcon);
++	tmp |= WT_ENABLE;
++
++	__raw_writel(tmp,wtcon);
++	
++	return 0;
++}
++
++static int omahadog_release(struct inode *inode, struct file *file)
++{
++	volatile unsigned int wtcon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCON);
++	unsigned int tmp;
++
++	/*
++	 *	Shut off the timer.
++	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
++	 */
++#ifndef CONFIG_WATCHDOG_NOWAYOUT
++	tmp = __raw_readl(wtcon);
++	tmp &= ~WT_ENABLE;
++	__raw_writel(tmp,wtcon);
++#endif
++	omahawdt_users = 0;
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static ssize_t omahadog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
++{
++	volatile unsigned int wtcnt = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTCNT);
++
++	/*  Can't seek (pwrite) on this device  */
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++
++	/* Refresh timer. */
++	if(len) {
++		__raw_writel(pre_margin,wtcnt);
++		return 1;
++	}
++	return 0;
++}
++
++static int omahadog_ioctl(struct inode *inode, struct file *file,
++	unsigned int cmd, unsigned long arg)
++{
++	volatile unsigned int wtdat = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_WTDAT);
++	static struct watchdog_info ident = {
++		identity: "omaha Watchdog",
++	};
++
++	switch(cmd){
++	default:
++		return -ENOIOCTLCMD;
++	case WDIOC_GETSUPPORT:
++		return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident));
++	case WDIOC_GETSTATUS:
++		return put_user(0,(int *)arg);
++	case WDIOC_GETBOOTSTATUS:
++		return 0;
++	case WDIOC_KEEPALIVE:
++		__raw_writel(pre_margin,wtdat);
++		return 0;
++	}
++}
++
++static struct file_operations omahadog_fops=
++{
++	.owner		= THIS_MODULE,
++	.write		= omahadog_write,
++	.ioctl		= omahadog_ioctl,
++	.open		= omahadog_open,
++	.release	= omahadog_release,
++};
++
++static struct miscdevice omahadog_miscdev=
++{
++	.minor		= WATCHDOG_MINOR,
++	.name		= "omaha watchdog",
++	.fops		= &omahadog_fops
++};
++
++static int __init omahadog_init(void)
++{
++	int ret;
++
++	ret = misc_register(&omahadog_miscdev);
++
++	if (ret)
++		return ret;
++
++	printk("Omaha Watchdog Timer: timer margin %d sec\n", omaha_margin);
++
++	return 0;
++}
++
++static void __exit omahadog_exit(void)
++{
++	misc_deregister(&omahadog_miscdev);
++}
++
++module_init(omahadog_init);
++module_exit(omahadog_exit);
+--- linux-2.4.25/drivers/char/pcmcia/Config.in~2.4.25-vrs2.patch	2002-11-29 00:53:12.000000000 +0100
++++ linux-2.4.25/drivers/char/pcmcia/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -5,7 +5,13 @@
+ mainmenu_option next_comment
+ comment 'PCMCIA character devices'
+ 
+-dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_SERIAL
++if [ "$CONFIG_SERIAL" = "y" -o "$CONFIG_SERIAL_8250" = "y" ]; then
++  dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS y
++else
++  if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_SERIAL_8250" = "m" ]; then
++    dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS m
++  fi
++fi
+ if [ "$CONFIG_PCMCIA_SERIAL_CS" = "y" ]; then
+    define_bool CONFIG_PCMCIA_CHRDEV y
+ fi
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/pcmcia/memory_cs.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,214 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/mtd.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <linux/mtd/map.h>
++#include <linux/mtd/mtd.h>
++
++static dev_info_t dev_info = "memory_cs";
++static dev_link_t *dev_list;
++
++struct memcs_dev {
++	dev_link_t	link;
++	struct map_info	map;
++};
++
++static __u8 mem_cs_read8(struct map_info *map, unsigned long ofs)
++{
++	return readb(map->map_priv_1 + ofs);
++}
++
++static __u16 mem_cs_read16(struct map_info *map, unsigned long ofs)
++{
++	return readw(map->map_priv_1 + ofs);
++}
++
++static __u32 mem_cs_read32(struct map_info *map, unsigned long ofs)
++{
++	return readl(map->map_priv_1 + ofs);
++}
++
++static void mem_cs_copy_from(struct map_info *map, void *to, unsigned long ofs, ssize_t size)
++{
++	memcpy_fromio(to, map->map_priv_1 + ofs, size);
++}
++
++static void mem_cs_write8(struct map_info *map, __u8 val, unsigned long ofs)
++{
++	writeb(val, map->map_priv_1 + ofs);
++}
++
++static void mem_cs_write16(struct map_info *map, __u16 val, unsigned long ofs)
++{
++	writew(val, map->map_priv_1 + ofs);
++}
++
++static void mem_cs_write32(struct map_info *map, __u32 val, unsigned long ofs)
++{
++	writel(val, map->map_priv_1 + ofs);
++}
++
++static void mem_cs_copy_to(struct map_info *map, unsigned long ofs, const void *to, ssize_t size)
++{
++	memcpy_toio(map->map_priv_1 + ofs, from, size);
++}
++
++static void mem_cs_release(u_long arg);
++
++static void mem_cs_detach(dev_link_t *link)
++{
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG) {
++		mem_cs_release((u_long)link);
++		if (link->state & DEV_STALE_CONFIG) {
++			link->state |= DEV_STALE_LINK;
++			return;
++		}
++	}
++
++	if (link->handle)
++		CardServices(DeregisterClient, link->handle);
++
++	kfree(link);
++}
++
++static void mem_cs_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++
++	link->dev = NULL;
++	if (link->win) {
++		CardServices(ReleaseWindow, link->win);
++	}
++	link->state &= ~DEV_CONFIG;
++
++	if (link->state & DEV_STALE_LINK)
++		mem_cs_detach(link);
++}
++
++static void mem_cs_config(dev_link_t *link)
++{
++	struct memcs_dev *dev = link->priv;
++	cs_status_t status;
++	win_req_t req;
++
++	link->state |= DEV_CONFIG;
++
++	req.Attributes = word_width ? WIN_DATA_WIDTH_16 : WIN_DATA_WIDTH_8;
++	req.Base = 0;
++	req.Size = 0;
++	req.AccessSpeed = mem_speed;
++
++	link->win = (window_handle_t)link->handle;
++
++	CS_CHECK(RequestWindow, &link->win, &req);
++
++	CS_CHECK(GetStatus, link->handle, &status);
++
++	dev->map.buswidth = word_width ? 2 : 1;
++	dev->map.size = req.Size;
++	dev->map.map_priv_1 = ioremap(req.Base, req.Size);
++}
++
++static int
++mem_cs_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG)
++			mod_timer(&link->release, jiffies + HZ/20);
++		break;
++
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		mem_cs_config(link);
++		break;
++	}
++	return 0;
++}
++
++static dev_link_t *mem_cs_attach(void)
++{
++	struct memcs_dev *dev;
++	client_reg_t clnt;
++
++	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
++	if (dev) {
++		memset(dev, 0, sizeof(*dev));
++
++		dev->map.read8     = mem_cs_read8;
++		dev->map.read16    = mem_cs_read16;
++		dev->map.read32    = mem_cs_read32;
++		dev->map.copy_from = mem_cs_copy_from;
++		dev->map.write8    = mem_cs_write8;
++		dev->map.write16   = mem_cs_write16;
++		dev->map.write32   = mem_cs_write32;
++		dev->map.copy_to   = mem_cs_copy_to;
++
++		dev->link.release.function = &mem_cs_release;
++		dev->link.release.data = (u_long)link;
++		dev->link.priv = dev;
++
++		dev->link.next = dev_list;
++		dev_list = &dev->link;
++
++		clnt.dev_info = &dev_info;
++		clnt.Attributes = INOF_IO_CLIENT | INFO_CARD_SHARE;
++		clnt.EventMask =
++			CS_EVENT_WRITE_PROTECT  | CS_EVENT_CARD_INSERTION |
++			CS_EVENT_CARD_REMOVAL   | CS_EVENT_BATTERY_DEAD   |
++			CS_EVENT_BATTERY_LOW;
++
++		clnt.event_handler = &mem_cs_event;
++		clnt.Version = 0x0210;
++		clnt.event_callback_args.client_data = &dev->link;
++
++		ret = CardServices(RegisterClient, &dev->link.handle, &clnt);
++		if (ret != CS_SUCCESS) {
++			error_info_t err = { RegisterClient, ret };
++			CardServices(ReportError, dev->link.handle, &err);
++			mem_cs_detach(&dev->link);
++			dev = NULL;
++		}
++	}
++
++	return &dev->link;
++}
++
++static int __init mem_cs_init(void)
++{
++	servinfo_t serv;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "memory_cs: Card services release "
++			"does not match\n");
++		return -ENXIO;
++	}
++	register_pccard_driver(&dev_info, mem_cs_attach, mem_cs_detach);
++	return 0;
++}
++
++static void __exit mem_cs_exit(void)
++{
++	unregister_pccard_driver(&dev_info);
++	while (dev_list != NULL)
++		memory_detach(dev_list);
++}
++
++module_init(mem_cs_init);
++module_exit(mem_cs_exit);
++
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/sa1100-rtc.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,474 @@
++/*
++ *	Real Time Clock interface for Linux on StrongARM SA1100
++ *
++ *	Copyright (c) 2000 Nils Faerber
++ *
++ *	Based on rtc.c by Paul Gortmaker
++ *	Date/time conversion routines taken from arch/arm/kernel/time.c
++ *			by Linus Torvalds and Russel King
++ *		and the GNU C Library
++ *	( ... I love the GPL ... just take what you need! ;)
++ *
++ *	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.
++ *
++ *	1.00	2001-06-08	Nicolas Pitre <nico@cam.org>
++ *	- added periodic timer capability using OSMR1
++ *	- flag compatibility with other RTC chips
++ *	- permission checks for ioctls
++ *	- major cleanup, partial rewrite
++ *
++ *	0.03	2001-03-07	CIH <cih@coventive.com>
++ *	- Modify the bug setups RTC clock.
++ *
++ *	0.02	2001-02-27	Nils Faerber <nils@@kernelconcepts.de>
++ *	- removed mktime(), added alarm irq clear
++ *
++ *	0.01	2000-10-01	Nils Faerber <nils@@kernelconcepts.de>
++ *	- initial release
++ */
++
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/string.h>
++#include <linux/init.h>
++#include <linux/poll.h>
++#include <linux/proc_fs.h>
++#include <asm/bitops.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <linux/rtc.h>
++
++#define	DRIVER_VERSION		"1.00"
++
++#define TIMER_FREQ		3686400
++
++#define RTC_DEF_DIVIDER		32768 - 1
++#define RTC_DEF_TRIM		0
++
++/* Those are the bits from a classic RTC we want to mimic */
++#define RTC_IRQF		0x80	/* any of the following 3 is active */
++#define RTC_PF			0x40
++#define RTC_AF			0x20
++#define RTC_UF			0x10
++
++static unsigned long rtc_status;
++static unsigned long rtc_irq_data;
++static unsigned long rtc_freq = 1024;
++
++static struct fasync_struct *rtc_async_queue;
++static DECLARE_WAIT_QUEUE_HEAD(rtc_wait);
++
++extern spinlock_t rtc_lock;
++
++static const unsigned char days_in_mo[] =
++	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
++
++#define is_leap(year) \
++	((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
++
++/*
++ * Converts seconds since 1970-01-01 00:00:00 to Gregorian date.
++ */
++
++static void decodetime (unsigned long t, struct rtc_time *tval)
++{
++	long days, month, year, rem;
++
++	days = t / 86400;
++	rem = t % 86400;
++	tval->tm_hour = rem / 3600;
++	rem %= 3600;
++	tval->tm_min = rem / 60;
++	tval->tm_sec = rem % 60;
++	tval->tm_wday = (4 + days) % 7;
++
++#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
++
++	year = 1970 + days / 365;
++	days -= ((year - 1970) * 365
++			+ LEAPS_THRU_END_OF (year - 1)
++			- LEAPS_THRU_END_OF (1970 - 1));
++	if (days < 0) {
++		year -= 1;
++		days += 365 + is_leap(year);
++	}
++	tval->tm_year = year - 1900;
++	tval->tm_yday = days + 1;
++
++	month = 0;
++	if (days >= 31) {
++		days -= 31;
++		month++;
++		if (days >= (28 + is_leap(year))) {
++			days -= (28 + is_leap(year));
++			month++;
++			while (days >= days_in_mo[month]) {
++				days -= days_in_mo[month];
++				month++;
++			}
++		}
++	}
++	tval->tm_mon = month;
++	tval->tm_mday = days + 1;
++}
++
++static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned int rtsr = RTSR;
++
++	/* clear interrupt sources */
++	RTSR = 0;
++	RTSR = (RTSR_AL|RTSR_HZ);
++
++	/* clear alarm interrupt if it has occurred */
++	if (rtsr & RTSR_AL)
++		rtsr &= ~RTSR_ALE;
++	RTSR = rtsr & (RTSR_ALE|RTSR_HZE);
++
++	/* update irq data & counter */
++	if (rtsr & RTSR_AL)
++		rtc_irq_data |= (RTC_AF|RTC_IRQF);
++	if (rtsr & RTSR_HZ)
++		rtc_irq_data |= (RTC_UF|RTC_IRQF);
++	rtc_irq_data += 0x100;
++
++	/* wake up waiting process */
++	wake_up_interruptible(&rtc_wait);
++	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
++}
++
++static void timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	/*
++	 * If we match for the first time, the periodic interrupt flag won't
++	 * be set.  If it is, then we did wrap around (very unlikely but
++	 * still possible) and compute the amount of missed periods.
++	 * The match reg is updated only when the data is actually retrieved
++	 * to avoid unnecessary interrupts.
++	 */
++	OSSR = OSSR_M1;	/* clear match on timer1 */
++	if (rtc_irq_data & RTC_PF) {
++		rtc_irq_data += (rtc_freq * ((1<<30)/(TIMER_FREQ>>2))) << 8;
++	} else {
++		rtc_irq_data += (0x100|RTC_PF|RTC_IRQF);
++	}
++
++	wake_up_interruptible(&rtc_wait);
++	kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
++}
++
++static int rtc_open(struct inode *inode, struct file *file)
++{
++	if (test_and_set_bit (1, &rtc_status))
++		return -EBUSY;
++	rtc_irq_data = 0;
++	return 0;
++}
++
++static int rtc_release(struct inode *inode, struct file *file)
++{
++	spin_lock_irq (&rtc_lock);
++	RTSR = 0;
++	RTSR = (RTSR_AL|RTSR_HZ);
++	OIER &= ~OIER_E1;
++	OSSR = OSSR_M1;
++	spin_unlock_irq (&rtc_lock);
++	rtc_status = 0;
++	return 0;
++}
++
++static int rtc_fasync (int fd, struct file *filp, int on)
++{
++	return fasync_helper (fd, filp, on, &rtc_async_queue);
++}
++
++static unsigned int rtc_poll(struct file *file, poll_table *wait)
++{
++	poll_wait (file, &rtc_wait, wait);
++	return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM;
++}
++
++static loff_t rtc_llseek(struct file *file, loff_t offset, int origin)
++{
++	return -ESPIPE;
++}
++
++ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long data;
++	ssize_t retval;
++
++	if (count < sizeof(unsigned long))
++		return -EINVAL;
++
++	add_wait_queue(&rtc_wait, &wait);
++	set_current_state(TASK_INTERRUPTIBLE);
++	for (;;) {
++		spin_lock_irq (&rtc_lock);
++		data = rtc_irq_data;
++		if (data != 0) {
++			rtc_irq_data = 0;
++			break;
++		}
++		spin_unlock_irq (&rtc_lock);
++
++		if (file->f_flags & O_NONBLOCK) {
++			retval = -EAGAIN;
++			goto out;
++		}
++
++		if (signal_pending(current)) {
++			retval = -ERESTARTSYS;
++			goto out;
++		}
++
++		schedule();
++	}
++
++	if (data & RTC_PF) {
++		/* interpolate missed periods and set match for the next one */
++		unsigned long period = TIMER_FREQ/rtc_freq;
++		unsigned long oscr = OSCR;
++		unsigned long osmr1 = OSMR1;
++		unsigned long missed = (oscr - osmr1)/period;
++		data += missed << 8;
++		OSSR = OSSR_M1;	/* clear match on timer 1 */
++		OSMR1 = osmr1 + (missed + 1)*period;
++		/* ensure we didn't miss another match in the mean time */
++		while( (signed long)((osmr1 = OSMR1) - OSCR) <= 0 ) {
++			data += 0x100;
++			OSSR = OSSR_M1;	/* clear match on timer 1 */
++			OSMR1 = osmr1 + period;
++		}
++	}
++	spin_unlock_irq (&rtc_lock);
++
++	data -= 0x100;	/* the first IRQ wasn't actually missed */
++
++	retval = put_user(data, (unsigned long *)buf);
++	if (!retval)
++		retval = sizeof(unsigned long);
++
++out:
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&rtc_wait, &wait);
++	return retval;
++}
++
++static int rtc_ioctl(struct inode *inode, struct file *file,
++		     unsigned int cmd, unsigned long arg)
++{
++	struct rtc_time tm, tm2;
++
++	switch (cmd) {
++	case RTC_AIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		RTSR &= ~RTSR_ALE;
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_AIE_ON:
++		spin_lock_irq(&rtc_lock);
++		RTSR |= RTSR_ALE;
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_UIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		RTSR &= ~RTSR_HZE;
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_UIE_ON:
++		spin_lock_irq(&rtc_lock);
++		RTSR |= RTSR_HZE;
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_PIE_OFF:
++		spin_lock_irq(&rtc_lock);
++		OIER &= ~OIER_E1;
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_PIE_ON:
++		if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
++			return -EACCES;
++		spin_lock_irq(&rtc_lock);
++		OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
++		OIER |= OIER_E1;
++		rtc_irq_data = 0;
++		spin_unlock_irq(&rtc_lock);
++		return 0;
++	case RTC_ALM_READ:
++		decodetime (RTAR, &tm);
++		break;
++	case RTC_ALM_SET:
++		if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2)))
++			return -EFAULT;
++		decodetime (RCNR, &tm);
++		if ((unsigned)tm2.tm_hour < 24)
++			tm.tm_hour = tm2.tm_hour;
++		if ((unsigned)tm2.tm_min < 60)
++			tm.tm_min = tm2.tm_min;
++		if ((unsigned)tm2.tm_sec < 60)
++			tm.tm_sec = tm2.tm_sec;
++		RTAR = mktime (	tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
++				tm.tm_hour, tm.tm_min, tm.tm_sec);
++		return 0;
++	case RTC_RD_TIME:
++		decodetime (RCNR, &tm);
++		break;
++	case RTC_SET_TIME:
++		if (!capable(CAP_SYS_TIME))
++			return -EACCES;
++		if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm)))
++			return -EFAULT;
++		tm.tm_year += 1900;
++		if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >= 12 ||
++		    tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] +
++				(tm.tm_mon == 1 && is_leap(tm.tm_year))) ||
++		    (unsigned)tm.tm_hour >= 24 ||
++		    (unsigned)tm.tm_min >= 60 ||
++		    (unsigned)tm.tm_sec >= 60)
++			return -EINVAL;
++		RCNR = mktime (	tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
++				tm.tm_hour, tm.tm_min, tm.tm_sec);
++		return 0;
++	case RTC_IRQP_READ:
++		return put_user(rtc_freq, (unsigned long *)arg);
++	case RTC_IRQP_SET:
++		if (arg < 1 || arg > TIMER_FREQ)
++			        return -EINVAL;
++		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
++			        return -EACCES;
++		rtc_freq = arg;
++		return 0;
++	case RTC_EPOCH_READ:
++		return put_user (1970, (unsigned long *)arg);
++	default:
++		return -EINVAL;
++	}
++	return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0;
++}
++
++static struct file_operations rtc_fops = {
++	owner:		THIS_MODULE,
++	llseek:		rtc_llseek,
++	read:		rtc_read,
++	poll:		rtc_poll,
++	ioctl:		rtc_ioctl,
++	open:		rtc_open,
++	release:	rtc_release,
++	fasync:		rtc_fasync,
++};
++
++static struct miscdevice sa1100rtc_miscdev = {
++	RTC_MINOR,
++	"rtc",
++	&rtc_fops
++};
++
++static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
++{
++	char *p = page;
++	int len;
++	struct rtc_time tm;
++
++	decodetime (RCNR, &tm);
++	p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n"
++			"rtc_date\t: %04d-%02d-%02d\n"
++			"rtc_epoch\t: %04d\n",
++			tm.tm_hour, tm.tm_min, tm.tm_sec,
++			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1970);
++	decodetime (RTAR, &tm);
++	p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n"
++			"alrm_date\t: %04d-%02d-%02d\n",
++			tm.tm_hour, tm.tm_min, tm.tm_sec,
++			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
++	p += sprintf(p, "trim/divider\t: 0x%08x\n", RTTR);
++	p += sprintf(p, "alarm_IRQ\t: %s\n", (RTSR & RTSR_ALE) ? "yes" : "no" );
++	p += sprintf(p, "update_IRQ\t: %s\n", (RTSR & RTSR_HZE) ? "yes" : "no");
++	p += sprintf(p, "periodic_IRQ\t: %s\n", (OIER & OIER_E1) ? "yes" : "no");
++	p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq);
++
++	len = (p - page) - off;
++	if (len < 0)
++		len = 0;
++
++	*eof = (len <= count) ? 1 : 0;
++	*start = page + off;
++
++	return len;
++}
++
++static int __init rtc_init(void)
++{
++	int ret;
++
++	misc_register (&sa1100rtc_miscdev);
++	create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);
++	ret = request_irq (IRQ_RTC1Hz, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL);
++	if (ret) {
++		printk (KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTC1Hz);
++		goto IRQ_RTC1Hz_failed;
++	}
++	ret = request_irq (IRQ_RTCAlrm, rtc_interrupt, SA_INTERRUPT, "rtc Alrm", NULL);
++	if (ret) {
++		printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTCAlrm);
++		goto IRQ_RTCAlrm_failed;
++	}
++	ret = request_irq (IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", NULL);
++	if (ret) {
++		printk(KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_OST1);
++		goto IRQ_OST1_failed;
++	}
++
++	printk (KERN_INFO "SA1100 Real Time Clock driver v" DRIVER_VERSION "\n");
++
++	/*
++	 * According to the manual we should be able to let RTTR be zero
++	 * and then a default diviser for a 32.768KHz clock is used.
++	 * Apparently this doesn't work, at least for my SA1110 rev 5.
++	 * If the clock divider is uninitialized then reset it to the
++	 * default value to get the 1Hz clock.
++	 */
++	if (RTTR == 0) {
++		RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
++		printk (KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
++		/*  The current RTC value probably doesn't make sense either */
++		RCNR = 0;
++	}
++
++	return 0;
++
++IRQ_OST1_failed:
++	free_irq (IRQ_RTCAlrm, NULL);
++IRQ_RTCAlrm_failed:
++	free_irq (IRQ_RTC1Hz, NULL);
++IRQ_RTC1Hz_failed:
++	remove_proc_entry ("driver/rtc", NULL);
++	misc_deregister (&sa1100rtc_miscdev);
++	return ret;
++}
++
++static void __exit rtc_exit(void)
++{
++	free_irq (IRQ_OST1, NULL);
++	free_irq (IRQ_RTCAlrm, NULL);
++	free_irq (IRQ_RTC1Hz, NULL);
++	remove_proc_entry ("driver/rtc", NULL);
++	misc_deregister (&sa1100rtc_miscdev);
++}
++
++module_init(rtc_init);
++module_exit(rtc_exit);
++
++MODULE_AUTHOR("Nils Faerber <nils@@kernelconcepts.de>");
++MODULE_DESCRIPTION("SA1100 Realtime Clock Driver (RTC)");
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/sa1100_wdt.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,150 @@
++/*
++ *	Watchdog driver for the SA11x0
++ *
++ *      (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
++ *          Based on SoftDog driver by Alan Cox <alan@redhat.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.
++ *
++ *	Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
++ *	warranty for any of this software. This material is provided
++ *	"AS-IS" and at no charge.
++ *
++ *	(c) Copyright 2000           Oleg Drokin <green@crimea.edu>
++ *
++ *      27/11/2000 Initial release
++ */
++
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/watchdog.h>
++#include <linux/reboot.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/bitops.h>
++
++#define TIMER_MARGIN	60		/* (secs) Default is 1 minute */
++
++static int sa1100_margin = TIMER_MARGIN;	/* in seconds */
++static int sa1100wdt_users;
++static int pre_margin;
++#ifdef MODULE
++MODULE_PARM(sa1100_margin,"i");
++#endif
++
++/*
++ *	Allow only one person to hold it open
++ */
++
++static int sa1100dog_open(struct inode *inode, struct file *file)
++{
++	if(test_and_set_bit(1,&sa1100wdt_users))
++		return -EBUSY;
++	MOD_INC_USE_COUNT;
++	/* Activate SA1100 Watchdog timer */
++	pre_margin=3686400 * sa1100_margin;
++	OSMR3 = OSCR + pre_margin;
++	OSSR = OSSR_M3;
++	OWER = OWER_WME;
++	OIER |= OIER_E3;
++	return 0;
++}
++
++static int sa1100dog_release(struct inode *inode, struct file *file)
++{
++	/*
++	 *	Shut off the timer.
++	 * 	Lock it in if it's a module and we defined ...NOWAYOUT
++	 */
++	OSMR3 = OSCR + pre_margin;
++#ifndef CONFIG_WATCHDOG_NOWAYOUT
++	OIER &= ~OIER_E3;
++#endif
++	sa1100wdt_users = 0;
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static ssize_t sa1100dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
++{
++	/*  Can't seek (pwrite) on this device  */
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++
++	/* Refresh OSMR3 timer. */
++	if(len) {
++		OSMR3 = OSCR + pre_margin;
++		return 1;
++	}
++	return 0;
++}
++
++static int sa1100dog_ioctl(struct inode *inode, struct file *file,
++	unsigned int cmd, unsigned long arg)
++{
++	static struct watchdog_info ident = {
++		identity: "SA1100 Watchdog",
++	};
++
++	switch(cmd){
++	default:
++		return -ENOIOCTLCMD;
++	case WDIOC_GETSUPPORT:
++		return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident));
++	case WDIOC_GETSTATUS:
++		return put_user(0,(int *)arg);
++	case WDIOC_GETBOOTSTATUS:
++		return put_user((RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0, (int *)arg);
++	case WDIOC_KEEPALIVE:
++		OSMR3 = OSCR + pre_margin;
++		return 0;
++	}
++}
++
++static struct file_operations sa1100dog_fops=
++{
++	owner:		THIS_MODULE,
++	write:		sa1100dog_write,
++	ioctl:		sa1100dog_ioctl,
++	open:		sa1100dog_open,
++	release:	sa1100dog_release,
++};
++
++static struct miscdevice sa1100dog_miscdev=
++{
++	WATCHDOG_MINOR,
++	"SA1100 watchdog",
++	&sa1100dog_fops
++};
++
++static int __init sa1100dog_init(void)
++{
++	int ret;
++
++	ret = misc_register(&sa1100dog_miscdev);
++
++	if (ret)
++		return ret;
++
++	printk("SA1100 Watchdog Timer: timer margin %d sec\n", sa1100_margin);
++
++	return 0;
++}
++
++static void __exit sa1100dog_exit(void)
++{
++	misc_deregister(&sa1100dog_miscdev);
++}
++
++module_init(sa1100dog_init);
++module_exit(sa1100dog_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/char/sa1111_keyb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,1153 @@
++/*
++ * SA1111 PS/2 keyboard/mouse driver
++ *
++ * 2000 by VASARA RESEARCH INC.
++ *
++ * Changelog:
++ *     Jun.xx,2000:    Kunihiko IMAI <imai@vasara.co.jp>
++ *                     Port to 2.4.0test1-ac19-rmk1-np1
++ *     Apr.17,2000:    Takafumi Kawana <kawana@pro.or.jp>
++ *                     Internal Release for XP860
++ *
++ *
++ * This driver is based on linux/drivers/char/pc_keyb.c
++ * Original declaration follows:
++
++ *
++ * linux/drivers/char/pc_keyb.c
++ *
++ * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
++ * See keyboard.c for the whole history.
++ *
++ * Major cleanup by Martin Mares, May 1997
++ *
++ * Combined the keyboard and PS/2 mouse handling into one file,
++ * because they share the same hardware.
++ * Johan Myreen <jem@iki.fi> 1998-10-08.
++ *
++ * Code fixes to handle mouse ACKs properly.
++ * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29.
++ *
++ */
++#include <linux/config.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/mm.h>
++#include <linux/signal.h>
++#include <linux/init.h>
++#include <linux/kbd_ll.h>
++#include <linux/delay.h>
++#include <linux/random.h>
++#include <linux/poll.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/kbd_kern.h>
++#include <linux/ioport.h>
++
++#include <asm/hardware.h>
++#include <asm/bitops.h>
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++
++#include <asm/io.h>
++
++/* Some configuration switches are present in the include file... */
++
++#include <linux/pc_keyb.h>
++#include <asm/keyboard.h>
++#include <asm/hardware/sa1111.h>
++
++#define KBD_STAT_RXB    (1<<4)
++#define KBD_STAT_RXF    (1<<5)
++#define KBD_STAT_TXB    (1<<6)
++#define KBD_STAT_TXE    (1<<7)
++#define KBD_STAT_STP    (1<<8)
++
++#define MSE_STAT_RXB    (1<<4)
++#define MSE_STAT_RXF    (1<<5)
++#define MSE_STAT_TXB    (1<<6)
++#define MSE_STAT_TXE    (1<<7)
++#define MSE_STAT_STP    (1<<8)
++
++/* Simple translation table for the SysRq keys */
++
++#ifdef CONFIG_MAGIC_SYSRQ
++unsigned char sa1111_sysrq_xlate[128] = "\000\0331234567890-=\177\t"	/* 0x00 - 0x0f */
++    "qwertyuiop[]\r\000as"	/* 0x10 - 0x1f */
++    "dfghjkl;'`\000\\zxcv"	/* 0x20 - 0x2f */
++    "bnm,./\000*\000 \000\201\202\203\204\205"	/* 0x30 - 0x3f */
++    "\206\207\210\211\212\000\000789-456+1"	/* 0x40 - 0x4f */
++    "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000"	/* 0x50 - 0x5f */
++    "\r\000/";			/* 0x60 - 0x6f */
++#endif
++
++// static void kbd_write_command_w(int data);
++static void kbd_write_output_w(int data);
++
++spinlock_t kbd_controller_lock = SPIN_LOCK_UNLOCKED;
++static void handle_kbd_event(void);
++
++/* used only by send_data - set by keyboard_interrupt */
++static volatile unsigned char reply_expected = 0;
++static volatile unsigned char acknowledge = 0;
++static volatile unsigned char resend = 0;
++
++
++#if defined CONFIG_PSMOUSE
++/*
++ *     PS/2 Auxiliary Device
++ */
++
++static int __init psaux_init(void);
++
++static struct aux_queue *queue;	/* Mouse data buffer. */
++static int aux_count = 0;
++/* used when we send commands to the mouse that expect an ACK. */
++static unsigned char mouse_reply_expected = 0;
++
++#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
++#define AUX_INTS_ON  (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
++
++#define MAX_RETRIES    60	/* some aux operations take long time */
++#endif				/* CONFIG_PSMOUSE */
++
++/*
++ * Wait for keyboard controller input buffer to drain.
++ *
++ * Don't use 'jiffies' so that we don't depend on
++ * interrupts..
++ *
++ * Quote from PS/2 System Reference Manual:
++ *
++ * "Address hex 0060 and address hex 0064 should be written only when
++ * the input-buffer-full bit and output-buffer-full bit in the
++ * Controller Status register are set 0."
++ */
++
++static void kb_wait(void)
++{
++	unsigned long timeout = KBC_TIMEOUT;
++
++	do {
++		/*
++		 * "handle_kbd_event()" will handle any incoming events
++		 * while we wait - keypresses or mouse movement.
++		 */
++		handle_kbd_event();
++		if (KBDSTAT & KBD_STAT_TXE)
++			return;
++		mdelay(1);
++		timeout--;
++	}
++	while (timeout);
++#ifdef KBD_REPORT_TIMEOUTS
++	printk(KERN_WARNING "Keyboard timed out[1]\n");
++#endif
++}
++
++/*
++ * Translation of escaped scancodes to keycodes.
++ * This is now user-settable.
++ * The keycodes 1-88,96-111,119 are fairly standard, and
++ * should probably not be changed - changing might confuse X.
++ * X also interprets scancode 0x5d (KEY_Begin).
++ *
++ * For 1-88 keycode equals scancode.
++ */
++
++#define E0_KPENTER 96
++#define E0_RCTRL   97
++#define E0_KPSLASH 98
++#define E0_PRSCR   99
++#define E0_RALT    100
++#define E0_BREAK   101		/* (control-pause) */
++#define E0_HOME    102
++#define E0_UP      103
++#define E0_PGUP    104
++#define E0_LEFT    105
++#define E0_RIGHT   106
++#define E0_END     107
++#define E0_DOWN    108
++#define E0_PGDN    109
++#define E0_INS     110
++#define E0_DEL     111
++
++/* for USB 106 keyboard */
++#define E0_YEN         124
++#define E0_BACKSLASH   89
++
++
++#define E1_PAUSE   119
++
++/*
++ * The keycodes below are randomly located in 89-95,112-118,120-127.
++ * They could be thrown away (and all occurrences below replaced by 0),
++ * but that would force many users to use the `setkeycodes' utility, where
++ * they needed not before. It does not matter that there are duplicates, as
++ * long as no duplication occurs for any single keyboard.
++ */
++#define SC_LIM 89
++
++#define FOCUS_PF1 85		/* actual code! */
++#define FOCUS_PF2 89
++#define FOCUS_PF3 90
++#define FOCUS_PF4 91
++#define FOCUS_PF5 92
++#define FOCUS_PF6 93
++#define FOCUS_PF7 94
++#define FOCUS_PF8 95
++#define FOCUS_PF9 120
++#define FOCUS_PF10 121
++#define FOCUS_PF11 122
++#define FOCUS_PF12 123
++
++#define JAP_86     124
++/* tfj@olivia.ping.dk:
++ * The four keys are located over the numeric keypad, and are
++ * labelled A1-A4. It's an rc930 keyboard, from
++ * Regnecentralen/RC International, Now ICL.
++ * Scancodes: 59, 5a, 5b, 5c.
++ */
++#define RGN1 124
++#define RGN2 125
++#define RGN3 126
++#define RGN4 127
++
++static unsigned char high_keys[128 - SC_LIM] = {
++	RGN1, RGN2, RGN3, RGN4, 0, 0, 0,	/* 0x59-0x5f */
++	0, 0, 0, 0, 0, 0, 0, 0,	/* 0x60-0x67 */
++	0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12,	/* 0x68-0x6f */
++	0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3,	/* 0x70-0x77 */
++	FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7,	/* 0x78-0x7b */
++	FOCUS_PF8, JAP_86, FOCUS_PF10, 0	/* 0x7c-0x7f */
++};
++
++/* BTC */
++#define E0_MACRO   112
++/* LK450 */
++#define E0_F13     113
++#define E0_F14     114
++#define E0_HELP    115
++#define E0_DO      116
++#define E0_F17     117
++#define E0_KPMINPLUS 118
++/*
++ * My OmniKey generates e0 4c for  the "OMNI" key and the
++ * right alt key does nada. [kkoller@nyx10.cs.du.edu]
++ */
++#define E0_OK  124
++/*
++ * New microsoft keyboard is rumoured to have
++ * e0 5b (left window button), e0 5c (right window button),
++ * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU]
++ * [or: Windows_L, Windows_R, TaskMan]
++ */
++#define E0_MSLW        125
++#define E0_MSRW        126
++#define E0_MSTM        127
++
++static unsigned char e0_keys[128] = {
++	0, 0, 0, 0, 0, 0, 0, 0,	/* 0x00-0x07 */
++	0, 0, 0, 0, 0, 0, 0, 0,	/* 0x08-0x0f */
++	0, 0, 0, 0, 0, 0, 0, 0,	/* 0x10-0x17 */
++	0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0,	/* 0x18-0x1f */
++	0, 0, 0, 0, 0, 0, 0, 0,	/* 0x20-0x27 */
++	0, 0, 0, 0, 0, 0, 0, 0,	/* 0x28-0x2f */
++	0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR,	/* 0x30-0x37 */
++	E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP,	/* 0x38-0x3f */
++	E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME,	/* 0x40-0x47 */
++	E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END,	/* 0x48-0x4f */
++	E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0,	/* 0x50-0x57 */
++	0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0,	/* 0x58-0x5f */
++	0, 0, 0, 0, 0, 0, 0, 0,	/* 0x60-0x67 */
++	0, 0, 0, 0, 0, 0, 0, E0_MACRO,	/* 0x68-0x6f */
++	//0, 0, 0, 0, 0, 0, 0, 0,                          /* 0x70-0x77 */
++	0, 0, 0, 0, 0, E0_BACKSLASH, 0, 0,	/* 0x70-0x77 */
++	0, 0, 0, E0_YEN, 0, 0, 0, 0	/* 0x78-0x7f */
++};
++
++int sa1111_setkeycode(unsigned int scancode, unsigned int keycode)
++{
++	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
++		return -EINVAL;
++	if (scancode < 128)
++		high_keys[scancode - SC_LIM] = keycode;
++	else
++		e0_keys[scancode - 128] = keycode;
++	return 0;
++}
++
++int sa1111_getkeycode(unsigned int scancode)
++{
++	return
++	    (scancode < SC_LIM || scancode > 255) ? -EINVAL :
++	    (scancode <
++	     128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128];
++}
++
++static int do_acknowledge(unsigned char scancode)
++{
++	if (reply_expected) {
++		/* Unfortunately, we must recognise these codes only if we know they
++		 * are known to be valid (i.e., after sending a command), because there
++		 * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have
++		 * keys with such codes :(
++		 */
++		if (scancode == KBD_REPLY_ACK) {
++			acknowledge = 1;
++			reply_expected = 0;
++			return 0;
++		} else if (scancode == KBD_REPLY_RESEND) {
++			resend = 1;
++			reply_expected = 0;
++			return 0;
++		}
++		/* Should not happen... */
++#if 0
++		printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
++		       scancode);
++#endif
++	}
++	return 1;
++}
++
++int
++sa1111_translate(unsigned char scancode, unsigned char *keycode,
++		 char raw_mode)
++{
++	static int prev_scancode = 0;
++
++	/* special prefix scancodes.. */
++	if (scancode == 0xe0 || scancode == 0xe1) {
++		prev_scancode = scancode;
++		return 0;
++	}
++
++	/* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
++	if (scancode == 0x00 || scancode == 0xff) {
++		prev_scancode = 0;
++		return 0;
++	}
++
++	scancode &= 0x7f;
++
++	if (prev_scancode) {
++		/*
++		 * usually it will be 0xe0, but a Pause key generates
++		 * e1 1d 45 e1 9d c5 when pressed, and nothing when released
++		 */
++		if (prev_scancode != 0xe0) {
++			if (prev_scancode == 0xe1 && scancode == 0x1d) {
++				prev_scancode = 0x100;
++				return 0;
++			}
++				else if (prev_scancode == 0x100
++					 && scancode == 0x45) {
++				*keycode = E1_PAUSE;
++				prev_scancode = 0;
++			} else {
++#ifdef KBD_REPORT_UNKN
++				if (!raw_mode)
++					printk(KERN_INFO
++					       "keyboard: unknown e1 escape sequence\n");
++#endif
++				prev_scancode = 0;
++				return 0;
++			}
++		} else {
++			prev_scancode = 0;
++			/*
++			 *  The keyboard maintains its own internal caps lock and
++			 *  num lock statuses. In caps lock mode E0 AA precedes make
++			 *  code and E0 2A follows break code. In num lock mode,
++			 *  E0 2A precedes make code and E0 AA follows break code.
++			 *  We do our own book-keeping, so we will just ignore these.
++			 */
++			/*
++			 *  For my keyboard there is no caps lock mode, but there are
++			 *  both Shift-L and Shift-R modes. The former mode generates
++			 *  E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
++			 *  So, we should also ignore the latter. - aeb@cwi.nl
++			 */
++			if (scancode == 0x2a || scancode == 0x36)
++				return 0;
++
++			if (e0_keys[scancode])
++				*keycode = e0_keys[scancode];
++			else {
++#ifdef KBD_REPORT_UNKN
++				if (!raw_mode)
++					printk(KERN_INFO
++					       "keyboard: unknown scancode e0 %02x\n",
++					       scancode);
++#endif
++				return 0;
++			}
++		}
++	} else if (scancode >= SC_LIM) {
++		/* This happens with the FOCUS 9000 keyboard
++		   Its keys PF1..PF12 are reported to generate
++		   55 73 77 78 79 7a 7b 7c 74 7e 6d 6f
++		   Moreover, unless repeated, they do not generate
++		   key-down events, so we have to zero up_flag below */
++		/* Also, Japanese 86/106 keyboards are reported to
++		   generate 0x73 and 0x7d for \ - and \ | respectively. */
++		/* Also, some Brazilian keyboard is reported to produce
++		   0x73 and 0x7e for \ ? and KP-dot, respectively. */
++
++		*keycode = high_keys[scancode - SC_LIM];
++
++		if (!*keycode) {
++			if (!raw_mode) {
++#ifdef KBD_REPORT_UNKN
++				printk(KERN_INFO
++				       "keyboard: unrecognized scancode (%02x)"
++				       " - ignored\n", scancode);
++#endif
++			}
++			return 0;
++		}
++	} else
++		*keycode = scancode;
++	return 1;
++}
++
++char sa1111_unexpected_up(unsigned char keycode)
++{
++	/* unexpected, but this can happen: maybe this was a key release for a
++	   FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */
++	if (keycode >= SC_LIM || keycode == 85)
++		return 0;
++	else
++		return 0200;
++}
++
++static unsigned char kbd_exists = 1;
++
++static inline void handle_keyboard_event(unsigned char scancode)
++{
++#ifdef CONFIG_VT
++	kbd_exists = 1;
++	if (do_acknowledge(scancode))
++		handle_scancode(scancode, !(scancode & 0x80));
++#endif
++	tasklet_schedule(&keyboard_tasklet);
++}
++
++/*
++ * This reads the keyboard status port, and does the
++ * appropriate action.
++ *
++ * It requires that we hold the keyboard controller
++ * spinlock.
++ */
++static void handle_kbd_event(void)
++{
++	unsigned int status = KBDSTAT;
++	unsigned int work = 10000;
++	unsigned char scancode;
++
++	while (status & KBD_STAT_RXF) {
++		while (status & KBD_STAT_RXF) {
++			scancode = KBDDATA & 0xff;
++			if (!(status & KBD_STAT_STP))
++				handle_keyboard_event(scancode);
++			if (!--work) {
++				printk(KERN_ERR
++				       "pc_keyb: keyboard controller jammed (0x%02X).\n",
++				       status);
++				return;
++			}
++			status = KBDSTAT;
++		}
++		work = 10000;
++	}
++
++	if (status & KBD_STAT_STP)
++		KBDSTAT = KBD_STAT_STP;
++}
++
++static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned long flags;
++
++#ifdef CONFIG_VT
++	kbd_pt_regs = regs;
++#endif
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++	handle_kbd_event();
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++/*
++ * send_data sends a character to the keyboard and waits
++ * for an acknowledge, possibly retrying if asked to. Returns
++ * the success status.
++ *
++ * Don't use 'jiffies', so that we don't depend on interrupts
++ */
++static int send_data(unsigned char data)
++{
++	int retries = 3;
++
++	do {
++		unsigned long timeout = KBD_TIMEOUT;
++
++		acknowledge = 0;	/* Set by interrupt routine on receipt of ACK. */
++		resend = 0;
++		reply_expected = 1;
++		kbd_write_output_w(data);
++		for (;;) {
++			if (acknowledge)
++				return 1;
++			if (resend)
++				break;
++			mdelay(1);
++			if (!--timeout) {
++#ifdef KBD_REPORT_TIMEOUTS
++				printk(KERN_WARNING
++				       "keyboard: Timeout - AT keyboard not present?\n");
++#endif
++				return 0;
++			}
++		}
++	}
++	while (retries-- > 0);
++#ifdef KBD_REPORT_TIMEOUTS
++	printk(KERN_WARNING
++	       "keyboard: Too many NACKs -- noisy kbd cable?\n");
++#endif
++	return 0;
++}
++
++void sa1111_leds(unsigned char leds)
++{
++	if (kbd_exists
++	    && (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))) {
++		send_data(KBD_CMD_ENABLE);	/* re-enable kbd if any errors */
++		kbd_exists = 0;
++	}
++}
++
++#define KBD_NO_DATA    (-1)	/* No data */
++#define KBD_BAD_DATA   (-2)	/* Parity or other error */
++
++static int __init kbd_read_data(void)
++{
++	int retval = KBD_NO_DATA;
++	unsigned int status;
++
++	status = KBDSTAT;
++	if (status & KBD_STAT_RXF) {
++		unsigned char data = KBDDATA;
++
++		retval = data;
++		if (status & KBD_STAT_STP)
++			retval = KBD_BAD_DATA;
++	}
++	return retval;
++}
++
++static void __init kbd_clear_input(void)
++{
++	int maxread = 100;	/* Random number */
++
++	do {
++		if (kbd_read_data() == KBD_NO_DATA)
++			break;
++	}
++	while (--maxread);
++}
++
++static int __init kbd_wait_for_input(void)
++{
++	long timeout = KBD_INIT_TIMEOUT;
++
++	do {
++		int retval = kbd_read_data();
++		if (retval >= 0)
++			return retval;
++		mdelay(1);
++	}
++	while (--timeout);
++	return -1;
++}
++
++#if 0
++static void kbd_write_command_w(int data)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++	kb_wait();
++	kbd_write_command(data);
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++#endif
++
++static void kbd_write_output_w(int data)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++	kb_wait();
++	KBDDATA = data & 0xff;
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++/*
++ * Test the keyboard interface.  We basically check to make sure that
++ * we can drive each line to the keyboard independently of each other.
++ */
++static int kbdif_test(void)
++{
++	int ret = 0;
++
++	KBDCR = KBDCR_ENA | KBDCR_FKC;
++	udelay(2);
++	if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != KBDSTAT_KBD) {
++		printk("Keyboard interface test failed[1]: %02x\n",
++		       KBDSTAT);
++		ret = -ENODEV;
++	}
++
++	KBDCR = KBDCR_ENA;
++	udelay(2);
++	if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != (KBDSTAT_KBC | KBDSTAT_KBD)) {
++		printk("Keyboard interface test failed[2]: %02x\n",
++		       KBDSTAT);
++		ret = -ENODEV;
++	}
++
++	KBDCR = KBDCR_ENA | KBDCR_FKD;
++	udelay(2);
++	if ((KBDSTAT & (KBDSTAT_KBC | KBDSTAT_KBD)) != KBDSTAT_KBC) {
++		printk("Keyboard interface test failed[3]: %02x\n",
++		       KBDSTAT);
++		ret = -ENODEV;
++	}
++
++	return ret;
++}
++
++static char *__init initialize_kbd(void)
++{
++	int status;
++
++	/*
++	 * Test the keyboard interface.
++	 */
++	kbdif_test();
++
++	/*
++	 * Ok, drop the force low bits, and wait a while,
++	 * and clear the stop bit error flag.
++	 */
++	KBDCR = KBDCR_ENA;
++	udelay(4);
++	KBDSTAT = KBD_STAT_STP;
++
++	/*
++	 * Ok, we're now ready to talk to the keyboard.  Reset
++	 * it, just to make sure we're starting in a sane state.
++	 *
++	 * Set up to try again if the keyboard asks for RESEND.
++	 */
++	do {
++		KBDDATA = KBD_CMD_RESET;
++		status = kbd_wait_for_input();
++		if (status == KBD_REPLY_ACK)
++			break;
++		if (status != KBD_REPLY_RESEND)
++			return "Keyboard reset failed, no ACK";
++	} while (1);
++
++	if (kbd_wait_for_input() != KBD_REPLY_POR)
++		return "Keyboard reset failed, no POR";
++
++	/*
++	 * Set keyboard controller mode. During this, the keyboard should be
++	 * in the disabled state.
++	 *
++	 * Set up to try again if the keyboard asks for RESEND.
++	 */
++	do {
++		kbd_write_output_w(KBD_CMD_DISABLE);
++		status = kbd_wait_for_input();
++		if (status == KBD_REPLY_ACK)
++			break;
++		if (status != KBD_REPLY_RESEND)
++			return "Disable keyboard: no ACK";
++	} while (1);
++
++#if 0				/*@@@ */
++	kbd_write_command_w(KBD_CCMD_WRITE_MODE);
++	kbd_write_output_w(KBD_MODE_KBD_INT
++			   | KBD_MODE_SYS | KBD_MODE_DISABLE_MOUSE |
++			   KBD_MODE_KCC);
++
++	/* ibm powerpc portables need this to use scan-code set 1 -- Cort */
++	kbd_write_command_w(KBD_CCMD_READ_MODE);
++	if (!(kbd_wait_for_input() & KBD_MODE_KCC)) {
++		/*
++		 * If the controller does not support conversion,
++		 * Set the keyboard to scan-code set 1.
++		 */
++		kbd_write_output_w(0xF0);
++		kbd_wait_for_input();
++		kbd_write_output_w(0x01);
++		kbd_wait_for_input();
++	}
++#else
++	kbd_write_output_w(0xf0);
++	kbd_wait_for_input();
++	kbd_write_output_w(0x01);
++	kbd_wait_for_input();
++#endif
++
++
++	kbd_write_output_w(KBD_CMD_ENABLE);
++	if (kbd_wait_for_input() != KBD_REPLY_ACK)
++		return "Enable keyboard: no ACK";
++
++	/*
++	 * Finally, set the typematic rate to maximum.
++	 */
++	kbd_write_output_w(KBD_CMD_SET_RATE);
++	if (kbd_wait_for_input() != KBD_REPLY_ACK)
++		return "Set rate: no ACK";
++	kbd_write_output_w(0x00);
++	if (kbd_wait_for_input() != KBD_REPLY_ACK)
++		return "Set rate: no ACK";
++
++	return NULL;
++}
++
++int __init sa1111_kbd_init_hw(void)
++{
++	char *msg;
++	int ret;
++
++	if (!request_mem_region(_KBDCR, 512, "keyboard"))
++		return -EBUSY;
++
++	SKPCR |= SKPCR_PTCLKEN;
++	KBDCLKDIV = 0;
++	KBDPRECNT = 127;
++
++	/* Flush any pending input. */
++	kbd_clear_input();
++
++	msg = initialize_kbd();
++	if (msg)
++		printk(KERN_WARNING "initialize_kbd: %s\n", msg);
++
++#if defined CONFIG_PSMOUSE
++	psaux_init();
++#endif
++
++	k_setkeycode	= sa1111_setkeycode;
++	k_getkeycode	= sa1111_getkeycode;
++	k_translate	= sa1111_translate;
++	k_unexpected_up	= sa1111_unexpected_up;
++	k_leds		= sa1111_leds;
++#ifdef CONFIG_MAGIC_SYSRQ
++	k_sysrq_xlate	= sa1111_sysrq_xlate;
++	k_sysrq_key	= 0x54;
++#endif
++
++	/* Ok, finally allocate the IRQ, and off we go.. */
++	ret = request_irq(IRQ_TPRXINT, keyboard_interrupt, 0, "keyboard", NULL);
++	if (ret)
++		release_mem_region(_KBDCR, 512);
++
++	return ret;
++}
++
++#if defined CONFIG_PSMOUSE
++
++static inline void handle_mouse_event(unsigned char scancode)
++{
++	if (mouse_reply_expected) {
++		if (scancode == AUX_ACK) {
++			mouse_reply_expected--;
++			return;
++		}
++		mouse_reply_expected = 0;
++	}
++
++	add_mouse_randomness(scancode);
++	if (aux_count) {
++		int head = queue->head;
++
++		queue->buf[head] = scancode;
++		head = (head + 1) & (AUX_BUF_SIZE - 1);
++		if (head != queue->tail) {
++			queue->head = head;
++			if (queue->fasync)
++				kill_fasync(&queue->fasync, SIGIO,
++					    POLL_IN);
++			wake_up_interruptible(&queue->proc_list);
++		}
++	}
++}
++
++static void handle_mse_event(void)
++{
++	unsigned int msests = MSESTAT;
++	unsigned int work = 10000;
++	unsigned char scancode;
++
++	while (msests & MSE_STAT_RXF) {
++		while (msests & MSE_STAT_RXF) {
++			scancode = MSEDATA & 0xff;
++			if (!(msests & MSE_STAT_STP))
++				handle_mouse_event(scancode);
++			if (!--work) {
++				printk(KERN_ERR
++				       "pc_keyb: mouse controller jammed (0x%02X).\n",
++				       msests);
++				return;
++			 /*XXX*/}
++			msests = MSESTAT;
++		}
++		work = 10000;
++	}
++}
++
++static void ms_wait(void)
++{
++	unsigned long timeout = KBC_TIMEOUT;
++
++	do {
++		/*
++		 * "handle_kbd_event()" will handle any incoming events
++		 * while we wait - keypresses or mouse movement.
++		 */
++		handle_mse_event();
++		if (MSESTAT & MSE_STAT_TXE)
++			return;
++		mdelay(1);
++		timeout--;
++	}
++	while (timeout);
++#ifdef KBD_REPORT_TIMEOUTS
++	printk(KERN_WARNING "Mouse timed out[1]\n");
++#endif
++}
++
++static void mouse_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++	handle_mse_event();
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++/*
++ * Check if this is a dual port controller.
++ */
++static int __init detect_auxiliary_port(void)
++{
++	unsigned long flags;
++	int loops = 10;
++	int retval = 0;
++
++	/* Check if the BIOS detected a device on the auxiliary port. */
++	if (aux_device_present == 0xaa)
++		return 1;
++
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++
++	/* Put the value 0x5A in the output buffer using the "Write
++	 * Auxiliary Device Output Buffer" command (0xD3). Poll the
++	 * Status Register for a while to see if the value really
++	 * turns up in the Data Register. If the KBD_STAT_MOUSE_OBF
++	 * bit is also set to 1 in the Status Register, we assume this
++	 * controller has an Auxiliary Port (a.k.a. Mouse Port).
++	 */
++	// kb_wait();
++	// kbd_write_command(KBD_CCMD_WRITE_AUX_OBUF);
++
++	SKPCR |= SKPCR_PMCLKEN;
++
++	MSECLKDIV = 0;
++	MSEPRECNT = 127;
++	MSECR = MSECR_ENA;
++	mdelay(50);
++	MSEDATA = 0xf4;
++	mdelay(50);
++
++	do {
++		unsigned int msests = MSESTAT;
++
++		if (msests & MSE_STAT_RXF) {
++			do {
++				msests = MSEDATA;	/* dummy read */
++				mdelay(50);
++				msests = MSESTAT;
++			}
++			while (msests & MSE_STAT_RXF);
++			printk(KERN_INFO "Detected PS/2 Mouse Port.\n");
++			retval = 1;
++			break;
++		}
++		mdelay(1);
++	}
++	while (--loops);
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++
++	return retval;
++}
++
++/*
++ * Send a byte to the mouse.
++ */
++static void aux_write_dev(int val)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++	// kb_wait();
++	// kbd_write_command(KBD_CCMD_WRITE_MOUSE);
++	ms_wait();
++	MSEDATA = val;
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++/*
++ * Send a byte to the mouse & handle returned ack
++ */
++static void aux_write_ack(int val)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++	// kb_wait();
++	// kbd_write_command(KBD_CCMD_WRITE_MOUSE);
++	ms_wait();
++	MSEDATA = val;
++	/* we expect an ACK in response. */
++	mouse_reply_expected++;
++	ms_wait();
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++}
++
++static unsigned char get_from_queue(void)
++{
++	unsigned char result;
++	unsigned long flags;
++
++	spin_lock_irqsave(&kbd_controller_lock, flags);
++	result = queue->buf[queue->tail];
++	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE - 1);
++	spin_unlock_irqrestore(&kbd_controller_lock, flags);
++	return result;
++}
++
++
++static inline int queue_empty(void)
++{
++	return queue->head == queue->tail;
++}
++
++static int fasync_aux(int fd, struct file *filp, int on)
++{
++	int retval;
++
++	retval = fasync_helper(fd, filp, on, &queue->fasync);
++	if (retval < 0)
++		return retval;
++	return 0;
++}
++
++
++/*
++ * Random magic cookie for the aux device
++ */
++#define AUX_DEV ((void *)queue)
++
++static int release_aux(struct inode *inode, struct file *file)
++{
++	fasync_aux(-1, file, 0);
++	if (--aux_count)
++		return 0;
++	// kbd_write_cmd(AUX_INTS_OFF);                     /* Disable controller ints */
++	// kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE);
++	aux_write_ack(AUX_DISABLE_DEV);	/* Disable aux device */
++	MSECR &= ~MSECR_ENA;
++	free_irq(IRQ_MSRXINT, AUX_DEV);
++	return 0;
++}
++
++/*
++ * Install interrupt handler.
++ * Enable auxiliary device.
++ */
++
++static int open_aux(struct inode *inode, struct file *file)
++{
++	if (aux_count++) {
++		return 0;
++	}
++	queue->head = queue->tail = 0;	/* Flush input queue */
++	/* Don't enable the mouse controller until we've registered IRQ handler */
++	if (request_irq(IRQ_MSRXINT, mouse_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) {
++		aux_count--;
++		return -EBUSY;
++	}
++	MSECLKDIV = 0;
++	MSEPRECNT = 127;
++	MSECR &= ~MSECR_ENA;
++	mdelay(50);
++	MSECR = MSECR_ENA;
++	mdelay(50);
++	MSEDATA = 0xf4;
++	mdelay(50);
++	if (MSESTAT & 0x0100) {
++		MSESTAT = 0x0100;	/* clear IRQ status */
++	}
++/*  kbd_write_command_w(KBD_CCMD_MOUSE_ENABLE); *//* Enable the
++   auxiliary port on
++   controller. */
++	aux_write_ack(AUX_ENABLE_DEV);	/* Enable aux device */
++	// kbd_write_cmd(AUX_INTS_ON); /* Enable controller ints */
++
++	// send_data(KBD_CMD_ENABLE);   /* try to workaround toshiba4030cdt problem */
++
++	return 0;
++}
++
++/*
++ * Put bytes from input queue to buffer.
++ */
++
++static ssize_t
++read_aux(struct file *file, char *buffer, size_t count, loff_t * ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	ssize_t i = count;
++	unsigned char c;
++
++	if (queue_empty()) {
++		if (file->f_flags & O_NONBLOCK)
++			return -EAGAIN;
++		add_wait_queue(&queue->proc_list, &wait);
++	      repeat:
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (queue_empty() && !signal_pending(current)) {
++			schedule();
++			goto repeat;
++		}
++		current->state = TASK_RUNNING;
++		remove_wait_queue(&queue->proc_list, &wait);
++	}
++	while (i > 0 && !queue_empty()) {
++		c = get_from_queue();
++		put_user(c, buffer++);
++		i--;
++	}
++	if (count - i) {
++		file->f_dentry->d_inode->i_atime = CURRENT_TIME;
++		return count - i;
++	}
++	if (signal_pending(current))
++		return -ERESTARTSYS;
++	return 0;
++}
++
++/*
++ * Write to the aux device.
++ */
++
++static ssize_t
++write_aux(struct file *file, const char *buffer, size_t count,
++	  loff_t * ppos)
++{
++	ssize_t retval = 0;
++
++	if (count) {
++		ssize_t written = 0;
++
++		if (count > 32)
++			count = 32;	/* Limit to 32 bytes. */
++		do {
++			char c;
++			get_user(c, buffer++);
++			aux_write_dev(c);
++			written++;
++		}
++		while (--count);
++		retval = -EIO;
++		if (written) {
++			retval = written;
++			file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
++		}
++	}
++
++	return retval;
++}
++
++static unsigned int aux_poll(struct file *file, poll_table * wait)
++{
++	poll_wait(file, &queue->proc_list, wait);
++	if (!queue_empty())
++		return POLLIN | POLLRDNORM;
++	return 0;
++}
++
++struct file_operations psaux_fops = {
++	read:		read_aux,
++	write:		write_aux,
++	poll:		aux_poll,
++	open:		open_aux,
++	release:	release_aux,
++	fasync:		fasync_aux,
++};
++
++/*
++ * Initialize driver.
++ */
++static struct miscdevice psaux_mouse = {
++	PSMOUSE_MINOR, "psaux", &psaux_fops
++};
++
++
++static int __init psaux_init(void)
++{
++	int ret;
++
++	if (!request_mem_region(_MSECR, 512, "psaux"))
++		return -EBUSY;
++
++	if (!detect_auxiliary_port()) {
++		ret = -EIO;
++		goto out;
++	}
++
++	misc_register(&psaux_mouse);
++	queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
++	memset(queue, 0, sizeof(*queue));
++	queue->head = queue->tail = 0;
++	init_waitqueue_head(&queue->proc_list);
++
++#ifdef CONFIG_PSMOUSE
++	aux_write_ack(AUX_SET_SAMPLE);
++	aux_write_ack(100);	/* 100 samples/sec */
++	aux_write_ack(AUX_SET_RES);
++	aux_write_ack(3);	/* 8 counts per mm */
++	aux_write_ack(AUX_SET_SCALE21);	/* 2:1 scaling */
++#endif
++	ret = 0;
++
++ out:
++ 	if (ret)
++ 		release_mem_region(_MSECR, 512);
++	return ret;
++}
++
++#endif				/* CONFIG_PSMOUSE */
+--- linux-2.4.25/drivers/char/serial.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/char/serial.c	2004-03-31 17:15:09.000000000 +0200
+@@ -4527,6 +4527,14 @@
+ 	}
+ 
+ 	/*
++	 * If there is exactly one port of 8 bytes, use it.
++	 */
++	if (num_port == 1 && pci_resource_len(dev, first_port) == 8) {
++		board->flags = first_port;
++		return 0;
++	}
++
++	/*
+ 	 * If there is 1 or 0 iomem regions, and exactly one port, use
+ 	 * it.
+ 	 */
+--- linux-2.4.25/drivers/char/serial_21285.c~2.4.25-vrs2.patch
++++ linux-2.4.25/drivers/char/serial_21285.c
+-/*
+- * linux/drivers/char/serial_21285.c
+- *
+- * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
+- *
+- * Based on drivers/char/serial.c
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/errno.h>
+-#include <linux/signal.h>
+-#include <linux/sched.h>
+-#include <linux/interrupt.h>
+-#include <linux/tty.h>
+-#include <linux/tty_flip.h>
+-#include <linux/serial.h>
+-#include <linux/major.h>
+-#include <linux/ptrace.h>
+-#include <linux/ioport.h>
+-#include <linux/mm.h>
+-#include <linux/slab.h>
+-#include <linux/init.h>
+-#include <linux/console.h>
+-
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/uaccess.h>
+-#include <asm/dec21285.h>
+-#include <asm/hardware.h>
+-
+-#define BAUD_BASE		(mem_fclk_21285/64)
+-
+-#define SERIAL_21285_NAME	"ttyFB"
+-#define SERIAL_21285_MAJOR	204
+-#define SERIAL_21285_MINOR	4
+-
+-#define SERIAL_21285_AUXNAME	"cuafb"
+-#define SERIAL_21285_AUXMAJOR	205
+-#define SERIAL_21285_AUXMINOR	4
+-
+-static struct tty_driver rs285_driver, callout_driver;
+-static int rs285_refcount;
+-static struct tty_struct *rs285_table[1];
+-
+-static struct termios *rs285_termios[1];
+-static struct termios *rs285_termios_locked[1];
+-
+-static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char;
+-static struct tty_struct *rs285_tty;
+-static int rs285_use_count;
+-
+-static int rs285_write_room(struct tty_struct *tty)
+-{
+-	return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1);
+-}
+-
+-static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs)
+-{
+-	if (!rs285_tty) {
+-		disable_irq(IRQ_CONRX);
+-		return;
+-	}
+-	while (!(*CSR_UARTFLG & 0x10)) {
+-		int ch, flag;
+-		ch = *CSR_UARTDR;
+-		flag = *CSR_RXSTAT;
+-		if (flag & 4)
+-			tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN);
+-		if (flag & 2)
+-			flag = TTY_PARITY;
+-		else if (flag & 1)
+-			flag = TTY_FRAME;
+-		tty_insert_flip_char(rs285_tty, ch, flag);
+-	}
+-	tty_flip_buffer_push(rs285_tty);
+-}
+-
+-static void rs285_send_xchar(struct tty_struct *tty, char ch)
+-{
+-	x_char = ch;
+-	enable_irq(IRQ_CONTX);
+-}
+-
+-static void rs285_throttle(struct tty_struct *tty)
+-{
+-	if (I_IXOFF(tty))
+-		rs285_send_xchar(tty, STOP_CHAR(tty));
+-}
+-
+-static void rs285_unthrottle(struct tty_struct *tty)
+-{
+-	if (I_IXOFF(tty)) {
+-		if (x_char)
+-			x_char = 0;
+-		else
+-			rs285_send_xchar(tty, START_CHAR(tty));
+-	}
+-}
+-
+-static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs)
+-{
+-	while (!(*CSR_UARTFLG & 0x20)) {
+-		if (x_char) {
+-			*CSR_UARTDR = x_char;
+-			x_char = 0;
+-			continue;
+-		}
+-		if (putp == getp) {
+-			disable_irq(IRQ_CONTX);
+-			break;
+-		}
+-		*CSR_UARTDR = *getp;
+-		if (++getp >= wbuf + sizeof(wbuf))
+-			getp = wbuf;
+-	}
+-	if (rs285_tty)
+-		wake_up_interruptible(&rs285_tty->write_wait);
+-}
+-
+-static inline int rs285_xmit(int ch)
+-{
+-	if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf))
+-		return 0;
+-	*putp = ch;
+-	if (++putp >= wbuf + sizeof(wbuf))
+-		putp = wbuf;
+-	enable_irq(IRQ_CONTX);
+-	return 1;
+-}
+-
+-static int rs285_write(struct tty_struct *tty, int from_user,
+-		       const u_char * buf, int count)
+-{
+-	int i;
+-
+-	if (from_user && verify_area(VERIFY_READ, buf, count))
+-		return -EINVAL;
+-
+-	for (i = 0; i < count; i++) {
+-		char ch;
+-		if (from_user)
+-			__get_user(ch, buf + i);
+-		else
+-			ch = buf[i];
+-		if (!rs285_xmit(ch))
+-			break;
+-	}
+-	return i;
+-}
+-
+-static void rs285_put_char(struct tty_struct *tty, u_char ch)
+-{
+-	rs285_xmit(ch);
+-}
+-
+-static int rs285_chars_in_buffer(struct tty_struct *tty)
+-{
+-	return sizeof(wbuf) - rs285_write_room(tty);
+-}
+-
+-static void rs285_flush_buffer(struct tty_struct *tty)
+-{
+-	disable_irq(IRQ_CONTX);
+-	putp = getp = wbuf;
+-	if (x_char)
+-		enable_irq(IRQ_CONTX);
+-}
+-
+-static inline void rs285_set_cflag(int cflag)
+-{
+-	int h_lcr, baud, quot;
+-
+-	switch (cflag & CSIZE) {
+-	case CS5:
+-		h_lcr = 0x10;
+-		break;
+-	case CS6:
+-		h_lcr = 0x30;
+-		break;
+-	case CS7:
+-		h_lcr = 0x50;
+-		break;
+-	default: /* CS8 */
+-		h_lcr = 0x70;
+-		break;
+-
+-	}
+-	if (cflag & CSTOPB)
+-		h_lcr |= 0x08;
+-	if (cflag & PARENB)
+-		h_lcr |= 0x02;
+-	if (!(cflag & PARODD))
+-		h_lcr |= 0x04;
+-
+-	switch (cflag & CBAUD) {
+-	case B200:	baud = 200;		break;
+-	case B300:	baud = 300;		break;
+-	case B1200:	baud = 1200;		break;
+-	case B1800:	baud = 1800;		break;
+-	case B2400:	baud = 2400;		break;
+-	case B4800:	baud = 4800;		break;
+-	default:
+-	case B9600:	baud = 9600;		break;
+-	case B19200:	baud = 19200;		break;
+-	case B38400:	baud = 38400;		break;
+-	case B57600:	baud = 57600;		break;
+-	case B115200:	baud = 115200;		break;
+-	}
+-
+-	/*
+-	 * The documented expression for selecting the divisor is:
+-	 *  BAUD_BASE / baud - 1
+-	 * However, typically BAUD_BASE is not divisible by baud, so
+-	 * we want to select the divisor that gives us the minimum
+-	 * error.  Therefore, we want:
+-	 *  int(BAUD_BASE / baud - 0.5) ->
+-	 *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
+-	 *  int((BAUD_BASE - (baud >> 1)) / baud)
+-	 */
+-	quot = (BAUD_BASE - (baud >> 1)) / baud;
+-
+-	*CSR_UARTCON = 0;
+-	*CSR_L_UBRLCR = quot & 0xff;
+-	*CSR_M_UBRLCR = (quot >> 8) & 0x0f;
+-	*CSR_H_UBRLCR = h_lcr;
+-	*CSR_UARTCON = 1;
+-}
+-
+-static void rs285_set_termios(struct tty_struct *tty, struct termios *old)
+-{
+-	if (old && tty->termios->c_cflag == old->c_cflag)
+-		return;
+-	rs285_set_cflag(tty->termios->c_cflag);
+-}
+-
+-
+-static void rs285_stop(struct tty_struct *tty)
+-{
+-	disable_irq(IRQ_CONTX);
+-}
+-
+-static void rs285_start(struct tty_struct *tty)
+-{
+-	enable_irq(IRQ_CONTX);
+-}
+-
+-static void rs285_wait_until_sent(struct tty_struct *tty, int timeout)
+-{
+-	int orig_jiffies = jiffies;
+-	while (*CSR_UARTFLG & 8) {
+-		current->state = TASK_INTERRUPTIBLE;
+-		schedule_timeout(1);
+-		if (signal_pending(current))
+-			break;
+-		if (timeout && time_after(jiffies, orig_jiffies + timeout))
+-			break;
+-	}
+-	current->state = TASK_RUNNING;
+-}
+-
+-static int rs285_open(struct tty_struct *tty, struct file *filp)
+-{
+-	int line;
+-
+-	MOD_INC_USE_COUNT;
+-	line = MINOR(tty->device) - tty->driver.minor_start;
+-	if (line) {
+-		MOD_DEC_USE_COUNT;
+-		return -ENODEV;
+-	}
+-
+-	tty->driver_data = NULL;
+-	if (!rs285_tty)
+-		rs285_tty = tty;
+-
+-	enable_irq(IRQ_CONRX);
+-	rs285_use_count++;
+-	return 0;
+-}
+-
+-static void rs285_close(struct tty_struct *tty, struct file *filp)
+-{
+-	if (!--rs285_use_count) {
+-		rs285_wait_until_sent(tty, 0);
+-		disable_irq(IRQ_CONRX);
+-		disable_irq(IRQ_CONTX);
+-		rs285_tty = NULL;
+-	}
+-	MOD_DEC_USE_COUNT;
+-}
+-
+-static int __init rs285_init(void)
+-{
+-	int baud = B9600;
+-
+-	if (machine_is_personal_server())
+-		baud = B57600;
+-
+-	rs285_driver.magic = TTY_DRIVER_MAGIC;
+-	rs285_driver.driver_name = "serial_21285";
+-	rs285_driver.name = SERIAL_21285_NAME;
+-	rs285_driver.major = SERIAL_21285_MAJOR;
+-	rs285_driver.minor_start = SERIAL_21285_MINOR;
+-	rs285_driver.num = 1;
+-	rs285_driver.type = TTY_DRIVER_TYPE_SERIAL;
+-	rs285_driver.subtype = SERIAL_TYPE_NORMAL;
+-	rs285_driver.init_termios = tty_std_termios;
+-	rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL;
+-	rs285_driver.flags = TTY_DRIVER_REAL_RAW;
+-	rs285_driver.refcount = &rs285_refcount;
+-	rs285_driver.table = rs285_table;
+-	rs285_driver.termios = rs285_termios;
+-	rs285_driver.termios_locked = rs285_termios_locked;
+-
+-	rs285_driver.open = rs285_open;
+-	rs285_driver.close = rs285_close;
+-	rs285_driver.write = rs285_write;
+-	rs285_driver.put_char = rs285_put_char;
+-	rs285_driver.write_room = rs285_write_room;
+-	rs285_driver.chars_in_buffer = rs285_chars_in_buffer;
+-	rs285_driver.flush_buffer = rs285_flush_buffer;
+-	rs285_driver.throttle = rs285_throttle;
+-	rs285_driver.unthrottle = rs285_unthrottle;
+-	rs285_driver.send_xchar = rs285_send_xchar;
+-	rs285_driver.set_termios = rs285_set_termios;
+-	rs285_driver.stop = rs285_stop;
+-	rs285_driver.start = rs285_start;
+-	rs285_driver.wait_until_sent = rs285_wait_until_sent;
+-
+-	callout_driver = rs285_driver;
+-	callout_driver.name = SERIAL_21285_AUXNAME;
+-	callout_driver.major = SERIAL_21285_AUXMAJOR;
+-	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+-
+-	if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL))
+-		panic("Couldn't get rx irq for rs285");
+-
+-	if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL))
+-		panic("Couldn't get tx irq for rs285");
+-
+-	if (tty_register_driver(&rs285_driver))
+-		printk(KERN_ERR "Couldn't register 21285 serial driver\n");
+-	if (tty_register_driver(&callout_driver))
+-		printk(KERN_ERR "Couldn't register 21285 callout driver\n");
+-
+-	return 0;
+-}
+-
+-static void __exit rs285_fini(void)
+-{
+-	unsigned long flags;
+-	int ret;
+-
+-	save_flags(flags);
+-	cli();
+-	ret = tty_unregister_driver(&callout_driver);
+-	if (ret)
+-		printk(KERN_ERR "Unable to unregister 21285 callout driver "
+-			"(%d)\n", ret);
+-	ret = tty_unregister_driver(&rs285_driver);
+-	if (ret)
+-		printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n",
+-			ret);
+-	free_irq(IRQ_CONTX, NULL);
+-	free_irq(IRQ_CONRX, NULL);
+-	restore_flags(flags);
+-}
+-
+-module_init(rs285_init);
+-module_exit(rs285_fini);
+-
+-#ifdef CONFIG_SERIAL_21285_CONSOLE
+-/************** console driver *****************/
+-
+-static void rs285_console_write(struct console *co, const char *s, u_int count)
+-{
+-	int i;
+-
+-	disable_irq(IRQ_CONTX);
+-	for (i = 0; i < count; i++) {
+-		while (*CSR_UARTFLG & 0x20);
+-		*CSR_UARTDR = s[i];
+-		if (s[i] == '\n') {
+-			while (*CSR_UARTFLG & 0x20);
+-			*CSR_UARTDR = '\r';
+-		}
+-	}
+-	enable_irq(IRQ_CONTX);
+-}
+-
+-static kdev_t rs285_console_device(struct console *c)
+-{
+-	return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
+-}
+-
+-static int __init rs285_console_setup(struct console *co, char *options)
+-{
+-	int baud = 9600;
+-	int bits = 8;
+-	int parity = 'n';
+-	int cflag = CREAD | HUPCL | CLOCAL;
+-
+-	if (machine_is_personal_server())
+-		baud = 57600;
+-
+-	if (options) {
+-		char *s = options;
+-		baud = simple_strtoul(options, NULL, 10);
+-		while (*s >= '0' && *s <= '9')
+-			s++;
+-		if (*s)
+-			parity = *s++;
+-		if (*s)
+-			bits = *s - '0';
+-	}
+-
+-	/*
+-	 *    Now construct a cflag setting.
+-	 */
+-	switch (baud) {
+-	case 1200:
+-		cflag |= B1200;
+-		break;
+-	case 2400:
+-		cflag |= B2400;
+-		break;
+-	case 4800:
+-		cflag |= B4800;
+-		break;
+-	case 9600:
+-		cflag |= B9600;
+-		break;
+-	case 19200:
+-		cflag |= B19200;
+-		break;
+-	case 38400:
+-		cflag |= B38400;
+-		break;
+-	case 57600:
+-		cflag |= B57600;
+-		break;
+-	case 115200:
+-		cflag |= B115200;
+-		break;
+-	default:
+-		cflag |= B9600;
+-		break;
+-	}
+-	switch (bits) {
+-	case 7:
+-		cflag |= CS7;
+-		break;
+-	default:
+-		cflag |= CS8;
+-		break;
+-	}
+-	switch (parity) {
+-	case 'o':
+-	case 'O':
+-		cflag |= PARODD;
+-		break;
+-	case 'e':
+-	case 'E':
+-		cflag |= PARENB;
+-		break;
+-	}
+-	co->cflag = cflag;
+-	rs285_set_cflag(cflag);
+-	rs285_console_write(NULL, "\e[2J\e[Hboot ", 12);
+-	if (options)
+-		rs285_console_write(NULL, options, strlen(options));
+-	else
+-		rs285_console_write(NULL, "no options", 10);
+-	rs285_console_write(NULL, "\n", 1);
+-
+-	return 0;
+-}
+-
+-static struct console rs285_cons =
+-{
+-	name:		SERIAL_21285_NAME,
+-	write:		rs285_console_write,
+-	device:		rs285_console_device,
+-	setup:		rs285_console_setup,
+-	flags:		CON_PRINTBUFFER,
+-	index:		-1,
+-};
+-
+-void __init rs285_console_init(void)
+-{
+-	register_console(&rs285_cons);
+-}
+-
+-#endif	/* CONFIG_SERIAL_21285_CONSOLE */
+-
+-MODULE_LICENSE("GPL");
+-EXPORT_NO_SYMBOLS;
+--- linux-2.4.25/drivers/char/serial_amba.c~2.4.25-vrs2.patch
++++ linux-2.4.25/drivers/char/serial_amba.c
+-/*
+- *  linux/drivers/char/serial_amba.c
+- *
+- *  Driver for AMBA serial ports
+- *
+- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+- *
+- *  Copyright 1999 ARM Limited
+- *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- *
+- *
+- * This is a generic driver for ARM AMBA-type serial ports.  They
+- * have a lot of 16550-like features, but are not register compatable.
+- * Note that although they do have CTS, DCD and DSR inputs, they do
+- * not have an RI input, nor do they have DTR or RTS outputs.  If
+- * required, these have to be supplied via some other means (eg, GPIO)
+- * and hooked into this driver.
+- *
+- * This could very easily become a generic serial driver for dumb UARTs
+- * (eg, {82,16x}50, 21285, SA1100).
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/errno.h>
+-#include <linux/signal.h>
+-#include <linux/sched.h>
+-#include <linux/interrupt.h>
+-#include <linux/tty.h>
+-#include <linux/tty_flip.h>
+-#include <linux/major.h>
+-#include <linux/string.h>
+-#include <linux/fcntl.h>
+-#include <linux/ptrace.h>
+-#include <linux/ioport.h>
+-#include <linux/mm.h>
+-#include <linux/slab.h>
+-#include <linux/init.h>
+-#include <linux/circ_buf.h>
+-#include <linux/serial.h>
+-#include <linux/console.h>
+-#include <linux/sysrq.h>
+-
+-#include <asm/system.h>
+-#include <asm/io.h>
+-#include <asm/irq.h>
+-#include <asm/uaccess.h>
+-#include <asm/bitops.h>
+-
+-#include <asm/hardware/serial_amba.h>
+-
+-#define SERIAL_AMBA_NAME	"ttyAM"
+-#define SERIAL_AMBA_MAJOR	204
+-#define SERIAL_AMBA_MINOR	16
+-#define SERIAL_AMBA_NR		2
+-
+-#define CALLOUT_AMBA_NAME	"cuaam"
+-#define CALLOUT_AMBA_MAJOR	205
+-#define CALLOUT_AMBA_MINOR	16
+-#define CALLOUT_AMBA_NR		SERIAL_AMBA_NR
+-
+-#ifndef TRUE
+-#define TRUE 1
+-#endif
+-#ifndef FALSE
+-#define FALSE 0
+-#endif
+-
+-#define DEBUG 0
+-#define DEBUG_LEDS 0
+-
+-#if DEBUG_LEDS
+-extern int get_leds(void);
+-extern int set_leds(int);
+-#endif
+-
+-/*
+- * Access routines for the AMBA UARTs
+- */
+-#define UART_GET_INT_STATUS(p)	IO_READ((p)->uart_base + AMBA_UARTIIR)
+-#define UART_GET_FR(p)		IO_READ((p)->uart_base + AMBA_UARTFR)
+-#define UART_GET_CHAR(p)	IO_READ((p)->uart_base + AMBA_UARTDR)
+-#define UART_PUT_CHAR(p, c)	IO_WRITE((p)->uart_base + AMBA_UARTDR, (c))
+-#define UART_GET_RSR(p)		IO_READ((p)->uart_base + AMBA_UARTRSR)
+-#define UART_GET_CR(p)		IO_READ((p)->uart_base + AMBA_UARTCR)
+-#define UART_PUT_CR(p,c)	IO_WRITE((p)->uart_base + AMBA_UARTCR, (c))
+-#define UART_GET_LCRL(p)	IO_READ((p)->uart_base + AMBA_UARTLCR_L)
+-#define UART_PUT_LCRL(p,c)	IO_WRITE((p)->uart_base + AMBA_UARTLCR_L, (c))
+-#define UART_GET_LCRM(p)	IO_READ((p)->uart_base + AMBA_UARTLCR_M)
+-#define UART_PUT_LCRM(p,c)	IO_WRITE((p)->uart_base + AMBA_UARTLCR_M, (c))
+-#define UART_GET_LCRH(p)	IO_READ((p)->uart_base + AMBA_UARTLCR_H)
+-#define UART_PUT_LCRH(p,c)	IO_WRITE((p)->uart_base + AMBA_UARTLCR_H, (c))
+-#define UART_RX_DATA(s)		(((s) & AMBA_UARTFR_RXFE) == 0)
+-#define UART_TX_READY(s)	(((s) & AMBA_UARTFR_TXFF) == 0)
+-#define UART_TX_EMPTY(p)	((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0)
+-
+-#define AMBA_UARTRSR_ANY	(AMBA_UARTRSR_OE|AMBA_UARTRSR_BE|AMBA_UARTRSR_PE|AMBA_UARTRSR_FE)
+-#define AMBA_UARTFR_MODEM_ANY	(AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS)
+-
+-/*
+- * Things needed by tty driver
+- */
+-static struct tty_driver ambanormal_driver, ambacallout_driver;
+-static int ambauart_refcount;
+-static struct tty_struct *ambauart_table[SERIAL_AMBA_NR];
+-static struct termios *ambauart_termios[SERIAL_AMBA_NR];
+-static struct termios *ambauart_termios_locked[SERIAL_AMBA_NR];
+-
+-#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+-#define SUPPORT_SYSRQ
+-#endif
+-
+-/*
+- * Things needed internally to this driver
+- */
+-
+-/*
+- * tmp_buf is used as a temporary buffer by serial_write.  We need to
+- * lock it in case the copy_from_user blocks while swapping in a page,
+- * and some other program tries to do a serial write at the same time.
+- * Since the lock will only come under contention when the system is
+- * swapping and available memory is low, it makes sense to share one
+- * buffer across all the serial ports, since it significantly saves
+- * memory if large numbers of serial ports are open.
+- */
+-static u_char *tmp_buf;
+-static DECLARE_MUTEX(tmp_buf_sem);
+-
+-#define HIGH_BITS_OFFSET	((sizeof(long)-sizeof(int))*8)
+-
+-/* number of characters left in xmit buffer before we ask for more */
+-#define WAKEUP_CHARS		256
+-#define AMBA_ISR_PASS_LIMIT	256
+-
+-#define EVT_WRITE_WAKEUP	0
+-
+-struct amba_icount {
+-	__u32	cts;
+-	__u32	dsr;
+-	__u32	rng;
+-	__u32	dcd;
+-	__u32	rx;
+-	__u32	tx;
+-	__u32	frame;
+-	__u32	overrun;
+-	__u32	parity;
+-	__u32	brk;
+-	__u32	buf_overrun;
+-};
+-
+-/*
+- * Static information about the port
+- */
+-struct amba_port {
+-	unsigned int		uart_base;
+-	unsigned int		irq;
+-	unsigned int		uartclk;
+-	unsigned int		fifosize;
+-	unsigned int		tiocm_support;
+-	void (*set_mctrl)(struct amba_port *, u_int mctrl);
+-};	
+-
+-/*
+- * This is the state information which is persistent across opens
+- */
+-struct amba_state {
+-	struct amba_icount	icount;
+-	unsigned int		line;
+-	unsigned int		close_delay;
+-	unsigned int		closing_wait;
+-	unsigned int		custom_divisor;
+-	unsigned int		flags;
+-	struct termios		normal_termios;
+-	struct termios		callout_termios;
+-
+-	int			count;
+-	struct amba_info	*info;
+-};
+-
+-#define AMBA_XMIT_SIZE 1024
+-/*
+- * This is the state information which is only valid when the port is open.
+- */
+-struct amba_info {
+-	struct amba_port	*port;
+-	struct amba_state	*state;
+-	struct tty_struct	*tty;
+-	unsigned char		x_char;
+-	unsigned char		old_status;
+-	unsigned char		read_status_mask;
+-	unsigned char		ignore_status_mask;
+-	struct circ_buf		xmit;
+-	unsigned int		flags;
+-#ifdef SUPPORT_SYSRQ
+-	unsigned long		sysrq;
+-#endif
+-
+-	unsigned int		event;
+-	unsigned int		timeout;
+-	unsigned int		lcr_h;
+-	unsigned int		mctrl;
+-	int			blocked_open;
+-	pid_t			session;
+-	pid_t			pgrp;
+-
+-	struct tasklet_struct	tlet;
+-
+-	wait_queue_head_t	open_wait;
+-	wait_queue_head_t	close_wait;
+-	wait_queue_head_t	delta_msr_wait;
+-};
+-
+-#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+-static struct console ambauart_cons;
+-#endif
+-static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios);
+-static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout);
+-
+-#if 1 //def CONFIG_SERIAL_INTEGRATOR
+-static void amba_set_mctrl_null(struct amba_port *port, u_int mctrl)
+-{
+-}
+-
+-static struct amba_port amba_ports[SERIAL_AMBA_NR] = {
+-	{
+-		uart_base:	IO_ADDRESS(INTEGRATOR_UART0_BASE),
+-		irq:		IRQ_UARTINT0,
+-		uartclk:	14745600,
+-		fifosize:	8,
+-		set_mctrl:	amba_set_mctrl_null,
+-	},
+-	{
+-		uart_base:	IO_ADDRESS(INTEGRATOR_UART1_BASE),
+-		irq:		IRQ_UARTINT1,
+-		uartclk:	14745600,
+-		fifosize:	8,
+-		set_mctrl:	amba_set_mctrl_null,
+-	}
+-};
+-#endif
+-
+-static struct amba_state amba_state[SERIAL_AMBA_NR];
+-
+-static void ambauart_enable_rx_interrupt(struct amba_info *info)
+-{
+-	unsigned int cr;
+-
+-	cr = UART_GET_CR(info->port);
+-	cr |= AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE;
+-	UART_PUT_CR(info->port, cr);
+-}
+-
+-static void ambauart_disable_rx_interrupt(struct amba_info *info)
+-{
+-	unsigned int cr;
+-
+-	cr = UART_GET_CR(info->port);
+-	cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE);
+-	UART_PUT_CR(info->port, cr);
+-}
+-
+-static void ambauart_enable_tx_interrupt(struct amba_info *info)
+-{
+-	unsigned int cr;
+-
+-	cr = UART_GET_CR(info->port);
+-	cr |= AMBA_UARTCR_TIE;
+-	UART_PUT_CR(info->port, cr);
+-}
+-
+-static void ambauart_disable_tx_interrupt(struct amba_info *info)
+-{
+-	unsigned int cr;
+-
+-	cr = UART_GET_CR(info->port);
+-	cr &= ~AMBA_UARTCR_TIE;
+-	UART_PUT_CR(info->port, cr);
+-}
+-
+-static void ambauart_stop(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-
+-	save_flags(flags); cli();
+-	ambauart_disable_tx_interrupt(info);
+-	restore_flags(flags);
+-}
+-
+-static void ambauart_start(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-
+-	save_flags(flags); cli();
+-	if (info->xmit.head != info->xmit.tail
+-	    && info->xmit.buf)
+-		ambauart_enable_tx_interrupt(info);
+-	restore_flags(flags);
+-}
+-
+-
+-/*
+- * This routine is used by the interrupt handler to schedule
+- * processing in the software interrupt portion of the driver.
+- */
+-static void ambauart_event(struct amba_info *info, int event)
+-{
+-	info->event |= 1 << event;
+-	tasklet_schedule(&info->tlet);
+-}
+-
+-static void
+-#ifdef SUPPORT_SYSRQ
+-ambauart_rx_chars(struct amba_info *info, struct pt_regs *regs)
+-#else
+-ambauart_rx_chars(struct amba_info *info)
+-#endif
+-{
+-	struct tty_struct *tty = info->tty;
+-	unsigned int status, ch, rsr, flg, ignored = 0;
+-	struct amba_icount *icount = &info->state->icount;
+-	struct amba_port *port = info->port;
+-
+-	status = UART_GET_FR(port);
+-	while (UART_RX_DATA(status)) {
+-		ch = UART_GET_CHAR(port);
+-
+-		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+-			goto ignore_char;
+-		icount->rx++;
+-
+-		flg = TTY_NORMAL;
+-
+-		/*
+-		 * Note that the error handling code is
+-		 * out of the main execution path
+-		 */
+-		rsr = UART_GET_RSR(port);
+-		if (rsr & AMBA_UARTRSR_ANY)
+-			goto handle_error;
+-#ifdef SUPPORT_SYSRQ
+-		if (info->sysrq) {
+-			if (ch && time_before(jiffies, info->sysrq)) {
+-				handle_sysrq(ch, regs, NULL, NULL);
+-				info->sysrq = 0;
+-				goto ignore_char;
+-			}
+-			info->sysrq = 0;
+-		}
+-#endif
+-	error_return:
+-		*tty->flip.flag_buf_ptr++ = flg;
+-		*tty->flip.char_buf_ptr++ = ch;
+-		tty->flip.count++;
+-	ignore_char:
+-		status = UART_GET_FR(port);
+-	}
+-out:
+-	tty_flip_buffer_push(tty);
+-	return;
+-
+-handle_error:
+-	if (rsr & AMBA_UARTRSR_BE) {
+-		rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE);
+-		icount->brk++;
+-
+-#ifdef SUPPORT_SYSRQ
+-		if (info->state->line == ambauart_cons.index) {
+-			if (!info->sysrq) {
+-				info->sysrq = jiffies + HZ*5;
+-				goto ignore_char;
+-			}
+-		}
+-#endif
+-	} else if (rsr & AMBA_UARTRSR_PE)
+-		icount->parity++;
+-	else if (rsr & AMBA_UARTRSR_FE)
+-		icount->frame++;
+-	if (rsr & AMBA_UARTRSR_OE)
+-		icount->overrun++;
+-
+-	if (rsr & info->ignore_status_mask) {
+-		if (++ignored > 100)
+-			goto out;
+-		goto ignore_char;
+-	}
+-	rsr &= info->read_status_mask;
+-
+-	if (rsr & AMBA_UARTRSR_BE)
+-		flg = TTY_BREAK;
+-	else if (rsr & AMBA_UARTRSR_PE)
+-		flg = TTY_PARITY;
+-	else if (rsr & AMBA_UARTRSR_FE)
+-		flg = TTY_FRAME;
+-
+-	if (rsr & AMBA_UARTRSR_OE) {
+-		/*
+-		 * CHECK: does overrun affect the current character?
+-		 * ASSUMPTION: it does not.
+-		 */
+-		*tty->flip.flag_buf_ptr++ = flg;
+-		*tty->flip.char_buf_ptr++ = ch;
+-		tty->flip.count++;
+-		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+-			goto ignore_char;
+-		ch = 0;
+-		flg = TTY_OVERRUN;
+-	}
+-#ifdef SUPPORT_SYSRQ
+-	info->sysrq = 0;
+-#endif
+-	goto error_return;
+-}
+-
+-static void ambauart_tx_chars(struct amba_info *info)
+-{
+-	struct amba_port *port = info->port;
+-	int count;
+-
+-	if (info->x_char) {
+-		UART_PUT_CHAR(port, info->x_char);
+-		info->state->icount.tx++;
+-		info->x_char = 0;
+-		return;
+-	}
+-	if (info->xmit.head == info->xmit.tail
+-	    || info->tty->stopped
+-	    || info->tty->hw_stopped) {
+-		ambauart_disable_tx_interrupt(info);
+-		return;
+-	}
+-
+-	count = port->fifosize;
+-	do {
+-		UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
+-		info->xmit.tail = (info->xmit.tail + 1) & (AMBA_XMIT_SIZE - 1);
+-		info->state->icount.tx++;
+-		if (info->xmit.head == info->xmit.tail)
+-			break;
+-	} while (--count > 0);
+-
+-	if (CIRC_CNT(info->xmit.head,
+-		     info->xmit.tail,
+-		     AMBA_XMIT_SIZE) < WAKEUP_CHARS)
+-		ambauart_event(info, EVT_WRITE_WAKEUP);
+-
+-	if (info->xmit.head == info->xmit.tail) {
+-		ambauart_disable_tx_interrupt(info);
+-	}
+-}
+-
+-static void ambauart_modem_status(struct amba_info *info)
+-{
+-	unsigned int status, delta;
+-	struct amba_icount *icount = &info->state->icount;
+-
+-	status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY;
+-
+-	delta = status ^ info->old_status;
+-	info->old_status = status;
+-
+-	if (!delta)
+-		return;
+-
+-	if (delta & AMBA_UARTFR_DCD) {
+-		icount->dcd++;
+-#ifdef CONFIG_HARD_PPS
+-		if ((info->flags & ASYNC_HARDPPS_CD) &&
+-		    (status & AMBA_UARTFR_DCD)
+-			hardpps();
+-#endif
+-		if (info->flags & ASYNC_CHECK_CD) {
+-			if (status & AMBA_UARTFR_DCD)
+-				wake_up_interruptible(&info->open_wait);
+-			else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+-				   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+-				if (info->tty)
+-					tty_hangup(info->tty);
+-			}
+-		}
+-	}
+-
+-	if (delta & AMBA_UARTFR_DSR)
+-		icount->dsr++;
+-
+-	if (delta & AMBA_UARTFR_CTS) {
+-		icount->cts++;
+-
+-		if (info->flags & ASYNC_CTS_FLOW) {
+-			status &= AMBA_UARTFR_CTS;
+-
+-			if (info->tty->hw_stopped) {
+-				if (status) {
+-					info->tty->hw_stopped = 0;
+-					ambauart_enable_tx_interrupt(info);
+-					ambauart_event(info, EVT_WRITE_WAKEUP);
+-				}
+-			} else {
+-				if (!status) {
+-					info->tty->hw_stopped = 1;
+-					ambauart_disable_tx_interrupt(info);
+-				}
+-			}
+-		}
+-	}
+-	wake_up_interruptible(&info->delta_msr_wait);
+-
+-}
+-
+-static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs)
+-{
+-	struct amba_info *info = dev_id;
+-	unsigned int status, pass_counter = 0;
+-
+-#if DEBUG_LEDS
+-	// tell the world
+-	set_leds(get_leds() | RED_LED);
+-#endif
+-
+-	status = UART_GET_INT_STATUS(info->port);
+-	do {
+-		/*
+-		 * FIXME: what about clearing the interrupts?
+-		 */
+-
+-		if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS))
+-#ifdef SUPPORT_SYSRQ
+-			ambauart_rx_chars(info, regs);
+-#else
+-			ambauart_rx_chars(info);
+-#endif
+-		if (status & AMBA_UARTIIR_TIS)
+-			ambauart_tx_chars(info);
+-		if (status & AMBA_UARTIIR_MIS)
+-			ambauart_modem_status(info);
+-		if (pass_counter++ > AMBA_ISR_PASS_LIMIT)
+-			break;
+-
+-		status = UART_GET_INT_STATUS(info->port);
+-	} while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | AMBA_UARTIIR_TIS));
+-
+-#if DEBUG_LEDS
+-	// tell the world
+-	set_leds(get_leds() & ~RED_LED);
+-#endif
+-}
+-
+-static void ambauart_tasklet_action(unsigned long data)
+-{
+-	struct amba_info *info = (struct amba_info *)data;
+-	struct tty_struct *tty;
+-
+-	tty = info->tty;
+-	if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))
+-		return;
+-
+-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+-	    tty->ldisc.write_wakeup)
+-		(tty->ldisc.write_wakeup)(tty);
+-	wake_up_interruptible(&tty->write_wait);
+-}
+-
+-static int ambauart_startup(struct amba_info *info)
+-{
+-	unsigned long flags;
+-	unsigned long page;
+-	int retval = 0;
+-
+-	page = get_zeroed_page(GFP_KERNEL);
+-	if (!page)
+-		return -ENOMEM;
+-
+-	save_flags(flags); cli();
+-
+-	if (info->flags & ASYNC_INITIALIZED) {
+-		free_page(page);
+-		goto errout;
+-	}
+-
+-	if (info->xmit.buf)
+-		free_page(page);
+-	else
+-		info->xmit.buf = (unsigned char *) page;
+-
+-	/*
+-	 * Allocate the IRQ
+-	 */
+-	retval = request_irq(info->port->irq, ambauart_int, 0, "amba", info);
+-	if (retval) {
+-		if (capable(CAP_SYS_ADMIN)) {
+-			if (info->tty)
+-				set_bit(TTY_IO_ERROR, &info->tty->flags);
+-			retval = 0;
+-		}
+-		goto errout;
+-	}
+-
+-	info->mctrl = 0;
+-	if (info->tty->termios->c_cflag & CBAUD)
+-		info->mctrl = TIOCM_RTS | TIOCM_DTR;
+-	info->port->set_mctrl(info->port, info->mctrl);
+-
+-	/*
+-	 * initialise the old status of the modem signals
+-	 */
+-	info->old_status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY;
+-
+-	/*
+-	 * Finally, enable interrupts
+-	 */
+-	ambauart_enable_rx_interrupt(info);
+-
+-	if (info->tty)
+-		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+-	info->xmit.head = info->xmit.tail = 0;
+-
+-	/*
+-	 * Set up the tty->alt_speed kludge
+-	 */
+-	if (info->tty) {
+-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+-			info->tty->alt_speed = 57600;
+-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+-			info->tty->alt_speed = 115200;
+-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+-			info->tty->alt_speed = 230400;
+-		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+-			info->tty->alt_speed = 460800;
+-	}
+-
+-	/*
+-	 * and set the speed of the serial port
+-	 */
+-	ambauart_change_speed(info, 0);
+-
+-	info->flags |= ASYNC_INITIALIZED;
+-	restore_flags(flags);
+-	return 0;
+-
+-errout:
+-	restore_flags(flags);
+-	return retval;
+-}
+-
+-/*
+- * This routine will shutdown a serial port; interrupts are disabled, and
+- * DTR is dropped if the hangup on close termio flag is on.
+- */
+-static void ambauart_shutdown(struct amba_info *info)
+-{
+-	unsigned long flags;
+-
+-	if (!(info->flags & ASYNC_INITIALIZED))
+-		return;
+-
+-	save_flags(flags); cli(); /* Disable interrupts */
+-
+-	/*
+-	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+-	 * here so the queue might never be woken up
+-	 */
+-	wake_up_interruptible(&info->delta_msr_wait);
+-
+-	/*
+-	 * Free the IRQ
+-	 */
+-	free_irq(info->port->irq, info);
+-
+-	if (info->xmit.buf) {
+-		unsigned long pg = (unsigned long) info->xmit.buf;
+-		info->xmit.buf = NULL;
+-		free_page(pg);
+-	}
+-
+-	/*
+-	 * disable all interrupts, disable the port
+-	 */
+-	UART_PUT_CR(info->port, 0);
+-
+-	/* disable break condition and fifos */
+-	UART_PUT_LCRH(info->port, UART_GET_LCRH(info->port) &
+-		~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN));
+-
+-	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+-		info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS);
+-	info->port->set_mctrl(info->port, info->mctrl);
+-
+-	/* kill off our tasklet */
+-	tasklet_kill(&info->tlet);
+-	if (info->tty)
+-		set_bit(TTY_IO_ERROR, &info->tty->flags);
+-
+-	info->flags &= ~ASYNC_INITIALIZED;
+-	restore_flags(flags);
+-}
+-
+-static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios)
+-{
+-	unsigned int lcr_h, baud, quot, cflag, old_cr, bits;
+-	unsigned long flags;
+-
+-	if (!info->tty || !info->tty->termios)
+-		return;
+-
+-	cflag = info->tty->termios->c_cflag;
+-
+-#if DEBUG
+-	printk("ambauart_set_cflag(0x%x) called\n", cflag);
+-#endif
+-	/* byte size and parity */
+-	switch (cflag & CSIZE) {
+-	case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; bits = 7;  break;
+-	case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; bits = 8;  break;
+-	case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; bits = 9;  break;
+-	default:  lcr_h = AMBA_UARTLCR_H_WLEN_8; bits = 10; break; // CS8
+-	}
+-	if (cflag & CSTOPB) {
+-		lcr_h |= AMBA_UARTLCR_H_STP2;
+-		bits ++;
+-	}
+-	if (cflag & PARENB) {
+-		lcr_h |= AMBA_UARTLCR_H_PEN;
+-		bits++;
+-		if (!(cflag & PARODD))
+-			lcr_h |= AMBA_UARTLCR_H_EPS;
+-	}
+-	if (info->port->fifosize > 1)
+-		lcr_h |= AMBA_UARTLCR_H_FEN;
+-
+-	do {
+-		/* Determine divisor based on baud rate */
+-		baud = tty_get_baud_rate(info->tty);
+-		if (!baud)
+-			baud = 9600;
+-
+-		if (baud == 38400 &&
+-		    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+-			quot = info->state->custom_divisor;
+-		else
+-			quot = (info->port->uartclk / (16 * baud)) - 1;
+-
+-		if (!quot && old_termios) {
+-			info->tty->termios->c_cflag &= ~CBAUD;
+-			info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+-			old_termios = NULL;
+-		}
+-	} while (quot == 0 && old_termios);
+-
+-	/* As a last resort, if the quotient is zero, default to 9600 bps */
+-	if (!quot)
+-		quot = (info->port->uartclk / (16 * 9600)) - 1;
+-		
+-	info->timeout = (info->port->fifosize * HZ * bits * quot) /
+-			 (info->port->uartclk / 16);
+-	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+-
+-	if (cflag & CRTSCTS)
+-		info->flags |= ASYNC_CTS_FLOW;
+-	else
+-		info->flags &= ~ASYNC_CTS_FLOW;
+-	if (cflag & CLOCAL)
+-		info->flags &= ~ASYNC_CHECK_CD;
+-	else
+-		info->flags |= ASYNC_CHECK_CD;
+-
+-	/*
+-	 * Set up parity check flag
+-	 */
+-#define RELEVENT_IFLAG(iflag)	((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+-
+-	info->read_status_mask = AMBA_UARTRSR_OE;
+-	if (I_INPCK(info->tty))
+-		info->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
+-	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+-		info->read_status_mask |= AMBA_UARTRSR_BE;
+-
+-	/*
+-	 * Characters to ignore
+-	 */
+-	info->ignore_status_mask = 0;
+-	if (I_IGNPAR(info->tty))
+-		info->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
+-	if (I_IGNBRK(info->tty)) {
+-		info->ignore_status_mask |= AMBA_UARTRSR_BE;
+-		/*
+-		 * If we're ignoring parity and break indicators,
+-		 * ignore overruns to (for real raw support).
+-		 */
+-		if (I_IGNPAR(info->tty))
+-			info->ignore_status_mask |= AMBA_UARTRSR_OE;
+-	}
+-
+-	/* first, disable everything */
+-	save_flags(flags); cli();
+-	old_cr = UART_GET_CR(info->port) &= ~AMBA_UARTCR_MSIE;
+-
+-	if ((info->flags & ASYNC_HARDPPS_CD) ||
+-	    (cflag & CRTSCTS) ||
+-	    !(cflag & CLOCAL))
+-		old_cr |= AMBA_UARTCR_MSIE;
+-
+-	UART_PUT_CR(info->port, 0);
+-	restore_flags(flags);
+-
+-	/* Set baud rate */
+-	UART_PUT_LCRM(info->port, ((quot & 0xf00) >> 8));
+-	UART_PUT_LCRL(info->port, (quot & 0xff));
+-
+-	/*
+-	 * ----------v----------v----------v----------v-----
+-	 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+-	 * ----------^----------^----------^----------^-----
+-	 */
+-	UART_PUT_LCRH(info->port, lcr_h);
+-	UART_PUT_CR(info->port, old_cr);
+-}
+-
+-static void ambauart_put_char(struct tty_struct *tty, u_char ch)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-
+-	if (!tty || !info->xmit.buf)
+-		return;
+-
+-	save_flags(flags); cli();
+-	if (CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE) != 0) {
+-		info->xmit.buf[info->xmit.head] = ch;
+-		info->xmit.head = (info->xmit.head + 1) & (AMBA_XMIT_SIZE - 1);
+-	}
+-	restore_flags(flags);
+-}
+-
+-static void ambauart_flush_chars(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-
+-	if (info->xmit.head == info->xmit.tail
+-	    || tty->stopped
+-	    || tty->hw_stopped
+-	    || !info->xmit.buf)
+-		return;
+-
+-	save_flags(flags); cli();
+-	ambauart_enable_tx_interrupt(info);
+-	restore_flags(flags);
+-}
+-
+-static int ambauart_write(struct tty_struct *tty, int from_user,
+-			  const u_char * buf, int count)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-	int c, ret = 0;
+-
+-	if (!tty || !info->xmit.buf || !tmp_buf)
+-		return 0;
+-
+-	save_flags(flags);
+-	if (from_user) {
+-		down(&tmp_buf_sem);
+-		while (1) {
+-			int c1;
+-			c = CIRC_SPACE_TO_END(info->xmit.head,
+-					      info->xmit.tail,
+-					      AMBA_XMIT_SIZE);
+-			if (count < c)
+-				c = count;
+-			if (c <= 0)
+-				break;
+-
+-			c -= copy_from_user(tmp_buf, buf, c);
+-			if (!c) {
+-				if (!ret)
+-					ret = -EFAULT;
+-				break;
+-			}
+-			cli();
+-			c1 = CIRC_SPACE_TO_END(info->xmit.head,
+-					       info->xmit.tail,
+-					       AMBA_XMIT_SIZE);
+-			if (c1 < c)
+-				c = c1;
+-			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+-			info->xmit.head = (info->xmit.head + c) &
+-					  (AMBA_XMIT_SIZE - 1);
+-			restore_flags(flags);
+-			buf += c;
+-			count -= c;
+-			ret += c;
+-		}
+-		up(&tmp_buf_sem);
+-	} else {
+-		cli();
+-		while (1) {
+-			c = CIRC_SPACE_TO_END(info->xmit.head,
+-					      info->xmit.tail,
+-					      AMBA_XMIT_SIZE);
+-			if (count < c)
+-				c = count;
+-			if (c <= 0)
+-				break;
+-			memcpy(info->xmit.buf + info->xmit.head, buf, c);
+-			info->xmit.head = (info->xmit.head + c) &
+-					  (AMBA_XMIT_SIZE - 1);
+-			buf += c;
+-			count -= c;
+-			ret += c;
+-		}
+-		restore_flags(flags);
+-	}
+-	if (info->xmit.head != info->xmit.tail
+-	    && !tty->stopped
+-	    && !tty->hw_stopped)
+-		ambauart_enable_tx_interrupt(info);
+-	return ret;
+-}
+-
+-static int ambauart_write_room(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-
+-	return CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE);
+-}
+-
+-static int ambauart_chars_in_buffer(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-
+-	return CIRC_CNT(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE);
+-}
+-
+-static void ambauart_flush_buffer(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-
+-#if DEBUG
+-	printk("ambauart_flush_buffer(%d) called\n",
+-	       MINOR(tty->device) - tty->driver.minor_start);
+-#endif
+-	save_flags(flags); cli();
+-	info->xmit.head = info->xmit.tail = 0;
+-	restore_flags(flags);
+-	wake_up_interruptible(&tty->write_wait);
+-	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+-	    tty->ldisc.write_wakeup)
+-		(tty->ldisc.write_wakeup)(tty);
+-}
+-
+-/*
+- * This function is used to send a high-priority XON/XOFF character to
+- * the device
+- */
+-static void ambauart_send_xchar(struct tty_struct *tty, char ch)
+-{
+-	struct amba_info *info = tty->driver_data;
+-
+-	info->x_char = ch;
+-	if (ch)
+-		ambauart_enable_tx_interrupt(info);
+-}
+-
+-static void ambauart_throttle(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-
+-	if (I_IXOFF(tty))
+-		ambauart_send_xchar(tty, STOP_CHAR(tty));
+-
+-	if (tty->termios->c_cflag & CRTSCTS) {
+-		save_flags(flags); cli();
+-		info->mctrl &= ~TIOCM_RTS;
+-		info->port->set_mctrl(info->port, info->mctrl);
+-		restore_flags(flags);
+-	}
+-}
+-
+-static void ambauart_unthrottle(struct tty_struct *tty)
+-{
+-	struct amba_info *info = (struct amba_info *) tty->driver_data;
+-	unsigned long flags;
+-
+-	if (I_IXOFF(tty)) {
+-		if (info->x_char)
+-			info->x_char = 0;
+-		else
+-			ambauart_send_xchar(tty, START_CHAR(tty));
+-	}
+-
+-	if (tty->termios->c_cflag & CRTSCTS) {
+-		save_flags(flags); cli();
+-		info->mctrl |= TIOCM_RTS;
+-		info->port->set_mctrl(info->port, info->mctrl);
+-		restore_flags(flags);
+-	}
+-}
+-
+-static int get_serial_info(struct amba_info *info, struct serial_struct *retinfo)
+-{
+-	struct amba_state *state = info->state;
+-	struct amba_port *port = info->port;
+-	struct serial_struct tmp;
+-
+-	memset(&tmp, 0, sizeof(tmp));
+-	tmp.type	   = 0;
+-	tmp.line	   = state->line;
+-	tmp.port	   = port->uart_base;
+-	if (HIGH_BITS_OFFSET)
+-		tmp.port_high = port->uart_base >> HIGH_BITS_OFFSET;
+-	tmp.irq		   = port->irq;
+-	tmp.flags	   = 0;
+-	tmp.xmit_fifo_size = port->fifosize;
+-	tmp.baud_base	   = port->uartclk / 16;
+-	tmp.close_delay	   = state->close_delay;
+-	tmp.closing_wait   = state->closing_wait;
+-	tmp.custom_divisor = state->custom_divisor;
+-
+-	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+-		return -EFAULT;
+-	return 0;
+-}
+-
+-static int set_serial_info(struct amba_info *info,
+-			   struct serial_struct *newinfo)
+-{
+-	struct serial_struct new_serial;
+-	struct amba_state *state, old_state;
+-	struct amba_port *port;
+-	unsigned long new_port;
+-	unsigned int i, change_irq, change_port;
+-	int retval = 0;
+-
+-	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+-		return -EFAULT;
+-
+-	state = info->state;
+-	old_state = *state;
+-	port = info->port;
+-
+-	new_port = new_serial.port;
+-	if (HIGH_BITS_OFFSET)
+-		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+-
+-	change_irq  = new_serial.irq != port->irq;
+-	change_port = new_port != port->uart_base;
+-
+-	if (!capable(CAP_SYS_ADMIN)) {
+-		if (change_irq || change_port ||
+-		    (new_serial.baud_base != port->uartclk / 16) ||
+-		    (new_serial.close_delay != state->close_delay) ||
+-		    (new_serial.xmit_fifo_size != port->fifosize) ||
+-		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+-		     (state->flags & ~ASYNC_USR_MASK)))
+-			return -EPERM;
+-		state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+-				(new_serial.flags & ASYNC_USR_MASK));
+-		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+-			       (new_serial.flags & ASYNC_USR_MASK));
+-		state->custom_divisor = new_serial.custom_divisor;
+-		goto check_and_exit;
+-	}
+-
+-	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+-	    (new_serial.baud_base < 9600))
+-		return -EINVAL;
+-
+-	if (new_serial.type && change_port) {
+-		for (i = 0; i < SERIAL_AMBA_NR; i++)
+-			if ((port != amba_ports + i) &&
+-			    amba_ports[i].uart_base != new_port)
+-				return -EADDRINUSE;
+-	}
+-
+-	if ((change_port || change_irq) && (state->count > 1))
+-		return -EBUSY;
+-
+-	/*
+-	 * OK, past this point, all the error checking has been done.
+-	 * At this point, we start making changes.....
+-	 */
+-	port->uartclk = new_serial.baud_base * 16;
+-	state->flags = ((state->flags & ~ASYNC_FLAGS) |
+-			(new_serial.flags & ASYNC_FLAGS));
+-	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+-		       (info->flags & ASYNC_INTERNAL_FLAGS));
+-	state->custom_divisor = new_serial.custom_divisor;
+-	state->close_delay = new_serial.close_delay * HZ / 100;
+-	state->closing_wait = new_serial.closing_wait * HZ / 100;
+-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+-	port->fifosize = new_serial.xmit_fifo_size;
+-
+-	if (change_port || change_irq) {
+-		/*
+-		 * We need to shutdown the serial port at the old
+-		 * port/irq combination.
+-		 */
+-		ambauart_shutdown(info);
+-		port->irq = new_serial.irq;
+-		port->uart_base = new_port;
+-	}
+-
+-check_and_exit:
+-	if (!port->uart_base)
+-		return 0;
+-	if (info->flags & ASYNC_INITIALIZED) {
+-		if ((old_state.flags & ASYNC_SPD_MASK) !=
+-		    (state->flags & ASYNC_SPD_MASK) ||
+-		    (old_state.custom_divisor != state->custom_divisor)) {
+-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+-				info->tty->alt_speed = 57600;
+-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+-				info->tty->alt_speed = 115200;
+-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+-				info->tty->alt_speed = 230400;
+-			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+-				info->tty->alt_speed = 460800;
+-			ambauart_change_speed(info, NULL);
+-		}
+-	} else
+-		retval = ambauart_startup(info);
+-	return retval;
+-}
+-
+-
+-/*
+- * get_lsr_info - get line status register info
+- */
+-static int get_lsr_info(struct amba_info *info, unsigned int *value)
+-{
+-	unsigned int result, status;
+-	unsigned long flags;
+-
+-	save_flags(flags); cli();
+-	status = UART_GET_FR(info->port);
+-	restore_flags(flags);
+-	result = status & AMBA_UARTFR_BUSY ? TIOCSER_TEMT : 0;
+-
+-	/*
+-	 * If we're about to load something into the transmit
+-	 * register, we'll pretend the transmitter isn't empty to
+-	 * avoid a race condition (depending on when the transmit
+-	 * interrupt happens).
+-	 */
+-	if (info->x_char ||
+-	    ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+-		       AMBA_XMIT_SIZE) > 0) &&
+-	     !info->tty->stopped && !info->tty->hw_stopped))
+-		result &= TIOCSER_TEMT;
+-	
+-	return put_user(result, value);
+-}
+-
+-static int get_modem_info(struct amba_info *info, unsigned int *value)
+-{
+-	unsigned int result = info->mctrl;
+-	unsigned int status;
+-
+-	status = UART_GET_FR(info->port);
+-	if (status & AMBA_UARTFR_DCD)
+-		result |= TIOCM_CAR;
+-	if (status & AMBA_UARTFR_DSR)
+-		result |= TIOCM_DSR;
+-	if (status & AMBA_UARTFR_CTS)
+-		result |= TIOCM_CTS;
+-
+-	return put_user(result, value);
+-}
+-
+-static int set_modem_info(struct amba_info *info, unsigned int cmd,
+-			  unsigned int *value)
+-{
+-	unsigned int arg, old;
+-	unsigned long flags;
+-
+-	if (get_user(arg, value))
+-		return -EFAULT;
+-
+-	old = info->mctrl;
+-	switch (cmd) {
+-	case TIOCMBIS:
+-		info->mctrl |= arg;
+-		break;
+-
+-	case TIOCMBIC:
+-		info->mctrl &= ~arg;
+-		break;
+-
+-	case TIOCMSET:
+-		info->mctrl = arg;
+-		break;
+-
+-	default:
+-		return -EINVAL;
+-	}
+-	save_flags(flags); cli();
+-	if (old != info->mctrl)
+-		info->port->set_mctrl(info->port, info->mctrl);
+-	restore_flags(flags);
+-	return 0;
+-}
+-
+-static void ambauart_break_ctl(struct tty_struct *tty, int break_state)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-	unsigned int lcr_h;
+-
+-	save_flags(flags); cli();
+-	lcr_h = UART_GET_LCRH(info->port);
+-	if (break_state == -1)
+-		lcr_h |= AMBA_UARTLCR_H_BRK;
+-	else
+-		lcr_h &= ~AMBA_UARTLCR_H_BRK;
+-	UART_PUT_LCRH(info->port, lcr_h);
+-	restore_flags(flags);
+-}
+-
+-static int ambauart_ioctl(struct tty_struct *tty, struct file *file,
+-			   unsigned int cmd, unsigned long arg)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	struct amba_icount cprev, cnow;
+-	struct serial_icounter_struct icount;
+-	unsigned long flags;
+-
+-	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+-	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+-	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+-		if (tty->flags & (1 << TTY_IO_ERROR))
+-			return -EIO;
+-	}
+-
+-	switch (cmd) {
+-		case TIOCMGET:
+-			return get_modem_info(info, (unsigned int *)arg);
+-		case TIOCMBIS:
+-		case TIOCMBIC:
+-		case TIOCMSET:
+-			return set_modem_info(info, cmd, (unsigned int *)arg);
+-		case TIOCGSERIAL:
+-			return get_serial_info(info,
+-					       (struct serial_struct *)arg);
+-		case TIOCSSERIAL:
+-			return set_serial_info(info,
+-					       (struct serial_struct *)arg);
+-		case TIOCSERGETLSR: /* Get line status register */
+-			return get_lsr_info(info, (unsigned int *)arg);
+-		/*
+-		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+-		 * - mask passed in arg for lines of interest
+-		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+-		 * Caller should use TIOCGICOUNT to see which one it was
+-		 */
+-		case TIOCMIWAIT:
+-			save_flags(flags); cli();
+-			/* note the counters on entry */
+-			cprev = info->state->icount;
+-			/* Force modem status interrupts on */
+-			UART_PUT_CR(info->port, UART_GET_CR(info->port) | AMBA_UARTCR_MSIE);
+-			restore_flags(flags);
+-			while (1) {
+-				interruptible_sleep_on(&info->delta_msr_wait);
+-				/* see if a signal did it */
+-				if (signal_pending(current))
+-					return -ERESTARTSYS;
+-				save_flags(flags); cli();
+-				cnow = info->state->icount; /* atomic copy */
+-				restore_flags(flags);
+-				if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+-				    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+-					return -EIO; /* no change => error */
+-				if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+-				    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+-				    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
+-				    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+-					return 0;
+-				}
+-				cprev = cnow;
+-			}
+-			/* NOTREACHED */
+-
+-		/*
+-		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+-		 * Return: write counters to the user passed counter struct
+-		 * NB: both 1->0 and 0->1 transitions are counted except for
+-		 *     RI where only 0->1 is counted.
+-		 */
+-		case TIOCGICOUNT:
+-			save_flags(flags); cli();
+-			cnow = info->state->icount;
+-			restore_flags(flags);
+-			icount.cts = cnow.cts;
+-			icount.dsr = cnow.dsr;
+-			icount.rng = cnow.rng;
+-			icount.dcd = cnow.dcd;
+-			icount.rx  = cnow.rx;
+-			icount.tx  = cnow.tx;
+-			icount.frame = cnow.frame;
+-			icount.overrun = cnow.overrun;
+-			icount.parity = cnow.parity;
+-			icount.brk = cnow.brk;
+-			icount.buf_overrun = cnow.buf_overrun;
+-
+-			return copy_to_user((void *)arg, &icount, sizeof(icount))
+-					? -EFAULT : 0;
+-
+-		default:
+-			return -ENOIOCTLCMD;
+-	}
+-	return 0;
+-}
+-
+-static void ambauart_set_termios(struct tty_struct *tty, struct termios *old_termios)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	unsigned long flags;
+-	unsigned int cflag = tty->termios->c_cflag;
+-
+-	if ((cflag ^ old_termios->c_cflag) == 0 &&
+-	    RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+-		return;
+-
+-	ambauart_change_speed(info, old_termios);
+-
+-	/* Handle transition to B0 status */
+-	if ((old_termios->c_cflag & CBAUD) &&
+-	    !(cflag & CBAUD)) {
+-		save_flags(flags); cli();
+-		info->mctrl &= ~(TIOCM_RTS | TIOCM_DTR);
+-		info->port->set_mctrl(info->port, info->mctrl);
+-		restore_flags(flags);
+-	}
+-
+-	/* Handle transition away from B0 status */
+-	if (!(old_termios->c_cflag & CBAUD) &&
+-	    (cflag & CBAUD)) {
+-		save_flags(flags); cli();
+-		info->mctrl |= TIOCM_DTR;
+-		if (!(cflag & CRTSCTS) ||
+-		    !test_bit(TTY_THROTTLED, &tty->flags))
+-			info->mctrl |= TIOCM_RTS;
+-		info->port->set_mctrl(info->port, info->mctrl);
+-		restore_flags(flags);
+-	}
+-
+-	/* Handle turning off CRTSCTS */
+-	if ((old_termios->c_cflag & CRTSCTS) &&
+-	    !(cflag & CRTSCTS)) {
+-		tty->hw_stopped = 0;
+-		ambauart_start(tty);
+-	}
+-
+-#if 0
+-	/*
+-	 * No need to wake up processes in open wait, since they
+-	 * sample the CLOCAL flag once, and don't recheck it.
+-	 * XXX  It's not clear whether the current behavior is correct
+-	 * or not.  Hence, this may change.....
+-	 */
+-	if (!(old_termios->c_cflag & CLOCAL) &&
+-	    (tty->termios->c_cflag & CLOCAL))
+-		wake_up_interruptible(&info->open_wait);
+-#endif
+-}
+-
+-static void ambauart_close(struct tty_struct *tty, struct file *filp)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	struct amba_state *state;
+-	unsigned long flags;
+-
+-	if (!info)
+-		return;
+-
+-	state = info->state;
+-
+-#if DEBUG
+-	printk("ambauart_close() called\n");
+-#endif
+-
+-	save_flags(flags); cli();
+-
+-	if (tty_hung_up_p(filp)) {
+-		MOD_DEC_USE_COUNT;
+-		restore_flags(flags);
+-		return;
+-	}
+-
+-	if ((tty->count == 1) && (state->count != 1)) {
+-		/*
+-		 * Uh, oh.  tty->count is 1, which means that the tty
+-		 * structure will be freed.  state->count should always
+-		 * be one in these conditions.  If it's greater than
+-		 * one, we've got real problems, since it means the
+-		 * serial port won't be shutdown.
+-		 */
+-		printk("ambauart_close: bad serial port count; tty->count is 1, "
+-		       "state->count is %d\n", state->count);
+-		state->count = 1;
+-	}
+-	if (--state->count < 0) {
+-		printk("rs_close: bad serial port count for %s%d: %d\n",
+-		       tty->driver.name, info->state->line, state->count);
+-		state->count = 0;
+-	}
+-	if (state->count) {
+-		MOD_DEC_USE_COUNT;
+-		restore_flags(flags);
+-		return;
+-	}
+-	info->flags |= ASYNC_CLOSING;
+-	restore_flags(flags);
+-	/*
+-	 * Save the termios structure, since this port may have
+-	 * separate termios for callout and dialin.
+-	 */
+-	if (info->flags & ASYNC_NORMAL_ACTIVE)
+-		info->state->normal_termios = *tty->termios;
+-	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+-		info->state->callout_termios = *tty->termios;
+-	/*
+-	 * Now we wait for the transmit buffer to clear; and we notify
+-	 * the line discipline to only process XON/XOFF characters.
+-	 */
+-	tty->closing = 1;
+-	if (info->state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+-		tty_wait_until_sent(tty, info->state->closing_wait);
+-	/*
+-	 * At this point, we stop accepting input.  To do this, we
+-	 * disable the receive line status interrupts.
+-	 */
+-	if (info->flags & ASYNC_INITIALIZED) {
+-		ambauart_disable_rx_interrupt(info);
+-		/*
+-		 * Before we drop DTR, make sure the UART transmitter
+-		 * has completely drained; this is especially
+-		 * important if there is a transmit FIFO!
+-		 */
+-		ambauart_wait_until_sent(tty, info->timeout);
+-	}
+-	ambauart_shutdown(info);
+-	if (tty->driver.flush_buffer)
+-		tty->driver.flush_buffer(tty);
+-	if (tty->ldisc.flush_buffer)
+-		tty->ldisc.flush_buffer(tty);
+-	tty->closing = 0;
+-	info->event = 0;
+-	info->tty = NULL;
+-	if (info->blocked_open) {
+-		if (info->state->close_delay) {
+-			set_current_state(TASK_INTERRUPTIBLE);
+-			schedule_timeout(info->state->close_delay);
+-		}
+-		wake_up_interruptible(&info->open_wait);
+-	}
+-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+-			 ASYNC_CLOSING);
+-	wake_up_interruptible(&info->close_wait);
+-	MOD_DEC_USE_COUNT;
+-}
+-
+-static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout)
+-{
+-	struct amba_info *info = (struct amba_info *) tty->driver_data;
+-	unsigned long char_time, expire;
+-	unsigned int status;
+-
+-	if (info->port->fifosize == 0)
+-		return;
+-
+-	/*
+-	 * Set the check interval to be 1/5 of the estimated time to
+-	 * send a single character, and make it at least 1.  The check
+-	 * interval should also be less than the timeout.
+-	 *
+-	 * Note: we have to use pretty tight timings here to satisfy
+-	 * the NIST-PCTS.
+-	 */
+-	char_time = (info->timeout - HZ/50) / info->port->fifosize;
+-	char_time = char_time / 5;
+-	if (char_time == 0)
+-		char_time = 1;
+-	if (timeout && timeout < char_time)
+-		char_time = timeout;
+-	/*
+-	 * If the transmitter hasn't cleared in twice the approximate
+-	 * amount of time to send the entire FIFO, it probably won't
+-	 * ever clear.  This assumes the UART isn't doing flow
+-	 * control, which is currently the case.  Hence, if it ever
+-	 * takes longer than info->timeout, this is probably due to a
+-	 * UART bug of some kind.  So, we clamp the timeout parameter at
+-	 * 2*info->timeout.
+-	 */
+-	if (!timeout || timeout > 2 * info->timeout)
+-		timeout = 2 * info->timeout;
+-
+-	expire = jiffies + timeout;
+-#if DEBUG
+-	printk("ambauart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n",
+-	       MINOR(tty->device) - tty->driver.minor_start, jiffies,
+-	       expire);
+-#endif
+-	while (UART_GET_FR(info->port) & AMBA_UARTFR_BUSY) {
+-		set_current_state(TASK_INTERRUPTIBLE);
+-		schedule_timeout(char_time);
+-		if (signal_pending(current))
+-			break;
+-		if (timeout && time_after(jiffies, expire))
+-			break;
+-		status = UART_GET_FR(info->port);
+-	}
+-	set_current_state(TASK_RUNNING);
+-}
+-
+-static void ambauart_hangup(struct tty_struct *tty)
+-{
+-	struct amba_info *info = tty->driver_data;
+-	struct amba_state *state = info->state;
+-
+-	ambauart_flush_buffer(tty);
+-	if (info->flags & ASYNC_CLOSING)
+-		return;
+-	ambauart_shutdown(info);
+-	info->event = 0;
+-	state->count = 0;
+-	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+-	info->tty = NULL;
+-	wake_up_interruptible(&info->open_wait);
+-}
+-
+-static int block_til_ready(struct tty_struct *tty, struct file *filp,
+-			   struct amba_info *info)
+-{
+-	DECLARE_WAITQUEUE(wait, current);
+-	struct amba_state *state = info->state;
+-	unsigned long flags;
+-	int do_clocal = 0, extra_count = 0, retval;
+-
+-	/*
+-	 * If the device is in the middle of being closed, then block
+-	 * until it's done, and then try again.
+-	 */
+-	if (tty_hung_up_p(filp) ||
+-	    (info->flags & ASYNC_CLOSING)) {
+-		if (info->flags & ASYNC_CLOSING)
+-			interruptible_sleep_on(&info->close_wait);
+-		return (info->flags & ASYNC_HUP_NOTIFY) ?
+-			-EAGAIN : -ERESTARTSYS;
+-	}
+-
+-	/*
+-	 * If this is a callout device, then just make sure the normal
+-	 * device isn't being used.
+-	 */
+-	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+-		if (info->flags & ASYNC_NORMAL_ACTIVE)
+-			return -EBUSY;
+-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+-		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+-		    (info->session != current->session))
+-			return -EBUSY;
+-		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+-		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+-		    (info->pgrp != current->pgrp))
+-			return -EBUSY;
+-		info->flags |= ASYNC_CALLOUT_ACTIVE;
+-		return 0;
+-	}
+-
+-	/*
+-	 * If non-blocking mode is set, or the port is not enabled,
+-	 * then make the check up front and then exit.
+-	 */
+-	if ((filp->f_flags & O_NONBLOCK) ||
+-	    (tty->flags & (1 << TTY_IO_ERROR))) {
+-		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+-			return -EBUSY;
+-		info->flags |= ASYNC_NORMAL_ACTIVE;
+-		return 0;
+-	}
+-
+-	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+-		if (state->normal_termios.c_cflag & CLOCAL)
+-			do_clocal = 1;
+-	} else {
+-		if (tty->termios->c_cflag & CLOCAL)
+-			do_clocal = 1;
+-	}
+-
+-	/*
+-	 * Block waiting for the carrier detect and the line to become
+-	 * free (i.e., not in use by the callout).  While we are in
+-	 * this loop, state->count is dropped by one, so that
+-	 * rs_close() knows when to free things.  We restore it upon
+-	 * exit, either normal or abnormal.
+-	 */
+-	retval = 0;
+-	add_wait_queue(&info->open_wait, &wait);
+-	save_flags(flags); cli();
+-	if (!tty_hung_up_p(filp)) {
+-		extra_count = 1;
+-		state->count--;
+-	}
+-	restore_flags(flags);
+-	info->blocked_open++;
+-	while (1) {
+-		save_flags(flags); cli();
+-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+-		    (tty->termios->c_cflag & CBAUD)) {
+-			info->mctrl = TIOCM_DTR | TIOCM_RTS;
+-			info->port->set_mctrl(info->port, info->mctrl);
+-		}
+-		restore_flags(flags);
+-		set_current_state(TASK_INTERRUPTIBLE);
+-		if (tty_hung_up_p(filp) ||
+-		    !(info->flags & ASYNC_INITIALIZED)) {
+-			if (info->flags & ASYNC_HUP_NOTIFY)
+-				retval = -EAGAIN;
+-			else
+-				retval = -ERESTARTSYS;
+-			break;
+-		}
+-		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+-		    !(info->flags & ASYNC_CLOSING) &&
+-		    (do_clocal || (UART_GET_FR(info->port) & AMBA_UARTFR_DCD)))
+-			break;
+-		if (signal_pending(current)) {
+-			retval = -ERESTARTSYS;
+-			break;
+-		}
+-		schedule();
+-	}
+-	set_current_state(TASK_RUNNING);
+-	remove_wait_queue(&info->open_wait, &wait);
+-	if (extra_count)
+-		state->count++;
+-	info->blocked_open--;
+-	if (retval)
+-		return retval;
+-	info->flags |= ASYNC_NORMAL_ACTIVE;
+-	return 0;
+-}
+-
+-static struct amba_info *ambauart_get(int line)
+-{
+-	struct amba_info *info;
+-	struct amba_state *state = amba_state + line;
+-
+-	state->count++;
+-	if (state->info)
+-		return state->info;
+-	info = kmalloc(sizeof(struct amba_info), GFP_KERNEL);
+-	if (info) {
+-		memset(info, 0, sizeof(struct amba_info));
+-		init_waitqueue_head(&info->open_wait);
+-		init_waitqueue_head(&info->close_wait);
+-		init_waitqueue_head(&info->delta_msr_wait);
+-		info->flags = state->flags;
+-		info->state = state;
+-		info->port  = amba_ports + line;
+-		tasklet_init(&info->tlet, ambauart_tasklet_action,
+-			     (unsigned long)info);
+-	}
+-	if (state->info) {
+-		kfree(info);
+-		return state->info;
+-	}
+-	state->info = info;
+-	return info;
+-}
+-
+-static int ambauart_open(struct tty_struct *tty, struct file *filp)
+-{
+-	struct amba_info *info;
+-	int retval, line = MINOR(tty->device) - tty->driver.minor_start;
+-
+-#if DEBUG
+-	printk("ambauart_open(%d) called\n", line);
+-#endif
+-
+-	// is this a line that we've got?
+-	MOD_INC_USE_COUNT;
+-	if (line >= SERIAL_AMBA_NR) {
+-		MOD_DEC_USE_COUNT;
+-		return -ENODEV;
+-	}
+-
+-	info = ambauart_get(line);
+-	if (!info)
+-		return -ENOMEM;
+-
+-	tty->driver_data = info;
+-	info->tty = tty;
+-	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+-
+-	/*
+-	 * Make sure we have the temporary buffer allocated
+-	 */
+-	if (!tmp_buf) {
+-		unsigned long page = get_zeroed_page(GFP_KERNEL);
+-		if (tmp_buf)
+-			free_page(page);
+-		else if (!page) {
+-			MOD_DEC_USE_COUNT;
+-			return -ENOMEM;
+-		}
+-		tmp_buf = (u_char *)page;
+-	}
+-
+-	/*
+-	 * If the port is in the middle of closing, bail out now.
+-	 */
+-	if (tty_hung_up_p(filp) ||
+-	    (info->flags & ASYNC_CLOSING)) {
+-		if (info->flags & ASYNC_CLOSING)
+-			interruptible_sleep_on(&info->close_wait);
+-		MOD_DEC_USE_COUNT;
+-		return -EAGAIN;
+-	}
+-
+-	/*
+-	 * Start up the serial port
+-	 */
+-	retval = ambauart_startup(info);
+-	if (retval) {
+-		MOD_DEC_USE_COUNT;
+-		return retval;
+-	}
+-
+-	retval = block_til_ready(tty, filp, info);
+-	if (retval) {
+-		MOD_DEC_USE_COUNT;
+-		return retval;
+-	}
+-
+-	if ((info->state->count == 1) &&
+-	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
+-		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+-			*tty->termios = info->state->normal_termios;
+-		else
+-			*tty->termios = info->state->callout_termios;
+-	}
+-#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+-	if (ambauart_cons.cflag && ambauart_cons.index == line) {
+-		tty->termios->c_cflag = ambauart_cons.cflag;
+-		ambauart_cons.cflag = 0;
+-	}
+-#endif
+-	ambauart_change_speed(info, NULL);
+-	info->session = current->session;
+-	info->pgrp = current->pgrp;
+-	return 0;
+-}
+-
+-int __init ambauart_init(void)
+-{
+-	int i;
+-
+-	ambanormal_driver.magic = TTY_DRIVER_MAGIC;
+-	ambanormal_driver.driver_name = "serial_amba";
+-	ambanormal_driver.name = SERIAL_AMBA_NAME;
+-	ambanormal_driver.major = SERIAL_AMBA_MAJOR;
+-	ambanormal_driver.minor_start = SERIAL_AMBA_MINOR;
+-	ambanormal_driver.num = SERIAL_AMBA_NR;
+-	ambanormal_driver.type = TTY_DRIVER_TYPE_SERIAL;
+-	ambanormal_driver.subtype = SERIAL_TYPE_NORMAL;
+-	ambanormal_driver.init_termios = tty_std_termios;
+-	ambanormal_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+-	ambanormal_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+-	ambanormal_driver.refcount = &ambauart_refcount;
+-	ambanormal_driver.table = ambauart_table;
+-	ambanormal_driver.termios = ambauart_termios;
+-	ambanormal_driver.termios_locked = ambauart_termios_locked;
+-
+-	ambanormal_driver.open = ambauart_open;
+-	ambanormal_driver.close = ambauart_close;
+-	ambanormal_driver.write = ambauart_write;
+-	ambanormal_driver.put_char = ambauart_put_char;
+-	ambanormal_driver.flush_chars = ambauart_flush_chars;
+-	ambanormal_driver.write_room = ambauart_write_room;
+-	ambanormal_driver.chars_in_buffer = ambauart_chars_in_buffer;
+-	ambanormal_driver.flush_buffer	= ambauart_flush_buffer;
+-	ambanormal_driver.ioctl = ambauart_ioctl;
+-	ambanormal_driver.throttle = ambauart_throttle;
+-	ambanormal_driver.unthrottle = ambauart_unthrottle;
+-	ambanormal_driver.send_xchar = ambauart_send_xchar;
+-	ambanormal_driver.set_termios = ambauart_set_termios;
+-	ambanormal_driver.stop = ambauart_stop;
+-	ambanormal_driver.start = ambauart_start;
+-	ambanormal_driver.hangup = ambauart_hangup;
+-	ambanormal_driver.break_ctl = ambauart_break_ctl;
+-	ambanormal_driver.wait_until_sent = ambauart_wait_until_sent;
+-	ambanormal_driver.read_proc = NULL;
+-
+-	/*
+-	 * The callout device is just like the normal device except for
+-	 * the major number and the subtype code.
+-	 */
+-	ambacallout_driver = ambanormal_driver;
+-	ambacallout_driver.name = CALLOUT_AMBA_NAME;
+-	ambacallout_driver.major = CALLOUT_AMBA_MAJOR;
+-	ambacallout_driver.subtype = SERIAL_TYPE_CALLOUT;
+-	ambacallout_driver.read_proc = NULL;
+-	ambacallout_driver.proc_entry = NULL;
+-
+-	if (tty_register_driver(&ambanormal_driver))
+-		panic("Couldn't register AMBA serial driver\n");
+-	if (tty_register_driver(&ambacallout_driver))
+-		panic("Couldn't register AMBA callout driver\n");
+-
+-	for (i = 0; i < SERIAL_AMBA_NR; i++) {
+-		struct amba_state *state = amba_state + i;
+-		state->line		= i;
+-		state->close_delay	= 5 * HZ / 10;
+-		state->closing_wait	= 30 * HZ;
+-		state->callout_termios	= ambacallout_driver.init_termios;
+-		state->normal_termios	= ambanormal_driver.init_termios;
+-	}
+-
+-	return 0;
+-}
+-
+-__initcall(ambauart_init);
+-
+-#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+-/************** console driver *****************/
+-
+-/*
+- * This code is currently never used; console->read is never called.
+- * Therefore, although we have an implementation, we don't use it.
+- * FIXME: the "const char *s" should be fixed to "char *s" some day.
+- * (when the definition in include/linux/console.h is also fixed)
+- */
+-#ifdef used_and_not_const_char_pointer
+-static int ambauart_console_read(struct console *co, const char *s, u_int count)
+-{
+-	struct amba_port *port = &amba_ports[co->index];
+-	unsigned int status;
+-	char *w;
+-	int c;
+-#if DEBUG
+-	printk("ambauart_console_read() called\n");
+-#endif
+-
+-	c = 0;
+-	w = s;
+-	while (c < count) {
+-		status = UART_GET_FR(port);
+-		if (UART_RX_DATA(status)) {
+-			*w++ = UART_GET_CHAR(port);
+-			c++;
+-		} else {
+-			// nothing more to get, return
+-			return c;
+-		}
+-	}
+-	// return the count
+-	return c;
+-}
+-#endif
+-
+-/*
+- *	Print a string to the serial port trying not to disturb
+- *	any possible real use of the port...
+- *
+- *	The console must be locked when we get here.
+- */
+-static void ambauart_console_write(struct console *co, const char *s, u_int count)
+-{
+-	struct amba_port *port = &amba_ports[co->index];
+-	unsigned int status, old_cr;
+-	int i;
+-
+-	/*
+-	 *	First save the CR then disable the interrupts
+-	 */
+-	old_cr = UART_GET_CR(port);
+-	UART_PUT_CR(port, AMBA_UARTCR_UARTEN);
+-
+-	/*
+-	 *	Now, do each character
+-	 */
+-	for (i = 0; i < count; i++) {
+-		do {
+-			status = UART_GET_FR(port);
+-		} while (!UART_TX_READY(status));
+-		UART_PUT_CHAR(port, s[i]);
+-		if (s[i] == '\n') {
+-			do {
+-				status = UART_GET_FR(port);
+-			} while (!UART_TX_READY(status));
+-			UART_PUT_CHAR(port, '\r');
+-		}
+-	}
+-
+-	/*
+-	 *	Finally, wait for transmitter to become empty
+-	 *	and restore the TCR
+-	 */
+-	do {
+-		status = UART_GET_FR(port);
+-	} while (status & AMBA_UARTFR_BUSY);
+-	UART_PUT_CR(port, old_cr);
+-}
+-
+-static kdev_t ambauart_console_device(struct console *c)
+-{
+-	return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index);
+-}
+-
+-static int __init ambauart_console_setup(struct console *co, char *options)
+-{
+-	struct amba_port *port;
+-	int baud = 38400;
+-	int bits = 8;
+-	int parity = 'n';
+-	u_int cflag = CREAD | HUPCL | CLOCAL;
+-	u_int lcr_h, quot;
+-
+-	if (co->index >= SERIAL_AMBA_NR)
+-		co->index = 0;
+-
+-	port = &amba_ports[co->index];
+-
+-	if (options) {
+-		char *s = options;
+-		baud = simple_strtoul(s, NULL, 10);
+-		while (*s >= '0' && *s <= '9')
+-			s++;
+-		if (*s) parity = *s++;
+-		if (*s) bits = *s - '0';
+-	}
+-
+-	/*
+-	 *    Now construct a cflag setting.
+-	 */
+-	switch (baud) {
+-	case 1200:	cflag |= B1200;			break;
+-	case 2400:	cflag |= B2400;			break;
+-	case 4800:	cflag |= B4800;			break;
+-	default:	cflag |= B9600;   baud = 9600;	break;
+-	case 19200:	cflag |= B19200;		break;
+-	case 38400:	cflag |= B38400;		break;
+-	case 57600:	cflag |= B57600;		break;
+-	case 115200:	cflag |= B115200;		break;
+-	}
+-	switch (bits) {
+-	case 7:	  cflag |= CS7;	lcr_h = AMBA_UARTLCR_H_WLEN_7;	break;
+-	default:  cflag |= CS8;	lcr_h = AMBA_UARTLCR_H_WLEN_8;	break;
+-	}
+-	switch (parity) {
+-	case 'o':
+-	case 'O': cflag |= PARODD; lcr_h |= AMBA_UARTLCR_H_PEN;	break;
+-	case 'e':
+-	case 'E': cflag |= PARENB; lcr_h |= AMBA_UARTLCR_H_PEN |
+-					    AMBA_UARTLCR_H_EPS; break;
+-	}
+-
+-	co->cflag = cflag;
+-
+-	if (port->fifosize > 1)
+-		lcr_h |= AMBA_UARTLCR_H_FEN;
+-
+-	quot = (port->uartclk / (16 * baud)) - 1;
+-
+-	UART_PUT_LCRL(port, (quot & 0xff));
+-	UART_PUT_LCRM(port, (quot >> 8));
+-	UART_PUT_LCRH(port, lcr_h);
+-
+-	/* we will enable the port as we need it */
+-	UART_PUT_CR(port, 0);
+-
+-	return 0;
+-}
+-
+-static struct console ambauart_cons =
+-{
+-	name:		SERIAL_AMBA_NAME,
+-	write:		ambauart_console_write,
+-#ifdef used_and_not_const_char_pointer
+-	read:		ambauart_console_read,
+-#endif
+-	device:		ambauart_console_device,
+-	setup:		ambauart_console_setup,
+-	flags:		CON_PRINTBUFFER,
+-	index:		-1,
+-};
+-
+-void __init ambauart_console_init(void)
+-{
+-	register_console(&ambauart_cons);
+-}
+-
+-#endif /* CONFIG_SERIAL_AMBA_CONSOLE */
+-
+-MODULE_LICENSE("GPL");
+-EXPORT_NO_SYMBOLS;
+--- linux-2.4.25/drivers/char/tty_io.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/char/tty_io.c	2004-03-31 17:15:09.000000000 +0200
+@@ -19,7 +19,7 @@
+  * Also restructured routines so that there is more of a separation
+  * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
+  * the low-level tty routines (serial.c, pty.c, console.c).  This
+- * makes for cleaner and more compact code.  -TYT, 9/17/92 
++ * makes for cleaner and more compact code.  -TYT, 9/17/92
+  *
+  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
+  * which can be dynamically activated and de-activated by the line
+@@ -41,7 +41,7 @@
+  *
+  * New TIOCLINUX variants added.
+  *	-- mj@k332.feld.cvut.cz, 19-Nov-95
+- * 
++ *
+  * Restrict vt switching via ioctl()
+  *      -- grif@cs.ucr.edu, 5-Dec-95
+  *
+@@ -151,8 +151,7 @@
+ extern void tty3215_init(void);
+ extern void tub3270_con_init(void);
+ extern void tub3270_init(void);
+-extern void rs285_console_init(void);
+-extern void sa1100_rs_console_init(void);
++extern void uart_console_init(void);
+ extern void sgi_serial_console_init(void);
+ extern void sn_sal_serial_console_init(void);
+ extern void sci_console_init(void);
+@@ -164,6 +163,7 @@
+ extern void txx9_serial_console_init(void);
+ extern void sb1250_serial_console_init(void);
+ extern void arc_console_init(void);
++extern void rs285_console_init(void);
+ extern int hvc_console_init(void);
+ 
+ #ifndef MIN
+@@ -201,7 +201,7 @@
+ 	else
+ 		sprintf(buf, name,
+ 			idx + tty->driver.name_base);
+-		
++
+ 	return buf;
+ }
+ 
+@@ -239,7 +239,7 @@
+ #ifdef CHECK_TTY_COUNT
+ 	struct list_head *p;
+ 	int count = 0;
+-	
++
+ 	file_list_lock();
+ 	for(p = tty->tty_files.next; p != &tty->tty_files; p = p->next) {
+ 		if(list_entry(p, struct file, f_list)->private_data == tty)
+@@ -255,7 +255,7 @@
+ 				    "!= #fd's(%d) in %s\n",
+ 		       kdevname(tty->device), tty->count, count, routine);
+ 		return count;
+-       }	
++       }
+ #endif
+ 	return 0;
+ }
+@@ -264,14 +264,14 @@
+ {
+ 	if (disc < N_TTY || disc >= NR_LDISCS)
+ 		return -EINVAL;
+-	
++
+ 	if (new_ldisc) {
+ 		ldiscs[disc] = *new_ldisc;
+ 		ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
+ 		ldiscs[disc].num = disc;
+ 	} else
+ 		memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc));
+-	
++
+ 	return 0;
+ }
+ 
+@@ -301,7 +301,7 @@
+ 	o_ldisc = tty->ldisc;
+ 
+ 	tty_wait_until_sent(tty, 0);
+-	
++
+ 	/* Shutdown the current discipline. */
+ 	if (tty->ldisc.close)
+ 		(tty->ldisc.close)(tty);
+@@ -339,7 +339,7 @@
+ {
+ 	int	major, minor;
+ 	struct tty_driver *p;
+-	
++
+ 	minor = MINOR(device);
+ 	major = MAJOR(device);
+ 
+@@ -456,7 +456,7 @@
+ 		redirect = NULL;
+ 	}
+ 	spin_unlock(&redirect_lock);
+-	
++
+ 	check_tty_count(tty, "do_tty_hangup");
+ 	file_list_lock();
+ 	for (l = tty->tty_files.next; l != &tty->tty_files; l = l->next) {
+@@ -473,7 +473,7 @@
+ 		filp->f_op = &hung_up_tty_fops;
+ 	}
+ 	file_list_unlock();
+-	
++
+ 	/* FIXME! What are the locking issues here? This may me overdoing things.. */
+ 	{
+ 		unsigned long flags;
+@@ -510,7 +510,7 @@
+ 						"error %d\n", -i);
+ 		}
+ 	}
+-	
++
+ 	read_lock(&tasklist_lock);
+  	for_each_task(p) {
+ 		if ((tty->session > 0) && (p->session == tty->session) &&
+@@ -550,7 +550,7 @@
+ {
+ #ifdef TTY_DEBUG_HANGUP
+ 	char	buf[64];
+-	
++
+ 	printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
+ #endif
+ 	schedule_task(&tty->tq_hangup);
+@@ -650,7 +650,7 @@
+ 	wake_up_interruptible(&tty->write_wait);
+ }
+ 
+-static ssize_t tty_read(struct file * file, char * buf, size_t count, 
++static ssize_t tty_read(struct file * file, char * buf, size_t count,
+ 			loff_t *ppos)
+ {
+ 	int i;
+@@ -707,7 +707,7 @@
+ 	size_t count)
+ {
+ 	ssize_t ret = 0, written = 0;
+-	
++
+ 	if (file->f_flags & O_NONBLOCK) {
+ 		if (down_trylock(&tty->atomic_write))
+ 			return -EAGAIN;
+@@ -835,7 +835,7 @@
+ 	struct tty_struct *tty, *o_tty;
+ 	struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
+ 	struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
+-	struct tty_driver *driver;	
++	struct tty_driver *driver;
+ 	int retval=0;
+ 	int idx;
+ 
+@@ -845,7 +845,7 @@
+ 
+ 	idx = MINOR(device) - driver->minor_start;
+ 
+-	/* 
++	/*
+ 	 * Check whether we need to acquire the tty semaphore to avoid
+ 	 * race conditions.  For now, play it safe.
+ 	 */
+@@ -859,7 +859,7 @@
+ 	 * First time open is complex, especially for PTY devices.
+ 	 * This code guarantees that either everything succeeds and the
+ 	 * TTY is ready for operation, or else the table slots are vacated
+-	 * and the allocated memory released.  (Except that the termios 
++	 * and the allocated memory released.  (Except that the termios
+ 	 * and locked termios may be retained.)
+ 	 */
+ 
+@@ -938,13 +938,13 @@
+ 		o_tty->link = tty;
+ 	}
+ 
+-	/* 
++	/*
+ 	 * All structures have been allocated, so now we install them.
+-	 * Failures after this point use release_mem to clean up, so 
++	 * Failures after this point use release_mem to clean up, so
+ 	 * there's no need to null out the local pointers.
+ 	 */
+ 	driver->table[idx] = tty;
+-	
++
+ 	if (!*tp_loc)
+ 		*tp_loc = tp;
+ 	if (!*ltp_loc)
+@@ -954,7 +954,7 @@
+ 	(*driver->refcount)++;
+ 	tty->count++;
+ 
+-	/* 
++	/*
+ 	 * Structures all installed ... call the ldisc open routines.
+ 	 * If we fail here just call release_mem to clean up.  No need
+ 	 * to decrement the use counts, as release_mem doesn't care.
+@@ -988,7 +988,7 @@
+ 	if (driver->type == TTY_DRIVER_TYPE_PTY &&
+ 	    driver->subtype == PTY_TYPE_MASTER) {
+ 		/*
+-		 * special case for PTY masters: only one open permitted, 
++		 * special case for PTY masters: only one open permitted,
+ 		 * and the slave side open count is incremented as well.
+ 		 */
+ 		if (tty->count) {
+@@ -1002,7 +1002,7 @@
+ 
+ success:
+ 	*ret_tty = tty;
+-	
++
+ 	/* All paths come through here to release the semaphore */
+ end_init:
+ 	up_tty_sem(idx);
+@@ -1080,7 +1080,7 @@
+ 	int	pty_master, tty_closing, o_tty_closing, do_sleep;
+ 	int	idx;
+ 	char	buf[64];
+-	
++
+ 	tty = (struct tty_struct *)filp->private_data;
+ 	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev"))
+ 		return;
+@@ -1138,7 +1138,7 @@
+ 			       idx, kdevname(tty->device));
+ 			return;
+ 		}
+-		if (o_tty->termios_locked != 
++		if (o_tty->termios_locked !=
+ 		      tty->driver.other->termios_locked[idx]) {
+ 			printk(KERN_DEBUG "release_dev: other->termios_locked["
+ 					  "%d] not o_termios_locked for (%s)\n",
+@@ -1204,11 +1204,11 @@
+ 		printk(KERN_WARNING "release_dev: %s: read/write wait queue "
+ 				    "active!\n", tty_name(tty, buf));
+ 		schedule();
+-	}	
++	}
+ 
+ 	/*
+-	 * The closing flags are now consistent with the open counts on 
+-	 * both sides, and we've completed the last operation that could 
++	 * The closing flags are now consistent with the open counts on
++	 * both sides, and we've completed the last operation that could
+ 	 * block, so it's safe to proceed with closing.
+ 	 */
+ 	if (pty_master) {
+@@ -1266,7 +1266,7 @@
+ 	/* check whether both sides are closing ... */
+ 	if (!tty_closing || (o_tty && !o_tty_closing))
+ 		return;
+-	
++
+ #ifdef TTY_DEBUG_HANGUP
+ 	printk(KERN_DEBUG "freeing tty structure...");
+ #endif
+@@ -1284,14 +1284,14 @@
+ 			(o_tty->ldisc.close)(o_tty);
+ 		o_tty->ldisc = ldiscs[N_TTY];
+ 	}
+-	
++
+ 	/*
+-	 * Make sure that the tty's task queue isn't activated. 
++	 * Make sure that the tty's task queue isn't activated.
+ 	 */
+ 	run_task_queue(&tq_timer);
+ 	flush_scheduled_tasks();
+ 
+-	/* 
++	/*
+ 	 * The release_mem function takes care of the details of clearing
+ 	 * the slots and preserving the termios structure.
+ 	 */
+@@ -1482,7 +1482,7 @@
+ 	tty = (struct tty_struct *)filp->private_data;
+ 	if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_fasync"))
+ 		return 0;
+-	
++
+ 	retval = fasync_helper(fd, filp, on, &tty->fasync);
+ 	if (retval <= 0)
+ 		return retval;
+@@ -1697,7 +1697,7 @@
+ 
+ static int tty_generic_brk(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+ {
+-	if (cmd == TCSBRK && arg) 
++	if (cmd == TCSBRK && arg)
+ 	{
+ 		/* tcdrain case */
+ 		int retval = tty_check_change(tty);
+@@ -1718,7 +1718,7 @@
+ {
+ 	struct tty_struct *tty, *real_tty;
+ 	int retval;
+-	
++
+ 	tty = (struct tty_struct *)file->private_data;
+ 	if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl"))
+ 		return -EINVAL;
+@@ -1738,7 +1738,7 @@
+ 			if (tty->driver.ioctl)
+ 				return tty->driver.ioctl(tty, file, cmd, arg);
+ 			return -EINVAL;
+-			
++
+ 		/* These two ioctl's always return success; even if */
+ 		/* the driver doesn't support them. */
+ 		case TCSBRK:
+@@ -1761,7 +1761,7 @@
+ 	case TIOCSBRK:
+ 	case TIOCCBRK:
+ 	case TCSBRK:
+-	case TCSBRKP:			
++	case TCSBRKP:
+ 		retval = tty_check_change(tty);
+ 		if (retval)
+ 			return retval;
+@@ -1824,7 +1824,7 @@
+ 		case TIOCSBRK:	/* Turn break on, unconditionally */
+ 			tty->driver.break_ctl(tty, -1);
+ 			return 0;
+-			
++
+ 		case TIOCCBRK:	/* Turn break off, unconditionally */
+ 			tty->driver.break_ctl(tty, 0);
+ 			return 0;
+@@ -1837,7 +1837,7 @@
+ 			if (!arg)
+ 				return send_break(tty, HZ/4);
+ 			return 0;
+-		case TCSBRKP:	/* support for POSIX tcsendbreak() */	
++		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+ 			return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
+ 	}
+ 	if (tty->driver.ioctl) {
+@@ -1859,7 +1859,7 @@
+  * prevent trojan horses by killing all processes associated with this
+  * tty when the user hits the "Secure Attention Key".  Required for
+  * super-paranoid applications --- see the Orange Book for more details.
+- * 
++ *
+  * This code could be nicer; ideally it should send a HUP, wait a few
+  * seconds, then send a INT, and then a KILL signal.  But you then
+  * have to coordinate with the init process, since all processes associated
+@@ -1883,7 +1883,7 @@
+ 	int session;
+ 	int		i;
+ 	struct file	*filp;
+-	
++
+ 	if (!tty)
+ 		return;
+ 	session  = tty->session;
+@@ -1968,7 +1968,7 @@
+ 	count = tty->flip.count;
+ 	tty->flip.count = 0;
+ 	restore_flags(flags);
+-	
++
+ 	tty->ldisc.receive_buf(tty, cp, fp, count);
+ }
+ 
+@@ -2000,7 +2000,7 @@
+ 	i = cflag & CBAUD;
+ 	if (i & CBAUDEX) {
+ 		i &= ~CBAUDEX;
+-		if (i < 1 || i+15 >= n_baud_table) 
++		if (i < 1 || i+15 >= n_baud_table)
+ 			tty->termios->c_cflag &= ~CBAUDEX;
+ 		else
+ 			i += 15;
+@@ -2013,7 +2013,7 @@
+ 		}
+ 		return(tty->alt_speed);
+ 	}
+-	
++
+ 	return baud_table[i];
+ }
+ 
+@@ -2079,7 +2079,7 @@
+ 				mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+ 			break;
+ 	}
+-	if ( (minor <  driver->minor_start) || 
++	if ( (minor <  driver->minor_start) ||
+ 	     (minor >= driver->minor_start + driver->num) ) {
+ 		printk(KERN_ERR "Attempt to register invalid minor number "
+ 		       "with devfs (%d:%d).\n", (int)driver->major,(int)minor);
+@@ -2132,12 +2132,12 @@
+ 
+ 	if (!driver->put_char)
+ 		driver->put_char = tty_default_put_char;
+-	
++
+ 	driver->prev = 0;
+ 	driver->next = tty_drivers;
+ 	if (tty_drivers) tty_drivers->prev = driver;
+ 	tty_drivers = driver;
+-	
++
+ 	if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
+ 		for(i = 0; i < driver->num; i++)
+ 		    tty_register_devfs(driver, 0, driver->minor_start + i);
+@@ -2156,7 +2156,7 @@
+ 	int	i, found = 0;
+ 	struct termios *tp;
+ 	const char *othername = NULL;
+-	
++
+ 	if (*driver->refcount)
+ 		return -EBUSY;
+ 
+@@ -2166,7 +2166,7 @@
+ 		else if (p->major == driver->major)
+ 			othername = p->name;
+ 	}
+-	
++
+ 	if (!found)
+ 		return -ENOENT;
+ 
+@@ -2181,7 +2181,7 @@
+ 		driver->prev->next = driver->next;
+ 	else
+ 		tty_drivers = driver->next;
+-	
++
+ 	if (driver->next)
+ 		driver->next->prev = driver->prev;
+ 
+@@ -2221,7 +2221,7 @@
+ 	(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
+ 
+ 	/*
+-	 * Set up the standard termios.  Individual tty drivers may 
++	 * Set up the standard termios.  Individual tty drivers may
+ 	 * deviate from this; this is used as a template.
+ 	 */
+ 	memset(&tty_std_termios, 0, sizeof(struct termios));
+@@ -2233,11 +2233,11 @@
+ 		ECHOCTL | ECHOKE | IEXTEN;
+ 
+ 	/*
+-	 * set up the console device so that later boot sequences can 
++	 * set up the console device so that later boot sequences can
+ 	 * inform about problems etc..
+ 	 */
+ #ifdef CONFIG_EARLY_PRINTK
+-	disable_early_printk(); 
++	disable_early_printk();
+ #endif
+ #ifdef CONFIG_HVC_CONSOLE
+ 	hvc_console_init();
+@@ -2288,18 +2288,12 @@
+ #ifdef CONFIG_STDIO_CONSOLE
+ 	stdio_console_init();
+ #endif
+-#ifdef CONFIG_SERIAL_21285_CONSOLE
+-	rs285_console_init();
+-#endif
+-#ifdef CONFIG_SERIAL_SA1100_CONSOLE
+-	sa1100_rs_console_init();
++#ifdef CONFIG_SERIAL_CORE_CONSOLE
++	uart_console_init();
+ #endif
+ #ifdef CONFIG_ARC_CONSOLE
+ 	arc_console_init();
+ #endif
+-#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+-	ambauart_console_init();
+-#endif
+ #ifdef CONFIG_SERIAL_TX3912_CONSOLE
+ 	tx3912_console_init();
+ #endif
+@@ -2315,6 +2309,9 @@
+ #ifdef CONFIG_IP22_SERIAL
+ 	sgi_serial_console_init();
+ #endif
++#ifdef CONFIG_SERIAL_21285_CONSOLE
++	rs285_console_init();
++#endif
+ }
+ 
+ static struct tty_driver dev_tty_driver, dev_syscons_driver;
+@@ -2347,7 +2344,7 @@
+ 	dev_tty_driver.num = 1;
+ 	dev_tty_driver.type = TTY_DRIVER_TYPE_SYSTEM;
+ 	dev_tty_driver.subtype = SYSTEM_TYPE_TTY;
+-	
++
+ 	if (tty_register_driver(&dev_tty_driver))
+ 		panic("Couldn't register /dev/tty driver\n");
+ 
+@@ -2363,7 +2360,7 @@
+ 		panic("Couldn't register /dev/console driver\n");
+ 
+ 	/* console calls tty_register_driver() before kmalloc() works.
+-	 * Thus, we can't devfs_register() then.  Do so now, instead. 
++	 * Thus, we can't devfs_register() then.  Do so now, instead.
+ 	 */
+ #ifdef CONFIG_VT
+ 	con_init_devfs();
+@@ -2381,7 +2378,7 @@
+ 	if (tty_register_driver(&dev_ptmx_driver))
+ 		panic("Couldn't register /dev/ptmx driver\n");
+ #endif
+-	
++
+ #ifdef CONFIG_VT
+ 	dev_console_driver = dev_tty_driver;
+ 	dev_console_driver.driver_name = "/dev/vc/0";
+@@ -2441,10 +2438,10 @@
+ 	pty_init();
+ #ifdef CONFIG_MOXA_SMARTIO
+ 	mxser_init();
+-#endif	
++#endif
+ #ifdef CONFIG_MOXA_INTELLIO
+ 	moxa_init();
+-#endif	
++#endif
+ #ifdef CONFIG_VT
+ 	vcs_init();
+ #endif
+--- linux-2.4.25/drivers/char/wdt285.c~2.4.25-vrs2.patch	2003-06-13 16:51:33.000000000 +0200
++++ linux-2.4.25/drivers/char/wdt285.c	2004-03-31 17:15:09.000000000 +0200
+@@ -151,7 +151,7 @@
+ 			if (get_user(new_margin, (int *)arg))
+ 				return -EFAULT;
+ 			/* Arbitrary, can't find the card's limits */
+-			if ((new_marg < 0) || (new_margin > 60))
++			if ((new_margin < 0) || (new_margin > 60))
+ 				return -EINVAL;
+ 			soft_margin = new_margin;
+ 			watchdog_ping();
+--- linux-2.4.25/drivers/char/wdt977.c~2.4.25-vrs2.patch	2002-11-29 00:53:12.000000000 +0100
++++ linux-2.4.25/drivers/char/wdt977.c	2004-03-31 17:15:09.000000000 +0200
+@@ -27,6 +27,7 @@
+ #include <asm/io.h>
+ #include <asm/system.h>
+ #include <asm/mach-types.h>
++#include <asm/uaccess.h>
+ 
+ #define WATCHDOG_MINOR	130
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/cpufreq/Kconfig	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,38 @@
++config CPU_FREQ_PROC_INTF
++	tristate "/proc/cpufreq interface (deprecated)"
++	depends on CPU_FREQ && PROC_FS
++	help
++	  This enables the /proc/cpufreq interface for controlling
++	  CPUFreq. Please note that it is recommended to use the sysfs
++	  interface instead (which is built automatically). 
++	  
++	  For details, take a look at linux/Documentation/cpufreq. 
++	  
++	  If in doubt, say N.
++
++config CPU_FREQ_GOV_USERSPACE
++       tristate "'userspace' governor for userspace frequency scaling"
++       depends on CPU_FREQ
++       help
++	  Enable this cpufreq governor when you either want to set the
++	  CPU frequency manually or when an userspace programm shall
++          be able to set the CPU dynamically, like on LART 
++	  ( http://www.lart.tudelft.nl/ )
++
++	  For details, take a look at linux/Documentation/cpufreq. 
++
++	  If in doubt, say Y.
++
++config CPU_FREQ_24_API
++	bool "/proc/sys/cpu/ interface (2.4. / OLD)"
++	depends on CPU_FREQ && SYSCTL && CPU_FREQ_GOV_USERSPACE
++	help
++	  This enables the /proc/sys/cpu/ sysctl interface for controlling
++	  the CPUFreq,"userspace" governor. This is the same interface
++	  as known from the.4.-kernel patches for CPUFreq, and offers
++	  the same functionality as long as "userspace" is the
++	  selected governor for the specified CPU.
++	
++	  For details, take a look at linux/Documentation/cpufreq. 
++
++	  If in doubt, say N.
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/cpufreq/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,4 @@
++#CPUfreq governors and cross-arch helpers
++obj-$(CONFIG_CPU_FREQ_TABLE)		+= freq_table.o
++obj-$(CONFIG_CPU_FREQ_PROC_INTF)	+= proc_intf.o
++obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE)	+= userspace.o
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/cpufreq/cpufreq.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,720 @@
++/*
++ *  linux/kernel/cpufreq.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *            (C) 2002 - 2003 Dominik Brodowski <linux@brodo.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/notifier.h>
++#include <linux/cpufreq.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++
++#include <asm/semaphore.h>
++/**
++ * The "cpufreq driver" - the arch- or hardware-dependend low
++ * level driver of CPUFreq support, and its spinlock. This lock
++ * also protects the cpufreq_cpu_data array.
++ */
++static struct cpufreq_driver   	*cpufreq_driver;
++static struct cpufreq_policy	*cpufreq_cpu_data[NR_CPUS];
++static spinlock_t		cpufreq_driver_lock = SPIN_LOCK_UNLOCKED;
++
++/* internal prototype */
++static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
++
++
++/**
++ * Two notifier lists: the "policy" list is involved in the 
++ * validation process for a new CPU frequency policy; the 
++ * "transition" list for kernel code that needs to handle
++ * changes to devices when the CPU clock speed changes.
++ * The mutex locks both lists.
++ */
++static struct notifier_block    *cpufreq_policy_notifier_list;
++static struct notifier_block    *cpufreq_transition_notifier_list;
++static DECLARE_RWSEM		(cpufreq_notifier_rwsem);
++
++
++static LIST_HEAD(cpufreq_governor_list);
++static DECLARE_MUTEX		(cpufreq_governor_sem);
++
++/*
++ * backport info:
++ * we don't have a kobj we can use for ref-counting, so use a
++ * "unsigned int policy->use_count" and an "unload_sem" [idea from
++ * Pat Mochel's struct driver unload_sem] for proper reference counting.
++ */
++
++static struct cpufreq_policy * cpufreq_cpu_get(unsigned int cpu)
++{
++	struct cpufreq_policy *data;
++	unsigned long flags;
++
++	if (cpu >= NR_CPUS)
++		goto err_out;
++
++	/* get the cpufreq driver */
++	spin_lock_irqsave(&cpufreq_driver_lock, flags);
++
++	if (!cpufreq_driver)
++		goto err_out_unlock;
++
++	/* get the CPU */
++	data = cpufreq_cpu_data[cpu];
++
++	if (!data)
++		goto err_out_unlock;
++
++	if (!data->use_count)
++		goto err_out_unlock;
++
++	data->use_count += 1;
++
++	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++
++	return data;
++
++ err_out_unlock:
++	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++ err_out:
++	return NULL;
++}
++
++static void cpufreq_cpu_put(struct cpufreq_policy *data)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&cpufreq_driver_lock, flags);
++	data->use_count -= 1;
++	if (!data->use_count) {
++		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++		up(&data->unload_sem);
++		return;
++	}
++	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++}
++
++/*********************************************************************
++ *                          SYSFS INTERFACE                          *
++ *********************************************************************/
++
++/**
++ * cpufreq_parse_governor - parse a governor string
++ */
++int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
++				struct cpufreq_governor **governor)
++{
++	if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
++		*policy = CPUFREQ_POLICY_PERFORMANCE;
++		return 0;
++	} else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
++		*policy = CPUFREQ_POLICY_POWERSAVE;
++		return 0;
++	} else 	{
++		struct cpufreq_governor *t;
++		down(&cpufreq_governor_sem);
++		if (!cpufreq_driver || !cpufreq_driver->target)
++			goto out;
++		list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
++			if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) {
++				*governor = t;
++				*policy = CPUFREQ_POLICY_GOVERNOR;
++				up(&cpufreq_governor_sem);
++				return 0;
++			}
++		}
++	out:
++		up(&cpufreq_governor_sem);
++	}
++	return -EINVAL;
++}
++EXPORT_SYMBOL_GPL(cpufreq_parse_governor);
++
++
++/* backport info:
++ * all the sysfs stuff is missing -- of course
++ */
++
++/**
++ * cpufreq_add_dev - add a CPU device
++ *
++ * Adds the cpufreq interface for a CPU device. 
++ */
++static int cpufreq_add_dev (unsigned int cpu)
++{
++	int ret = 0;
++	struct cpufreq_policy new_policy;
++	struct cpufreq_policy *policy;
++	unsigned long flags;
++
++	policy = kmalloc(sizeof(struct cpufreq_policy), GFP_KERNEL);
++	if (!policy)
++		return -ENOMEM;
++	memset(policy, 0, sizeof(struct cpufreq_policy));
++
++	policy->cpu = cpu;
++	policy->use_count = 1;
++	init_MUTEX_LOCKED(&policy->lock);
++	init_MUTEX_LOCKED(&policy->unload_sem);
++
++	/* call driver. From then on the cpufreq must be able
++	 * to accept all calls to ->verify and ->setpolicy for this CPU
++	 */
++	ret = cpufreq_driver->init(policy);
++	if (ret)
++		goto err_out;
++
++	memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
++
++	spin_lock_irqsave(&cpufreq_driver_lock, flags);
++	cpufreq_cpu_data[cpu] = policy;
++	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++
++	up(&policy->lock);
++	
++	/* set default policy */
++	ret = cpufreq_set_policy(&new_policy);
++	if (ret)
++		goto err_out_unregister;
++
++	return 0;
++
++
++ err_out_unregister:
++	spin_lock_irqsave(&cpufreq_driver_lock, flags);
++	cpufreq_cpu_data[cpu] = NULL;
++	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++
++ err_out:
++	kfree(policy);
++	return ret;
++}
++
++
++/**
++ * cpufreq_remove_dev - remove a CPU device
++ *
++ * Removes the cpufreq interface for a CPU device.
++ */
++static int cpufreq_remove_dev (unsigned int cpu)
++{
++	unsigned long flags;
++	struct cpufreq_policy *data;
++
++	spin_lock_irqsave(&cpufreq_driver_lock, flags);
++	data = cpufreq_cpu_data[cpu];
++	if (!data) {
++		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++		return -EINVAL;
++	}
++	cpufreq_cpu_data[cpu] = NULL;
++
++	data->use_count -= 1;
++	if (!data->use_count) {
++		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++		up(&data->unload_sem);
++	} else {
++		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++		/* this will sleep until data->use_count gets to zero */
++		down(&data->unload_sem);
++		up(&data->unload_sem);
++	}
++
++	if (cpufreq_driver->target)
++		__cpufreq_governor(data, CPUFREQ_GOV_STOP);
++
++	if (cpufreq_driver->exit)
++		cpufreq_driver->exit(data);
++
++	kfree(data);
++
++	return 0;
++}
++
++
++/*********************************************************************
++ *                     NOTIFIER LISTS INTERFACE                      *
++ *********************************************************************/
++
++/**
++ *	cpufreq_register_notifier - register a driver with cpufreq
++ *	@nb: notifier function to register
++ *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
++ *
++ *	Add a driver to one of two lists: either a list of drivers that 
++ *      are notified about clock rate changes (once before and once after
++ *      the transition), or a list of drivers that are notified about
++ *      changes in cpufreq policy.
++ *
++ *	This function may sleep, and has the same return conditions as
++ *	notifier_chain_register.
++ */
++int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
++{
++	int ret;
++
++	down_write(&cpufreq_notifier_rwsem);
++	switch (list) {
++	case CPUFREQ_TRANSITION_NOTIFIER:
++		ret = notifier_chain_register(&cpufreq_transition_notifier_list, nb);
++		break;
++	case CPUFREQ_POLICY_NOTIFIER:
++		ret = notifier_chain_register(&cpufreq_policy_notifier_list, nb);
++		break;
++	default:
++		ret = -EINVAL;
++	}
++	up_write(&cpufreq_notifier_rwsem);
++
++	return ret;
++}
++EXPORT_SYMBOL(cpufreq_register_notifier);
++
++
++/**
++ *	cpufreq_unregister_notifier - unregister a driver with cpufreq
++ *	@nb: notifier block to be unregistered
++ *      @list: CPUFREQ_TRANSITION_NOTIFIER or CPUFREQ_POLICY_NOTIFIER
++ *
++ *	Remove a driver from the CPU frequency notifier list.
++ *
++ *	This function may sleep, and has the same return conditions as
++ *	notifier_chain_unregister.
++ */
++int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
++{
++	int ret;
++
++	down_write(&cpufreq_notifier_rwsem);
++	switch (list) {
++	case CPUFREQ_TRANSITION_NOTIFIER:
++		ret = notifier_chain_unregister(&cpufreq_transition_notifier_list, nb);
++		break;
++	case CPUFREQ_POLICY_NOTIFIER:
++		ret = notifier_chain_unregister(&cpufreq_policy_notifier_list, nb);
++		break;
++	default:
++		ret = -EINVAL;
++	}
++	up_write(&cpufreq_notifier_rwsem);
++
++	return ret;
++}
++EXPORT_SYMBOL(cpufreq_unregister_notifier);
++
++
++/*********************************************************************
++ *                              GOVERNORS                            *
++ *********************************************************************/
++
++
++int __cpufreq_driver_target(struct cpufreq_policy *policy,
++			    unsigned int target_freq,
++			    unsigned int relation)
++{
++	return cpufreq_driver->target(policy, target_freq, relation);
++}
++EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
++
++
++int cpufreq_driver_target(struct cpufreq_policy *policy,
++			  unsigned int target_freq,
++			  unsigned int relation)
++{
++	unsigned int ret;
++
++	policy = cpufreq_cpu_get(policy->cpu);
++	if (!policy)
++		return -EINVAL;
++
++	down(&policy->lock);
++
++	ret = __cpufreq_driver_target(policy, target_freq, relation);
++
++	up(&policy->lock);
++
++	cpufreq_cpu_put(policy);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(cpufreq_driver_target);
++
++
++static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
++{
++	int ret = 0;
++
++	switch (policy->policy) {
++	case CPUFREQ_POLICY_POWERSAVE: 
++		if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START)) {
++			ret = __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
++		}
++		break;
++	case CPUFREQ_POLICY_PERFORMANCE:
++		if ((event == CPUFREQ_GOV_LIMITS) || (event == CPUFREQ_GOV_START)) {
++			ret = __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
++		}
++		break;
++	case CPUFREQ_POLICY_GOVERNOR:
++		ret = policy->governor->governor(policy, event);
++		break;
++	default:
++		ret = -EINVAL;
++	}
++
++	return ret;
++}
++
++
++int cpufreq_governor(unsigned int cpu, unsigned int event)
++{
++	int ret = 0;
++	struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
++
++	if (!policy)
++		return -EINVAL;
++
++	down(&policy->lock);
++	ret = __cpufreq_governor(policy, event);
++	up(&policy->lock);
++
++	cpufreq_cpu_put(policy);
++
++	return ret;
++}
++EXPORT_SYMBOL_GPL(cpufreq_governor);
++
++
++int cpufreq_register_governor(struct cpufreq_governor *governor)
++{
++	struct cpufreq_governor *t;
++
++	if (!governor)
++		return -EINVAL;
++
++	if (!strnicmp(governor->name,"powersave",CPUFREQ_NAME_LEN))
++		return -EBUSY;
++	if (!strnicmp(governor->name,"performance",CPUFREQ_NAME_LEN))
++		return -EBUSY;
++
++	down(&cpufreq_governor_sem);
++	
++	list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
++		if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) {
++			up(&cpufreq_governor_sem);
++			return -EBUSY;
++		}
++	}
++	list_add(&governor->governor_list, &cpufreq_governor_list);
++
++ 	up(&cpufreq_governor_sem);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(cpufreq_register_governor);
++
++
++void cpufreq_unregister_governor(struct cpufreq_governor *governor)
++{
++	/* backport info: 
++	 * As the module usage count isn't assured in 2.4., check for removal
++	 * of running cpufreq governor
++	 */
++	unsigned int i;
++
++	if (!governor)
++		return;
++
++	down(&cpufreq_governor_sem);
++
++	for (i=0; i<NR_CPUS; i++) {
++		struct cpufreq_policy *policy = cpufreq_cpu_get(i);
++		if (!policy)
++			goto done;
++		down(&policy->lock);
++
++		if (policy->policy != CPUFREQ_POLICY_GOVERNOR)
++			goto unlock_done;
++		if (policy->governor != governor)
++			goto unlock_done;
++
++		/* stop old one, start performance [always present] */
++		__cpufreq_governor(policy, CPUFREQ_GOV_STOP);
++		policy->policy = CPUFREQ_POLICY_PERFORMANCE;
++		__cpufreq_governor(policy, CPUFREQ_GOV_START);
++
++	unlock_done:
++		up(&policy->lock);
++	done:
++		cpufreq_cpu_put(policy);
++	}
++	list_del(&governor->governor_list);
++	up(&cpufreq_governor_sem);
++	return;
++}
++EXPORT_SYMBOL_GPL(cpufreq_unregister_governor);
++
++
++
++/*********************************************************************
++ *                          POLICY INTERFACE                         *
++ *********************************************************************/
++
++/**
++ * cpufreq_get_policy - get the current cpufreq_policy
++ * @policy: struct cpufreq_policy into which the current cpufreq_policy is written
++ *
++ * Reads the current cpufreq policy.
++ */
++int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
++{
++	struct cpufreq_policy *cpu_policy;
++	if (!policy)
++		return -EINVAL;
++
++	cpu_policy = cpufreq_cpu_get(cpu);
++	if (!cpu_policy)
++		return -EINVAL;
++
++	down(&cpu_policy->lock);
++	memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy));
++	up(&cpu_policy->lock);
++
++	cpufreq_cpu_put(cpu_policy);
++
++	return 0;
++}
++EXPORT_SYMBOL(cpufreq_get_policy);
++
++
++/**
++ *	cpufreq_set_policy - set a new CPUFreq policy
++ *	@policy: policy to be set.
++ *
++ *	Sets a new CPU frequency and voltage scaling policy.
++ */
++int cpufreq_set_policy(struct cpufreq_policy *policy)
++{
++	int ret = 0;
++	struct cpufreq_policy *data;
++
++	if (!policy)
++		return -EINVAL;
++
++	data = cpufreq_cpu_get(policy->cpu);
++	if (!data)
++		return -EINVAL;
++
++	/* lock this CPU */
++	down(&data->lock);
++
++	memcpy(&policy->cpuinfo, 
++	       &data->cpuinfo, 
++	       sizeof(struct cpufreq_cpuinfo));
++
++	/* verify the cpu speed can be set within this limit */
++	ret = cpufreq_driver->verify(policy);
++	if (ret)
++		goto error_out;
++
++	down_read(&cpufreq_notifier_rwsem);
++
++	/* adjust if necessary - all reasons */
++	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST,
++			    policy);
++
++	/* adjust if necessary - hardware incompatibility*/
++	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_INCOMPATIBLE,
++			    policy);
++
++	/* verify the cpu speed can be set within this limit,
++	   which might be different to the first one */
++	ret = cpufreq_driver->verify(policy);
++	if (ret) {
++		up_read(&cpufreq_notifier_rwsem);
++		goto error_out;
++	}
++
++	/* notification of the new policy */
++	notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY,
++			    policy);
++
++	up_read(&cpufreq_notifier_rwsem);
++
++	data->min    = policy->min;
++	data->max    = policy->max;
++
++	if (cpufreq_driver->setpolicy) {
++		data->policy = policy->policy;
++		ret = cpufreq_driver->setpolicy(policy);
++	} else {
++		if ((policy->policy != data->policy) || 
++		    ((policy->policy == CPUFREQ_POLICY_GOVERNOR) && (policy->governor != data->governor))) {
++			/* save old, working values */
++			unsigned int old_pol = data->policy;
++			struct cpufreq_governor *old_gov = data->governor;
++
++			/* end old governor */
++			__cpufreq_governor(data, CPUFREQ_GOV_STOP);
++
++			/* start new governor */
++			data->policy = policy->policy;
++			data->governor = policy->governor;
++			if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
++				/* new governor failed, so re-start old one */
++				data->policy = old_pol;
++				data->governor = old_gov;
++				__cpufreq_governor(data, CPUFREQ_GOV_START);
++			}
++			/* might be a policy change, too, so fall through */
++		}
++		__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
++	}
++
++ error_out:
++	up(&data->lock);
++	cpufreq_cpu_put(data);
++
++	return ret;
++}
++EXPORT_SYMBOL(cpufreq_set_policy);
++
++
++
++/*********************************************************************
++ *            EXTERNALLY AFFECTING FREQUENCY CHANGES                 *
++ *********************************************************************/
++
++/**
++ * adjust_jiffies - adjust the system "loops_per_jiffy"
++ *
++ * This function alters the system "loops_per_jiffy" for the clock
++ * speed change. Note that loops_per_jiffy cannot be updated on SMP
++ * systems as each CPU might be scaled differently. So, use the arch 
++ * per-CPU loops_per_jiffy value wherever possible.
++ */
++#ifndef CONFIG_SMP
++static unsigned long l_p_j_ref = 0;
++static unsigned int  l_p_j_ref_freq = 0;
++
++static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
++{
++	if (!l_p_j_ref_freq) {
++		l_p_j_ref = loops_per_jiffy;
++		l_p_j_ref_freq = ci->old;
++	}
++	if ((val == CPUFREQ_PRECHANGE  && ci->old < ci->new) ||
++	    (val == CPUFREQ_POSTCHANGE && ci->old > ci->new))
++		loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq, ci->new);
++}
++#else
++#define adjust_jiffies(x...) do {} while (0)
++#endif
++
++
++/**
++ * cpufreq_notify_transition - call notifier chain and adjust_jiffies on frequency transition
++ *
++ * This function calls the transition notifiers and the "adjust_jiffies" function. It is called
++ * twice on all CPU frequency changes that have external effects. 
++ */
++void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
++{
++	down_read(&cpufreq_notifier_rwsem);
++	switch (state) {
++	case CPUFREQ_PRECHANGE:
++		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_PRECHANGE, freqs);
++		adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
++		break;
++	case CPUFREQ_POSTCHANGE:
++		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
++		notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs);
++		cpufreq_cpu_data[freqs->cpu]->cur = freqs->new;
++		break;
++	}
++	up_read(&cpufreq_notifier_rwsem);
++}
++EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
++
++
++
++/*********************************************************************
++ *               REGISTER / UNREGISTER CPUFREQ DRIVER                *
++ *********************************************************************/
++
++/**
++ * cpufreq_register_driver - register a CPU Frequency driver
++ * @driver_data: A struct cpufreq_driver containing the values#
++ * submitted by the CPU Frequency driver.
++ *
++ *   Registers a CPU Frequency driver to this core code. This code 
++ * returns zero on success, -EBUSY when another driver got here first
++ * (and isn't unregistered in the meantime). 
++ *
++ */
++int cpufreq_register_driver(struct cpufreq_driver *driver_data)
++{
++	unsigned long flags;
++	unsigned int i;
++
++	if (!driver_data || !driver_data->verify || !driver_data->init ||
++	    ((!driver_data->setpolicy) && (!driver_data->target)))
++		return -EINVAL;
++
++	spin_lock_irqsave(&cpufreq_driver_lock, flags);
++	if (cpufreq_driver) {
++		spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++		return -EBUSY;
++	}
++	cpufreq_driver = driver_data;
++	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++
++	for (i=0; i<NR_CPUS; i++) {
++		if (cpu_online(i)) 
++			cpufreq_add_dev(i);
++	}
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(cpufreq_register_driver);
++
++
++/**
++ * cpufreq_unregister_driver - unregister the current CPUFreq driver
++ *
++ *    Unregister the current CPUFreq driver. Only call this if you have 
++ * the right to do so, i.e. if you have succeeded in initialising before!
++ * Returns zero if successful, and -EINVAL if the cpufreq_driver is
++ * currently not initialised.
++ */
++int cpufreq_unregister_driver(struct cpufreq_driver *driver)
++{
++	unsigned long flags;
++	unsigned int i;
++
++	if (!cpufreq_driver || (driver != cpufreq_driver))
++		return -EINVAL;
++
++	for (i=0; i<NR_CPUS; i++) {
++		if (cpu_online(i)) 
++			cpufreq_remove_dev(i);
++	}
++
++	spin_lock_irqsave(&cpufreq_driver_lock, flags);
++	cpufreq_driver = NULL;
++	spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/cpufreq/freq_table.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,203 @@
++/*
++ * linux/drivers/cpufreq/freq_table.c
++ *
++ * Copyright (C) 2002 - 2003 Dominik Brodowski
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++
++/*********************************************************************
++ *                     FREQUENCY TABLE HELPERS                       *
++ *********************************************************************/
++
++int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
++				    struct cpufreq_frequency_table *table)
++{
++	unsigned int min_freq = ~0;
++	unsigned int max_freq = 0;
++	unsigned int i = 0;
++
++	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
++		unsigned int freq = table[i].frequency;
++		if (freq == CPUFREQ_ENTRY_INVALID)
++			continue;
++		if (freq < min_freq)
++			min_freq = freq;
++		if (freq > max_freq)
++			max_freq = freq;
++	}
++
++	policy->min = policy->cpuinfo.min_freq = min_freq;
++	policy->max = policy->cpuinfo.max_freq = max_freq;
++
++	if (policy->min == ~0)
++		return -EINVAL;
++	else
++		return 0;
++}
++EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
++
++
++int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
++				   struct cpufreq_frequency_table *table)
++{
++	unsigned int next_larger = ~0;
++	unsigned int i = 0;
++	unsigned int count = 0;
++
++	if (!cpu_online(policy->cpu))
++		return -EINVAL;
++
++	cpufreq_verify_within_limits(policy, 
++				     policy->cpuinfo.min_freq, 
++				     policy->cpuinfo.max_freq);
++
++	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
++		unsigned int freq = table[i].frequency;
++		if (freq == CPUFREQ_ENTRY_INVALID)
++			continue;
++		if ((freq >= policy->min) && (freq <= policy->max))
++			count++;
++		else if ((next_larger > freq) && (freq > policy->max))
++			next_larger = freq;
++	}
++
++	if (!count)
++		policy->max = next_larger;
++
++	cpufreq_verify_within_limits(policy, 
++				     policy->cpuinfo.min_freq, 
++				     policy->cpuinfo.max_freq);
++
++	return 0;
++}
++EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify);
++
++
++int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
++				   struct cpufreq_frequency_table *table,
++				   unsigned int target_freq,
++				   unsigned int relation,
++				   unsigned int *index)
++{
++	struct cpufreq_frequency_table optimal = { .index = ~0, };
++	struct cpufreq_frequency_table suboptimal = { .index = ~0, };
++	unsigned int i;
++
++	switch (relation) {
++	case CPUFREQ_RELATION_H:
++		optimal.frequency = 0;
++		suboptimal.frequency = ~0;
++		break;
++	case CPUFREQ_RELATION_L:
++		optimal.frequency = ~0;
++		suboptimal.frequency = 0;
++		break;
++	}
++
++	if (!cpu_online(policy->cpu))
++		return -EINVAL;
++
++	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
++		unsigned int freq = table[i].frequency;
++		if (freq == CPUFREQ_ENTRY_INVALID)
++			continue;
++		if ((freq < policy->min) || (freq > policy->max))
++			continue;
++		switch(relation) {
++		case CPUFREQ_RELATION_H:
++			if (freq <= target_freq) {
++				if (freq >= optimal.frequency) {
++					optimal.frequency = freq;
++					optimal.index = i;
++				}
++			} else {
++				if (freq <= suboptimal.frequency) {
++					suboptimal.frequency = freq;
++					suboptimal.index = i;
++				}
++			}
++			break;
++		case CPUFREQ_RELATION_L:
++			if (freq >= target_freq) {
++				if (freq <= optimal.frequency) {
++					optimal.frequency = freq;
++					optimal.index = i;
++				}
++			} else {
++				if (freq >= suboptimal.frequency) {
++					suboptimal.frequency = freq;
++					suboptimal.index = i;
++				}
++			}
++			break;
++		}
++	}
++	if (optimal.index > i) {
++		if (suboptimal.index > i)
++			return -EINVAL;
++		*index = suboptimal.index;
++	} else
++		*index = optimal.index;
++	
++	return 0;
++}
++EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
++
++static struct cpufreq_frequency_table *show_table[NR_CPUS];
++/**
++ * show_scaling_governor - show the current policy for the specified CPU
++ */
++static ssize_t show_available_freqs (struct cpufreq_policy *policy, char *buf)
++{
++	unsigned int i = 0;
++	unsigned int cpu = policy->cpu;
++	ssize_t count = 0;
++	struct cpufreq_frequency_table *table;
++
++	if (!show_table[cpu])
++		return -ENODEV;
++
++	table = show_table[cpu];
++
++	for (i=0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
++		if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
++			continue;
++		count += sprintf(&buf[count], "%d ", table[i].frequency);
++	}
++	count += sprintf(&buf[count], "\n");
++
++	return count;
++
++}
++
++struct freq_attr cpufreq_freq_attr_scaling_available_freqs = {
++	.attr = { .name = "scaling_available_frequencies", .mode = 0444 },
++	.show = show_available_freqs,
++};
++EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
++
++/*
++ * if you use these, you must assure that the frequency table is valid
++ * all the time between get_attr and put_attr!
++ */
++void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table, 
++				      unsigned int cpu)
++{
++	show_table[cpu] = table;
++}
++EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
++
++void cpufreq_frequency_table_put_attr(unsigned int cpu)
++{
++	show_table[cpu] = NULL;
++}
++EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
++
++
++MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
++MODULE_DESCRIPTION ("CPUfreq frequency table helpers");
++MODULE_LICENSE ("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/cpufreq/proc_intf.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,244 @@
++/*
++ * linux/drivers/cpufreq/proc_intf.c
++ *
++ * Copyright (C) 2002 - 2003 Dominik Brodowski
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/cpufreq.h>
++#include <linux/ctype.h>
++#include <linux/proc_fs.h>
++#include <asm/uaccess.h>
++
++
++/**
++ * cpufreq_parse_policy - parse a policy string
++ * @input_string: the string to parse.
++ * @policy: the policy written inside input_string
++ *
++ * This function parses a "policy string" - something the user echo'es into
++ * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy.
++ * If there are invalid/missing entries, they are replaced with current
++ * cpufreq policy.
++ */
++static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy)
++{
++	unsigned int            min = 0;
++	unsigned int            max = 0;
++	unsigned int            cpu = 0;
++	char			str_governor[16];
++	struct cpufreq_policy   current_policy;
++	unsigned int            result = -EFAULT;
++
++	if (!policy)
++		return -EINVAL;
++
++	policy->min = 0;
++	policy->max = 0;
++	policy->policy = 0;
++	policy->cpu = CPUFREQ_ALL_CPUS;
++
++	if (sscanf(input_string, "%d:%d:%d:%15s", &cpu, &min, &max, str_governor) == 4) 
++	{
++		policy->min = min;
++		policy->max = max;
++		policy->cpu = cpu;
++		result = 0;
++		goto scan_policy;
++	}
++	if (sscanf(input_string, "%d%%%d%%%d%%%15s", &cpu, &min, &max, str_governor) == 4)
++	{
++		if (!cpufreq_get_policy(&current_policy, cpu)) {
++			policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
++			policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
++			policy->cpu = cpu;
++			result = 0;
++			goto scan_policy;
++		}
++	}
++
++	if (sscanf(input_string, "%d:%d:%15s", &min, &max, str_governor) == 3) 
++	{
++		policy->min = min;
++		policy->max = max;
++		result = 0;
++		goto scan_policy;
++	}
++
++	if (sscanf(input_string, "%d%%%d%%%15s", &min, &max, str_governor) == 3)
++	{
++		if (!cpufreq_get_policy(&current_policy, cpu)) {
++			policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
++			policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
++			result = 0;
++			goto scan_policy;
++		}
++	}
++
++	return -EINVAL;
++
++scan_policy:
++	result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor);
++
++	return result;
++}
++
++/**
++ * cpufreq_proc_read - read /proc/cpufreq
++ *
++ * This function prints out the current cpufreq policy.
++ */
++static int cpufreq_proc_read (
++	char			*page,
++	char			**start,
++	off_t			off,
++	int 			count,
++	int 			*eof,
++	void			*data)
++{
++	char			*p = page;
++	int			len = 0;
++	struct cpufreq_policy   policy;
++	unsigned int            min_pctg = 0;
++	unsigned int            max_pctg = 0;
++	unsigned int            i = 0;
++
++	if (off != 0)
++		goto end;
++
++	p += sprintf(p, "          minimum CPU frequency  -  maximum CPU frequency  -  policy\n");
++	for (i=0;i<NR_CPUS;i++) {
++		if (!cpu_online(i))
++			continue;
++
++		if (cpufreq_get_policy(&policy, i))
++			continue;
++
++		if (!policy.cpuinfo.max_freq)
++			continue;
++
++		min_pctg = (policy.min * 100) / policy.cpuinfo.max_freq;
++		max_pctg = (policy.max * 100) / policy.cpuinfo.max_freq;
++
++		p += sprintf(p, "CPU%3d    %9d kHz (%3d %%)  -  %9d kHz (%3d %%)  -  ",
++			     i , policy.min, min_pctg, policy.max, max_pctg);
++		switch (policy.policy) {
++		case CPUFREQ_POLICY_POWERSAVE:
++			p += sprintf(p, "powersave\n");
++			break;
++		case CPUFREQ_POLICY_PERFORMANCE:
++			p += sprintf(p, "performance\n");
++			break;
++		case CPUFREQ_POLICY_GOVERNOR:
++			p += snprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
++			break;
++		default:
++			p += sprintf(p, "INVALID\n");
++			break;
++		}
++	}
++end:
++	len = (p - page);
++	if (len <= off+count) 
++		*eof = 1;
++	*start = page + off;
++	len -= off;
++	if (len>count) 
++		len = count;
++	if (len<0) 
++		len = 0;
++
++	return len;
++}
++
++
++/**
++ * cpufreq_proc_write - handles writing into /proc/cpufreq
++ *
++ * This function calls the parsing script and then sets the policy
++ * accordingly.
++ */
++static int cpufreq_proc_write (
++        struct file		*file,
++        const char		*buffer,
++        unsigned long		count,
++        void			*data)
++{
++	int                     result = 0;
++	char			proc_string[42] = {'\0'};
++	struct cpufreq_policy   policy;
++	unsigned int            i = 0;
++
++
++	if ((count > sizeof(proc_string) - 1))
++		return -EINVAL;
++	
++	if (copy_from_user(proc_string, buffer, count))
++		return -EFAULT;
++	
++	proc_string[count] = '\0';
++
++	result = cpufreq_parse_policy(proc_string, &policy);
++	if (result)
++		return -EFAULT;
++
++	if (policy.cpu == CPUFREQ_ALL_CPUS)
++	{
++		for (i=0; i<NR_CPUS; i++) 
++		{
++			policy.cpu = i;
++			if (cpu_online(i))
++				cpufreq_set_policy(&policy);
++		}
++	} 
++	else
++		cpufreq_set_policy(&policy);
++
++	return count;
++}
++
++
++/**
++ * cpufreq_proc_init - add "cpufreq" to the /proc root directory
++ *
++ * This function adds "cpufreq" to the /proc root directory.
++ */
++static int __init cpufreq_proc_init (void)
++{
++	struct proc_dir_entry *entry = NULL;
++
++        /* are these acceptable values? */
++	entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, 
++				  &proc_root);
++
++	if (!entry) {
++		printk(KERN_ERR "unable to create /proc/cpufreq entry\n");
++		return -EIO;
++	} else {
++		entry->read_proc = cpufreq_proc_read;
++		entry->write_proc = cpufreq_proc_write;
++	}
++
++	return 0;
++}
++
++
++/**
++ * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory.
++ *
++ * This function removes "cpufreq" from the /proc root directory.
++ */
++static void __exit cpufreq_proc_exit (void)
++{
++	remove_proc_entry("cpufreq", &proc_root);
++	return;
++}
++
++MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
++MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface");
++MODULE_LICENSE ("GPL");
++
++module_init(cpufreq_proc_init);
++module_exit(cpufreq_proc_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/cpufreq/userspace.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,591 @@
++/*
++ *  drivers/cpufreq/userspace.c
++ *
++ *  Copyright (C)  2001 Russell King
++ *            (C)  2002 - 2003 Dominik Brodowski <linux@brodo.de>
++ *
++ * $Id$
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/smp.h>
++#include <linux/init.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/ctype.h>
++#include <linux/cpufreq.h>
++#include <linux/sysctl.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/sysfs.h>
++
++#include <asm/uaccess.h>
++
++#define CTL_CPU_VARS_SPEED_MAX(cpunr) { \
++                .ctl_name	= CPU_NR_FREQ_MAX, \
++                .data		= &cpu_max_freq[cpunr], \
++                .procname	= "speed-max", \
++                .maxlen		= sizeof(cpu_max_freq[cpunr]),\
++                .mode		= 0444, \
++                .proc_handler	= proc_dointvec, }
++
++#define CTL_CPU_VARS_SPEED_MIN(cpunr) { \
++                .ctl_name	= CPU_NR_FREQ_MIN, \
++                .data		= &cpu_min_freq[cpunr], \
++                .procname	= "speed-min", \
++                .maxlen		= sizeof(cpu_min_freq[cpunr]),\
++                .mode		= 0444, \
++                .proc_handler	= proc_dointvec, }
++
++#define CTL_CPU_VARS_SPEED(cpunr) { \
++                .ctl_name	= CPU_NR_FREQ, \
++                .procname	= "speed", \
++                .mode		= 0644, \
++                .proc_handler	= cpufreq_procctl, \
++                .strategy	= cpufreq_sysctl, \
++                .extra1		= (void*) (cpunr), }
++
++#define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\
++                CTL_CPU_VARS_SPEED_MAX(cpunr), \
++                CTL_CPU_VARS_SPEED_MIN(cpunr), \
++                CTL_CPU_VARS_SPEED(cpunr),  \
++                { .ctl_name = 0, }, }
++
++/* the ctl_table entry for each CPU */
++#define CPU_ENUM(s) { \
++                .ctl_name	= (CPU_NR + s), \
++                .procname	= #s, \
++                .mode		= 0555, \
++                .child		= ctl_cpu_vars_##s }
++
++/**
++ * A few values needed by the userspace governor
++ */
++static unsigned int	cpu_max_freq[NR_CPUS];
++static unsigned int	cpu_min_freq[NR_CPUS];
++static unsigned int	cpu_cur_freq[NR_CPUS];
++static unsigned int	cpu_is_managed[NR_CPUS];
++static struct cpufreq_policy current_policy[NR_CPUS];
++
++static DECLARE_MUTEX	(userspace_sem); 
++
++
++/* keep track of frequency transitions */
++static int 
++userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
++                       void *data)
++{
++        struct cpufreq_freqs *freq = data;
++
++	cpu_cur_freq[freq->cpu] = freq->new;
++
++        return 0;
++}
++
++static struct notifier_block userspace_cpufreq_notifier_block = {
++        .notifier_call  = userspace_cpufreq_notifier
++};
++
++
++/** 
++ * cpufreq_set - set the CPU frequency
++ * @freq: target frequency in kHz
++ * @cpu: CPU for which the frequency is to be set
++ *
++ * Sets the CPU frequency to freq.
++ */
++int cpufreq_set(unsigned int freq, unsigned int cpu)
++{
++	int ret = -EINVAL;
++
++	down(&userspace_sem);
++	if (!cpu_is_managed[cpu])
++		goto err;
++
++	if (freq < cpu_min_freq[cpu])
++		freq = cpu_min_freq[cpu];
++	if (freq > cpu_max_freq[cpu])
++		freq = cpu_max_freq[cpu];
++
++	ret = cpufreq_driver_target(&current_policy[cpu], freq, 
++	      CPUFREQ_RELATION_L);
++
++ err:
++	up(&userspace_sem);
++	return ret;
++}
++EXPORT_SYMBOL_GPL(cpufreq_set);
++
++
++/** 
++ * cpufreq_setmax - set the CPU to the maximum frequency
++ * @cpu - affected cpu;
++ *
++ * Sets the CPU frequency to the maximum frequency supported by
++ * this CPU.
++ */
++int cpufreq_setmax(unsigned int cpu)
++{
++	if (!cpu_is_managed[cpu] || !cpu_online(cpu))
++		return -EINVAL;
++	return cpufreq_set(cpu_max_freq[cpu], cpu);
++}
++EXPORT_SYMBOL_GPL(cpufreq_setmax);
++
++
++/** 
++ * cpufreq_get - get the current CPU frequency (in kHz)
++ * @cpu: CPU number
++ *
++ * Get the CPU current (static) CPU frequency
++ */
++unsigned int cpufreq_get(unsigned int cpu)
++{
++	return cpu_cur_freq[cpu];
++}
++EXPORT_SYMBOL(cpufreq_get);
++
++
++#ifdef CONFIG_CPU_FREQ_24_API
++
++
++/*********************** cpufreq_sysctl interface ********************/
++static int
++cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
++		void *buffer, size_t *lenp)
++{
++	char buf[16], *p;
++	int cpu = (int) ctl->extra1;
++	int len, left = *lenp;
++
++	if (!left || (filp->f_pos && !write) || !cpu_online(cpu)) {
++		*lenp = 0;
++		return 0;
++	}
++
++	if (write) {
++		unsigned int freq;
++
++		len = left;
++		if (left > sizeof(buf))
++			left = sizeof(buf);
++		if (copy_from_user(buf, buffer, left))
++			return -EFAULT;
++		buf[sizeof(buf) - 1] = '\0';
++
++		freq = simple_strtoul(buf, &p, 0);
++		cpufreq_set(freq, cpu);
++	} else {
++		len = sprintf(buf, "%d\n", cpufreq_get(cpu));
++		if (len > left)
++			len = left;
++		if (copy_to_user(buffer, buf, len))
++			return -EFAULT;
++	}
++
++	*lenp = len;
++	filp->f_pos += len;
++	return 0;
++}
++
++static int
++cpufreq_sysctl(ctl_table *table, int *name, int nlen,
++	       void *oldval, size_t *oldlenp,
++	       void *newval, size_t newlen, void **context)
++{
++	int cpu = (int) table->extra1;
++
++	if (!cpu_online(cpu))
++		return -EINVAL;
++
++	if (oldval && oldlenp) {
++		size_t oldlen;
++
++		if (get_user(oldlen, oldlenp))
++			return -EFAULT;
++
++		if (oldlen != sizeof(unsigned int))
++			return -EINVAL;
++
++		if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) ||
++		    put_user(sizeof(unsigned int), oldlenp))
++			return -EFAULT;
++	}
++	if (newval && newlen) {
++		unsigned int freq;
++
++		if (newlen != sizeof(unsigned int))
++			return -EINVAL;
++
++		if (get_user(freq, (unsigned int *)newval))
++			return -EFAULT;
++
++		cpufreq_set(freq, cpu);
++	}
++	return 1;
++}
++
++/* ctl_table ctl_cpu_vars_{0,1,...,(NR_CPUS-1)} */
++/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
++        CTL_TABLE_CPU_VARS(0);
++#if NR_CPUS > 1
++	CTL_TABLE_CPU_VARS(1);
++#endif
++#if NR_CPUS > 2
++	CTL_TABLE_CPU_VARS(2);
++#endif
++#if NR_CPUS > 3
++	CTL_TABLE_CPU_VARS(3);
++#endif
++#if NR_CPUS > 4
++	CTL_TABLE_CPU_VARS(4);
++#endif
++#if NR_CPUS > 5
++	CTL_TABLE_CPU_VARS(5);
++#endif
++#if NR_CPUS > 6
++	CTL_TABLE_CPU_VARS(6);
++#endif
++#if NR_CPUS > 7
++	CTL_TABLE_CPU_VARS(7);
++#endif
++#if NR_CPUS > 8
++	CTL_TABLE_CPU_VARS(8);
++#endif
++#if NR_CPUS > 9
++	CTL_TABLE_CPU_VARS(9);
++#endif
++#if NR_CPUS > 10
++	CTL_TABLE_CPU_VARS(10);
++#endif
++#if NR_CPUS > 11
++	CTL_TABLE_CPU_VARS(11);
++#endif
++#if NR_CPUS > 12
++	CTL_TABLE_CPU_VARS(12);
++#endif
++#if NR_CPUS > 13
++	CTL_TABLE_CPU_VARS(13);
++#endif
++#if NR_CPUS > 14
++	CTL_TABLE_CPU_VARS(14);
++#endif
++#if NR_CPUS > 15
++	CTL_TABLE_CPU_VARS(15);
++#endif
++#if NR_CPUS > 16
++	CTL_TABLE_CPU_VARS(16);
++#endif
++#if NR_CPUS > 17
++	CTL_TABLE_CPU_VARS(17);
++#endif
++#if NR_CPUS > 18
++	CTL_TABLE_CPU_VARS(18);
++#endif
++#if NR_CPUS > 19
++	CTL_TABLE_CPU_VARS(19);
++#endif
++#if NR_CPUS > 20
++	CTL_TABLE_CPU_VARS(20);
++#endif
++#if NR_CPUS > 21
++	CTL_TABLE_CPU_VARS(21);
++#endif
++#if NR_CPUS > 22
++	CTL_TABLE_CPU_VARS(22);
++#endif
++#if NR_CPUS > 23
++	CTL_TABLE_CPU_VARS(23);
++#endif
++#if NR_CPUS > 24
++	CTL_TABLE_CPU_VARS(24);
++#endif
++#if NR_CPUS > 25
++	CTL_TABLE_CPU_VARS(25);
++#endif
++#if NR_CPUS > 26
++	CTL_TABLE_CPU_VARS(26);
++#endif
++#if NR_CPUS > 27
++	CTL_TABLE_CPU_VARS(27);
++#endif
++#if NR_CPUS > 28
++	CTL_TABLE_CPU_VARS(28);
++#endif
++#if NR_CPUS > 29
++	CTL_TABLE_CPU_VARS(29);
++#endif
++#if NR_CPUS > 30
++	CTL_TABLE_CPU_VARS(30);
++#endif
++#if NR_CPUS > 31
++	CTL_TABLE_CPU_VARS(31);
++#endif
++#if NR_CPUS > 32
++#error please extend CPU enumeration
++#endif
++
++/* due to NR_CPUS tweaking, a lot of if/endifs are required, sorry */
++static ctl_table ctl_cpu_table[NR_CPUS + 1] = {
++	CPU_ENUM(0),
++#if NR_CPUS > 1
++	CPU_ENUM(1),
++#endif
++#if NR_CPUS > 2
++	CPU_ENUM(2),
++#endif
++#if NR_CPUS > 3
++	CPU_ENUM(3),
++#endif
++#if NR_CPUS > 4
++	CPU_ENUM(4),
++#endif
++#if NR_CPUS > 5
++	CPU_ENUM(5),
++#endif
++#if NR_CPUS > 6
++	CPU_ENUM(6),
++#endif
++#if NR_CPUS > 7
++	CPU_ENUM(7),
++#endif
++#if NR_CPUS > 8
++	CPU_ENUM(8),
++#endif
++#if NR_CPUS > 9
++	CPU_ENUM(9),
++#endif
++#if NR_CPUS > 10
++	CPU_ENUM(10),
++#endif
++#if NR_CPUS > 11
++	CPU_ENUM(11),
++#endif
++#if NR_CPUS > 12
++	CPU_ENUM(12),
++#endif
++#if NR_CPUS > 13
++	CPU_ENUM(13),
++#endif
++#if NR_CPUS > 14
++	CPU_ENUM(14),
++#endif
++#if NR_CPUS > 15
++	CPU_ENUM(15),
++#endif
++#if NR_CPUS > 16
++	CPU_ENUM(16),
++#endif
++#if NR_CPUS > 17
++	CPU_ENUM(17),
++#endif
++#if NR_CPUS > 18
++	CPU_ENUM(18),
++#endif
++#if NR_CPUS > 19
++	CPU_ENUM(19),
++#endif
++#if NR_CPUS > 20
++	CPU_ENUM(20),
++#endif
++#if NR_CPUS > 21
++	CPU_ENUM(21),
++#endif
++#if NR_CPUS > 22
++	CPU_ENUM(22),
++#endif
++#if NR_CPUS > 23
++	CPU_ENUM(23),
++#endif
++#if NR_CPUS > 24
++	CPU_ENUM(24),
++#endif
++#if NR_CPUS > 25
++	CPU_ENUM(25),
++#endif
++#if NR_CPUS > 26
++	CPU_ENUM(26),
++#endif
++#if NR_CPUS > 27
++	CPU_ENUM(27),
++#endif
++#if NR_CPUS > 28
++	CPU_ENUM(28),
++#endif
++#if NR_CPUS > 29
++	CPU_ENUM(29),
++#endif
++#if NR_CPUS > 30
++	CPU_ENUM(30),
++#endif
++#if NR_CPUS > 31
++	CPU_ENUM(31),
++#endif
++#if NR_CPUS > 32
++#error please extend CPU enumeration
++#endif
++	{
++		.ctl_name	= 0,
++	}
++};
++
++static ctl_table ctl_cpu[2] = {
++	{
++		.ctl_name	= CTL_CPU,
++		.procname	= "cpu",
++		.mode		= 0555,
++		.child		= ctl_cpu_table,
++	},
++	{
++		.ctl_name	= 0,
++	}
++};
++
++struct ctl_table_header *cpufreq_sysctl_table;
++
++static inline void cpufreq_sysctl_init(void)
++{
++	cpufreq_sysctl_table = register_sysctl_table(ctl_cpu, 0);
++}
++
++static inline void cpufreq_sysctl_exit(void)
++{
++	unregister_sysctl_table(cpufreq_sysctl_table);
++}
++
++#else
++#define cpufreq_sysctl_init() do {} while(0)
++#define cpufreq_sysctl_exit() do {} while(0)
++#endif /* CONFIG_CPU_FREQ_24API */
++
++
++/************************** sysfs interface ************************/
++static ssize_t show_speed (struct cpufreq_policy *policy, char *buf)
++{
++	return sprintf (buf, "%u\n", cpu_cur_freq[policy->cpu]);
++}
++
++static ssize_t 
++store_speed (struct cpufreq_policy *policy, const char *buf, size_t count) 
++{
++	unsigned int freq = 0;
++	unsigned int ret;
++
++	ret = sscanf (buf, "%u", &freq);
++	if (ret != 1)
++		return -EINVAL;
++
++	cpufreq_set(freq, policy->cpu);
++
++	return count;
++}
++
++static struct freq_attr freq_attr_scaling_setspeed = {
++	.attr = { .name = "scaling_setspeed", .mode = 0644 },
++	.show = show_speed,
++	.store = store_speed,
++};
++
++static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
++				   unsigned int event)
++{
++	unsigned int cpu = policy->cpu;
++	switch (event) {
++	case CPUFREQ_GOV_START:
++		if ((!cpu_online(cpu)) || (!try_module_get(THIS_MODULE)) ||
++		    !policy->cur)
++			return -EINVAL;
++		down(&userspace_sem);
++		cpu_is_managed[cpu] = 1;		
++		cpu_min_freq[cpu] = policy->min;
++		cpu_max_freq[cpu] = policy->max;
++		cpu_cur_freq[cpu] = policy->cur;
++		sysfs_create_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
++		memcpy (&current_policy[cpu], policy, sizeof(struct cpufreq_policy));
++		up(&userspace_sem);
++		break;
++	case CPUFREQ_GOV_STOP:
++		down(&userspace_sem);
++		cpu_is_managed[cpu] = 0;
++		cpu_min_freq[cpu] = 0;
++		cpu_max_freq[cpu] = 0;
++		sysfs_remove_file (&policy->kobj, &freq_attr_scaling_setspeed.attr);
++		up(&userspace_sem);
++		module_put(THIS_MODULE);
++		break;
++	case CPUFREQ_GOV_LIMITS:
++		down(&userspace_sem);
++		cpu_min_freq[cpu] = policy->min;
++		cpu_max_freq[cpu] = policy->max;
++		if (policy->max < cpu_cur_freq[cpu])
++			cpufreq_driver_target(&current_policy[cpu], policy->max, 
++			      CPUFREQ_RELATION_H);
++		else if (policy->min > cpu_cur_freq[cpu])
++			cpufreq_driver_target(&current_policy[cpu], policy->min, 
++			      CPUFREQ_RELATION_L);
++		memcpy (&current_policy[cpu], policy, sizeof(struct cpufreq_policy));
++		up(&userspace_sem);
++		break;
++	}
++	return 0;
++}
++
++/* on ARM SA1100 we need to rely on the values of cpufreq_get() - because 
++ * of this, cpu_cur_freq[] needs to be set early.
++ */
++#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_SA1100)
++extern unsigned int sa11x0_getspeed(void);
++
++static void cpufreq_sa11x0_compat(void)
++{
++	cpu_cur_freq[0] = sa11x0_getspeed();
++}
++#else
++#define cpufreq_sa11x0_compat() do {} while(0)
++#endif
++
++
++static struct cpufreq_governor cpufreq_gov_userspace = {
++	.name		= "userspace",
++	.governor	= cpufreq_governor_userspace,
++	.owner		= THIS_MODULE,
++};
++EXPORT_SYMBOL(cpufreq_gov_userspace);
++
++static int already_init = 0;
++
++int cpufreq_gov_userspace_init(void)
++{
++	if (!already_init) {
++		down(&userspace_sem);
++		cpufreq_sa11x0_compat();
++		cpufreq_sysctl_init();
++		cpufreq_register_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
++		already_init = 1;
++		up(&userspace_sem);
++	}
++	return cpufreq_register_governor(&cpufreq_gov_userspace);
++}
++EXPORT_SYMBOL(cpufreq_gov_userspace_init);
++
++
++static void __exit cpufreq_gov_userspace_exit(void)
++{
++	cpufreq_unregister_governor(&cpufreq_gov_userspace);
++        cpufreq_unregister_notifier(&userspace_cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
++	cpufreq_sysctl_exit();
++}
++
++
++MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>, Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION ("CPUfreq policy governor 'userspace'");
++MODULE_LICENSE ("GPL");
++
++module_init(cpufreq_gov_userspace_init);
++module_exit(cpufreq_gov_userspace_exit);
+--- linux-2.4.25/drivers/i2c/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -17,6 +17,15 @@
+          int  '    GPIO pin used for SCL' CONFIG_SCx200_I2C_SCL 12
+          int  '    GPIO pin used for SDA' CONFIG_SCx200_I2C_SDA 13
+       fi
++
++      dep_tristate '  Guide GPIO adapter' CONFIG_I2C_GUIDE $CONFIG_I2C_ALGOBIT
++      if [ "$CONFIG_ARCH_OMAHA" = "y" ]; then
++         dep_tristate '  Omaha I2C interface' CONFIG_I2C_OMAHA $CONFIG_I2C
++      fi
++      if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
++         dep_tristate '  Frodo I2C adapter' CONFIG_I2C_FRODO $CONFIG_I2C_ALGOBIT
++         dep_tristate '  SA1100 I2C GPIO adapter' CONFIG_I2C_BIT_SA1100_GPIO $CONFIG_I2C_ALGOBIT
++      fi
+    fi
+ 
+    dep_tristate 'NatSemi SCx200 ACCESS.bus' CONFIG_SCx200_ACB $CONFIG_I2C
+@@ -49,6 +58,10 @@
+       dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C
+    fi
+ 
++   if [ "$CONFIG_ARCH_AT91RM9200" = "y" ] ; then
++      dep_tristate 'Atmel AT91RM9200 I2C Two-Wire interface (TWI)' CONFIG_I2C_AT91 $CONFIG_I2C
++   fi
++
+    if [ "$CONFIG_SIBYTE_SB1xxx_SOC" = "y" ]; then
+       dep_tristate 'SiByte SMBus interface' CONFIG_I2C_ALGO_SIBYTE $CONFIG_I2C
+       dep_tristate '  MAX1617 Temperature Sensor' CONFIG_I2C_MAX1617 $CONFIG_I2C_ALGO_SIBYTE
+--- linux-2.4.25/drivers/i2c/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -8,12 +8,21 @@
+ 		   i2c-algo-ite.o i2c-algo-sibyte.o i2c-algo-sgi.o \
+ 		   i2c-proc.o
+ 
++# Init order: core, chardev, bit adapters, pcf adapters
++
+ obj-$(CONFIG_I2C)		+= i2c-core.o
+ obj-$(CONFIG_I2C_CHARDEV)	+= i2c-dev.o
++
++# Bit adapters
+ obj-$(CONFIG_I2C_ALGOBIT)	+= i2c-algo-bit.o
+ obj-$(CONFIG_I2C_PHILIPSPAR)	+= i2c-philips-par.o
+ obj-$(CONFIG_I2C_ELV)		+= i2c-elv.o
+ obj-$(CONFIG_I2C_VELLEMAN)	+= i2c-velleman.o
++obj-$(CONFIG_I2C_GUIDE)		+= i2c-guide.o
++obj-$(CONFIG_I2C_FRODO)		+= i2c-frodo.o
++obj-$(CONFIG_I2C_OMAHA)		+= i2c-omaha.o
++
++# PCF adapters
+ obj-$(CONFIG_I2C_ALGOPCF)	+= i2c-algo-pcf.o
+ obj-$(CONFIG_I2C_ELEKTOR)	+= i2c-elektor.o
+ obj-$(CONFIG_ITE_I2C_ALGO)	+= i2c-algo-ite.o
+@@ -30,4 +39,3 @@
+ # This is needed for automatic patch generation: sensors code ends here
+ 
+ include $(TOPDIR)/Rules.make
+-
+--- linux-2.4.25/drivers/i2c/i2c-algo-bit.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-algo-bit.c	2004-03-31 17:15:09.000000000 +0200
+@@ -169,7 +169,14 @@
+  * 1 if the device acknowledged
+  * 0 if the device did not ack
+  * -ETIMEDOUT if an error occurred (while raising the scl line)
+- */
++
++ * tsong@iders.ca: an instruction to disable any timeconsuming interrupt
++   here except the heart beat of timer2 should be added before setsda(adap, sb).
++   because when interrupt occurs during
++   scl is set high, the interrupt service routine is served and may take long,
++   after the interrupt returns, sda could be sampled by the device(slave)
++   more than once, and this cause error problem.
++*/
+ static int i2c_outb(struct i2c_adapter *i2c_adap, char c)
+ {
+ 	int i;
+@@ -582,9 +589,7 @@
+ 		printk("\n");
+ 	}
+ 
+-#ifdef MODULE
+ 	MOD_INC_USE_COUNT;
+-#endif
+ 	i2c_add_adapter(adap);
+ 
+ 	return 0;
+@@ -600,15 +605,13 @@
+ 
+ 	DEB2(printk("i2c-algo-bit.o: adapter unregistered: %s\n",adap->name));
+ 
+-#ifdef MODULE
+ 	MOD_DEC_USE_COUNT;
+-#endif
+ 	return 0;
+ }
+ 
+-int __init i2c_algo_bit_init (void)
++static int __init i2c_algo_bit_init (void)
+ {
+-	printk(KERN_INFO "i2c-algo-bit.o: i2c bit algorithm module\n");
++	printk(KERN_DEBUG "i2c-algo-bit.o: i2c bit algorithm module\n");
+ 	return 0;
+ }
+ 
+@@ -617,7 +620,6 @@
+ EXPORT_SYMBOL(i2c_bit_add_bus);
+ EXPORT_SYMBOL(i2c_bit_del_bus);
+ 
+-#ifdef MODULE
+ MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+ MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm");
+ MODULE_LICENSE("GPL");
+@@ -631,12 +633,4 @@
+ MODULE_PARM_DESC(i2c_debug,
+             "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol");
+ 
+-int init_module(void) 
+-{
+-	return i2c_algo_bit_init();
+-}
+-
+-void cleanup_module(void) 
+-{
+-}
+-#endif
++module_init(i2c_algo_bit_init);
+--- linux-2.4.25/drivers/i2c/i2c-algo-pcf.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-algo-pcf.c	2004-03-31 17:15:09.000000000 +0200
+@@ -475,9 +475,7 @@
+ 		return i;
+ 	}
+ 
+-#ifdef MODULE
+ 	MOD_INC_USE_COUNT;
+-#endif
+ 
+ 	i2c_add_adapter(adap);
+ 
+@@ -515,13 +513,11 @@
+ 		return res;
+ 	DEB2(printk("i2c-algo-pcf.o: adapter unregistered: %s\n",adap->name));
+ 
+-#ifdef MODULE
+ 	MOD_DEC_USE_COUNT;
+-#endif
+ 	return 0;
+ }
+ 
+-int __init i2c_algo_pcf_init (void)
++static int __init i2c_algo_pcf_init (void)
+ {
+ 	printk("i2c-algo-pcf.o: i2c pcf8584 algorithm module\n");
+ 	return 0;
+@@ -531,7 +527,6 @@
+ EXPORT_SYMBOL(i2c_pcf_add_bus);
+ EXPORT_SYMBOL(i2c_pcf_del_bus);
+ 
+-#ifdef MODULE
+ MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+ MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm");
+ MODULE_LICENSE("GPL");
+@@ -543,13 +538,4 @@
+ MODULE_PARM_DESC(i2c_debug,
+         "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol");
+ 
+-
+-int init_module(void) 
+-{
+-	return i2c_algo_pcf_init();
+-}
+-
+-void cleanup_module(void) 
+-{
+-}
+-#endif
++module_init(i2c_algo_pcf_init);
+--- linux-2.4.25/drivers/i2c/i2c-core.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-core.c	2004-03-31 17:15:09.000000000 +0200
+@@ -41,7 +41,7 @@
+ 
+ /* exclusive access to the bus */
+ #define I2C_LOCK(adap) down(&adap->lock)
+-#define I2C_UNLOCK(adap) up(&adap->lock) 
++#define I2C_UNLOCK(adap) up(&adap->lock)
+ 
+ #define ADAP_LOCK()	down(&adap_lock)
+ #define ADAP_UNLOCK()	up(&adap_lock)
+@@ -67,7 +67,7 @@
+ static int driver_count;
+ 
+ /**** debug level */
+-static int i2c_debug=1;
++static int i2c_debug = 0;
+ 
+ /* ---------------------------------------------------
+  * /proc entry declarations
+@@ -77,14 +77,14 @@
+ #ifdef CONFIG_PROC_FS
+ 
+ static int i2cproc_init(void);
+-static int i2cproc_cleanup(void);
++static void i2cproc_cleanup(void);
+ 
+-static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
++static ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
+                                 loff_t *ppos);
+ static int read_bus_i2c(char *buf, char **start, off_t offset, int len,
+                            int *eof , void *private);
+ 
+-/* To implement the dynamic /proc/bus/i2c-? files, we need our own 
++/* To implement the dynamic /proc/bus/i2c-? files, we need our own
+    implementation of the read hook */
+ static struct file_operations i2cproc_operations = {
+ 	read:		i2cproc_bus_read,
+@@ -101,8 +101,8 @@
+ 
+ 
+ /* ---------------------------------------------------
+- * registering functions 
+- * --------------------------------------------------- 
++ * registering functions
++ * ---------------------------------------------------
+  */
+ 
+ /* -----
+@@ -119,7 +119,7 @@
+ 		if (NULL == adapters[i])
+ 			break;
+ 	if (I2C_ADAP_MAX == i) {
+-		printk(KERN_WARNING 
++		printk(KERN_WARNING
+ 		       " i2c-core.o: register_adapter(%s) - enlarge I2C_ADAP_MAX.\n",
+ 			adap->name);
+ 		res = -ENOMEM;
+@@ -129,7 +129,7 @@
+ 	adapters[i] = adap;
+ 	adap_count++;
+ 	ADAP_UNLOCK();
+-	
++
+ 	/* init data types */
+ 	init_MUTEX(&adap->lock);
+ 
+@@ -157,18 +157,18 @@
+ #endif /* def CONFIG_PROC_FS */
+ 
+ 	/* inform drivers of new adapters */
+-	DRV_LOCK();	
++	DRV_LOCK();
+ 	for (j=0;j<I2C_DRIVER_MAX;j++)
+-		if (drivers[j]!=NULL && 
++		if (drivers[j]!=NULL &&
+ 		    (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY)))
+ 			/* We ignore the return code; if it fails, too bad */
+ 			drivers[j]->attach_adapter(adap);
+ 	DRV_UNLOCK();
+-	
++
+ 	DEB(printk(KERN_DEBUG "i2c-core.o: adapter %s registered as adapter %d.\n",
+ 	           adap->name,i));
+ 
+-	return 0;	
++	return 0;
+ 
+ 
+ ERROR1:
+@@ -203,13 +203,13 @@
+ 	 * this or hell will break loose...
+ 	 */
+ 	DRV_LOCK();
+-	for (j = 0; j < I2C_DRIVER_MAX; j++) 
++	for (j = 0; j < I2C_DRIVER_MAX; j++)
+ 		if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))
+ 			if ((res = drivers[j]->attach_adapter(adap))) {
+ 				printk(KERN_WARNING "i2c-core.o: can't detach adapter %s "
+ 				       "while detaching driver %s: driver not "
+ 				       "detached!",adap->name,drivers[j]->name);
+-				goto ERROR1;	
++				goto ERROR1;
+ 			}
+ 	DRV_UNLOCK();
+ 
+@@ -241,8 +241,8 @@
+ 
+ 	adapters[i] = NULL;
+ 	adap_count--;
+-	
+-	ADAP_UNLOCK();	
++
++	ADAP_UNLOCK();
+ 	DEB(printk(KERN_DEBUG "i2c-core.o: adapter unregistered: %s\n",adap->name));
+ 	return 0;
+ 
+@@ -269,7 +269,7 @@
+ 		if (NULL == drivers[i])
+ 			break;
+ 	if (I2C_DRIVER_MAX == i) {
+-		printk(KERN_WARNING 
++		printk(KERN_WARNING
+ 		       " i2c-core.o: register_driver(%s) "
+ 		       "- enlarge I2C_DRIVER_MAX.\n",
+ 			driver->name);
+@@ -279,11 +279,11 @@
+ 
+ 	drivers[i] = driver;
+ 	driver_count++;
+-	
++
+ 	DRV_UNLOCK();	/* driver was successfully added */
+-	
++
+ 	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
+-	
++
+ 	ADAP_LOCK();
+ 
+ 	/* now look for instances of driver on our adapters
+@@ -314,11 +314,11 @@
+ 		return -ENODEV;
+ 	}
+ 	/* Have a look at each adapter, if clients of this driver are still
+-	 * attached. If so, detach them to be able to kill the driver 
++	 * attached. If so, detach them to be able to kill the driver
+ 	 * afterwards.
+ 	 */
+ 	DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n"));
+-	/* removing clients does not depend on the notify flag, else 
++	/* removing clients does not depend on the notify flag, else
+ 	 * invalid operation might (will!) result, when using stale client
+ 	 * pointers.
+ 	 */
+@@ -333,7 +333,7 @@
+ 		/* DUMMY drivers do not register their clients, so we have to
+ 		 * use a trick here: we call driver->attach_adapter to
+ 		 * *detach* it! Of course, each dummy driver should know about
+-		 * this or hell will break loose...  
++		 * this or hell will break loose...
+ 		 */
+ 			if ((res = driver->attach_adapter(adap))) {
+ 				printk(KERN_WARNING "i2c-core.o: while unregistering "
+@@ -345,9 +345,9 @@
+ 				return res;
+ 			}
+ 		} else {
+-			for (j=0;j<I2C_CLIENT_MAX;j++) { 
++			for (j=0;j<I2C_CLIENT_MAX;j++) {
+ 				struct i2c_client *client = adap->clients[j];
+-				if (client != NULL && 
++				if (client != NULL &&
+ 				    client->driver == driver) {
+ 					DEB2(printk(KERN_DEBUG "i2c-core.o: "
+ 						    "detaching client %s:\n",
+@@ -376,7 +376,7 @@
+ 	drivers[i] = NULL;
+ 	driver_count--;
+ 	DRV_UNLOCK();
+-	
++
+ 	DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));
+ 	return 0;
+ }
+@@ -384,7 +384,7 @@
+ int i2c_check_addr (struct i2c_adapter *adapter, int addr)
+ {
+ 	int i;
+-	for (i = 0; i < I2C_CLIENT_MAX ; i++) 
++	for (i = 0; i < I2C_CLIENT_MAX ; i++)
+ 		if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+ 			return -EBUSY;
+ 	return 0;
+@@ -402,7 +402,7 @@
+ 		if (NULL == adapter->clients[i])
+ 			break;
+ 	if (I2C_CLIENT_MAX == i) {
+-		printk(KERN_WARNING 
++		printk(KERN_WARNING
+ 		       " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
+ 			client->name);
+ 		return -ENOMEM;
+@@ -410,9 +410,9 @@
+ 
+ 	adapter->clients[i] = client;
+ 	adapter->client_count++;
+-	
+-	if (adapter->client_register) 
+-		if (adapter->client_register(client)) 
++
++	if (adapter->client_register)
++		if (adapter->client_register(client))
+ 			printk(KERN_DEBUG "i2c-core.o: warning: client_register seems "
+ 			       "to have failed for client %02x at adapter %s\n",
+ 			       client->addr,adapter->name);
+@@ -421,7 +421,7 @@
+ 
+ 	if(client->flags & I2C_CLIENT_ALLOW_USE)
+ 		client->usage_count = 0;
+-	
++
+ 	return 0;
+ }
+ 
+@@ -440,12 +440,12 @@
+ 			client->name);
+ 		return -ENODEV;
+ 	}
+-	
+-	if( (client->flags & I2C_CLIENT_ALLOW_USE) && 
++
++	if( (client->flags & I2C_CLIENT_ALLOW_USE) &&
+ 	    (client->usage_count>0))
+ 		return -EBUSY;
+-	
+-	if (adapter->client_unregister != NULL) 
++
++	if (adapter->client_unregister != NULL)
+ 		if ((res = adapter->client_unregister(client))) {
+ 			printk(KERN_ERR "i2c-core.o: client_unregister [%s] failed, "
+ 			       "client not detached",client->name);
+@@ -471,7 +471,7 @@
+ 
+ void i2c_dec_use_client(struct i2c_client *client)
+ {
+-	
++
+ 	if (client->driver->dec_use != NULL)
+ 		client->driver->dec_use(client);
+ 
+@@ -479,65 +479,65 @@
+ 		client->adapter->dec_use(client->adapter);
+ }
+ 
+-struct i2c_client *i2c_get_client(int driver_id, int adapter_id, 
++struct i2c_client *i2c_get_client(int driver_id, int adapter_id,
+ 					struct i2c_client *prev)
+ {
+ 	int i,j;
+-	
++
+ 	/* Will iterate through the list of clients in each adapter of adapters-list
+-	   in search for a client that matches the search criteria. driver_id or 
+-	   adapter_id are ignored if set to 0. If both are ignored this returns 
++	   in search for a client that matches the search criteria. driver_id or
++	   adapter_id are ignored if set to 0. If both are ignored this returns
+ 	   first client found. */
+-	
+-	i = j = 0;  
+-	
+-	/* set starting point */ 
++
++	i = j = 0;
++
++	/* set starting point */
+ 	if(prev)
+ 	{
+ 		if(!(prev->adapter))
+ 			return (struct i2c_client *) -EINVAL;
+-		
++
+ 		for(j=0; j < I2C_ADAP_MAX; j++)
+ 			if(prev->adapter == adapters[j])
+ 				break;
+-		
++
+ 		/* invalid starting point? */
+ 		if (I2C_ADAP_MAX == j) {
+ 			printk(KERN_WARNING " i2c-core.o: get_client adapter for client:[%s] not found\n",
+ 				prev->name);
+ 			return (struct i2c_client *) -ENODEV;
+-		}	
+-		
++		}
++
+ 		for(i=0; i < I2C_CLIENT_MAX; i++)
+ 			if(prev == adapters[j]->clients[i])
+ 				break;
+-		
++
+ 		/* invalid starting point? */
+ 		if (I2C_CLIENT_MAX == i) {
+ 			printk(KERN_WARNING " i2c-core.o: get_client client:[%s] not found\n",
+ 				prev->name);
+ 			return (struct i2c_client *) -ENODEV;
+-		}	
+-		
++		}
++
+ 		i++; /* start from one after prev */
+ 	}
+-	
++
+ 	for(; j < I2C_ADAP_MAX; j++)
+ 	{
+ 		if(!adapters[j])
+ 			continue;
+-			
++
+ 		if(adapter_id && (adapters[j]->id != adapter_id))
+ 			continue;
+-		
++
+ 		for(; i < I2C_CLIENT_MAX; i++)
+ 		{
+ 			if(!adapters[j]->clients[i])
+ 				continue;
+-				
++
+ 			if(driver_id && (adapters[j]->clients[i]->driver->id != driver_id))
+ 				continue;
+-			if(adapters[j]->clients[i]->flags & I2C_CLIENT_ALLOW_USE)	
++			if(adapters[j]->clients[i]->flags & I2C_CLIENT_ALLOW_USE)
+ 				return adapters[j]->clients[i];
+ 		}
+ 		i = 0;
+@@ -549,12 +549,12 @@
+ int i2c_use_client(struct i2c_client *client)
+ {
+ 	if(client->flags & I2C_CLIENT_ALLOW_USE) {
+-		if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE) 
++		if (client->flags & I2C_CLIENT_ALLOW_MULTIPLE_USE)
+ 			client->usage_count++;
+ 		else {
+-			if(client->usage_count > 0) 
++			if(client->usage_count > 0)
+ 				return -EBUSY;
+-			 else 
++			 else
+ 				client->usage_count++;
+ 		}
+ 	}
+@@ -575,9 +575,9 @@
+ 			return -EPERM;
+ 		}
+ 	}
+-	
++
+ 	i2c_dec_use_client(client);
+-	
++
+ 	return 0;
+ }
+ 
+@@ -589,7 +589,7 @@
+ #ifdef CONFIG_PROC_FS
+ 
+ /* This function generates the output for /proc/bus/i2c */
+-int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof, 
++int read_bus_i2c(char *buf, char **start, off_t offset, int len, int *eof,
+                  void *private)
+ {
+ 	int i;
+@@ -615,7 +615,7 @@
+ }
+ 
+ /* This function generates the output for /proc/bus/i2c-? */
+-ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count, 
++ssize_t i2cproc_bus_read(struct file * file, char * buf,size_t count,
+                          loff_t *ppos)
+ {
+ 	struct inode * inode = file->f_dentry->d_inode;
+@@ -626,7 +626,7 @@
+ 	int order[I2C_CLIENT_MAX];
+ 
+ 	if (count > 4000)
+-		return -EINVAL; 
++		return -EINVAL;
+ 	len_total = file->f_pos + count;
+ 	/* Too bad if this gets longer (unlikely) */
+ 	if (len_total > 4000)
+@@ -641,12 +641,12 @@
+ 			   sorted by address */
+ 			order_nr=0;
+ 			for (j = 0; j < I2C_CLIENT_MAX; j++) {
+-				if ((client = adapters[i]->clients[j]) && 
++				if ((client = adapters[i]->clients[j]) &&
+ 				    (client->driver->id != I2C_DRIVERID_I2CDEV))  {
+-					for(k = order_nr; 
+-					    (k > 0) && 
++					for(k = order_nr;
++					    (k > 0) &&
+ 					    adapters[i]->clients[order[k-1]]->
+-					             addr > client->addr; 
++					             addr > client->addr;
+ 					    k--)
+ 						order[k] = order[k-1];
+ 					order[k] = j;
+@@ -665,7 +665,7 @@
+ 			len = len - file->f_pos;
+ 			if (len > count)
+ 				len = count;
+-			if (len < 0) 
++			if (len < 0)
+ 				len = 0;
+ 			if (copy_to_user (buf,kbuf+file->f_pos, len)) {
+ 				kfree(kbuf);
+@@ -689,7 +689,7 @@
+ 		printk("i2c-core.o: /proc/bus/ does not exist");
+ 		i2cproc_cleanup();
+ 		return -ENOENT;
+- 	} 
++ 	}
+ 	proc_bus_i2c = create_proc_entry("i2c",0,proc_bus);
+ 	if (!proc_bus_i2c) {
+ 		printk(KERN_ERR "i2c-core.o: Could not create /proc/bus/i2c");
+@@ -702,14 +702,13 @@
+ 	return 0;
+ }
+ 
+-int i2cproc_cleanup(void)
++static void i2cproc_cleanup(void)
+ {
+ 
+ 	if (i2cproc_initialized >= 1) {
+ 		remove_proc_entry("i2c",proc_bus);
+ 		i2cproc_initialized -= 2;
+ 	}
+-	return 0;
+ }
+ 
+ 
+@@ -751,10 +750,10 @@
+ 		msg.flags = client->flags & I2C_M_TEN;
+ 		msg.len = count;
+ 		(const char *)msg.buf = buf;
+-	
++
+ 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_send: writing %d bytes on %s.\n",
+ 			count,client->adapter->name));
+-	
++
+ 		I2C_LOCK(adap);
+ 		ret = adap->algo->master_xfer(adap,&msg,1);
+ 		I2C_UNLOCK(adap);
+@@ -784,14 +783,14 @@
+ 
+ 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: reading %d bytes on %s.\n",
+ 			count,client->adapter->name));
+-	
++
+ 		I2C_LOCK(adap);
+ 		ret = adap->algo->master_xfer(adap,&msg,1);
+ 		I2C_UNLOCK(adap);
+-	
++
+ 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
+ 			ret, count, client->addr));
+-	
++
+ 		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
+ 	 	* transmitted, else error code.
+ 	 	*/
+@@ -852,7 +851,7 @@
+ 		found = 0;
+ 
+ 		for (i = 0; !found && (address_data->force[i] != I2C_CLIENT_END); i += 3) {
+-			if (((adap_id == address_data->force[i]) || 
++			if (((adap_id == address_data->force[i]) ||
+ 			     (address_data->force[i] == ANY_I2C_BUS)) &&
+ 			     (addr == address_data->force[i+1])) {
+ 				DEB2(printk(KERN_DEBUG "i2c-core.o: found force parameter for adapter %d, addr %04x\n",
+@@ -862,7 +861,7 @@
+ 				found = 1;
+ 			}
+ 		}
+-		if (found) 
++		if (found)
+ 			continue;
+ 
+ 		/* If this address is in one of the ignores, we can forget about
+@@ -870,7 +869,7 @@
+ 		for (i = 0;
+ 		     !found && (address_data->ignore[i] != I2C_CLIENT_END);
+ 		     i += 2) {
+-			if (((adap_id == address_data->ignore[i]) || 
++			if (((adap_id == address_data->ignore[i]) ||
+ 			    ((address_data->ignore[i] == ANY_I2C_BUS))) &&
+ 			    (addr == address_data->ignore[i+1])) {
+ 				DEB2(printk(KERN_DEBUG "i2c-core.o: found ignore parameter for adapter %d, "
+@@ -890,11 +889,11 @@
+ 				found = 1;
+ 			}
+ 		}
+-		if (found) 
++		if (found)
+ 			continue;
+ 
+-		/* Now, we will do a detection, but only if it is in the normal or 
+-		   probe entries */  
++		/* Now, we will do a detection, but only if it is in the normal or
++		   probe entries */
+ 		for (i = 0;
+ 		     !found && (address_data->normal_i2c[i] != I2C_CLIENT_END);
+ 		     i += 1) {
+@@ -939,7 +938,7 @@
+ 				            "addr %04x\n", adap_id,addr));
+ 			}
+ 		}
+-		if (!found) 
++		if (!found)
+ 			continue;
+ 
+ 		/* OK, so we really should examine this address. First check
+@@ -1087,11 +1086,11 @@
+ 	                      I2C_SMBUS_I2C_BLOCK_DATA,&data);
+ }
+ 
+-/* Simulate a SMBus command using the i2c protocol 
++/* Simulate a SMBus command using the i2c protocol
+    No checking of parameters is done!  */
+-static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, 
++static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
+                                    unsigned short flags,
+-                                   char read_write, u8 command, int size, 
++                                   char read_write, u8 command, int size,
+                                    union i2c_smbus_data * data)
+ {
+ 	/* So we need to generate a series of msgs. In the case of writing, we
+@@ -1101,7 +1100,7 @@
+ 	unsigned char msgbuf0[34];
+ 	unsigned char msgbuf1[34];
+ 	int num = read_write == I2C_SMBUS_READ?2:1;
+-	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 }, 
++	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
+ 	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }
+ 	                        };
+ 	int i;
+@@ -1179,7 +1178,7 @@
+ 			case I2C_SMBUS_BYTE_DATA:
+ 				data->byte = msgbuf1[0];
+ 				break;
+-			case I2C_SMBUS_WORD_DATA: 
++			case I2C_SMBUS_WORD_DATA:
+ 			case I2C_SMBUS_PROC_CALL:
+ 				data->word = msgbuf1[0] | (msgbuf1[1] << 8);
+ 				break;
+@@ -1189,7 +1188,7 @@
+ 
+ 
+ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags,
+-                   char read_write, u8 command, int size, 
++                   char read_write, u8 command, int size,
+                    union i2c_smbus_data * data)
+ {
+ 	s32 res;
+@@ -1207,7 +1206,7 @@
+ 
+ 
+ /* You should always define `functionality'; the 'else' is just for
+-   backward compatibility. */ 
++   backward compatibility. */
+ u32 i2c_get_functionality (struct i2c_adapter *adap)
+ {
+ 	if (adap->algo->functionality)
+@@ -1233,122 +1232,12 @@
+ 
+ 	init_MUTEX(&adap_lock);
+ 	init_MUTEX(&driver_lock);
+-	
+-	i2cproc_init();
+-	
+-	return 0;
+-}
+-
+-#ifndef MODULE
+-#ifdef CONFIG_I2C_CHARDEV
+-	extern int i2c_dev_init(void);
+-#endif
+-#ifdef CONFIG_I2C_ALGOBIT
+-	extern int i2c_algo_bit_init(void);
+-#endif
+-#ifdef CONFIG_I2C_PHILIPSPAR
+-	extern int i2c_bitlp_init(void);
+-#endif
+-#ifdef CONFIG_I2C_ELV
+-	extern int i2c_bitelv_init(void);
+-#endif
+-#ifdef CONFIG_I2C_VELLEMAN
+-	extern int i2c_bitvelle_init(void);
+-#endif
+-#ifdef CONFIG_I2C_BITVIA
+-	extern int i2c_bitvia_init(void);
+-#endif
+ 
+-#ifdef CONFIG_I2C_ALGOPCF
+-	extern int i2c_algo_pcf_init(void);	
+-#endif
+-#ifdef CONFIG_I2C_ELEKTOR
+-	extern int i2c_pcfisa_init(void);
+-#endif
+-
+-#ifdef CONFIG_I2C_ALGO8XX
+-	extern int i2c_algo_8xx_init(void);
+-#endif
+-#ifdef CONFIG_I2C_RPXLITE
+-	extern int i2c_rpx_init(void);
+-#endif
+-
+-#ifdef CONFIG_I2C_ALGO_SIBYTE
+-	extern int i2c_algo_sibyte_init(void);
+-	extern int i2c_sibyte_init(void);
+-#endif
+-#ifdef CONFIG_I2C_MAX1617
+-	extern int i2c_max1617_init(void);
+-#endif
+-
+-#ifdef CONFIG_I2C_PROC
+-	extern int sensors_init(void);
+-#endif
+-
+-/* This is needed for automatic patch generation: sensors code starts here */
+-/* This is needed for automatic patch generation: sensors code ends here   */
+-
+-int __init i2c_init_all(void)
+-{
+-	/* --------------------- global ----- */
+-	i2c_init();
+-
+-#ifdef CONFIG_I2C_CHARDEV
+-	i2c_dev_init();
+-#endif
+-	/* --------------------- bit -------- */
+-#ifdef CONFIG_I2C_ALGOBIT
+-	i2c_algo_bit_init();
+-#endif
+-#ifdef CONFIG_I2C_PHILIPSPAR
+-	i2c_bitlp_init();
+-#endif
+-#ifdef CONFIG_I2C_ELV
+-	i2c_bitelv_init();
+-#endif
+-#ifdef CONFIG_I2C_VELLEMAN
+-	i2c_bitvelle_init();
+-#endif
+-
+-	/* --------------------- pcf -------- */
+-#ifdef CONFIG_I2C_ALGOPCF
+-	i2c_algo_pcf_init();	
+-#endif
+-#ifdef CONFIG_I2C_ELEKTOR
+-	i2c_pcfisa_init();
+-#endif
+-
+-	/* --------------------- 8xx -------- */
+-#ifdef CONFIG_I2C_ALGO8XX
+-	i2c_algo_8xx_init();
+-#endif
+-#ifdef CONFIG_I2C_RPXLITE
+-	i2c_rpx_init();
+-#endif
+-
+-	/* --------------------- SiByte -------- */
+-#ifdef CONFIG_I2C_ALGO_SIBYTE
+-	i2c_algo_sibyte_init();
+-	i2c_sibyte_init();
+-#endif
+-#ifdef CONFIG_I2C_MAX1617
+-	i2c_max1617_init();
+-#endif
+-
+-	/* -------------- proc interface ---- */
+-#ifdef CONFIG_I2C_PROC
+-	sensors_init();
+-#endif
+-/* This is needed for automatic patch generation: sensors code starts here */
+-/* This is needed for automatic patch generation: sensors code ends here */
++	i2cproc_init();
+ 
+ 	return 0;
+ }
+ 
+-#endif
+-
+-
+-
+ EXPORT_SYMBOL(i2c_add_adapter);
+ EXPORT_SYMBOL(i2c_del_adapter);
+ EXPORT_SYMBOL(i2c_add_driver);
+@@ -1385,7 +1274,6 @@
+ EXPORT_SYMBOL(i2c_get_functionality);
+ EXPORT_SYMBOL(i2c_check_functionality);
+ 
+-#ifdef MODULE
+ MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+ MODULE_DESCRIPTION("I2C-Bus main module");
+ MODULE_LICENSE("GPL");
+@@ -1393,13 +1281,5 @@
+ MODULE_PARM(i2c_debug, "i");
+ MODULE_PARM_DESC(i2c_debug,"debug level");
+ 
+-int init_module(void) 
+-{
+-	return i2c_init();
+-}
+-
+-void cleanup_module(void) 
+-{
+-	i2cproc_cleanup();
+-}
+-#endif
++module_init(i2c_init);
++module_exit(i2cproc_cleanup);
+--- linux-2.4.25/drivers/i2c/i2c-dev.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-dev.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*
+-    i2c-dev.c - i2c-bus driver, char device interface  
++    i2c-dev.c - i2c-bus driver, char device interface
+ 
+     Copyright (C) 1995-97 Simon G. Vogl
+     Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+@@ -25,7 +25,7 @@
+ 
+ /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */
+ 
+-/* The devfs code is contributed by Philipp Matthias Hahn 
++/* The devfs code is contributed by Philipp Matthias Hahn
+    <pmhahn@titan.lahn.de> */
+ 
+ /* $Id$ */
+@@ -50,19 +50,14 @@
+ #include <linux/i2c.h>
+ #include <linux/i2c-dev.h>
+ 
+-#ifdef MODULE
+-extern int init_module(void);
+-extern int cleanup_module(void);
+-#endif /* def MODULE */
+-
+ /* struct file_operations changed too often in the 2.1 series for nice code */
+ 
+-static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, 
++static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
+                             loff_t *offset);
+-static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, 
++static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count,
+                              loff_t *offset);
+ 
+-static int i2cdev_ioctl (struct inode *inode, struct file *file, 
++static int i2cdev_ioctl (struct inode *inode, struct file *file,
+                          unsigned int cmd, unsigned long arg);
+ static int i2cdev_open (struct inode *inode, struct file *file);
+ 
+@@ -73,13 +68,8 @@
+ static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
+                            void *arg);
+ 
+-#ifdef MODULE
+-static
+-#else
+-extern
+-#endif
+-       int __init i2c_dev_init(void);
+-static int i2cdev_cleanup(void);
++static int __init i2c_dev_init(void);
++static void i2cdev_cleanup(void);
+ 
+ static struct file_operations i2cdev_fops = {
+ 	owner:		THIS_MODULE,
+@@ -185,7 +175,7 @@
+ 	return ret;
+ }
+ 
+-int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd, 
++int i2cdev_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
+                   unsigned long arg)
+ {
+ 	struct i2c_client *client = (struct i2c_client *)file->private_data;
+@@ -198,14 +188,14 @@
+ 	unsigned long funcs;
+ 
+ #ifdef DEBUG
+-	printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n", 
++	printk(KERN_DEBUG "i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
+ 	       MINOR(inode->i_rdev),cmd, arg);
+ #endif /* DEBUG */
+ 
+ 	switch ( cmd ) {
+ 	case I2C_SLAVE:
+ 	case I2C_SLAVE_FORCE:
+-		if ((arg > 0x3ff) || 
++		if ((arg > 0x3ff) ||
+ 		    (((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
+ 			return -EINVAL;
+ 		if ((cmd == I2C_SLAVE) && i2c_check_addr(client->adapter,arg))
+@@ -224,8 +214,8 @@
+ 		                     sizeof(unsigned long)))?-EFAULT:0;
+ 
+ 	case I2C_RDWR:
+-		if (copy_from_user(&rdwr_arg, 
+-				   (struct i2c_rdwr_ioctl_data *)arg, 
++		if (copy_from_user(&rdwr_arg,
++				   (struct i2c_rdwr_ioctl_data *)arg,
+ 				   sizeof(rdwr_arg)))
+ 			return -EFAULT;
+ 
+@@ -233,9 +223,9 @@
+ 		 * be sent at once */
+ 		if (rdwr_arg.nmsgs > 42)
+ 			return -EINVAL;
+-		
++
+ 		rdwr_pa = (struct i2c_msg *)
+-			kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), 
++			kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
+ 			GFP_KERNEL);
+ 
+ 		if (rdwr_pa == NULL) return -ENOMEM;
+@@ -312,9 +302,9 @@
+ 		                   (struct i2c_smbus_ioctl_data *) arg,
+ 		                   sizeof(struct i2c_smbus_ioctl_data)))
+ 			return -EFAULT;
+-		if ((data_arg.size != I2C_SMBUS_BYTE) && 
++		if ((data_arg.size != I2C_SMBUS_BYTE) &&
+ 		    (data_arg.size != I2C_SMBUS_QUICK) &&
+-		    (data_arg.size != I2C_SMBUS_BYTE_DATA) && 
++		    (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
+ 		    (data_arg.size != I2C_SMBUS_WORD_DATA) &&
+ 		    (data_arg.size != I2C_SMBUS_PROC_CALL) &&
+ 		    (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
+@@ -325,9 +315,9 @@
+ #endif
+ 			return -EINVAL;
+ 		}
+-		/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, 
++		/* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
+ 		   so the check is valid if size==I2C_SMBUS_QUICK too. */
+-		if ((data_arg.read_write != I2C_SMBUS_READ) && 
++		if ((data_arg.read_write != I2C_SMBUS_READ) &&
+ 		    (data_arg.read_write != I2C_SMBUS_WRITE)) {
+ #ifdef DEBUG
+ 			printk(KERN_DEBUG "i2c-dev.o: read_write out of range (%x) in ioctl I2C_SMBUS.\n",
+@@ -339,7 +329,7 @@
+ 		/* Note that command values are always valid! */
+ 
+ 		if ((data_arg.size == I2C_SMBUS_QUICK) ||
+-		    ((data_arg.size == I2C_SMBUS_BYTE) && 
++		    ((data_arg.size == I2C_SMBUS_BYTE) &&
+ 		    (data_arg.read_write == I2C_SMBUS_WRITE)))
+ 			/* These are special: we do not use data */
+ 			return i2c_smbus_xfer(client->adapter, client->addr,
+@@ -358,13 +348,13 @@
+ 		if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
+ 		    (data_arg.size == I2C_SMBUS_BYTE))
+ 			datasize = sizeof(data_arg.data->byte);
+-		else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 
++		else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
+ 		         (data_arg.size == I2C_SMBUS_PROC_CALL))
+ 			datasize = sizeof(data_arg.data->word);
+ 		else /* size == I2C_SMBUS_BLOCK_DATA */
+ 			datasize = sizeof(data_arg.data->block);
+ 
+-		if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
++		if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ 		    (data_arg.read_write == I2C_SMBUS_WRITE)) {
+ 			if (copy_from_user(&temp, data_arg.data, datasize))
+ 				return -EFAULT;
+@@ -372,7 +362,7 @@
+ 		res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
+ 		      data_arg.read_write,
+ 		      data_arg.command,data_arg.size,&temp);
+-		if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 
++		if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
+ 			      (data_arg.read_write == I2C_SMBUS_READ))) {
+ 			if (copy_to_user(data_arg.data, &temp, datasize))
+ 				return -EFAULT;
+@@ -479,7 +469,7 @@
+ 	return -1;
+ }
+ 
+-int __init i2c_dev_init(void)
++static int __init i2c_dev_init(void)
+ {
+ 	int res;
+ 
+@@ -509,7 +499,7 @@
+ 	return 0;
+ }
+ 
+-int i2cdev_cleanup(void)
++static void i2cdev_cleanup(void)
+ {
+ 	int res;
+ 
+@@ -517,9 +507,9 @@
+ 		if ((res = i2c_del_driver(&i2cdev_driver))) {
+ 			printk("i2c-dev.o: Driver deregistration failed, "
+ 			       "module not removed.\n");
+-			return res;
++			return;
+ 		}
+-	i2cdev_initialized --;
++		i2cdev_initialized --;
+ 	}
+ 
+ 	if (i2cdev_initialized >= 1) {
+@@ -531,30 +521,17 @@
+ #endif
+ 			printk("i2c-dev.o: unable to release major %d for i2c bus\n",
+ 			       I2C_MAJOR);
+-			return res;
++			return;
+ 		}
+ 		i2cdev_initialized --;
+ 	}
+-	return 0;
+ }
+ 
+ EXPORT_NO_SYMBOLS;
+ 
+-#ifdef MODULE
+-
+ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+ MODULE_DESCRIPTION("I2C /dev entries driver");
+ MODULE_LICENSE("GPL");
+ 
+-int init_module(void)
+-{
+-	return i2c_dev_init();
+-}
+-
+-int cleanup_module(void)
+-{
+-	return i2cdev_cleanup();
+-}
+-
+-#endif /* def MODULE */
+-
++module_init(i2c_dev_init);
++module_exit(i2cdev_cleanup);
+--- linux-2.4.25/drivers/i2c/i2c-elektor.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-elektor.c	2004-03-31 17:15:09.000000000 +0200
+@@ -181,16 +181,12 @@
+ 
+ static void pcf_isa_inc_use(struct i2c_adapter *adap)
+ {
+-#ifdef MODULE
+ 	MOD_INC_USE_COUNT;
+-#endif
+ }
+ 
+ static void pcf_isa_dec_use(struct i2c_adapter *adap)
+ {
+-#ifdef MODULE
+ 	MOD_DEC_USE_COUNT;
+-#endif
+ }
+ 
+ 
+@@ -219,7 +215,7 @@
+ 	pcf_isa_unreg,
+ };
+ 
+-int __init i2c_pcfisa_init(void) 
++static int __init i2c_pcfisa_init(void) 
+ {
+ #ifdef __alpha__
+ 	/* check to see we have memory mapped PCF8584 connected to the 
+@@ -289,10 +285,14 @@
+ 	return 0;
+ }
+ 
++static void i2c_pcfisa_exit(void)
++{
++	i2c_pcf_del_bus(&pcf_isa_ops);
++	pcf_isa_exit();
++}
+ 
+ EXPORT_NO_SYMBOLS;
+ 
+-#ifdef MODULE
+ MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>");
+ MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter");
+ MODULE_LICENSE("GPL");
+@@ -304,15 +304,5 @@
+ MODULE_PARM(mmapped, "i");
+ MODULE_PARM(i2c_debug, "i");
+ 
+-int init_module(void) 
+-{
+-	return i2c_pcfisa_init();
+-}
+-
+-void cleanup_module(void) 
+-{
+-	i2c_pcf_del_bus(&pcf_isa_ops);
+-	pcf_isa_exit();
+-}
+-
+-#endif
++module_init(i2c_pcfisa_init);
++module_exit(i2c_pcfisa_exit);
+--- linux-2.4.25/drivers/i2c/i2c-elv.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-elv.c	2004-03-31 17:15:09.000000000 +0200
+@@ -75,7 +75,7 @@
+ 		PortData |=2;
+ 	}
+ 	outb(PortData, DATA);
+-} 
++}
+ 
+ static int bit_elv_getscl(void *data)
+ {
+@@ -90,7 +90,7 @@
+ static int bit_elv_init(void)
+ {
+ 	if (check_region(base,(base == 0x3bc)? 3 : 8) < 0 ) {
+-		return -ENODEV;	
++		return -ENODEV;
+ 	} else {
+ 						/* test for ELV adap. 	*/
+ 		if (inb(base+1) & 0x80) {	/* BUSY should be high	*/
+@@ -131,16 +131,12 @@
+ 
+ static void bit_elv_inc_use(struct i2c_adapter *adap)
+ {
+-#ifdef MODULE
+ 	MOD_INC_USE_COUNT;
+-#endif
+ }
+ 
+ static void bit_elv_dec_use(struct i2c_adapter *adap)
+ {
+-#ifdef MODULE
+ 	MOD_DEC_USE_COUNT;
+-#endif
+ }
+ 
+ /* ------------------------------------------------------------------------
+@@ -164,10 +160,10 @@
+ 	bit_elv_inc_use,
+ 	bit_elv_dec_use,
+ 	bit_elv_reg,
+-	bit_elv_unreg,	
++	bit_elv_unreg,
+ };
+ 
+-int __init i2c_bitelv_init(void)
++static int __init i2c_bitelv_init(void)
+ {
+ 	printk(KERN_INFO "i2c-elv.o: i2c ELV parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
+ 	if (base==0) {
+@@ -194,24 +190,19 @@
+ }
+ 
+ 
++static void __exit i2c_bitelv_exit(void)
++{
++	i2c_bit_del_bus(&bit_elv_ops);
++	bit_elv_exit();
++}
++
+ EXPORT_NO_SYMBOLS;
+ 
+-#ifdef MODULE
+ MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+ MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter");
+ MODULE_LICENSE("GPL");
+ 
+ MODULE_PARM(base, "i");
+ 
+-int init_module(void)
+-{
+-	return i2c_bitelv_init();
+-}
+-
+-void cleanup_module(void)
+-{
+-	i2c_bit_del_bus(&bit_elv_ops);
+-	bit_elv_exit();
+-}
+-
+-#endif
++module_init(i2c_bitelv_init);
++module_exit(i2c_bitelv_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/i2c/i2c-frodo.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,114 @@
++
++/*
++ * linux/drivers/i2c/i2c-frodo.c
++ *
++ * Author: Abraham van der Merwe <abraham@2d3d.co.za>
++ *
++ * An I2C adapter driver for the 2d3D, Inc. StrongARM SA-1110
++ * Development board (Frodo).
++ *
++ * This source code is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation.
++ */
++
++#include <linux/config.h>
++#include <linux/version.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <asm/hardware.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-algo-bit.h>
++
++static void frodo_setsda (void *data,int state)
++{
++	if (state)
++		frodo_cpld_set (FRODO_CPLD_I2C,FRODO_I2C_SDA_OUT);
++	else
++		frodo_cpld_clear (FRODO_CPLD_I2C,FRODO_I2C_SDA_OUT);
++}
++
++static void frodo_setscl (void *data,int state)
++{
++	if (state)
++		frodo_cpld_set (FRODO_CPLD_I2C,FRODO_I2C_SCL_OUT);
++	else
++		frodo_cpld_clear (FRODO_CPLD_I2C,FRODO_I2C_SCL_OUT);
++}
++
++static int frodo_getsda (void *data)
++{
++	return ((frodo_cpld_read (FRODO_CPLD_I2C) & FRODO_I2C_SDA_IN) != 0);
++}
++
++static int frodo_getscl (void *data)
++{
++	return ((frodo_cpld_read (FRODO_CPLD_I2C) & FRODO_I2C_SCL_IN) != 0);
++}
++
++static struct i2c_algo_bit_data bit_frodo_data = {
++	setsda:		frodo_setsda,
++	setscl:		frodo_setscl,
++	getsda:		frodo_getsda,
++	getscl:		frodo_getscl,
++	udelay:		80,
++	mdelay:		80,
++	timeout:	100
++};
++
++static int frodo_client_register (struct i2c_client *client)
++{
++	return (0);
++}
++
++static int frodo_client_unregister (struct i2c_client *client)
++{
++	return (0);
++}
++
++static void frodo_inc_use (struct i2c_adapter *adapter)
++{
++	MOD_INC_USE_COUNT;
++}
++
++static void frodo_dec_use (struct i2c_adapter *adapter)
++{
++	MOD_DEC_USE_COUNT;
++}
++
++static struct i2c_adapter frodo_ops = {
++	name:				"Frodo adapter driver",
++	id:					I2C_HW_B_FRODO,
++	algo:				NULL,
++	algo_data:			&bit_frodo_data,
++	inc_use:			frodo_inc_use,
++	dec_use:			frodo_dec_use,
++	client_register:	frodo_client_register,
++	client_unregister:	frodo_client_unregister
++};
++
++static int __init i2c_frodo_init (void)
++{
++	return (i2c_bit_add_bus (&frodo_ops));
++}
++
++EXPORT_NO_SYMBOLS;
++
++static void __exit i2c_frodo_exit (void)
++{
++	i2c_bit_del_bus (&frodo_ops);
++}
++
++MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>");
++MODULE_DESCRIPTION ("I2C-Bus adapter routines for Frodo");
++MODULE_LICENSE ("GPL");
++EXPORT_NO_SYMBOLS;
++
++module_init (i2c_frodo_init);
++module_exit (i2c_frodo_exit);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/i2c/i2c-guide.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,199 @@
++/************************************************************************************\
++Copyright	: Copyright (C) 1995-2000 Simon G. Vogl
++		  Copyright 2002 IDERs Incorporated
++File Name	: i2c-guide.c
++Description	: this i2c driver uses the GPIO port B pin 0 and pin 1 on the cs89712.
++Notes		: To change the bit rate, change the structure i2c_algo_bit_data
++                : to 10 10 100
++Contact		: tsong@iders.ca
++License		: This source code is free software; you can redistribute it and/or
++		  modify it under the terms of the GNU General Public License
++		  version 2 as published by the Free Software Foundation.
++\************************************************************************************/
++
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/string.h>  /* for 2.0 kernels to get NULL   */
++#include <asm/errno.h>     /* for 2.0 kernels to get ENODEV */
++#include <asm/io.h>
++
++#include <asm/hardware/cs89712.h>   // io operation ep_writel()
++#include <asm/hardware/clps7111.h>   // io operation clps_writel()
++#include <asm/arch-clps711x/hardware.h>   // io operation clps_writel()
++
++#include <linux/i2c.h>
++#include <linux/i2c-algo-bit.h>
++
++/* ----- global defines -----------------------------------------------	*/
++
++#define DEB(x)		/* should be reasonable open, close &c. 	*/
++#define DEB2(x) 	/* low level debugging - very slow 		*/
++#define DEBE(x)	x	/* error messages 				*/
++					/*  Pin Port  Inverted	name	*/
++#define I2C_SDA		0x08		/*  port B ctrl pin 3  	(inv)	*/
++#define I2C_SCL		0x04		/*  port B ctrl pin 2 	(inv)	*/
++
++#define I2C_SDAIN	0x08		/*  use the same pin with output	*/
++#define I2C_SCLIN	0x04		/*  use the same pin with output        */
++
++#define I2C_DMASK	0xf7            /* inverse of I2C_SDA  */
++#define I2C_CMASK	0xfb            /* inverse of I2c_SCL  */
++
++#define PORTB_PIN0_SDA_OUTPUT 0x08               /* pin 3 direction  of port B output */
++#define PORTB_PIN0_SDA_INPUT  0xf7               /* pin 3 direction of port B input  */
++
++#define PORTB_PIN1_SCL_OUTPUT 0x04               /* pin 2 direction of port B output  */
++#define PORTB_PIN1_SCL_INPUT  0xfb               /* pin 2 direction of port B input  */
++
++int base = 0;
++#define DEFAULT_BASE PBDR
++
++/* ----- local functions --------------------------------------------------- */
++
++static void bit_guide_setscl(void* data, int state)
++{
++	if (state) {
++		// set port B pin2 input
++		clps_writeb((clps_readb(PBDDR)) & PORTB_PIN1_SCL_INPUT, PBDDR);
++	}
++	else {
++		// clear
++		clps_writeb((clps_readb(PBDR)) & I2C_CMASK,  PBDR);
++		// set port B pin2 output
++		clps_writeb((clps_readb(PBDDR)) | PORTB_PIN1_SCL_OUTPUT, PBDDR);
++	}
++}
++
++static void bit_guide_setsda(void* data, int state)
++{
++	if (state) {
++		clps_writeb((clps_readb(PBDDR)) & PORTB_PIN0_SDA_INPUT, PBDDR);
++		// float pin 0 (actually  drive high by pull up resistor)
++		// clps_writeb((clps_readb(PBDR)) | I2C_SDA, PBDR);   // set Jan4 ori: eff
++		// printk("set sda high, state=%i\n",state);
++	}
++	else {
++		// clear
++		clps_writeb((clps_readb(PBDR)) & I2C_DMASK,  PBDR);
++		// set port B pin 0 output
++		clps_writeb((clps_readb(PBDDR)) | PORTB_PIN0_SDA_OUTPUT, PBDDR);
++	}
++}
++
++static int bit_guide_getscl(void *data)
++{
++	return ( 0 != ( (clps_readb(PBDR)) & I2C_SCLIN  ) );
++}
++
++static int bit_guide_getsda(void *data)
++{
++	// set port B pin 0 input Jan4 ori eff
++	clps_writeb((clps_readb(PBDDR)) & PORTB_PIN0_SDA_INPUT, PBDDR);
++	return ( 0 != ( (clps_readb(PBDR) ) & I2C_SDAIN ) );
++}
++
++static int bit_guide_init(void)
++{
++	bit_guide_setsda((void*)base,1);
++	bit_guide_setscl((void*)base,1);
++	return 0;
++}
++
++static int bit_guide_reg(struct i2c_client *client)
++{
++	return 0;
++}
++
++static int bit_guide_unreg(struct i2c_client *client)
++{
++	return 0;
++}
++
++static void bit_guide_inc_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++	MOD_INC_USE_COUNT;
++#endif
++}
++
++static void bit_guide_dec_use(struct i2c_adapter *adap)
++{
++#ifdef MODULE
++	MOD_DEC_USE_COUNT;
++#endif
++}
++
++/* ------------------------------------------------------------------------
++ * Encapsulate the above functions in the correct operations structure.
++ * This is only done when more than one hardware adapter is supported.
++ */
++
++/* last line (us, ms, timout)
++ * us dominates the bit rate: 10us  means: 100Kbit/sec(25 means 40kbps)
++ *                            10ms  not known
++ *                            100ms timeout
++ */
++static struct i2c_algo_bit_data bit_guide_data = {
++	NULL,
++	bit_guide_setsda,
++	bit_guide_setscl,
++	bit_guide_getsda,
++	bit_guide_getscl,
++	50, 10, 100,	/* orginal (non-guide) value 10, 10, 100  */
++};
++
++static struct i2c_adapter bit_guide_ops = {
++	"Guide Port B: PIN2-SCL/PIN3-SDA",
++	I2C_HW_B_GUIDE,
++	NULL,
++	&bit_guide_data,
++	bit_guide_inc_use,
++	bit_guide_dec_use,
++	bit_guide_reg,
++	bit_guide_unreg,
++};
++
++static int __init  i2c_bitguide_init(void)
++{
++	printk("i2c-guide.o: Guide i2c port B adapter module.\n");
++	clps_writeb((clps_readb(PBDDR)) & 0xfd, PBDDR);  //  set service reuest pb1 as input
++	if (base==0) {
++		/* probe some values */
++		base=DEFAULT_BASE;
++		bit_guide_data.data=(void*)DEFAULT_BASE;
++		if (bit_guide_init()==0) {
++			if(i2c_bit_add_bus(&bit_guide_ops) < 0)
++				return -ENODEV;
++		} else {
++			return -ENODEV;
++		}
++	} else {
++		bit_guide_data.data=(void*)base;
++		if (bit_guide_init()==0) {
++			if(i2c_bit_add_bus(&bit_guide_ops) < 0)
++				return -ENODEV;
++		} else {
++			return -ENODEV;
++		}
++	}
++	printk("i2c-guide.o: found device at %#x.\n",base);
++	return 0;
++}
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_AUTHOR("T. C. Song  <tsong@iders.ca>");
++MODULE_DESCRIPTION("I2C-Bus adapter routines for Guide (cs89712) GPIO port B");
++MODULE_LICENSE("GPL");
++
++MODULE_PARM(base, "i");
++
++module_init(i2c_bitguide_init);
++/* for completeness, we should have a module_exit() function, but the
++   GUIDE requires this to always be loaded.  If it is unloaded, the
++   operation of the GUIDE is undefined.
++   Nobody has written the i2c_bitguide_exit() routine yet, so it is not included.
++module_exit(i2c_bitguide_exit);
++*/
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/i2c/i2c-omaha.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,276 @@
++/* ------------------------------------------------------------------------- *
++    Copyright ARM Limited 2002. All rights reserved.
++ 
++    i2c driver for Omaha					     
++ 
++    Notes:Based on i2c-elv.c
++ 
++    The S3C2400X01 has better support for I2C, but bit oriented operations 
++    are directly supported by the other I2C layers, so we use that method
++    of performing I2C operations.
++
++    Copyright (C) 1995-2000 Simon G. Vogl
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
++/* ------------------------------------------------------------------------- */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <linux/ioport.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++
++#include <linux/i2c.h>
++#include <linux/i2c-algo-bit.h>
++
++#include <asm/io.h>
++#include <asm/hardware.h>
++
++/* ----- global defines ----------------------------------------------- */
++#define DEB(x) if (i2c_debug>=1) x;
++#define DEB2(x) if (i2c_debug>=2) x;
++#define DEB3(x) if (i2c_debug>=3) x
++#define DEBE(x)	x	// error messages
++#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/
++#define DEBPROTO(x) if (i2c_debug>=9) { x; }
++ 	/* debug the protocol by showing transferred bits */
++
++/* Register and bitdefs for Omaha */
++
++// Port G control registers
++static volatile unsigned int pgcon = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_PGCON);
++static volatile unsigned int pgdat = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_PGDAT);
++
++static volatile unsigned int opencr = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_OPENCR);
++
++static int base = IO_ADDRESS(PLAT_PERIPHERAL_BASE+OMAHA_PGCON);
++
++// Open drain control registers
++#define OPC_CMD		BIT2
++#define OPC_DAT		BIT3
++
++// data bits in GPIO Port G data register
++#define OMAHA_SDA	BIT5
++#define OMAHA_SCL	BIT6
++#define IIC_WP		BIT3	// Write Protect for EEPROM
++
++// input/out select bits in GPIO G control register
++#define IIC_BITS	(BIT12|BIT10|BIT6);
++
++
++/* ----- local functions ----------------------------------------------	*/
++
++
++static void bit_omaha_setscl(void *data, int state)
++{
++	unsigned int tmp;
++	
++	if (state)
++	{
++		tmp = __raw_readl(pgdat);
++		tmp |= OMAHA_SCL;
++		__raw_writel(tmp,pgdat);
++	}
++	else
++	{
++		tmp = __raw_readl(pgdat);
++		tmp &= ~OMAHA_SCL;
++		__raw_writel(tmp,pgdat);
++	}
++}
++
++static void bit_omaha_setsda(void *data, int state)
++{
++	unsigned int tmp;
++	
++	// ensure that sda is an output at the moment
++	tmp = __raw_readl(pgcon);
++	tmp = tmp | BIT10;
++	__raw_writel(tmp,pgcon);
++		
++	if (state)
++	{
++		tmp = __raw_readl(pgdat);
++		tmp |= OMAHA_SDA;
++		__raw_writel(tmp,pgdat);
++	}
++	else
++	{
++		tmp = __raw_readl(pgdat);
++		tmp &= ~OMAHA_SDA;
++		__raw_writel(tmp,pgdat);
++	}
++} 
++
++static int bit_omaha_getscl(void *data)
++{
++	if (__raw_readl(pgdat) & OMAHA_SCL)
++		return 1;
++	else
++		return 0;
++}
++
++static int bit_omaha_getsda(void *data)
++{
++	unsigned int tmp;
++	
++	// ensure that sda is an output at the moment
++	tmp = __raw_readl(pgcon);
++	tmp = tmp & ~BIT10;
++	__raw_writel(tmp,pgcon);
++	
++	if (__raw_readl(pgdat) & OMAHA_SDA)
++		return 1;
++	else
++		return 0;
++}
++
++static int bit_omaha_init(void)
++{
++	// Have we got some mmapped space?
++	if (request_region(base, 0x100, "i2c (omaha bus adapter)") < 0 )
++	{
++		printk("i2c-omaha.o: requested I/O region (0x%08x) is in use.\n", base);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++static int bit_omaha_reg(struct i2c_client *client)
++{
++	return 0;
++}
++
++
++static int bit_omaha_unreg(struct i2c_client *client)
++{
++	return 0;
++}
++
++static void bit_omaha_inc_use(struct i2c_adapter *adap)
++{
++	MOD_INC_USE_COUNT;
++}
++
++static void bit_omaha_dec_use(struct i2c_adapter *adap)
++{
++	MOD_DEC_USE_COUNT;
++}
++
++
++
++/* ------------------------------------------------------------------------
++ * Encapsulate the above functions in the correct operations structure.
++ * This is only done when more than one hardware adapter is supported.
++ */
++static struct i2c_algo_bit_data bit_omaha_data = {
++	NULL,
++	bit_omaha_setsda,
++	bit_omaha_setscl,
++	bit_omaha_getsda,
++	bit_omaha_getscl,
++	10, 10, 20,		/*	waits, timeout */
++};
++
++static struct i2c_adapter bit_omaha_ops = {
++	"BIT-Type Omaha I2C adapter",
++	I2C_HW_B_OMAHA,
++	NULL,
++	&bit_omaha_data,
++	bit_omaha_inc_use,
++	bit_omaha_dec_use,
++	bit_omaha_reg,
++	bit_omaha_unreg,
++};     
++
++static int __init i2c_omaha_init (void)
++{
++	unsigned int tmp;
++
++	printk("i2c-omaha.o: i2c omaha adapter module\n");
++	
++	if (bit_omaha_init() == 0) {
++		if(i2c_bit_add_bus(&bit_omaha_ops) < 0)
++		{
++			printk("Could not add bus!\n");
++			return -ENODEV;
++		}
++	} else {
++		printk("Could not pcf_omaha_init\n");
++		return -ENODEV;
++	}	
++	
++	// Program Port G bits to output function
++	tmp = __raw_readl(pgcon);
++	tmp |= IIC_BITS;	   	
++	__raw_writel(tmp,pgcon);
++	
++	// Ensure SDA and SCL are open-drain
++	tmp = __raw_readl(opencr);
++	tmp = tmp | OPC_CMD | OPC_DAT;
++	__raw_writel(tmp,opencr);
++
++	bit_omaha_setsda((void*)base,1);
++	bit_omaha_setscl((void*)base,1);
++
++	// Disable WP
++	tmp = __raw_readl(pgdat);
++	tmp = tmp & ~IIC_WP;
++	__raw_writel(tmp,pgdat);
++			       		
++	return 0;
++}
++
++static void bit_omaha_exit(void)
++{
++	release_region(base , 2);
++}
++
++static void i2c_omaha_exit(void)
++{
++
++	i2c_bit_del_bus(&bit_omaha_ops);
++
++	bit_omaha_exit();
++
++}
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_AUTHOR("ARM Limited <support@arm.com>");
++MODULE_DESCRIPTION("I2C-Bus adapter routines for Omaha");
++MODULE_LICENSE("GPL");
++			
++MODULE_PARM(base, "i");
++MODULE_PARM(irq, "i");
++MODULE_PARM(clock, "i");
++MODULE_PARM(own, "i");
++MODULE_PARM(mmapped, "i");
++MODULE_PARM(i2c_debug, "i");
++
++
++module_init(i2c_omaha_init);
++module_exit(i2c_omaha_exit);
++
++
+--- linux-2.4.25/drivers/i2c/i2c-philips-par.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-philips-par.c	2004-03-31 17:15:09.000000000 +0200
+@@ -16,7 +16,7 @@
+     You should have received a copy of the GNU General Public License
+     along with this program; if not, write to the Free Software
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
+-/* ------------------------------------------------------------------------- */ 
++/* ------------------------------------------------------------------------- */
+ 
+ /* With some changes from Ky�sti M�lkki <kmalkki@cc.hut.fi> and even
+    Frodo Looijaard <frodol@dds.nl> */
+@@ -72,7 +72,7 @@
+ 
+ static void bit_lp_setscl(void *data, int state)
+ {
+-	/*be cautious about state of the control register - 
++	/*be cautious about state of the control register -
+ 		touch only the one bit needed*/
+ 	if (state) {
+ 		parport_write_control((struct parport *) data,
+@@ -126,7 +126,7 @@
+ 
+ static int bit_lp_getsda2(void *data)
+ {
+-	return (parport_read_status((struct parport *) data) & 
++	return (parport_read_status((struct parport *) data) &
+ 			             PARPORT_STATUS_BUSY) ? 0 : 1;
+ }
+ 
+@@ -154,7 +154,7 @@
+  * Encapsulate the above functions in the correct operations structure.
+  * This is only done when more than one hardware adapter is supported.
+  */
+- 
++
+ static struct i2c_algo_bit_data bit_lp_data = {
+ 	NULL,
+ 	bit_lp_setsda,
+@@ -162,7 +162,7 @@
+ 	bit_lp_getsda,
+ 	bit_lp_getscl,
+ 	80, 80, 100,		/*	waits, timeout */
+-}; 
++};
+ 
+ static struct i2c_algo_bit_data bit_lp_data2 = {
+ 	NULL,
+@@ -171,7 +171,7 @@
+ 	bit_lp_getsda2,
+ 	NULL,
+ 	80, 80, 100,		/*	waits, timeout */
+-}; 
++};
+ 
+ static struct i2c_adapter bit_lp_ops = {
+ 	"Philips Parallel port adapter",
+@@ -197,7 +197,7 @@
+ 	printk(KERN_DEBUG "i2c-philips-par.o: attaching to %s\n", port->name);
+ 
+ 	adapter->pdev = parport_register_device(port, "i2c-philips-par",
+-						NULL, NULL, NULL, 
++						NULL, NULL, NULL,
+ 						PARPORT_FLAG_EXCL,
+ 						NULL);
+ 	if (!adapter->pdev) {
+@@ -257,16 +257,16 @@
+ 	NULL
+ };
+ 
+-int __init i2c_bitlp_init(void)
++static int __init i2c_bitlp_init(void)
+ {
+ 	printk(KERN_INFO "i2c-philips-par.o: i2c Philips parallel port adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
+ 
+ 	parport_register_driver(&i2c_driver);
+-	
++
+ 	return 0;
+ }
+ 
+-void __exit i2c_bitlp_exit(void)
++static void __exit i2c_bitlp_exit(void)
+ {
+ 	parport_unregister_driver(&i2c_driver);
+ }
+@@ -279,14 +279,5 @@
+ 
+ MODULE_PARM(type, "i");
+ 
+-#ifdef MODULE
+-int init_module(void)
+-{
+-	return i2c_bitlp_init();
+-}
+-
+-void cleanup_module(void)
+-{
+-	i2c_bitlp_exit();
+-}
+-#endif
++module_init(i2c_bitlp_init);
++module_exit(i2c_bitlp_exit);
+--- linux-2.4.25/drivers/i2c/i2c-velleman.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/i2c/i2c-velleman.c	2004-03-31 17:15:09.000000000 +0200
+@@ -65,7 +65,7 @@
+ 	} else {
+ 		outb(inb(CTRL) | I2C_SCL, CTRL);
+ 	}
+-	
++
+ }
+ 
+ static void bit_velle_setsda(void *data, int state)
+@@ -75,8 +75,8 @@
+ 	} else {
+ 		outb(inb(CTRL) | I2C_SDA, CTRL);
+ 	}
+-	
+-} 
++
++}
+ 
+ static int bit_velle_getscl(void *data)
+ {
+@@ -95,7 +95,7 @@
+ 		     base));
+ 		return -ENODEV;
+ 	} else {
+-		request_region(base, (base == 0x3bc)? 3 : 8, 
++		request_region(base, (base == 0x3bc)? 3 : 8,
+ 			"i2c (Vellemann adapter)");
+ 		bit_velle_setsda((void*)base,1);
+ 		bit_velle_setscl((void*)base,1);
+@@ -104,7 +104,7 @@
+ }
+ 
+ static void __exit bit_velle_exit(void)
+-{	
++{
+ 	release_region( base , (base == 0x3bc)? 3 : 8 );
+ }
+ 
+@@ -121,16 +121,12 @@
+ 
+ static void bit_velle_inc_use(struct i2c_adapter *adap)
+ {
+-#ifdef MODULE
+ 	MOD_INC_USE_COUNT;
+-#endif
+ }
+ 
+ static void bit_velle_dec_use(struct i2c_adapter *adap)
+ {
+-#ifdef MODULE
+ 	MOD_DEC_USE_COUNT;
+-#endif
+ }
+ 
+ /* ------------------------------------------------------------------------
+@@ -158,7 +154,7 @@
+ 	bit_velle_unreg,
+ };
+ 
+-int __init  i2c_bitvelle_init(void)
++static int __init i2c_bitvelle_init(void)
+ {
+ 	printk(KERN_INFO "i2c-velleman.o: i2c Velleman K8000 adapter module version %s (%s)\n", I2C_VERSION, I2C_DATE);
+ 	if (base==0) {
+@@ -184,24 +180,19 @@
+ 	return 0;
+ }
+ 
++static void __exit i2c_bitvelle_exit(void)
++{
++	i2c_bit_del_bus(&bit_velle_ops);
++	bit_velle_exit();
++}
++
+ EXPORT_NO_SYMBOLS;
+ 
+-#ifdef MODULE
+ MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+ MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter");
+ MODULE_LICENSE("GPL");
+ 
+ MODULE_PARM(base, "i");
+ 
+-int init_module(void) 
+-{
+-	return i2c_bitvelle_init();
+-}
+-
+-void cleanup_module(void) 
+-{
+-	i2c_bit_del_bus(&bit_velle_ops);
+-	bit_velle_exit();
+-}
+-
+-#endif
++module_init(i2c_bitvelle_init);
++module_exit(i2c_bitvelle_exit);
+--- linux-2.4.25/drivers/ide/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/ide/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -106,6 +106,9 @@
+ 	 define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_ICS
+ 	 dep_bool '    RapIDE interface support' CONFIG_BLK_DEV_IDE_RAPIDE $CONFIG_ARCH_ACORN
+       fi
++      if [ "$CONFIG_ARCH_RISCSTATION" = "y" ]; then
++         dep_bool '    RiscStation IDE' CONFIG_BLK_DEV_IDE_RISCSTATION $CONFIG_ARCH_RISCSTATION
++      fi
+       if [ "$CONFIG_AMIGA" = "y" ]; then
+ 	 dep_bool '  Amiga Gayle IDE interface support' CONFIG_BLK_DEV_GAYLE $CONFIG_AMIGA
+ 	 dep_mbool '    Amiga IDE Doubler support (EXPERIMENTAL)' CONFIG_BLK_DEV_IDEDOUBLER $CONFIG_BLK_DEV_GAYLE $CONFIG_EXPERIMENTAL
+--- linux-2.4.25/drivers/ide/arm/Makefile~2.4.25-vrs2.patch	2003-06-13 16:51:33.000000000 +0200
++++ linux-2.4.25/drivers/ide/arm/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -6,6 +6,7 @@
+ 
+ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+ obj-$(CONFIG_BLK_DEV_IDE_RAPIDE)	+= rapide.o
++obj-$(CONFIG_BLK_DEV_IDE_RISCSTATION)	+= rstation-ide.o
+ 
+ EXTRA_CFLAGS	:= -I../
+ 
+--- linux-2.4.25/drivers/ide/arm/icside.c~2.4.25-vrs2.patch	2003-06-13 16:51:33.000000000 +0200
++++ linux-2.4.25/drivers/ide/arm/icside.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1,7 +1,7 @@
+ /*
+  * linux/drivers/ide/arm/icside.c
+  *
+- * Copyright (c) 1996,1997 Russell King.
++ * Copyright (c) 1996-2003 Russell King.
+  *
+  * Changelog:
+  *  08-Jun-1996	RMK	Created
+@@ -26,24 +26,6 @@
+ #include <asm/ecard.h>
+ #include <asm/io.h>
+ 
+-#include "ide-noise.h"
+-
+-/*
+- * FIXME: We want to drop the the MACRO CRAP!
+- *
+- * ec->iops->in{b/w/l}
+- * ec->iops->in{b/w/l}_p
+- * ec->iops->out{b/w/l}
+- * ec->iops->out{b/w/l}_p
+- *
+- * the new core supports clean MMIO calls and other goodies
+- */
+-
+-/*
+- * Maximum number of interfaces per card
+- */
+-#define MAX_IFS	2
+-
+ #define ICS_IDENT_OFFSET		0x8a0
+ 
+ #define ICS_ARCIN_V5_INTRSTAT		0x000
+@@ -86,17 +68,20 @@
+ 	ICS_ARCIN_V6_IDESTEPPING
+ };
+ 
+-static const card_ids icside_cids[] = {
+-	{ MANU_ICS,  PROD_ICS_IDE  },
+-	{ MANU_ICS2, PROD_ICS2_IDE },
+-	{ 0xffff, 0xffff }
++struct icside_state {
++	unsigned int channel;
++	unsigned int enabled;
++	unsigned long irq_port;
++	unsigned long slot_port;
++	unsigned int type;
++	ide_hwif_t *hwif[2];
+ };
+ 
+-typedef enum {
+-	ics_if_unknown,
+-	ics_if_arcin_v5,
+-	ics_if_arcin_v6
+-} iftype_t;
++#define ICS_TYPE_A3IN	0
++#define ICS_TYPE_A3USER	1
++#define ICS_TYPE_V6	3
++#define ICS_TYPE_V5	15
++#define ICS_TYPE_NOTYPE	((unsigned int)-1)
+ 
+ /* ---------------- Version 5 PCB Support Functions --------------------- */
+ /* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+@@ -104,8 +89,10 @@
+  */
+ static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ {
+-	unsigned int memc_port = (unsigned int)ec->irq_data;
+-	outb(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
++	struct icside_state *state = ec->irq_data;
++	unsigned int base = state->irq_port;
++
++	outb(0, base + ICS_ARCIN_V5_INTROFFSET);
+ }
+ 
+ /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+@@ -113,17 +100,15 @@
+  */
+ static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
+ {
+-	unsigned int memc_port = (unsigned int)ec->irq_data;
+-	inb(memc_port + ICS_ARCIN_V5_INTROFFSET);
++	struct icside_state *state = ec->irq_data;
++	unsigned int base = state->irq_port;
++
++	inb(base + ICS_ARCIN_V5_INTROFFSET);
+ }
+ 
+ static const expansioncard_ops_t icside_ops_arcin_v5 = {
+-	icside_irqenable_arcin_v5,
+-	icside_irqdisable_arcin_v5,
+-	NULL,
+-	NULL,
+-	NULL,
+-	NULL
++	.irqenable	= icside_irqenable_arcin_v5,
++	.irqdisable	= icside_irqdisable_arcin_v5,
+ };
+ 
+ 
+@@ -133,10 +118,21 @@
+  */
+ static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ {
+-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
++	struct icside_state *state = ec->irq_data;
++	unsigned int base = state->irq_port;
+ 
+-	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+-	outb(0, ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
++	state->enabled = 1;
++
++	switch (state->channel) {
++	case 0:
++		outb(0, base + ICS_ARCIN_V6_INTROFFSET_1);
++		inb(base + ICS_ARCIN_V6_INTROFFSET_2);
++		break;
++	case 1:
++		outb(0, base + ICS_ARCIN_V6_INTROFFSET_2);
++		inb(base + ICS_ARCIN_V6_INTROFFSET_1);
++		break;
++	}
+ }
+ 
+ /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+@@ -144,10 +140,12 @@
+  */
+ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr)
+ {
+-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
++	struct icside_state *state = ec->irq_data;
+ 
+-	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_1);
+-	inb(ide_base_port + ICS_ARCIN_V6_INTROFFSET_2);
++	state->enabled = 0;
++
++	inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
++	inb (state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+ }
+ 
+ /* Prototype: icside_irqprobe(struct expansion_card *ec)
+@@ -155,70 +153,49 @@
+  */
+ static int icside_irqpending_arcin_v6(struct expansion_card *ec)
+ {
+-	unsigned int ide_base_port = (unsigned int)ec->irq_data;
++	struct icside_state *state = ec->irq_data;
+ 
+-	return inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
+-	       inb(ide_base_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
++	return inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_1) & 1 ||
++	       inb(state->irq_port + ICS_ARCIN_V6_INTRSTAT_2) & 1;
+ }
+ 
+ static const expansioncard_ops_t icside_ops_arcin_v6 = {
+-	icside_irqenable_arcin_v6,
+-	icside_irqdisable_arcin_v6,
+-	icside_irqpending_arcin_v6,
+-	NULL,
+-	NULL,
+-	NULL
++	.irqenable	= icside_irqenable_arcin_v6,
++	.irqdisable	= icside_irqdisable_arcin_v6,
++	.irqpending	= icside_irqpending_arcin_v6,
+ };
+ 
+-/* Prototype: icside_identifyif (struct expansion_card *ec)
+- * Purpose  : identify IDE interface type
+- * Notes    : checks the description string
++/*
++ * Handle routing of interrupts.  This is called before
++ * we write the command to the drive.
+  */
+-static iftype_t __init icside_identifyif (struct expansion_card *ec)
++static void icside_maskproc(ide_drive_t *drive, int mask)
+ {
+-	unsigned int addr;
+-	iftype_t iftype;
+-	int id = 0;
+-
+-	iftype = ics_if_unknown;
+-
+-	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
+-
+-	id = inb(addr) & 1;
+-	id |= (inb(addr + 1) & 1) << 1;
+-	id |= (inb(addr + 2) & 1) << 2;
+-	id |= (inb(addr + 3) & 1) << 3;
+-
+-	switch (id) {
+-	case 0: /* A3IN */
+-		printk("icside: A3IN unsupported\n");
+-		break;
+-
+-	case 1: /* A3USER */
+-		printk("icside: A3USER unsupported\n");
+-		break;
++	ide_hwif_t *hwif = HWIF(drive);
++	struct icside_state *state = hwif->hwif_data;
++	unsigned long flags;
+ 
+-	case 3:	/* ARCIN V6 */
+-		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
+-		iftype = ics_if_arcin_v6;
+-		break;
++	local_irq_save(flags);
+ 
+-	case 15:/* ARCIN V5 (no id) */
+-		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
+-		iftype = ics_if_arcin_v5;
+-		break;
++	state->channel = hwif->channel;
+ 
+-	default:/* we don't know - complain very loudly */
+-		printk("icside: ***********************************\n");
+-		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
+-		printk("icside: ***********************************\n");
+-		printk("icside: please report this to linux@arm.linux.org.uk\n");
+-		printk("icside: defaulting to ARCIN V5\n");
+-		iftype = ics_if_arcin_v5;
+-		break;
++	if (state->enabled && !mask) {
++		switch (hwif->channel) {
++		case 0:
++			outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
++			inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
++			break;
++		case 1:
++			outb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
++			inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
++			break;
++		}
++	} else {
++		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
++		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+ 	}
+ 
+-	return iftype;
++	local_irq_restore(flags);
+ }
+ 
+ #ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+@@ -234,125 +211,138 @@
+ #define NR_ENTRIES 256
+ #define TABLE_SIZE (NR_ENTRIES * 8)
+ 
+-static int ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
++static void ide_build_sglist(ide_drive_t *drive, struct request *rq)
+ {
+-	struct buffer_head *bh;
++	ide_hwif_t *hwif = HWIF(drive);
+ 	struct scatterlist *sg = hwif->sg_table;
++	struct buffer_head *bh;
+ 	int nents = 0;
+ 
+-	if (rq->cmd == READ)
+-		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+-	else
+-		hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+-	bh = rq->bh;
+-	do {
+-		unsigned char *virt_addr = bh->b_data;
+-		unsigned int size = bh->b_size;
++	BUG_ON(hwif->sg_dma_active);
+ 
+-		while ((bh = bh->b_reqnext) != NULL) {
+-			if ((virt_addr + size) != (unsigned char *)bh->b_data)
+-				break;
+-			size += bh->b_size;
+-		}
+-		memset(&sg[nents], 0, sizeof(*sg));
+-		sg[nents].address = virt_addr;
+-		sg[nents].length = size;
+-		nents++;
+-	} while (bh != NULL);
++	if (rq->cmd == IDE_DRIVE_TASKFILE) {
++		ide_task_t *args = rq->special;
+ 
+-	return pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+-}
++		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
++			hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++		else
++			hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+ 
+-static int
+-icside_build_dmatable(ide_drive_t *drive, int ddir)
+-{
+-	return HWIF(drive)->sg_nents = ide_build_sglist(HWIF(drive), HWGROUP(drive)->rq, ddir);
+-}
++		memset(sg, 0, sizeof(*sg));
++		sg->address = rq->buffer;
++		sg->length = rq->nr_sectors * SECTOR_SIZE;
++		nents = 1;
++	} else {
++		if (rq->cmd == READ)
++			hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
++		else
++			hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+ 
+-/* Teardown mappings after DMA has completed.  */
+-static void icside_destroy_dmatable(ide_drive_t *drive)
+-{
+-	struct scatterlist *sg = HWIF(drive)->sg_table;
+-	int nents = HWIF(drive)->sg_nents;
++		bh = rq->bh;
++		do {
++			unsigned long lastend;
+ 
+-	pci_unmap_sg(NULL, sg, nents, HWIF(drive)->sg_dma_direction);
++			memset(sg, 0, sizeof(*sg));
++			sg->page = bh->b_page;
++			lastend = bh_phys(bh);
++
++			do {
++				lastend += bh->b_size;
++				sg->length += bh->b_size;
++
++				bh = bh->b_reqnext;
++				if (bh == NULL)
++					break;
++			} while (lastend == bh_phys(bh));
++
++			sg++;
++			nents++;
++		} while (bh != NULL);
++	}
++
++	nents = pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
++
++	hwif->sg_nents = nents;
+ }
+ 
+-static int
+-icside_config_if(ide_drive_t *drive, int xfer_mode)
++
++/*
++ * Configure the IOMD to give the appropriate timings for the transfer
++ * mode being requested.  We take the advice of the ATA standards, and
++ * calculate the cycle time based on the transfer mode, and the EIDE
++ * MW DMA specs that the drive provides in the IDENTIFY command.
++ *
++ * We have the following IOMD DMA modes to choose from:
++ *
++ *	Type	Active		Recovery	Cycle
++ *	A	250 (250)	312 (550)	562 (800)
++ *	B	187		250		437
++ *	C	125 (125)	125 (375)	250 (500)
++ *	D	62		125		187
++ *
++ * (figures in brackets are actual measured timings)
++ *
++ * However, we also need to take care of the read/write active and
++ * recovery timings:
++ *
++ *			Read	Write
++ *  	Mode	Active	-- Recovery --	Cycle	IOMD type
++ *	MW0	215	50	215	480	A
++ *	MW1	80	50	50	150	C
++ *	MW2	70	25	25	120	C
++ */
++static int icside_set_speed(ide_drive_t *drive, u8 xfer_mode)
+ {
+-	int func = ide_dma_off;
++	int on = 0, cycle_time = 0, use_dma_info = 0;
++
++	/*
++	 * Limit the transfer speed to MW_DMA_2.
++	 */
++	if (xfer_mode > XFER_MW_DMA_2)
++		xfer_mode = XFER_MW_DMA_2;
+ 
+ 	switch (xfer_mode) {
+ 	case XFER_MW_DMA_2:
+-		/*
+-		 * The cycle time is limited to 250ns by the r/w
+-		 * pulse width (90ns), however we should still
+-		 * have a maximum burst transfer rate of 8MB/s.
+-		 */
+-		drive->drive_data = 250;
++		cycle_time = 250;
++		use_dma_info = 1;
+ 		break;
+ 
+ 	case XFER_MW_DMA_1:
+-		drive->drive_data = 250;
++		cycle_time = 250;
++		use_dma_info = 1;
+ 		break;
+ 
+ 	case XFER_MW_DMA_0:
+-		drive->drive_data = 480;
++		cycle_time = 480;
+ 		break;
+ 
+-	default:
+-		drive->drive_data = 0;
++	case XFER_SW_DMA_2:
++	case XFER_SW_DMA_1:
++	case XFER_SW_DMA_0:
++		cycle_time = 480;
+ 		break;
+ 	}
+ 
+-	if (!drive->init_speed)
+-		drive->init_speed = (u8) xfer_mode;
++	/*
++	 * If we're going to be doing MW_DMA_1 or MW_DMA_2, we should
++	 * take care to note the values in the ID...
++	 */
++	if (use_dma_info && drive->id->eide_dma_time > cycle_time)
++		cycle_time = drive->id->eide_dma_time;
+ 
+-	if (drive->drive_data &&
+-	    ide_config_drive_speed(drive, (u8) xfer_mode) == 0)
+-		func = ide_dma_on;
++	drive->drive_data = cycle_time;
++
++	if (cycle_time && ide_config_drive_speed(drive, xfer_mode) == 0)
++		on = 1;
+ 	else
+ 		drive->drive_data = 480;
+ 
+ 	printk("%s: %s selected (peak %dMB/s)\n", drive->name,
+ 		ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data);
+ 
+-	drive->current_speed = (u8) xfer_mode;
+-
+-	return func;
+-}
+-
+-static int
+-icside_set_speed(ide_drive_t *drive, u8 speed)
+-{
+-	return icside_config_if(drive, speed);
+-}
+-
+-/*
+- * dma_intr() is the handler for disk read/write DMA interrupts
+- */
+-static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
+-{
+-	u8 dma_stat	= HWIF(drive)->ide_dma_end(drive);
+-	/* get drive status */
+-	u8 stat		= HWIF(drive)->INB(IDE_STATUS_REG);
+-	int i;
++	drive->current_speed = xfer_mode;
+ 
+-	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {
+-		if (!dma_stat) {
+-			struct request *rq = HWGROUP(drive)->rq;
+-			rq = HWGROUP(drive)->rq;
+-			for (i = rq->nr_sectors; i > 0;) {
+-				i -= rq->current_nr_sectors;
+-				DRIVER(drive)->end_request(drive, 1);
+-			}
+-			return ide_stopped;
+-		}
+-		printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", 
+-		       drive->name, dma_stat);
+-	}
+-	return DRIVER(drive)->error(drive, "dma_intr", stat);
++	return on;
+ }
+ 
+ /*
+@@ -361,19 +351,19 @@
+  * This should be defined in one place only.
+  */
+ struct drive_list_entry {
+-	char * id_model;
+-	char * id_firmware;
++	const char * id_model;
++	const char * id_firmware;
+ };
+ 
+-static struct drive_list_entry drive_whitelist [] = {
++static const struct drive_list_entry drive_whitelist [] = {
+ 	{ "Micropolis 2112A",			"ALL"		},
+ 	{ "CONNER CTMA 4000",			"ALL"		},
+ 	{ "CONNER CTT8000-A",			"ALL"		},
+ 	{ "ST34342A",				"ALL"		},
+-	{ NULL,					0		}
++	{ NULL,					NULL		}
+ };
+ 
+-static struct drive_list_entry drive_blacklist [] = {
++static const struct drive_list_entry drive_blacklist [] = {
+ 	{ "WDC AC11000H",			"ALL"		},
+ 	{ "WDC AC22100H",			"ALL"		},
+ 	{ "WDC AC32500H",			"ALL"		},
+@@ -407,10 +397,11 @@
+ 	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},
+ 	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},
+ 	{ "_NEC DV5800A",			"ALL"		},
+-	{ NULL,					0		}
++	{ NULL,					NULL		}
+ };
+ 
+-static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table)
++static int
++in_drive_list(struct hd_driveid *id, const struct drive_list_entry *drive_table)
+ {
+ 	for ( ; drive_table->id_model ; drive_table++)
+ 		if ((!strcmp(drive_table->id_model, id->model)) &&
+@@ -420,41 +411,52 @@
+ 	return 0;
+ }
+ 
+-/*
+- *  For both Blacklisted and Whitelisted drives.
+- *  This is setup to be called as an extern for future support
+- *  to other special driver code.
+- */
+-int check_drive_good_lists (ide_drive_t *drive)
++static int icside_dma_host_off(ide_drive_t *drive)
+ {
+-	struct hd_driveid *id = drive->id;
+-	return in_drive_list(id, drive_whitelist);
++	return 0;
+ }
+ 
+-int check_drive_bad_lists (ide_drive_t *drive)
++static int icside_dma_off_quietly(ide_drive_t *drive)
+ {
+-	struct hd_driveid *id = drive->id;
+-	int blacklist = in_drive_list(id, drive_blacklist);
+-	if (blacklist)
+-		printk("%s: Disabling DMA for %s\n", drive->name, id->model);
+-	return(blacklist);
++	drive->using_dma = 0;
++	return icside_dma_host_off(drive);
+ }
+ 
+-int icside_dma_check(ide_drive_t *drive)
++static int icside_dma_off(ide_drive_t *drive)
++{
++	printk("%s: DMA disabled\n", drive->name);
++	return icside_dma_off_quietly(drive);
++}
++
++static int icside_dma_host_on(ide_drive_t *drive)
++{
++	return 0;
++}
++
++static int icside_dma_on(ide_drive_t *drive)
++{
++	drive->using_dma = 1;
++	return icside_dma_host_on(drive);
++}
++
++static int icside_dma_check(ide_drive_t *drive)
+ {
+ 	struct hd_driveid *id = drive->id;
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	int autodma = hwif->autodma;
+ 	int xfer_mode = XFER_PIO_2;
++	int on;
+ 
+-	if (!id || !(id->capability & 1) || !autodma)
+-		return hwif->ide_dma_off_quietly(drive);
++	if (!id || !(id->capability & 1) || !hwif->autodma)
++		goto out;
+ 
+ 	/*
+ 	 * Consult the list of known "bad" drives
+ 	 */
+-	if (check_drive_bad_lists(drive))
+-		return hwif->ide_dma_off(drive);
++	if (in_drive_list(id, drive_blacklist)) {
++		printk("%s: Disabling DMA for %s (blacklisted)\n",
++			drive->name, id->model);
++		goto out;
++	}
+ 
+ 	/*
+ 	 * Enable DMA on any drive that has multiword DMA
+@@ -473,192 +475,241 @@
+ 	/*
+ 	 * Consult the list of known "good" drives
+ 	 */
+-	if (check_drive_good_lists(drive)) {
++	if (in_drive_list(id, drive_whitelist)) {
+ 		if (id->eide_dma_time > 150)
+ 			goto out;
+ 		xfer_mode = XFER_MW_DMA_1;
+ 	}
+ 
+ out:
+-	if (icside_config_if(drive, xfer_mode))
+-		return hwif->ide_dma_on(drive);
+-	return hwif->ide_dma_off(drive);
+-}
++	on = icside_set_speed(drive, xfer_mode);
+ 
+-int icside_dma_verbose(ide_drive_t *drive)
+-{
+-	printk(", DMA");
+-	return 1;
++	if (on)
++		return icside_dma_on(drive);
++	else
++		return icside_dma_off(drive);
+ }
+ 
+-int icside_dma_test_irq(ide_drive_t *drive)
++static int icside_dma_end(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+-	return inb((unsigned long)hwif->hw.priv) & 1;
+-}
+ 
+-int icside_dma_host_off(ide_drive_t *drive)
+-{
+-	return 0;
+-}
++	drive->waiting_for_dma = 0;
+ 
+-int icside_dma_off_quietly(ide_drive_t *drive)
+-{
+-	drive->using_dma = 0;
+-	return icside_dma_host_off(drive);
+-}
++	disable_dma(hwif->hw.dma);
+ 
+-int icside_dma_off(ide_drive_t *drive)
+-{
+-	printk("%s: DMA disabled\n", drive->name);
+-	return icside_dma_off_quietly(drive);
+-}
++	/* Teardown mappings after DMA has completed. */
++	pci_unmap_sg(NULL, hwif->sg_table, hwif->sg_nents,
++		     hwif->sg_dma_direction);
+ 
+-int icside_dma_host_on(ide_drive_t *drive)
+-{
+-	return 0;
+-}
++	hwif->sg_dma_active = 0;
+ 
+-int icside_dma_on(ide_drive_t *drive)
+-{
+-	drive->using_dma = 1;
+-	return icside_dma_host_on(drive);
++	return get_dma_residue(hwif->hw.dma) != 0;
+ }
+ 
+-int icside_dma_begin(ide_drive_t *drive)
++static int icside_dma_begin(ide_drive_t *drive)
+ {
+ 	ide_hwif_t *hwif = HWIF(drive);
+ 
++	/* We can not enable DMA on both channels simultaneously. */
++	BUG_ON(dma_channel_active(hwif->hw.dma));
+ 	enable_dma(hwif->hw.dma);
+ 	return 0;
+ }
+ 
+-int icside_dma_end(ide_drive_t *drive)
++static int icside_dma_count(ide_drive_t *drive)
+ {
+-	ide_hwif_t *hwif = HWIF(drive);
+- 
+-	drive->waiting_for_dma = 0;
+-	disable_dma(hwif->hw.dma);
+-	icside_destroy_dmatable(drive);
+-	return get_dma_residue(hwif->hw.dma) != 0;
++	return icside_dma_begin(drive);
+ }
+ 
+-int icside_dma_count (ide_drive_t *drive)
++/*
++ * dma_intr() is the handler for disk read/write DMA interrupts
++ */
++static ide_startstop_t icside_dmaintr(ide_drive_t *drive)
+ {
+-        return icside_dma_begin(drive);
++	unsigned int stat;
++	int dma_stat;
++
++	dma_stat = icside_dma_end(drive);
++	stat = HWIF(drive)->INB(IDE_STATUS_REG);
++	if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) {
++		if (!dma_stat) {
++			struct request *rq = HWGROUP(drive)->rq;
++			int i;
++
++			for (i = rq->nr_sectors; i > 0; ) {
++				i -= rq->current_nr_sectors;
++				DRIVER(drive)->end_request(drive, 1);
++			}
++
++			return ide_stopped;
++		}
++		printk(KERN_ERR "%s: bad DMA status (dma_stat=%x)\n",
++		       drive->name, dma_stat);
++	}
++
++	return DRIVER(drive)->error(drive, __FUNCTION__, stat);
+ }
+ 
+-int icside_dma_read(ide_drive_t *drive)
++static int
++icside_dma_common(ide_drive_t *drive, struct request *rq,
++		  unsigned int dma_mode)
+ {
+-	ide_hwif_t *hwif	= HWIF(drive);
+-//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+-	int count		= 0;
+-	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+-	task_ioreg_t command	= WIN_NOP;
++	ide_hwif_t *hwif = HWIF(drive);
+ 
+-	count = icside_build_dmatable(drive, PCI_DMA_FROMDEVICE);
+-	if (!count)
+-		return 1;
+-	disable_dma(hwif->hw.dma);
++	/*
++	 * We can not enable DMA on both channels.
++	 */
++	BUG_ON(hwif->sg_dma_active);
++	BUG_ON(dma_channel_active(hwif->hw.dma));
+ 
+-	/* Route the DMA signals to
+-	 * to the correct interface.
++	ide_build_sglist(drive, rq);
++
++	/*
++	 * Ensure that we have the right interrupt routed.
+ 	 */
+-	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
++	icside_maskproc(drive, 0);
+ 
+-	/* Select the correct timing
+-	 * for this drive
++	/*
++	 * Route the DMA signals to the correct interface.
++	 */
++	outb(hwif->select_data, hwif->config_data);
++
++	/*
++	 * Select the correct timing for this drive.
+ 	 */
+ 	set_dma_speed(hwif->hw.dma, drive->drive_data);
+ 
+-	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+-	set_dma_mode(hwif->hw.dma, DMA_MODE_READ);
++	/*
++	 * Tell the DMA engine about the SG table and
++	 * data direction.
++	 */
++	set_dma_sg(hwif->hw.dma, hwif->sg_table, hwif->sg_nents);
++	set_dma_mode(hwif->hw.dma, dma_mode);
++
++	return 0;
++}
++
++static int icside_dma_read(ide_drive_t *drive)
++{
++	struct request *rq = HWGROUP(drive)->rq;
++	task_ioreg_t cmd;
++
++	if (icside_dma_common(drive, rq, DMA_MODE_READ))
++		return 1;
+ 
+ 	drive->waiting_for_dma = 1;
++
+ 	if (drive->media != ide_disk)
+ 		return 0;
+ 
+-	if (HWGROUP(drive)->handler != NULL)	/* paranoia check */
+-		BUG();
+-	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+ 	/*
+ 	 * FIX ME to use only ACB ide_task_t args Struct
+ 	 */
+ #if 0
+ 	{
+-		ide_task_t *args = HWGROUP(drive)->rq->special;
+-		command = args->tfRegister[IDE_COMMAND_OFFSET];
++		ide_task_t *args = rq->special;
++		cmd = args->tfRegister[IDE_COMMAND_OFFSET];
+ 	}
+ #else
+-	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
+-		if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+-		ide_task_t *args = HWGROUP(drive)->rq->special;
+-		command = args->tfRegister[IDE_COMMAND_OFFSET];
++	if (rq->cmd == IDE_DRIVE_TASKFILE) {
++		ide_task_t *args = rq->special;
++		cmd = args->tfRegister[IDE_COMMAND_OFFSET];
++	} else if (drive->addressing == 1) {
++		cmd = WIN_READDMA_EXT;
++	} else {
++		cmd = WIN_READDMA;
+ 	}
+ #endif
+-	/* issue cmd to drive */
+-	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+ 
+-	return icside_dma_count(drive);
++	ide_execute_command(drive, cmd, icside_dmaintr, 2*WAIT_CMD, NULL);
++
++	return icside_dma_begin(drive);
+ }
+ 
+-int icside_dma_write(ide_drive_t *drive)
++static int icside_dma_write(ide_drive_t *drive)
+ {
+-	ide_hwif_t *hwif	= HWIF(drive);
+-//	ide_task_t *args	= HWGROUP(drive)->rq->special;
+-	int count		= 0;
+-	u8 lba48		= (drive->addressing == 1) ? 1 : 0;
+-	task_ioreg_t command	= WIN_NOP;
++	struct request *rq = HWGROUP(drive)->rq;
++	task_ioreg_t cmd;
+ 
+-	count = icside_build_dmatable(drive, PCI_DMA_TODEVICE);
+-	if (!count)
++	if (icside_dma_common(drive, rq, DMA_MODE_WRITE))
+ 		return 1;
+-	disable_dma(hwif->hw.dma);
+-
+-	/* Route the DMA signals to
+-	 * to the correct interface.
+-	 */
+-	HWIF(drive)->OUTB(hwif->select_data, hwif->config_data);
+-
+-	/* Select the correct timing
+-	 * for this drive
+-	 */
+-	set_dma_speed(hwif->hw.dma, drive->drive_data);
+-
+-	set_dma_sg(hwif->hw.dma, HWIF(drive)->sg_table, count);
+-	set_dma_mode(hwif->hw.dma, DMA_MODE_WRITE);
+ 
+ 	drive->waiting_for_dma = 1;
++
+ 	if (drive->media != ide_disk)
+ 		return 0;
+ 
+-	if (HWGROUP(drive)->handler != NULL)
+-		BUG();
+-	ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL);
+ 	/*
+ 	 * FIX ME to use only ACB ide_task_t args Struct
+ 	 */
+ #if 0
+ 	{
+-		ide_task_t *args = HWGROUP(drive)->rq->special;
+-		command = args->tfRegister[IDE_COMMAND_OFFSET];
++		ide_task_t *args = rq->special;
++		cmd = args->tfRegister[IDE_COMMAND_OFFSET];
+ 	}
+ #else
+-	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
+-	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) {
+-		ide_task_t *args = HWGROUP(drive)->rq->special;
+-		command = args->tfRegister[IDE_COMMAND_OFFSET];
++	if (rq->cmd == IDE_DRIVE_TASKFILE) {
++		ide_task_t *args = rq->special;
++		cmd = args->tfRegister[IDE_COMMAND_OFFSET];
++	} else if (drive->addressing == 1) {
++		cmd = WIN_WRITEDMA_EXT;
++	} else {
++		cmd = WIN_WRITEDMA;
+ 	}
+ #endif
+-	/* issue cmd to drive */
+-	HWIF(drive)->OUTB(command, IDE_COMMAND_REG);
+ 
+-	return icside_dma_count(drive);
++	ide_execute_command(drive, cmd, icside_dmaintr, 2*WAIT_CMD, NULL);
++
++	return icside_dma_begin(drive);
+ }
+ 
+-static int
+-icside_setup_dma(ide_hwif_t *hwif, int autodma)
++static int icside_dma_test_irq(ide_drive_t *drive)
++{
++	ide_hwif_t *hwif = HWIF(drive);
++	struct icside_state *state = hwif->hwif_data;
++
++	return inb(state->irq_port +
++		   (hwif->channel ?
++			ICS_ARCIN_V6_INTRSTAT_2 :
++			ICS_ARCIN_V6_INTRSTAT_1)) & 1;
++}
++
++static int icside_dma_verbose(ide_drive_t *drive)
++{
++	printk(", %s (peak %dMB/s)",
++		ide_xfer_verbose(drive->current_speed),
++		2000 / drive->drive_data);
++	return 1;
++}
++
++static int icside_dma_timeout(ide_drive_t *drive)
+ {
++	printk(KERN_ERR "%s: DMA timeout occurred: ", drive->name);
++
++	if (icside_dma_test_irq(drive))
++		return 0;
++
++	ide_dump_status(drive, "DMA timeout",
++		HWIF(drive)->INB(IDE_STATUS_REG));
++
++	return icside_dma_end(drive);
++}
++
++static int icside_dma_lostirq(ide_drive_t *drive)
++{
++	printk(KERN_ERR "%s: IRQ lost\n", drive->name);
++	return 1;
++}
++
++static int icside_dma_init(ide_hwif_t *hwif)
++{
++	int autodma = 0;
++
++#ifdef CONFIG_IDEDMA_ICS_AUTO
++	autodma = 1;
++#endif
++
+ 	printk("    %s: SG-DMA", hwif->name);
+ 
+ 	hwif->sg_table = kmalloc(sizeof(struct scatterlist) * NR_ENTRIES,
+@@ -666,40 +717,53 @@
+ 	if (!hwif->sg_table)
+ 		goto failed;
+ 
+-	hwif->dmatable_cpu = NULL;
+-	hwif->dmatable_dma = 0;
+-	hwif->speedproc = icside_set_speed;
+-	hwif->autodma = autodma;
++	hwif->atapi_dma		= 1;
++	hwif->mwdma_mask	= 7; /* MW0..2 */
++	hwif->swdma_mask	= 7; /* SW0..2 */
+ 
+-	hwif->ide_dma_check = icside_dma_check;
+-	hwif->ide_dma_host_off = icside_dma_host_off;
++	hwif->dmatable_cpu	= NULL;
++	hwif->dmatable_dma	= 0;
++	hwif->speedproc		= icside_set_speed;
++	hwif->autodma		= autodma;
++
++	hwif->ide_dma_check	= icside_dma_check;
++	hwif->ide_dma_host_off	= icside_dma_host_off;
+ 	hwif->ide_dma_off_quietly = icside_dma_off_quietly;
+-	hwif->ide_dma_off = icside_dma_off;
+-	hwif->ide_dma_host_on = icside_dma_host_on;
+-	hwif->ide_dma_on = icside_dma_on;
+-	hwif->ide_dma_read = icside_dma_read;
+-	hwif->ide_dma_write = icside_dma_write;
+-	hwif->ide_dma_count = icside_dma_count;
+-	hwif->ide_dma_begin = icside_dma_begin;
+-	hwif->ide_dma_end = icside_dma_end;
+-	hwif->ide_dma_verbose = icside_dma_verbose;
+-	hwif->ide_dma_bad_drive = check_drive_bad_lists;
+-	hwif->ide_dma_good_drive = check_drive_good_lists;
+-	hwif->ide_dma_test_irq = icside_dma_test_irq;
++	hwif->ide_dma_off	= icside_dma_off;
++	hwif->ide_dma_host_on	= icside_dma_host_on;
++	hwif->ide_dma_on	= icside_dma_on;
++	hwif->ide_dma_read	= icside_dma_read;
++	hwif->ide_dma_write	= icside_dma_write;
++	hwif->ide_dma_count	= icside_dma_count;
++	hwif->ide_dma_begin	= icside_dma_begin;
++	hwif->ide_dma_end	= icside_dma_end;
++	hwif->ide_dma_test_irq	= icside_dma_test_irq;
++	hwif->ide_dma_verbose	= icside_dma_verbose;
++	hwif->ide_dma_timeout	= icside_dma_timeout;
++	hwif->ide_dma_lostirq	= icside_dma_lostirq;
+ 
+-	printk(" capable%s\n", autodma ?
+-		", auto-enable" : "");
++	printk(" capable%s\n", hwif->autodma ? ", auto-enable" : "");
+ 
+ 	return 1;
+ 
+ failed:
+-	printk(" -- ERROR, unable to allocate DMA table\n");
++	printk(" disabled, unable to allocate DMA table\n");
+ 	return 0;
+ }
++
++static void icside_dma_exit(ide_hwif_t *hwif)
++{
++	if (hwif->sg_table) {
++		kfree(hwif->sg_table);
++		hwif->sg_table = NULL;
++	}
++}
++#else
++#define icside_dma_init(hwif)	(0)
++#define icside_dma_exit(hwif)	do { } while (0)
+ #endif
+ 
+-static ide_hwif_t *
+-icside_find_hwif(unsigned long dataport)
++static ide_hwif_t *icside_find_hwif(unsigned long dataport)
+ {
+ 	ide_hwif_t *hwif;
+ 	int index;
+@@ -716,13 +780,13 @@
+ 			goto found;
+ 	}
+ 
+-	return NULL;
++	hwif = NULL;
+ found:
+ 	return hwif;
+ }
+ 
+ static ide_hwif_t *
+-icside_setup(unsigned long base, struct cardinfo *info, int irq)
++icside_setup(unsigned long base, struct cardinfo *info, struct expansion_card *ec)
+ {
+ 	unsigned long port = base + info->dataoffset;
+ 	ide_hwif_t *hwif;
+@@ -740,8 +804,8 @@
+ 		}
+ 		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+ 		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
+-		hwif->hw.irq  = irq;
+-		hwif->irq     = irq;
++		hwif->hw.irq  = ec->irq;
++		hwif->irq     = ec->irq;
+ 		hwif->hw.dma  = NO_DMA;
+ 		hwif->noprobe = 0;
+ 		hwif->chipset = ide_acorn;
+@@ -750,33 +814,39 @@
+ 	return hwif;
+ }
+ 
+-static int __init icside_register_v5(struct expansion_card *ec, int autodma)
++static int __init
++icside_register_v5(struct icside_state *state, struct expansion_card *ec)
+ {
+ 	unsigned long slot_port;
+ 	ide_hwif_t *hwif;
+ 
+ 	slot_port = ecard_address(ec, ECARD_MEMC, 0);
+ 
++	state->irq_port = slot_port;
++
+ 	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
+ 	ec->irqmask  = 1;
+-	ec->irq_data = (void *)slot_port;
+-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
++	ec->irq_data = state;
++	ec->ops      = &icside_ops_arcin_v5;
+ 
+ 	/*
+ 	 * Be on the safe side - disable interrupts
+ 	 */
+ 	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
+ 
+-	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
++	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec);
+ 
+-	return hwif ? 0 : -1;
++	state->hwif[0] = hwif;
++
++	return hwif ? 0 : -ENODEV;
+ }
+ 
+-static int __init icside_register_v6(struct expansion_card *ec, int autodma)
++static int __init
++icside_register_v6(struct icside_state *state, struct expansion_card *ec)
+ {
+ 	unsigned long slot_port, port;
+ 	ide_hwif_t *hwif, *mate;
+-	int sel = 0;
++	unsigned int sel = 0;
+ 
+ 	slot_port = ecard_address(ec, ECARD_IOC, ECARD_FAST);
+ 	port      = ecard_address(ec, ECARD_EASI, ECARD_FAST);
+@@ -788,88 +858,185 @@
+ 
+ 	outb(sel, slot_port);
+ 
+-	ec->irq_data = (void *)port;
+-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+-
+ 	/*
+ 	 * Be on the safe side - disable interrupts
+ 	 */
+ 	inb(port + ICS_ARCIN_V6_INTROFFSET_1);
+ 	inb(port + ICS_ARCIN_V6_INTROFFSET_2);
+ 
+-	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
+-	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
++	/*
++	 * Find and register the interfaces.
++	 */
++	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec);
++	mate = icside_setup(port, &icside_cardinfo_v6_2, ec);
+ 
+-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
+-	if (ec->dma != NO_DMA) {
+-		if (request_dma(ec->dma, hwif->name))
+-			goto no_dma;
++	if (!hwif || !mate)
++		return -ENODEV;
+ 
+-		if (hwif) {
+-			hwif->config_data = slot_port;
+-			hwif->select_data = sel;
+-			hwif->hw.dma  = ec->dma;
+-			hwif->hw.priv = (void *)
+-					(port + ICS_ARCIN_V6_INTRSTAT_1);
+-			hwif->channel = 0;
+-			icside_setup_dma(hwif, autodma);
+-			hwif->drives[0].autodma = autodma;
+-			hwif->drives[1].autodma = autodma;
+-		}
+-		if (mate) {
+-			mate->config_data = slot_port;
+-			mate->select_data = sel | 1;
+-			mate->hw.dma  = ec->dma;
+-			mate->hw.priv = (void *)
+-					(port + ICS_ARCIN_V6_INTRSTAT_2);
+-			mate->channel = 1;
+-			icside_setup_dma(mate, autodma);
+-			mate->drives[0].autodma = autodma;
+-			mate->drives[1].autodma = autodma;
+-		}
++	state->irq_port   = port;
++	state->slot_port  = slot_port;
++	state->hwif[0]    = hwif;
++	state->hwif[1]    = mate;
++
++	ec->irq_data      = state;
++	ec->ops           = &icside_ops_arcin_v6;
++
++	hwif->maskproc    = icside_maskproc;
++	hwif->channel     = 0;
++	hwif->hwif_data   = state;
++	hwif->mate        = mate;
++	hwif->serialized  = 1;
++	hwif->config_data = slot_port;
++	hwif->select_data = sel;
++	hwif->hw.dma      = ec->dma;
++
++	mate->maskproc    = icside_maskproc;
++	mate->channel     = 1;
++	mate->hwif_data   = state;
++	mate->mate        = hwif;
++	mate->serialized  = 1;
++	mate->config_data = slot_port;
++	mate->select_data = sel | 1;
++	mate->hw.dma      = ec->dma;
++
++	if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
++		icside_dma_init(hwif);
++		icside_dma_init(mate);
+ 	}
+-no_dma:
+-#endif
+-	return hwif || mate ? 0 : -1;
++	return 0;
+ }
+ 
+-int __init icside_init(void)
++static int __init icside_probe(struct expansion_card *ec, const struct ecard_id *id)
+ {
+-	int autodma = 0;
++	struct icside_state *state;
++	int ret;
+ 
+-#ifdef CONFIG_IDEDMA_ICS_AUTO
+-	autodma = 1;
+-#endif
++	state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
++	if (!state) {
++		ret = -ENOMEM;
++		goto out;
++	}
+ 
+-	ecard_startfind ();
++	memset(state, 0, sizeof(struct icside_state));
++	state->type	= ICS_TYPE_NOTYPE;
+ 
+-	do {
+-		struct expansion_card *ec;
+-		int result;
++	{
++		unsigned int addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
++		unsigned int type;
+ 
+-		ec = ecard_find(0, icside_cids);
+-		if (ec == NULL)
+-			break;
++		type = inb(addr) & 1;
++		type |= (inb(addr + 1) & 1) << 1;
++		type |= (inb(addr + 2) & 1) << 2;
++		type |= (inb(addr + 3) & 1) << 3;
+ 
+-		ecard_claim(ec);
++		state->type = type;
++	}
+ 
+-		switch (icside_identifyif(ec)) {
+-		case ics_if_arcin_v5:
+-			result = icside_register_v5(ec, autodma);
+-			break;
++	switch (state->type) {
++	case ICS_TYPE_A3IN:
++		printk(KERN_WARNING "icside: A3IN unsupported\n");
++		ret = -ENODEV;
++		break;
+ 
+-		case ics_if_arcin_v6:
+-			result = icside_register_v6(ec, autodma);
+-			break;
++	case ICS_TYPE_A3USER:
++		printk(KERN_WARNING "icside: A3USER unsupported\n");
++		ret = -ENODEV;
++		break;
+ 
+-		default:
+-			result = -1;
+-			break;
+-		}
++	case ICS_TYPE_V5:
++		ret = icside_register_v5(state, ec);
++		break;
+ 
+-		if (result)
+-			ecard_release(ec);
+-	} while (1);
++	case ICS_TYPE_V6:
++		ret = icside_register_v6(state, ec);
++		break;
+ 
+-	return 0;
++	default:
++		printk(KERN_WARNING "icside: unknown interface type\n");
++		ret = -ENODEV;
++		break;
++	}
++
++	if (ret == 0) {
++		ecard_set_drvdata(ec, state);
++	} else {
++		kfree(state);
++	}
++ out:
++	return ret;
++}
++
++static void __devexit icside_remove(struct expansion_card *ec)
++{
++	struct icside_state *state = ecard_get_drvdata(ec);
++
++	switch (state->type) {
++	case ICS_TYPE_V5:
++		/* FIXME: tell IDE to stop using the interface */
++
++		/* Disable interrupts */
++		inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
++		break;
++
++	case ICS_TYPE_V6:
++		/* FIXME: tell IDE to stop using the interface */
++		icside_dma_exit(state->hwif[1]);
++		icside_dma_exit(state->hwif[0]);
++
++		if (ec->dma != NO_DMA)
++			free_dma(ec->dma);
++
++		/* Disable interrupts */
++		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
++		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
++
++		/* Reset the ROM pointer/EASI selection */
++		outb(0, state->slot_port);
++		break;
++	}
++
++	ecard_set_drvdata(ec, NULL);
++	ec->ops = NULL;
++	ec->irq_data = NULL;
++
++	kfree(state);
++}
++
++static void icside_shutdown(struct expansion_card *ec)
++{
++	struct icside_state *state = ecard_get_drvdata(ec);
++
++	switch (state->type) {
++	case ICS_TYPE_V5:
++		/* Disable interrupts */
++		inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
++		break;
++
++	case ICS_TYPE_V6:
++		/* Disable interrupts */
++		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
++		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
++
++		/* Reset the ROM pointer/EASI selection */
++		outb(0, state->slot_port);
++		break;
++	}
++}
++
++static const struct ecard_id icside_ids[] = {
++	{ MANU_ICS,  PROD_ICS_IDE  },
++	{ MANU_ICS2, PROD_ICS2_IDE },
++	{ 0xffff, 0xffff }
++};
++
++static struct ecard_driver icside_driver = {
++	.probe		= icside_probe,
++	.remove		= __devexit_p(icside_remove),
++	.shutdown	= icside_shutdown,
++	.id_table	= icside_ids,
++};
++
++int __init icside_init(void)
++{
++	return ecard_register_driver(&icside_driver);
+ }
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ide/arm/rstation-ide.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,78 @@
++/*
++ * linux/drivers/ide/rs-ide.c
++ *
++ * Copyright (c) 2002 Ben Dooks
++ * Copyright (c) 2002 Simtec Electronics
++ *
++ * Simple RiscStation IDE support
++*/
++
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/blkdev.h>
++#include <linux/errno.h>
++#include <linux/ide.h>
++#include <linux/init.h>
++
++#include <asm/hardware/iomd.h>
++#include <asm/mach-types.h>
++#include <asm/io.h>
++
++#ifndef CONFIG_ARCH_RISCSTATION
++#error "compiling this code for non-riscstation hardware is dangerous!"
++#endif
++
++#define DRV_PREFIX "ide-rs"
++
++#define IRQ_PRI  (40+3)
++#define IRQ_SEC  (40+4)
++
++#define PORT_BASE ((0x2b800 - 0x10000) >> 2)
++#define SEC_OFF (0x400 >> 2)
++
++int __init rside_reg(unsigned long base, unsigned int irq);
++
++int __init rside_init(void)
++{
++    int iotcr;
++
++    if (!machine_is_riscstation()) {
++	printk(DRV_PREFIX ": hardware is not a RiscStation!\n");
++	return 0;
++    }
++
++    /* select correct area cycle time */
++
++    iotcr = inb(IOMD_IOTCR);
++    outb((iotcr & ~3) | 1, IOMD_IOTCR);
++
++    /* register h/w */
++
++    rside_reg(PORT_BASE, IRQ_PRI);
++    rside_reg(PORT_BASE + SEC_OFF, IRQ_SEC);
++
++    return 0;
++}
++
++
++int __init rside_reg(unsigned long port, unsigned int irq)
++{
++    unsigned long addr, i;
++    hw_regs_t hw;
++
++    hw.irq = irq;
++
++    addr = port;
++
++    for (i = IDE_DATA_OFFSET; i  <= IDE_STATUS_OFFSET; i++) {
++	hw.io_ports[i] = (ide_ioreg_t)addr;
++	addr += 0x40 >> 2;
++    }
++
++    hw.io_ports[IDE_CONTROL_OFFSET] = port + ((0xb80 - 0x800) >> 2);
++
++    printk(DRV_PREFIX ": registering channel at %08lx, %08lx, irq %d\n",
++	   port, hw.io_ports[IDE_CONTROL_OFFSET], irq);
++
++    return ide_register_hw(&hw, NULL);
++}
+--- linux-2.4.25/drivers/ide/ide-probe.c~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/ide/ide-probe.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1296,11 +1296,11 @@
+ 			hwif->name, hwif->major);
+ 		return (hwif->present = 0);
+ 	}
+-	
++
+ 	if (init_irq(hwif)) {
+ 		int i = hwif->irq;
+ 		/*
+-		 *	It failed to initialise. Find the default IRQ for 
++		 *	It failed to initialise. Find the default IRQ for
+ 		 *	this port and try that.
+ 		 */
+ 		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) {
+@@ -1318,7 +1318,7 @@
+ 		printk("%s: probed IRQ %d failed, using default.\n",
+ 			hwif->name, hwif->irq);
+ 	}
+-	
++
+ 	init_gendisk(hwif);
+ 	blk_dev[hwif->major].data = hwif;
+ 	blk_dev[hwif->major].queue = ide_get_queue;
+--- linux-2.4.25/drivers/ide/ide-proc.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/ide/ide-proc.c	2004-03-31 17:15:09.000000000 +0200
+@@ -425,6 +425,7 @@
+ 		case ide_cy82c693:	name = "cy82c693";	break;
+ 		case ide_4drives:	name = "4drives";	break;
+ 		case ide_pmac:		name = "pmac";		break;
++		case ide_acorn:		name = "acorn";		break;
+ 		default:		name = "(unknown)";	break;
+ 	}
+ 	len = sprintf(page, "%s\n", name);
+--- linux-2.4.25/drivers/ide/ide.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/ide/ide.c	2004-03-31 17:15:09.000000000 +0200
+@@ -218,23 +218,14 @@
+ static void init_hwif_data (unsigned int index)
+ {
+ 	unsigned int unit;
+-	hw_regs_t hw;
+ 	ide_hwif_t *hwif = &ide_hwifs[index];
+ 
+ 	/* bulk initialize hwif & drive info with zeros */
+ 	memset(hwif, 0, sizeof(ide_hwif_t));
+-	memset(&hw, 0, sizeof(hw_regs_t));
+ 
+ 	/* fill in any non-zero initial values */
+ 	hwif->index     = index;
+-	ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, &hwif->irq);
+-	memcpy(&hwif->hw, &hw, sizeof(hw));
+-	memcpy(hwif->io_ports, hw.io_ports, sizeof(hw.io_ports));
+-	hwif->noprobe	= !hwif->io_ports[IDE_DATA_OFFSET];
+-#ifdef CONFIG_BLK_DEV_HD
+-	if (hwif->io_ports[IDE_DATA_OFFSET] == HD_DATA)
+-		hwif->noprobe = 1; /* may be overridden by ide_setup() */
+-#endif /* CONFIG_BLK_DEV_HD */
++	hwif->noprobe	= 1;
+ 	hwif->major	= ide_hwif_to_major[index];
+ 	hwif->name[0]	= 'i';
+ 	hwif->name[1]	= 'd';
+@@ -276,6 +267,28 @@
+ }
+ 
+ /*
++ * Old compatability function - initialise ports using ide_default_io_base
++ */
++static void ide_old_init_default_hwifs(void)
++{
++	unsigned int index;
++	ide_ioreg_t base;
++	ide_hwif_t *hwif;
++
++	for (index = 0; index < MAX_HWIFS; index++) {
++		hwif = &ide_hwifs[index];
++
++		base = ide_default_io_base(index);
++
++		if (base) {
++			ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->hw.irq);
++			memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports));
++			hwif->noprobe = 0;
++		}
++	}
++}
++
++/*
+  * init_ide_data() sets reasonable default values into all fields
+  * of all instances of the hwifs and drives, but only on the first call.
+  * Subsequent calls have no effect (they don't wipe out anything).
+@@ -307,6 +320,7 @@
+ 		init_hwif_data(index);
+ 
+ 	/* Add default hw interfaces */
++	ide_old_init_default_hwifs();
+ 	ide_init_default_hwifs();
+ 
+ 	idebus_parameter = 0;
+@@ -2530,6 +2544,12 @@
+ 		rapide_init();
+ 	}
+ #endif /* CONFIG_BLK_DEV_IDE_RAPIDE */
++#ifdef CONFIG_BLK_DEV_IDE_RISCSTATION
++	{
++	    extern void rside_init(void);
++	    rside_init();
++	}
++#endif /* CONFIG_BLK_DEV_IDE_RISCSTATION */
+ #ifdef CONFIG_BLK_DEV_GAYLE
+ 	{
+ 		extern void gayle_init(void);
+--- linux-2.4.25/drivers/ide/pci/Makefile~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/ide/pci/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -15,7 +15,6 @@
+ obj-$(CONFIG_BLK_DEV_HPT34X)		+= hpt34x.o
+ obj-$(CONFIG_BLK_DEV_HPT366)		+= hpt366.o
+ #obj-$(CONFIG_BLK_DEV_HPT37X)		+= hpt37x.o
+-obj-$(CONFIG_BLK_DEV_IDE_ICSIDE)	+= icside.o
+ obj-$(CONFIG_BLK_DEV_IT8172)		+= it8172.o
+ obj-$(CONFIG_BLK_DEV_NS87415)		+= ns87415.o
+ obj-$(CONFIG_BLK_DEV_OPTI621)		+= opti621.o
+--- linux-2.4.25/drivers/ide/pci/sl82c105.c~2.4.25-vrs2.patch	2003-06-13 16:51:33.000000000 +0200
++++ linux-2.4.25/drivers/ide/pci/sl82c105.c	2004-03-31 17:15:09.000000000 +0200
+@@ -37,7 +37,7 @@
+ #ifdef DEBUG
+ #define DBG(arg) printk arg
+ #else
+-#define DBG(fmt,...)
++#define DBG(fmt...)
+ #endif
+ /*
+  * SL82C105 PCI config register 0x40 bits.
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ide/pci/sl82c105.c.2419	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,380 @@
++/*
++ * linux/drivers/ide/sl82c105.c
++ *
++ * SL82C105/Winbond 553 IDE driver
++ *
++ * Maintainer unknown.
++ *
++ * Changelog:
++ *
++ * 15/11/1998	RMK	Drive tuning added from Rebel.com's kernel
++ *			sources
++ * 30/03/2002	RMK	Add fixes specified in W83C553F errata.
++ *			(with special thanks to Todd Inglett)
++ */
++
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/timer.h>
++#include <linux/mm.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/blkdev.h>
++#include <linux/hdreg.h>
++#include <linux/pci.h>
++#include <linux/ide.h>
++
++#include <asm/io.h>
++#include <asm/dma.h>
++
++#include "ide_modes.h"
++
++extern char *ide_xfer_verbose (byte xfer_rate);
++
++/*
++ * SL82C105 PCI config register 0x40 bits.
++ */
++#define CTRL_IDE_IRQB	(1 << 30)
++#define CTRL_IDE_IRQA	(1 << 28)
++#define CTRL_LEGIRQ	(1 << 11)
++#define CTRL_P1F16	(1 << 5)
++#define CTRL_P1EN	(1 << 4)
++#define CTRL_P0F16	(1 << 1)
++#define	CTRL_P0EN	(1 << 0)
++
++/*
++ * Convert a PIO mode and cycle time to the required on/off
++ * times for the interface.  This has protection against run-away
++ * timings.
++ */
++static unsigned int get_timing_sl82c105(ide_pio_data_t *p)
++{
++	unsigned int cmd_on;
++	unsigned int cmd_off;
++
++	cmd_on = (ide_pio_timings[p->pio_mode].active_time + 29) / 30;
++	cmd_off = (p->cycle_time - 30 * cmd_on + 29) / 30;
++
++	if (cmd_on > 32)
++		cmd_on = 32;
++	if (cmd_on == 0)
++		cmd_on = 1;
++
++	if (cmd_off > 32)
++		cmd_off = 32;
++	if (cmd_off == 0)
++		cmd_off = 1;
++
++	return (cmd_on - 1) << 8 | (cmd_off - 1) | (p->use_iordy ? 0x40 : 0x00);
++}
++
++/*
++ * Configure the drive and chipset for PIO
++ */
++static void config_for_pio(ide_drive_t *drive, int pio, int report)
++{
++	ide_hwif_t *hwif = HWIF(drive);
++	struct pci_dev *dev = hwif->pci_dev;
++	ide_pio_data_t p;
++	unsigned short drv_ctrl = 0x909;
++	unsigned int xfer_mode, reg;
++
++	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
++
++	pio = ide_get_best_pio_mode(drive, pio, 5, &p);
++
++	switch (pio) {
++	default:
++	case 0:		xfer_mode = XFER_PIO_0;		break;
++	case 1:		xfer_mode = XFER_PIO_1;		break;
++	case 2:		xfer_mode = XFER_PIO_2;		break;
++	case 3:		xfer_mode = XFER_PIO_3;		break;
++	case 4:		xfer_mode = XFER_PIO_4;		break;
++	}
++
++	if (ide_config_drive_speed(drive, xfer_mode) == 0)
++		drv_ctrl = get_timing_sl82c105(&p);
++
++	if (drive->using_dma == 0) {
++		/*
++		 * If we are actually using MW DMA, then we can not
++		 * reprogram the interface drive control register.
++		 */
++		pci_write_config_word(dev, reg, drv_ctrl);
++		pci_read_config_word(dev, reg, &drv_ctrl);
++
++		if (report) {
++			printk("%s: selected %s (%dns) (%04X)\n", drive->name,
++			       ide_xfer_verbose(xfer_mode), p.cycle_time, drv_ctrl);
++		}
++	}
++}
++
++/*
++ * Configure the drive and the chipset for DMA
++ */
++static int config_for_dma(ide_drive_t *drive)
++{
++	ide_hwif_t *hwif = HWIF(drive);
++	struct pci_dev *dev = hwif->pci_dev;
++	unsigned short drv_ctrl = 0x909;
++	unsigned int reg;
++
++	reg = (hwif->channel ? 0x4c : 0x44) + (drive->select.b.unit ? 4 : 0);
++
++	if (ide_config_drive_speed(drive, XFER_MW_DMA_2) == 0)
++		drv_ctrl = 0x0240;
++
++	pci_write_config_word(dev, reg, drv_ctrl);
++
++	return 0;
++}
++
++
++/*
++ * Check to see if the drive and
++ * chipset is capable of DMA mode
++ */
++static int sl82c105_check_drive(ide_drive_t *drive)
++{
++	ide_dma_action_t dma_func = ide_dma_off_quietly;
++
++	do {
++		struct hd_driveid *id = drive->id;
++		ide_hwif_t *hwif = HWIF(drive);
++
++		if (!hwif->autodma)
++			break;
++
++		if (!id || !(id->capability & 1))
++			break;
++
++		/* Consult the list of known "bad" drives */
++		if (ide_dmaproc(ide_dma_bad_drive, drive)) {
++			dma_func = ide_dma_off;
++			break;
++		}
++
++		if (id->field_valid & 2) {
++			if  (id->dma_mword & 7 || id->dma_1word & 7)
++				dma_func = ide_dma_on;
++			break;
++		}
++
++		if (ide_dmaproc(ide_dma_good_drive, drive)) {
++			dma_func = ide_dma_on;
++			break;
++		}
++	} while (0);
++
++	return HWIF(drive)->dmaproc(dma_func, drive);
++}
++
++/*
++ * The SL82C105 holds off all IDE interrupts while in DMA mode until
++ * all DMA activity is completed.  Sometimes this causes problems (eg,
++ * when the drive wants to report an error condition).
++ *
++ * 0x7e is a "chip testing" register.  Bit 2 resets the DMA controller
++ * state machine.  We need to kick this to work around various bugs.
++ */
++static inline void sl82c105_reset_host(struct pci_dev *dev)
++{
++	u16 val;
++
++	pci_read_config_word(dev, 0x7e, &val);
++	pci_write_config_word(dev, 0x7e, val | (1 << 2));
++	pci_write_config_word(dev, 0x7e, val & ~(1 << 2));
++}
++
++/*
++ * If we get an IRQ timeout, it might be that the DMA state machine
++ * got confused.  Fix from Todd Inglett.  Details from Winbond.
++ *
++ * This function is called when the IDE timer expires, the drive
++ * indicates that it is READY, and we were waiting for DMA to complete.
++ */
++static int sl82c105_lostirq(ide_drive_t *drive)
++{
++	ide_hwif_t *hwif = HWIF(drive);
++	struct pci_dev *dev = hwif->pci_dev;
++	u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA;
++	unsigned long dma_base = hwif->dma_base;
++
++	printk("sl82c105: lost IRQ: resetting host\n");
++
++	/*
++	 * Check the raw interrupt from the drive.
++	 */
++	pci_read_config_dword(dev, 0x40, &val);
++	if (val & mask)
++		printk("sl82c105: drive was requesting IRQ, but host lost it\n");
++
++	/*
++	 * Was DMA enabled?  If so, disable it - we're resetting the
++	 * host.  The IDE layer will be handling the drive for us.
++	 */
++	val = inb(dma_base);
++	if (val & 1) {
++		outb(val & ~1, dma_base);
++		printk("sl82c105: DMA was enabled\n");
++	}
++
++	sl82c105_reset_host(dev);
++
++	/* ide_dmaproc would return 1, so we do as well */
++	return 1;
++}
++
++/*
++ * ATAPI devices can cause the SL82C105 DMA state machine to go gaga.
++ * Winbond recommend that the DMA state machine is reset prior to
++ * setting the bus master DMA enable bit.
++ *
++ * The generic IDE core will have disabled the BMEN bit before this
++ * function is called.
++ */
++static void sl82c105_before_bm_enable(ide_drive_t *drive)
++{
++	ide_hwif_t *hwif = HWIF(drive);
++	struct pci_dev *dev = hwif->pci_dev;
++
++	sl82c105_reset_host(dev);
++}
++
++/*
++ * Our very own dmaproc.  We need to intercept various calls
++ * to fix up the SL82C105 specific behaviour.
++ */
++static int sl82c105_dmaproc(ide_dma_action_t func, ide_drive_t *drive)
++{
++	switch (func) {
++	case ide_dma_check:
++		return sl82c105_check_drive(drive);
++
++	case ide_dma_on:
++		if (config_for_dma(drive))
++			func = ide_dma_off;
++		/* fall through */
++
++	case ide_dma_off_quietly:
++	case ide_dma_off:
++		config_for_pio(drive, 4, 0);
++		break;
++
++	case ide_dma_read:
++	case ide_dma_write:
++	case ide_dma_begin:
++	case ide_dma_timeout:
++		sl82c105_before_bm_enable(drive);
++		break;
++
++	case ide_dma_lostirq:
++		return sl82c105_lostirq(drive);
++
++	default:
++		break;
++	}
++	return ide_dmaproc(func, drive);
++}
++
++/*
++ * We only deal with PIO mode here - DMA mode 'using_dma' is not
++ * initialised at the point that this function is called.
++ */
++static void tune_sl82c105(ide_drive_t *drive, byte pio)
++{
++	config_for_pio(drive, pio, 1);
++
++	/*
++	 * We support 32-bit I/O on this interface, and it
++	 * doesn't have problems with interrupts.
++	 */
++	drive->io_32bit = 1;
++	drive->unmask = 1;
++}
++
++/*
++ * Return the revision of the Winbond bridge
++ * which this function is part of.
++ */
++static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
++{
++	struct pci_dev *bridge;
++	unsigned char rev;
++
++	/*
++	 * The bridge should be part of the same device, but function 0.
++	 */
++	bridge = pci_find_slot(dev->bus->number,
++			       PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
++	if (!bridge)
++		return -1;
++
++	/*
++	 * Make sure it is a Winbond 553 and is an ISA bridge.
++	 */
++	if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
++	    bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
++	    bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA)
++		return -1;
++
++	/*
++	 * We need to find function 0's revision, not function 1
++	 */
++	pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
++
++	return rev;
++}
++
++/*
++ * Enable the PCI device
++ */
++unsigned int __init pci_init_sl82c105(struct pci_dev *dev, const char *msg)
++{
++	u32 val;
++
++	pci_read_config_dword(dev, 0x40, &val);
++	val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1EN | CTRL_P1F16;
++	pci_write_config_dword(dev, 0x40, val);
++
++	return dev->irq;
++}
++
++void __init dma_init_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
++{
++	unsigned int bridge_rev;
++	byte dma_state;
++
++	dma_state = inb(dma_base + 2);
++	bridge_rev = sl82c105_bridge_revision(hwif->pci_dev);
++	if (bridge_rev <= 5) {
++		hwif->autodma = 0;
++		hwif->drives[0].autotune = 1;
++		hwif->drives[1].autotune = 1;
++		printk("    %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
++		       hwif->name, bridge_rev);
++		dma_state &= ~0x60;
++	} else {
++		dma_state |= 0x60;
++		hwif->autodma = 1;
++	}
++	outb(dma_state, dma_base + 2);
++
++	ide_setup_dma(hwif, dma_base, 8);
++
++	if (bridge_rev <= 5)
++		hwif->dmaproc = NULL;
++	else
++		hwif->dmaproc = sl82c105_dmaproc;
++}
++
++/*
++ * Initialise the chip
++ */
++void __init ide_init_sl82c105(ide_hwif_t *hwif)
++{
++	hwif->tuneproc = tune_sl82c105;
++}
++
+--- linux-2.4.25/drivers/input/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/input/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -15,5 +15,6 @@
+ dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+ dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+ dep_tristate '  User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT
++dep_tristate '  MX1 touchscreen support' CONFIG_INPUT_MX1TS $CONFIG_INPUT_MOUSEDEV $CONFIG_ARCH_MX1ADS
+ 
+ endmenu
+--- linux-2.4.25/drivers/input/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/input/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -24,6 +24,7 @@
+ obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
+ obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
+ obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o
++obj-$(CONFIG_INPUT_MX1TS)	+= mx1ts.o
+ obj-$(CONFIG_INPUT_UINPUT)	+= uinput.o
+ 
+ # The global Rules.make.
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/input/mx1ts.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,508 @@
++/*
++ *  linux/drivers/misc/mx1ts.c
++ *
++ *  Copyright (C) 2003 Blue Mug, Inc. for Motorola, Inc.
++ *
++ *  Cloned from ucb1x00_ts.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/sched.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/pm.h>
++
++#include <asm/dma.h>
++
++#include <linux/input.h>
++
++#include "mx1ts.h"
++
++#define DEV_IRQ_ID	"mx1-ts"
++
++struct mx1_ts {
++	struct input_dev	idev;
++#ifdef CONFIG_PM
++	struct pm_dev		*pmdev;
++#endif
++
++	wait_queue_head_t	irq_wait;
++	struct completion	init_exit;
++	int			use_count;
++	u16			x_res;
++	u16			y_res;
++
++	int			restart:1;
++};
++
++static struct mx1_ts mx1ts;
++static u8 mx1_performing_auto_calibration = 0;
++static u16 mx1_cal_auto_zero = 0;
++static u16 mx1_cal_range_x = 0;
++static u16 mx1_cal_range_y = 0;
++
++static int mx1_ts_startup(struct mx1_ts *ts);
++static void mx1_ts_shutdown(struct mx1_ts *ts);
++
++static void mx1_ts_pendata_int(int irq, void *dev_id, struct pt_regs *regs);
++static void mx1_ts_touch_int(int irq, void *dev_id, struct pt_regs *regs);
++static void mx1_ts_compare_int(int irq, void *dev_id, struct pt_regs *regs);
++
++static void mx1_ts_enable_pen_touch_interrupt(void);
++static void mx1_ts_disable_pen_touch_interrupt(void);
++static void mx1_ts_enable_pen_up_interrupt(void);
++static void mx1_ts_disable_pen_up_interrupt(void);
++static void mx1_ts_enable_auto_sample(void);
++static void mx1_ts_disable_auto_sample(void);
++static void mx1_ts_start_auto_calibration(void);
++
++static inline void mx1_reg_write(unsigned int reg, unsigned int val)
++{
++	*((volatile unsigned int *)reg) = val;
++}
++
++static inline unsigned int mx1_reg_read(unsigned int reg)
++{
++	return *((volatile unsigned int *)reg);
++}
++
++static inline void mx1_reg_clear_bit(unsigned int reg, unsigned int bit)
++{
++	*((volatile unsigned int *)reg) &= ~bit;
++}
++
++static inline void mx1_reg_set_bit(unsigned int reg, unsigned int bit)
++{
++	*((volatile unsigned int *)reg) |= bit;
++}
++
++static inline void mx1_ts_evt_add(struct mx1_ts *ts, u16 pressure, u16 x, u16 y)
++{
++	input_report_abs(&ts->idev, ABS_X, (int)x - 32768);
++	input_report_abs(&ts->idev, ABS_Y, (int)y - 32768);
++	input_report_abs(&ts->idev, ABS_PRESSURE, (int)pressure);
++}
++
++static inline void mx1_ts_flush_fifo(void)
++{
++	int i;
++	for (i = 0; i < 12; i++)
++		if (mx1_reg_read(ASP_ISTATR) & (ASP_PFF | ASP_PDR))
++			mx1_reg_read(ASP_PADFIFO);
++}
++
++static int mx1_ts_open(struct input_dev *idev)
++{
++	struct mx1_ts *ts = (struct mx1_ts *)idev;
++
++	mx1_performing_auto_calibration = 0;
++	return mx1_ts_startup(ts);
++}
++
++static void mx1_ts_close(struct input_dev *idev)
++{
++	struct mx1_ts *ts = (struct mx1_ts *)idev;
++
++	mx1_ts_shutdown(ts);
++}
++
++static inline int mx1_ts_enable_irqs(void)
++{
++	int result;
++
++	result = request_irq(ASP_PENDATA_IRQ,
++			     mx1_ts_pendata_int,
++			     SA_INTERRUPT,
++			     DEV_IRQ_ID,
++			     DEV_IRQ_ID);
++	if (result) {
++		printk("Couldn't request pen data IRQ.\n");
++		return result;
++	}
++
++	result = request_irq(ASP_TOUCH_IRQ,
++			     mx1_ts_touch_int,
++			     SA_INTERRUPT,
++			     DEV_IRQ_ID,
++			     DEV_IRQ_ID);
++	if (result) {
++		printk("Couldn't request pen touch IRQ.\n");
++		free_irq(ASP_PENDATA_IRQ, DEV_IRQ_ID);
++		return result;
++	}
++
++	return result;
++}
++
++static inline int mx1_ts_disable_irqs(void)
++{
++	free_irq(ASP_PENDATA_IRQ, DEV_IRQ_ID);
++	free_irq(ASP_TOUCH_IRQ, DEV_IRQ_ID);
++
++	return 0;
++}
++
++static inline int mx1_ts_register(struct mx1_ts *ts)
++{
++	ts->idev.name      = "Touchscreen panel";
++	ts->idev.open      = mx1_ts_open;
++	ts->idev.close     = mx1_ts_close;
++
++	__set_bit(EV_ABS, ts->idev.evbit);
++	__set_bit(ABS_X, ts->idev.absbit);
++	__set_bit(ABS_Y, ts->idev.absbit);
++	__set_bit(ABS_PRESSURE, ts->idev.absbit);
++
++	ts->idev.absmin[ABS_X] = 0;
++	ts->idev.absmax[ABS_X] = (u32)0x0000FFFF;
++	ts->idev.absfuzz[ABS_X] = 50;
++	ts->idev.absflat[ABS_X] = 0;
++
++	ts->idev.absmin[ABS_Y] = 0;
++	ts->idev.absmax[ABS_Y] = (u32)0x0000FFFF;
++	ts->idev.absfuzz[ABS_Y] = 50;
++	ts->idev.absflat[ABS_Y] = 0;
++
++	input_register_device(&ts->idev);
++
++	return 0;
++}
++
++static inline void mx1_ts_deregister(struct mx1_ts *ts)
++{
++	input_unregister_device(&ts->idev);
++}
++
++/*
++ * Handle the touch interrupt, generated when the pen is pressed/
++ * released.
++ */
++static void mx1_ts_touch_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	/* Clear the interrupt. */
++	mx1_reg_set_bit(ASP_ISTATR, ASP_PEN);
++
++	mx1_ts_disable_pen_touch_interrupt();
++	mx1_ts_start_auto_calibration();
++	mx1_ts_enable_pen_up_interrupt();
++}
++
++/*
++ * Handle the pen data ready interrupt, generated when pen data is
++ * in the FIFO.
++ */
++static void mx1_ts_pendata_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	static unsigned int auto_zero, pen_x, pen_y, pen_u;
++
++	if (mx1_reg_read(ASP_ISTATR) & 0x400) {
++		mx1_reg_set_bit(ASP_ISTATR, 0x400);
++
++		mx1_ts_disable_auto_sample();
++		mx1_ts_disable_pen_up_interrupt();
++		mx1_ts_enable_pen_touch_interrupt();
++
++		mx1_ts_evt_add(&mx1ts, 0, pen_x, pen_y);
++
++		mx1_ts_flush_fifo();
++
++		return;
++	}
++
++	if (mx1_performing_auto_calibration) {
++		unsigned int value;
++
++		mx1_cal_auto_zero = mx1_reg_read(ASP_PADFIFO) & 0xFFFF;
++		mx1_cal_range_x = mx1_reg_read(ASP_PADFIFO) & 0xFFFF;
++		mx1_cal_range_y = mx1_reg_read(ASP_PADFIFO) & 0xFFFF;
++
++		if ((mx1_cal_auto_zero >= mx1_cal_range_x) ||
++		    (mx1_cal_auto_zero >= mx1_cal_range_y)) {
++			/* Invalid data. */
++			mx1_ts_start_auto_calibration();
++			return;
++		}
++
++		mx1_cal_range_x -= mx1_cal_auto_zero;
++		mx1_cal_range_y -= mx1_cal_auto_zero;
++
++		value = mx1_reg_read(ASP_ACNTLCR);
++		value &= ~0x04000000; /* XXX Undocumented. */
++		mx1_reg_write(ASP_ACNTLCR, value);
++
++		mx1_performing_auto_calibration = 0;
++
++		mx1_ts_enable_auto_sample();
++	} else {
++		/* There could be more than one sample in the FIFO, but we're
++		 * only going to read one per call. The interrupt will be
++		 * generated as long as there is data in the FIFO. */
++
++		if ((mx1_reg_read(ASP_ISTATR) & ASP_PDR) != ASP_PDR) {
++			return;
++		}
++
++		auto_zero = mx1_reg_read(ASP_PADFIFO);
++		if (auto_zero > (mx1_cal_auto_zero + 0x200)) {
++			return;
++		}
++
++		pen_x = mx1_reg_read(ASP_PADFIFO);
++		pen_y = mx1_reg_read(ASP_PADFIFO);
++		pen_u = mx1_reg_read(ASP_PADFIFO);
++
++		pen_x = (u32)(((pen_x - mx1_cal_auto_zero) << 16) /
++			      mx1_cal_range_x);
++		pen_y = (u32)(((pen_y - mx1_cal_auto_zero) << 16) /
++			      mx1_cal_range_y);
++
++		mx1_ts_evt_add(&mx1ts, pen_u, pen_x, pen_y);
++	}
++}
++
++static void mx1_ts_reset_asp(void)
++{
++	unsigned int value;
++
++	mx1_ts_flush_fifo();
++
++	/* Soft reset the ASP module */
++        mx1_reg_write(ASP_ACNTLCR, ASP_SWRST);
++
++	/* Read back the reset value of the control register */
++	value = mx1_reg_read(ASP_ACNTLCR);
++
++	/* Enable the clock and wait for a short while */
++	value |= ASP_CLKEN;
++        mx1_reg_write(ASP_ACNTLCR, value);
++	udelay(100);
++
++	/* Set the value of the conrtol register. */
++	value = ASP_CLKEN | ASP_NM | ASP_SW6 | ASP_BGE;
++        mx1_reg_write(ASP_ACNTLCR, value);
++
++	/* Set the clock divide ratio to 2. */
++	mx1_reg_write(ASP_CLKDIV, 0x01);
++
++	/* Set the sample rate control register. These values should yield
++         * about 150 samples per second, which seems to give good smooth
++         * lines. */
++	value = (0x2 << ASP_DMCNT_SCALE) | 	/* Decimation ratio is 3 */
++		(0x1 << ASP_IDLECNT_SCALE) | 	/* Idle count is 1 clock */
++		(0x2 << ASP_DSCNT_SCALE);	/* Data setup is 2 clocks */
++	mx1_reg_write(ASP_PSMPLRG, value);
++
++	/* Disable the compare function. */
++	mx1_reg_write(ASP_CMPCNTL, 0);
++}
++
++static void mx1_ts_enable_auto_sample(void)
++{
++	unsigned int value;
++
++	mx1_ts_flush_fifo();
++
++	value = mx1_reg_read(ASP_ACNTLCR);
++
++	/* Set the mode to X then Y */
++	value &= ~ASP_MODE_MASK;
++	value |= ASP_MODE_ONLY_Y;
++
++	/* Enable auto zero. */
++	value |= ASP_AZE;
++
++	/* Enable auto sample. */
++	value |= ASP_AUTO;
++
++	/* Enable pen A/D. */
++	value |= ASP_PADE;
++	mx1_reg_write(ASP_ACNTLCR, value);
++
++	/* Enable pen data ready and full interrupt. */
++	value = mx1_reg_read(ASP_ICNTLR);
++	value |= ASP_PFFE | ASP_PDRE;
++	mx1_reg_write(ASP_ICNTLR, value);
++}
++
++static void mx1_ts_disable_auto_sample(void)
++{
++	unsigned int value;
++
++	value = mx1_reg_read(ASP_ACNTLCR);
++
++	/* Set the mode to none */
++	value &= ~ASP_MODE_MASK;
++
++	/* Disable auto zero. */
++	value &= ~ASP_AZE;
++
++	/* Disable auto sample. */
++	value &= ~ASP_AUTO;
++
++	/* Disable pen A/D. */
++	value &= ~ASP_PADE;
++	mx1_reg_write(ASP_ACNTLCR, value);
++
++	/* Disable pen data ready and full interrupt. */
++	value = mx1_reg_read(ASP_ICNTLR);
++	value &= ~(ASP_PFFE | ASP_PDRE);
++	mx1_reg_write(ASP_ICNTLR, value);
++}
++
++static void mx1_ts_enable_pen_touch_interrupt(void)
++{
++	unsigned int value;
++
++	/* Enable pen touch interrupt. */
++	value = mx1_reg_read(ASP_ICNTLR);
++	value |= ASP_EDGE | ASP_PIRQE;
++	mx1_reg_write(ASP_ICNTLR, value);
++}
++
++static void mx1_ts_disable_pen_touch_interrupt(void)
++{
++	unsigned int value;
++
++	/* Enable pen touch interrupt. */
++	value = mx1_reg_read(ASP_ICNTLR);
++	value &= ~ASP_PIRQE;
++	mx1_reg_write(ASP_ICNTLR, value);
++}
++
++static void mx1_ts_enable_pen_up_interrupt(void)
++{
++	unsigned int value;
++
++	/* Enable pen up interrupt. XXX: This feature is undocumented. */
++	value = mx1_reg_read(ASP_ICNTLR);
++	value |= ASP_PUPE;
++	mx1_reg_write(ASP_ICNTLR, value);
++}
++
++static void mx1_ts_disable_pen_up_interrupt(void)
++{
++	unsigned int value;
++
++	/* Enable pen up interrupt. XXX: This feature is undocumented. */
++	value = mx1_reg_read(ASP_ICNTLR);
++	value &= ~ASP_PUPE;
++	mx1_reg_write(ASP_ICNTLR, value);
++}
++
++static void mx1_ts_start_auto_calibration(void)
++{
++	unsigned int value;
++
++	mx1_performing_auto_calibration = 1;
++
++	value = mx1_reg_read(ASP_ACNTLCR);
++
++	/* Set the mode to X then Y */
++	value &= ~ASP_MODE_MASK;
++	value |= ASP_MODE_ONLY_X;
++
++	/* Enable auto zero. */
++	value |= ASP_AZE;
++
++	/* Enable auto calibrate. XXX: Undocumented bitfield. */
++	value |= 0x04000000;
++
++	/* Enable auto sample. */
++	value |= ASP_AUTO;
++
++	/* Enable pen A/D. */
++	value |= ASP_PADE;
++	mx1_reg_write(ASP_ACNTLCR, value);
++
++	/* Enable pen data ready and full interrupt. */
++	value = mx1_reg_read(ASP_ICNTLR);
++	value |= ASP_PFFE | ASP_PDRE | ASP_PUPE;
++	mx1_reg_write(ASP_ICNTLR, value);
++}
++
++static int mx1_ts_startup(struct mx1_ts *ts)
++{
++	int ret = 0;
++
++	if (ts->use_count++ != 0)
++		goto out;
++
++        /*
++         * Reset the ASP.
++         */
++        mx1_ts_reset_asp();
++
++
++	/*
++	 * XXX: Figure out if we need this...
++	 * If we do this at all, we should allow the user to
++	 * measure and read the X and Y resistance at any time.
++	 */
++	//ts->x_res = mx1_ts_read_xres(ts);
++	//ts->y_res = mx1_ts_read_yres(ts);
++
++	mx1_ts_enable_pen_touch_interrupt();
++
++ out:
++	if (ret)
++		ts->use_count--;
++	return ret;
++}
++
++/*
++ * Release touchscreen resources.  Disable IRQs.
++ */
++static void mx1_ts_shutdown(struct mx1_ts *ts)
++{
++	if (--ts->use_count == 0) {
++		unsigned int value;
++
++		/* Turn off the ADC and associated circuitry. */
++		value = mx1_reg_read(ASP_ACNTLCR);
++		value &= !(ASP_CLKEN | ASP_PADE | ASP_BGE);
++		mx1_reg_write(ASP_ACNTLCR, value);
++	}
++}
++
++/*
++ * Initialization.
++ */
++static int __init mx1_ts_init(void)
++{
++	int ret = 0;
++	struct mx1_ts *ts = &mx1ts;
++
++	mx1_ts_reset_asp();
++
++	/*
++	 * Enable the IRQ's
++	 */
++	if ((ret = mx1_ts_enable_irqs()))
++		return ret;
++
++	return mx1_ts_register(ts);
++}
++
++static void __exit mx1_ts_exit(void)
++{
++	struct mx1_ts *ts = &mx1ts;
++
++	mx1_ts_disable_irqs();
++	mx1_ts_deregister(ts);
++}
++
++module_init(mx1_ts_init);
++module_exit(mx1_ts_exit);
++
++MODULE_AUTHOR("Jon McClintock <jonm@bluemug.com>");
++MODULE_DESCRIPTION("MX1 touchscreen driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/input/mx1ts.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,108 @@
++/*
++ *  linux/drivers/misc/mx1ts.h
++ *
++ *  Copyright (C) 2003 Blue Mug, Inc. for Motorola, Inc.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++/* Interrupt numbers */
++#define ASP_COMPARE_IRQ         5
++#define ASP_PENDATA_IRQ         33
++#define ASP_TOUCH_IRQ           46
++
++/* Analog signal processor (ASP) control registers */
++#define ASP_ACNTLCR		0xF0215010      /* Control register */
++#define ASP_PSMPLRG		0xF0215014      /* Pen A/D sampe rate control */
++#define ASP_CMPCNTL		0xF0215030      /* Compare control register */
++#define ASP_ICNTLR		0xF0215018      /* Interrupt control register */
++#define ASP_ISTATR		0xF021501C      /* Interrupt status register */
++#define ASP_PADFIFO		0xF0215000      /* Pen sample FIFO */
++#define ASP_CLKDIV		0xF021502C      /* Clock divide register */
++
++/* ASP control register bits */
++#define ASP_CLKEN               (1 << 25)       /* Clock enable */
++#define ASP_SWRST               (1 << 23)       /* Software reset */
++#define ASP_U_SEL               (1 << 21)       /* U-channel resistor select */
++#define ASP_AZ_SEL              (1 << 20)       /* Auto-zero position select */
++#define ASP_LVM                 (1 << 19)       /* Low voltage output */
++#define ASP_NM                  (1 << 18)       /* Normal voltage output */
++#define ASP_HPM                 (1 << 17)       /* High voltage output */
++#define ASP_GLO                 (1 << 16)       /* Low gain enable */
++#define ASP_AZE                 (1 << 15)       /* Auto-zero enable */
++#define ASP_AUTO                (1 << 14)       /* Auto sampling */
++#define ASP_SW8                 (1 << 11)       /* Switch control 8 */
++#define ASP_SW7                 (1 << 10)
++#define ASP_SW6                 (1 << 9)
++#define ASP_SW5                 (1 << 8)
++#define ASP_SW4                 (1 << 7)
++#define ASP_SW3                 (1 << 6)
++#define ASP_SW2                 (1 << 5)
++#define ASP_SW1                 (1 << 4)        /* Switch control 1 */
++#define ASP_VDAE                (1 << 3)        /* Voice D/A enable */
++#define ASP_VADE                (1 << 2)        /* Voice A/D enable */
++#define ASP_PADE                (1 << 1)        /* Pen A/D enable */
++#define ASP_BGE                 (1 << 0)        /* Bandgap enable */
++
++#define ASP_MODE_MASK           0x00003000
++#define ASP_MODE_NONE           0x00000000
++#define ASP_MODE_ONLY_X         0x00001000
++#define ASP_MODE_ONLY_Y         0x00002000
++#define ASP_MODE_ONLY_U         0x00003000
++
++/* ASP Pen A/D sample rate control register */
++#define ASP_DMCNT_MASK          (0x00007000)    /* Decimation ratio count */
++#define ASP_DMCNT_SCALE         (12)
++#define ASP_BIT_SELECT_MASK     (0x00000C00)    /* Bit select */
++#define ASP_BIT_SELECT_SCALE    (10)
++#define ASP_IDLECNT_MASK        (0x000003F0)    /* Idle count */
++#define ASP_IDLECNT_SCALE       (4)
++#define ASP_DSCNT_MASK          (0x0000000F)    /* Data setup count */
++#define ASP_DSCNT_SCALE         (0)
++
++/* ASP compare control register */
++#define ASP_INT                 (1 << 19)       /* Interrupt status */
++#define ASP_CC                  (1 << 18)       /* Trigger on greater than */
++#define ASP_INSEL_MASK          (0x00030000)
++#define ASP_INSEL_DISABLE       (0x00000000)
++#define ASP_INSEL_X             (0x00010000)
++#define ASP_INSEL_Y             (0x00020000)
++#define ASP_INSEL_U             (0x00030000)
++#define ASP_COMPARE_VAL_MASK    (0x0000FFFF)
++#define ASP_COMPARE_VAL_SCALE   (0)
++
++/* ASP interrupt control register bits */
++#define ASP_PUPE                (1 << 10)       /* Pen up XXX undocumented */
++#define ASP_VDDMAE              (1 << 8)        /* VDAC FIFO empty DMA */
++#define ASP_VADMAE              (1 << 7)        /* VADC FIFO full DMA */
++#define ASP_POL                 (1 << 6)        /* Pen interrupt polarity */
++#define ASP_EDGE                (1 << 5)        /* Edge trigger enable */
++#define ASP_PIRQE               (1 << 4)        /* Pen interrupt enable */
++#define ASP_VDAFEE              (1 << 3)        /* VDAC FIFO empty interrupt */
++#define ASP_VADFFE              (1 << 2)        /* VADC FIFO full interrupt */
++#define ASP_PFFE                (1 << 1)        /* Pen FIFO full interrupt */
++#define ASP_PDRE                (1 << 0)        /* Pen data ready interrupt */
++
++/* ASP interrupt/error status register bits */
++#define ASP_PUP                 (1 << 10)       /* Pen up XXX undocumented */
++#define ASP_BGR                 (1 << 9)        /* Bandgap ready */
++#define ASP_VOV                 (1 << 8)        /* Voice sample data overflow */
++#define ASP_POV                 (1 << 7)        /* Pen sample data overflow */
++#define ASP_PEN                 (1 << 6)        /* Pen interrupt */
++#define ASP_VDAFF               (1 << 5)        /* VDAC FIFO full */
++#define ASP_VDAFE               (1 << 4)        /* VDAC FIFO empty */
++#define ASP_VADFF               (1 << 3)        /* VADC FIFO full */
++#define ASP_VADDR               (1 << 2)        /* VADC data ready */
++#define ASP_PFF                 (1 << 1)        /* Pen sample FIFO full */
++#define ASP_PDR                 (1 << 0)        /* Pen data ready */
++
++/* ASP Clock divide register */
++#define ASP_PADC_CLK_MASK       (0x0000001F)
++#define ASP_PADC_CLK_SCALE      (0)
++#define ASP_VADC_CLK_MASK       (0x000003E0)
++#define ASP_VADC_CLK_SCALE      (5)
++#define ASP_VDAC_CLK_MASK       (0x00003C00)
++#define ASP_VDAC_CLK_SCALE      (10)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/l3/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,21 @@
++#
++# L3 bus configuration
++#
++mainmenu_option next_comment
++comment 'L3 serial bus support'
++
++tristate 'L3 support' CONFIG_L3
++dep_bool '  L3 bit-banging interfaces' CONFIG_L3_ALGOBIT $CONFIG_L3
++dep_bool '    SA11x0 GPIO adapter' CONFIG_L3_BIT_SA1100_GPIO $CONFIG_L3_ALGOBIT $CONFIG_ARCH_SA1100
++
++comment 'Other L3 adapters'
++dep_bool '  SA1111 adapter' CONFIG_L3_SA1111 $CONFIG_L3
++endmenu
++
++# i2c must come before this
++if [ "$CONFIG_L3_BIT_SA1100_GPIO" = "y" -o \
++     "$CONFIG_I2C_BIT_SA1100_GPIO" = "y" ]; then
++   define_bool CONFIG_BIT_SA1100_GPIO y
++else
++   define_bool CONFIG_BIT_SA1100_GPIO n
++fi
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/l3/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,23 @@
++#
++# Makefile for the L3 bus driver.
++#
++
++O_TARGET := l3.o
++
++export-objs	:= l3-core.o l3-algo-bit.o
++l3-y		:=
++l3-n		:=
++l3-drv-y	:=
++l3-drv-n	:=
++
++# Link order:
++#  (core, adapters, algorithms, drivers) then clients
++
++l3-$(CONFIG_L3_ALGOBIT)		+= l3-algo-bit.o
++l3-$(CONFIG_BIT_SA1100_GPIO)	+= l3-bit-sa1100.o
++l3-$(CONFIG_L3_SA1111)		+= l3-sa1111.o
++
++obj-$(CONFIG_L3)		+= l3-core.o $(l3-y) $(l3-drv-y)
++
++include $(TOPDIR)/Rules.make
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/l3/l3-algo-bit.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,175 @@
++/*
++ * L3 bus algorithm module.
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Note that L3 buses can share the same pins as I2C buses, so we must
++ *  _not_ generate an I2C start condition.  An I2C start condition is
++ *  defined as a high-to-low transition of the data line while the clock
++ *  is high.  Therefore, we must only change the data line while the
++ *  clock is low.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/l3/l3.h>
++#include <linux/l3/algo-bit.h>
++
++#define setdat(adap,val)	adap->setdat(adap->data, val)
++#define setclk(adap,val)	adap->setclk(adap->data, val)
++#define setmode(adap,val)	adap->setmode(adap->data, val)
++#define setdatin(adap)		adap->setdir(adap->data, 1)
++#define setdatout(adap)		adap->setdir(adap->data, 0)
++#define getdat(adap)		adap->getdat(adap->data)
++
++/*
++ * Send one byte of data to the chip.  Data is latched into the chip on
++ * the rising edge of the clock.
++ */
++static void sendbyte(struct l3_algo_bit_data *adap, unsigned int byte)
++{
++	int i;
++
++	for (i = 0; i < 8; i++) {
++		setclk(adap, 0);
++		udelay(adap->data_hold);
++		setdat(adap, byte & 1);
++		udelay(adap->data_setup);
++		setclk(adap, 1);
++		udelay(adap->clock_high);
++		byte >>= 1;
++	}
++}
++
++/*
++ * Send a set of bytes to the chip.  We need to pulse the MODE line
++ * between each byte, but never at the start nor at the end of the
++ * transfer.
++ */
++static void sendbytes(struct l3_algo_bit_data *adap, const char *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++) {
++		if (i) {
++			udelay(adap->mode_hold);
++			setmode(adap, 0);
++			udelay(adap->mode);
++		}
++		setmode(adap, 1);
++		udelay(adap->mode_setup);
++		sendbyte(adap, buf[i]);
++	}
++}
++
++/*
++ * Read one byte of data from the chip.  Data is latched into the chip on
++ * the rising edge of the clock.
++ */
++static unsigned int readbyte(struct l3_algo_bit_data *adap)
++{
++	unsigned int byte = 0;
++	int i;
++
++	for (i = 0; i < 8; i++) {
++		setclk(adap, 0);
++		udelay(adap->data_hold + adap->data_setup);
++		setclk(adap, 1);
++		if (getdat(adap))
++			byte |= 1 << i;
++		udelay(adap->clock_high);
++	}
++
++	return byte;
++}
++
++/*
++ * Read a set of bytes from the chip.  We need to pulse the MODE line
++ * between each byte, but never at the start nor at the end of the
++ * transfer.
++ */
++static void readbytes(struct l3_algo_bit_data *adap, char *buf, int len)
++{
++	int i;
++
++	for (i = 0; i < len; i++) {
++		if (i) {
++			udelay(adap->mode_hold);
++			setmode(adap, 0);
++		}
++		setmode(adap, 1);
++		udelay(adap->mode_setup);
++		buf[i] = readbyte(adap);
++	}
++}
++
++static int l3_xfer(struct l3_adapter *l3_adap, struct l3_msg msgs[], int num)
++{
++	struct l3_algo_bit_data *adap = l3_adap->algo_data;
++	int i;
++
++	/*
++	 * If we share an I2C bus, ensure that it is in STOP mode
++	 */
++	setclk(adap, 1);
++	setdat(adap, 1);
++	setmode(adap, 1);
++	setdatout(adap);
++	udelay(adap->mode);
++
++	for (i = 0; i < num; i++) {
++		struct l3_msg *pmsg = &msgs[i];
++
++		if (!(pmsg->flags & L3_M_NOADDR)) {
++			setmode(adap, 0);
++			udelay(adap->mode_setup);
++			sendbyte(adap, pmsg->addr);
++			udelay(adap->mode_hold);
++		}
++
++		if (pmsg->flags & L3_M_RD) {
++			setdatin(adap);
++			readbytes(adap, pmsg->buf, pmsg->len);
++		} else {
++			setdatout(adap);
++			sendbytes(adap, pmsg->buf, pmsg->len);
++		}
++	}
++
++	/*
++	 * Ensure that we leave the bus in I2C stop mode.
++	 */
++	setclk(adap, 1);
++	setdat(adap, 1);
++	setmode(adap, 0);
++	setdatin(adap);
++
++	return num;
++}
++
++static struct l3_algorithm l3_bit_algo = {
++	name:	"L3 bit-shift algorithm",
++	xfer:	l3_xfer,
++};
++
++int l3_bit_add_bus(struct l3_adapter *adap)
++{
++	adap->algo = &l3_bit_algo;
++	return l3_add_adapter(adap);
++}
++
++int l3_bit_del_bus(struct l3_adapter *adap)
++{
++	return l3_del_adapter(adap);
++}
++
++EXPORT_SYMBOL(l3_bit_add_bus);
++EXPORT_SYMBOL(l3_bit_del_bus);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/l3/l3-bit-sa1100.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,277 @@
++/*
++ *  linux/drivers/l3/l3-bit-sa1100.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  This is a combined I2C and L3 bus driver.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/ioport.h>
++#include <linux/delay.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/i2c-algo-bit.h>
++#include <linux/l3/algo-bit.h>
++
++#include <asm/system.h>
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/arch/assabet.h>
++
++#define NAME "l3-bit-sa1100-gpio"
++
++struct bit_data {
++	unsigned int	sda;
++	unsigned int	scl;
++	unsigned int	l3_mode;
++};
++
++static int getsda(void *data)
++{
++	struct bit_data *bits = data;
++
++	return GPLR & bits->sda;
++}
++
++#ifdef CONFIG_I2C_BIT_SA1100_GPIO
++static void i2c_setsda(void *data, int state)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (state)
++		GPDR &= ~bits->sda;
++	else {
++		GPCR = bits->sda;
++		GPDR |= bits->sda;
++	}
++	local_irq_restore(flags);
++}
++
++static void i2c_setscl(void *data, int state)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (state)
++		GPDR &= ~bits->scl;
++	else {
++		GPCR = bits->scl;
++		GPDR |= bits->scl;
++	}
++	local_irq_restore(flags);
++}
++
++static int i2c_getscl(void *data)
++{
++	struct bit_data *bits = data;
++
++	return GPLR & bits->scl;
++}
++
++static struct i2c_algo_bit_data i2c_bit_data = {
++	setsda:		i2c_setsda,
++	setscl:		i2c_setscl,
++	getsda:		getsda,
++	getscl:		i2c_getscl,
++	udelay:		10,
++	mdelay:		10,
++	timeout:	100,
++};
++
++static struct i2c_adapter i2c_adapter = {
++	name:			NAME,
++	algo_data:		&i2c_bit_data,
++//	inc_use:		i2c_inc_use,
++//	dec_use:		i2c_dec_use,
++};
++
++#define LOCK	&i2c_adapter.lock
++
++static int __init i2c_init(struct bit_data *bits)
++{
++	i2c_bit_data.data = bits;
++	return i2c_bit_add_bus(&i2c_adapter);
++}
++
++static void i2c_exit(void)
++{
++	i2c_bit_del_bus(&i2c_adapter);
++}
++
++#else
++static DECLARE_MUTEX(l3_lock);
++#define LOCK		&l3_lock
++#define i2c_init(bits)	(0)
++#define i2c_exit()	do { } while (0)
++#endif
++
++#ifdef CONFIG_L3_BIT_SA1100_GPIO
++/*
++ * iPAQs need the clock line driven hard high and low.
++ */
++static void l3_setscl(void *data, int state)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (state)
++		GPSR = bits->scl;
++	else
++		GPCR = bits->scl;
++	GPDR |= bits->scl;
++	local_irq_restore(flags);
++}
++
++static void l3_setsda(void *data, int state)
++{
++	struct bit_data *bits = data;
++
++	if (state)
++		GPSR = bits->sda;
++	else
++		GPCR = bits->sda;
++}
++
++static void l3_setdir(void *data, int in)
++{
++	struct bit_data *bits = data;
++	unsigned long flags;
++
++	local_irq_save(flags);
++	if (in)
++		GPDR &= ~bits->sda;
++	else
++		GPDR |= bits->sda;
++	local_irq_restore(flags);
++}
++
++static void l3_setmode(void *data, int state)
++{
++	struct bit_data *bits = data;
++
++	if (state)
++		GPSR = bits->l3_mode;
++	else
++		GPCR = bits->l3_mode;
++}
++
++static struct l3_algo_bit_data l3_bit_data = {
++	data:		NULL,
++	setdat:		l3_setsda,
++	setclk:		l3_setscl,
++	setmode:	l3_setmode,
++	setdir:		l3_setdir,
++	getdat:		getsda,
++	data_hold:	1,
++	data_setup:	1,
++	clock_high:	1,
++	mode_hold:	1,
++	mode_setup:	1,
++};
++
++static struct l3_adapter l3_adapter = {
++	owner:		THIS_MODULE,
++	name:		NAME,
++	algo_data:	&l3_bit_data,
++	lock:		LOCK,
++};
++
++static int __init l3_init(struct bit_data *bits)
++{
++	l3_bit_data.data = bits;
++	return l3_bit_add_bus(&l3_adapter);
++}
++
++static void __exit l3_exit(void)
++{
++	l3_bit_del_bus(&l3_adapter);
++}
++#else
++#define l3_init(bits)	(0)
++#define l3_exit()	do { } while (0)
++#endif
++
++static struct bit_data bit_data;
++
++static int __init bus_init(void)
++{
++	struct bit_data *bit = &bit_data;
++	unsigned long flags;
++	int ret;
++
++	if (machine_is_assabet() || machine_is_pangolin()) {
++		bit->sda     = GPIO_GPIO15;
++		bit->scl     = GPIO_GPIO18;
++		bit->l3_mode = GPIO_GPIO17;
++	}
++
++#if defined(CONFIG_SA1100_H3600) || defined(CONFIG_SA1100_H3100)  
++	if (machine_is_h3600() || machine_is_h3100()) {
++		bit->sda     = GPIO_H3600_L3_DATA;
++		bit->scl     = GPIO_H3600_L3_CLOCK;
++		bit->l3_mode = GPIO_H3600_L3_MODE;
++	}
++#endif
++
++#ifdef CONFIG_SA1100_STORK
++	if (machine_is_stork()) {
++		bit->sda     = GPIO_STORK_L3_I2C_SDA;
++		bit->scl     = GPIO_STORK_L3_I2C_SCL;
++		bit->l3_mode = GPIO_STORK_L3_MODE;
++	}
++#endif
++
++	if (!bit->sda)
++		return -ENODEV;
++
++	/*
++	 * Default level for L3 mode is low.
++	 * We set SCL and SDA high (i2c idle state).
++	 */
++	local_irq_save(flags);
++	GPDR &= ~(bit->scl | bit->sda);
++	GPCR = bit->l3_mode | bit->scl | bit->sda;
++	GPDR |= bit->l3_mode;
++	local_irq_restore(flags);
++
++	if (machine_is_assabet()) {
++		/*
++		 * Release reset on UCB1300, ADI7171 and UDA1341.  We
++		 * need to do this here so that we can communicate on
++		 * the I2C/L3 buses.
++		 */
++		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
++		mdelay(1);
++		ASSABET_BCR_clear(ASSABET_BCR_CODEC_RST);
++		mdelay(1);
++		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
++	}
++
++	ret = i2c_init(bit);
++	if (ret == 0 && bit->l3_mode) {
++		ret = l3_init(bit);
++		if (ret)
++			i2c_exit();
++	}
++
++	return ret;
++}
++
++static void __exit bus_exit(void)
++{
++	l3_exit();
++	i2c_exit();
++}
++
++module_init(bus_init);
++module_exit(bus_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/l3/l3-core.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,377 @@
++/*
++ *  linux/drivers/l3/l3-core.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ *  General structure taken from i2c-core.c by Simon G. Vogl
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  See linux/Documentation/l3 for further documentation.
++ */
++#include <linux/module.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/proc_fs.h>
++#include <linux/kmod.h>
++#include <linux/init.h>
++#include <linux/l3/l3.h>
++
++static DECLARE_MUTEX(adapter_lock);
++static LIST_HEAD(adapter_list);
++
++static DECLARE_MUTEX(driver_lock);
++static LIST_HEAD(driver_list);
++
++/**
++ * l3_add_adapter - register a new L3 bus adapter
++ * @adap: l3_adapter structure for the registering adapter
++ *
++ * Make the adapter available for use by clients using name adap->name.
++ * The adap->adapters list is initialised by this function.
++ *
++ * Returns 0;
++ */
++int l3_add_adapter(struct l3_adapter *adap)
++{
++	INIT_LIST_HEAD(&adap->clients);
++	down(&adapter_lock);
++	list_add(&adap->adapters, &adapter_list);
++	up(&adapter_lock);
++	return 0;	
++}
++
++/**
++ * l3_del_adapter - unregister a L3 bus adapter
++ * @adap: l3_adapter structure to unregister
++ *
++ * Remove an adapter from the list of available L3 Bus adapters.
++ *
++ * Returns 0;
++ */
++int l3_del_adapter(struct l3_adapter *adap)
++{
++	down(&adapter_lock);
++	list_del(&adap->adapters);
++	up(&adapter_lock);
++	return 0;
++}
++
++static struct l3_adapter *__l3_get_adapter(const char *name)
++{
++	struct list_head *l;
++
++	list_for_each(l, &adapter_list) {
++		struct l3_adapter *adap = list_entry(l, struct l3_adapter, adapters);
++
++		if (strcmp(adap->name, name) == 0)
++			return adap;
++	}
++
++	return NULL;
++}
++
++/**
++ * l3_get_adapter - get a reference to an adapter
++ * @name: driver name
++ *
++ * Obtain a l3_adapter structure for the specified adapter.  If the adapter
++ * is not currently load, then load it.  The adapter will be locked in core
++ * until all references are released via l3_put_adapter.
++ */
++struct l3_adapter *l3_get_adapter(const char *name)
++{
++	struct l3_adapter *adap;
++	int try;
++
++	for (try = 0; try < 2; try ++) {
++		down(&adapter_lock);
++		adap = __l3_get_adapter(name);
++		if (adap && !try_inc_mod_count(adap->owner))
++			adap = NULL;
++		up(&adapter_lock);
++
++		if (adap)
++			break;
++
++		if (try == 0)
++			request_module(name);
++	}
++
++	return adap;
++}
++
++/**
++ * l3_put_adapter - release a reference to an adapter
++ * @adap: driver to release reference
++ *
++ * Indicate to the L3 core that you no longer require the adapter reference.
++ * The adapter module may be unloaded when there are no references to its
++ * data structure.
++ *
++ * You must not use the reference after calling this function.
++ */
++void l3_put_adapter(struct l3_adapter *adap)
++{
++	if (adap && adap->owner)
++		__MOD_DEC_USE_COUNT(adap->owner);
++}
++
++/**
++ * l3_add_driver - register a new L3 device driver
++ * @driver - driver structure to make available
++ *
++ * Make the driver available for use by clients using name driver->name.
++ * The driver->drivers list is initialised by this function.
++ *
++ * Returns 0;
++ */
++int l3_add_driver(struct l3_driver *driver)
++{
++	down(&driver_lock);
++	list_add(&driver->drivers, &driver_list);
++	up(&driver_lock);
++	return 0;
++}
++
++/**
++ * l3_del_driver - unregister a L3 device driver
++ * @driver: driver to remove
++ *
++ * Remove an driver from the list of available L3 Bus device drivers.
++ *
++ * Returns 0;
++ */
++int l3_del_driver(struct l3_driver *driver)
++{
++	down(&driver_lock);
++	list_del(&driver->drivers);
++	up(&driver_lock);
++	return 0;
++}
++
++static struct l3_driver *__l3_get_driver(const char *name)
++{
++	struct list_head *l;
++
++	list_for_each(l, &driver_list) {
++		struct l3_driver *drv = list_entry(l, struct l3_driver, drivers);
++
++		if (strcmp(drv->name, name) == 0)
++			return drv;
++	}
++
++	return NULL;
++}
++
++/**
++ * l3_get_driver - get a reference to a driver
++ * @name: driver name
++ *
++ * Obtain a l3_driver structure for the specified driver.  If the driver is
++ * not currently load, then load it.  The driver will be locked in core
++ * until all references are released via l3_put_driver.
++ */
++struct l3_driver *l3_get_driver(const char *name)
++{
++	struct l3_driver *drv;
++	int try;
++
++	for (try = 0; try < 2; try ++) {
++		down(&adapter_lock);
++		drv = __l3_get_driver(name);
++		if (drv && !try_inc_mod_count(drv->owner))
++			drv = NULL;
++		up(&adapter_lock);
++
++		if (drv)
++			break;
++
++		if (try == 0)
++			request_module(name);
++	}
++
++	return drv;
++}
++
++/**
++ * l3_put_driver - release a reference to a driver
++ * @drv: driver to release reference
++ *
++ * Indicate to the L3 core that you no longer require the driver reference.
++ * The driver module may be unloaded when there are no references to its
++ * data structure.
++ *
++ * You must not use the reference after calling this function.
++ */
++void l3_put_driver(struct l3_driver *drv)
++{
++	if (drv && drv->owner)
++		__MOD_DEC_USE_COUNT(drv->owner);
++}
++
++/**
++ * l3_attach_client - attach a client to an adapter and driver
++ * @client: client structure to attach
++ * @adap: adapter (module) name
++ * @drv: driver (module) name
++ *
++ * Attempt to attach a client (a user of a device driver) to a particular
++ * driver and adapter.  If the specified driver or adapter aren't registered,
++ * request_module is used to load the relevant modules.
++ *
++ * Returns 0 on success, or negative error code.
++ */
++int l3_attach_client(struct l3_client *client, const char *adap, const char *drv)
++{
++	struct l3_adapter *adapter = l3_get_adapter(adap);
++	struct l3_driver  *driver = l3_get_driver(drv);
++	int ret = -ENOENT;
++
++	if (!adapter)
++		printk(KERN_ERR "%s: unable to get adapter: %s\n",
++			__FUNCTION__, adap);
++	if (!driver)
++		printk(KERN_ERR "%s: unable to get driver: %s\n",
++			__FUNCTION__, drv);
++
++	if (adapter && driver) {
++		ret = 0;
++
++		client->adapter = adapter;
++		client->driver  = driver;
++
++		list_add(&client->__adap, &adapter->clients);
++
++		if (driver->attach_client)
++			ret = driver->attach_client(client);
++	}
++
++	if (ret) {
++		l3_put_driver(driver);
++		l3_put_adapter(adapter);
++	}
++	return ret;
++}
++
++/**
++ * l3_detach_client - detach a client from an adapter and driver
++ * @client: client structure to detach
++ *
++ * Detach the client from the adapter and driver.
++ */
++int l3_detach_client(struct l3_client *client)
++{
++	struct l3_adapter *adapter = client->adapter;
++	struct l3_driver  *driver = client->driver;
++
++	driver->detach_client(client);
++
++	client->adapter = NULL;
++	client->driver  = NULL;
++
++	l3_put_driver(driver);
++	l3_put_adapter(adapter);
++
++	list_del(&client->__adap);
++
++	return 0;
++}
++
++/**
++ * l3_transfer - transfer information on an L3 bus
++ * @adap: adapter structure to perform transfer on
++ * @msgs: array of l3_msg structures describing transfer
++ * @num: number of l3_msg structures
++ *
++ * Transfer the specified messages to/from a device on the L3 bus.
++ *
++ * Returns number of messages successfully transferred, otherwise negative
++ * error code.
++ */
++int l3_transfer(struct l3_adapter *adap, struct l3_msg msgs[], int num)
++{
++	int ret = -ENOSYS;
++
++	if (adap->algo->xfer) {
++		down(adap->lock);
++		ret = adap->algo->xfer(adap, msgs, num);
++		up(adap->lock);
++	}
++	return ret;
++}
++
++/**
++ * l3_write - send data to a device on an L3 bus
++ * @client: registered client structure
++ * @addr: L3 bus address
++ * @buf: buffer for bytes to send
++ * @len: number of bytes to send
++ *
++ * Send len bytes pointed to by buf to device address addr on the L3 bus
++ * described by client.
++ *
++ * Returns the number of bytes transferred, or negative error code.
++ */
++int l3_write(struct l3_client *client, int addr, const char *buf, int len)
++{
++	struct l3_adapter *adap = client->adapter;
++	struct l3_msg msg;
++	int ret;
++
++	msg.addr = addr;
++	msg.flags = 0;
++	msg.buf = (char *)buf;
++	msg.len = len;
++
++	ret = l3_transfer(adap, &msg, 1);
++	return ret == 1 ? len : ret;
++}
++
++/**
++ * l3_read - receive data from a device on an L3 bus
++ * @client: registered client structure
++ * @addr: L3 bus address
++ * @buf: buffer for bytes to receive
++ * @len: number of bytes to receive
++ *
++ * Receive len bytes from device address addr on the L3 bus described by
++ * client to a buffer pointed to by buf.
++ *
++ * Returns the number of bytes transferred, or negative error code.
++ */
++int l3_read(struct l3_client *client, int addr, char *buf, int len)
++{
++	struct l3_adapter *adap = client->adapter;
++	struct l3_msg msg;
++	int ret;
++
++	msg.addr = addr;
++	msg.flags = L3_M_RD;
++	msg.buf = buf;
++	msg.len = len;
++
++	ret = l3_transfer(adap, &msg, 1);
++	return ret == 1 ? len : ret;
++}
++
++EXPORT_SYMBOL(l3_add_adapter);
++EXPORT_SYMBOL(l3_del_adapter);
++EXPORT_SYMBOL(l3_get_adapter);
++EXPORT_SYMBOL(l3_put_adapter);
++
++EXPORT_SYMBOL(l3_add_driver);
++EXPORT_SYMBOL(l3_del_driver);
++EXPORT_SYMBOL(l3_get_driver);
++EXPORT_SYMBOL(l3_put_driver);
++
++EXPORT_SYMBOL(l3_attach_client);
++EXPORT_SYMBOL(l3_detach_client);
++
++EXPORT_SYMBOL(l3_transfer);
++EXPORT_SYMBOL(l3_write);
++EXPORT_SYMBOL(l3_read);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/l3/l3-sa1111.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,118 @@
++/*
++ * L3 SA1111 algorithm/adapter module.
++ *
++ *  By Russell King,
++ *    gratuitously ripped from sa1111-uda1341.c by John Dorsey.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/l3/l3.h>
++
++#include <asm/hardware.h>
++#include <asm/semaphore.h>
++#include <asm/mach-types.h>
++#include <asm/arch/assabet.h>
++#include <asm/hardware/sa1111.h>
++
++static inline unsigned char l3_sa1111_recv_byte(unsigned char addr)
++{
++	unsigned char dat;
++
++	L3_CAR = addr;
++	while ((SASR0 & SASR0_L3RD) == 0)
++		mdelay(1);
++	dat = L3_CDR;
++	SASCR = SASCR_RDD;
++	return dat;
++}
++
++static void l3_sa1111_recv_msg(struct l3_msg *msg)
++{
++	int len = msg->len;
++	char *p = msg->buf;
++
++	if (len > 1) {
++		SACR1 |= SACR1_L3MB;
++		while ((len--) > 1)
++			*p++ = l3_sa1111_recv_byte(msg->addr);
++	}
++	SACR1 &= ~SACR1_L3MB;
++	*p = l3_sa1111_recv_byte(msg->addr);
++}
++
++static inline void l3_sa1111_send_byte(unsigned char addr, unsigned char dat)
++{
++	L3_CAR = addr;
++	L3_CDR = dat;
++	while ((SASR0 & SASR0_L3WD) == 0)
++		mdelay(1);
++	SASCR = SASCR_DTS;
++}
++
++static void l3_sa1111_send_msg(struct l3_msg *msg)
++{
++	int len = msg->len;
++	char *p = msg->buf;
++
++	if (len > 1) {
++		SACR1 |= SACR1_L3MB;
++		while ((len--) > 1)
++			l3_sa1111_send_byte(msg->addr, *p++);
++	}
++	SACR1 &= ~SACR1_L3MB;
++	l3_sa1111_send_byte(msg->addr, *p);
++}
++
++static int l3_sa1111_xfer(struct l3_adapter *adap, struct l3_msg msgs[], int num)
++{
++	int i;
++
++	for (i = 0; i < num; i++) {
++		struct l3_msg *pmsg = &msgs[i];
++
++		if (pmsg->flags & L3_M_RD)
++			l3_sa1111_recv_msg(pmsg);
++		else
++			l3_sa1111_send_msg(pmsg);
++	}
++
++	return num;
++}
++
++static struct l3_algorithm l3_sa1111_algo = {
++	name:		"L3 SA1111 algorithm",
++	xfer:		l3_sa1111_xfer,
++};
++
++static DECLARE_MUTEX(sa1111_lock);
++
++static struct l3_adapter l3_sa1111_adapter = {
++	owner:		THIS_MODULE,
++	name:		"l3-sa1111",
++	algo:		&l3_sa1111_algo,
++	lock:		&sa1111_lock,
++};
++
++static int __init l3_sa1111_init(void)
++{
++	int ret = -ENODEV;
++	if ((machine_is_assabet() && machine_has_neponset()) ||
++	    machine_is_jornada720() || machine_is_accelent_sa() ||
++	    machine_is_badge4())
++		ret = l3_add_adapter(&l3_sa1111_adapter);
++	return ret;
++}
++
++static void __exit l3_sa1111_exit(void)
++{
++	l3_del_adapter(&l3_sa1111_adapter);
++}
++
++module_init(l3_sa1111_init);
++module_exit(l3_sa1111_exit);
+--- linux-2.4.25/drivers/media/video/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/media/video/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -52,5 +52,8 @@
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_tristate '  Sony Vaio Picturebook Motion Eye Video For Linux (EXPERIMENTAL)' CONFIG_VIDEO_MEYE $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_SONYPI
+ fi
++# unfortunately, this depends on having CONFIG_FB_CYBER2000
++# set as well - we hook off of the VGA driver
++dep_tristate '  NetWinder Video for Linux (EXPERIMENTAL)' CONFIG_VIDEO_CYBERPRO $CONFIG_VIDEO_DEV $CONFIG_EXPERIMENTAL $CONFIG_ARCH_NETWINDER
+ 
+ endmenu
+--- linux-2.4.25/drivers/media/video/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/media/video/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -16,7 +16,7 @@
+ obj-n		:=
+ obj-		:=
+ 
+-SUB_DIRS     := 
++SUB_DIRS     :=
+ MOD_SUB_DIRS := $(SUB_DIRS)
+ ALL_SUB_DIRS := $(SUB_DIRS)
+ 
+@@ -47,7 +47,8 @@
+ obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o i2c-old.o
+ obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o
+ obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o
+-obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o
++obj-$(CONFIG_VIDEO_CYBERPRO) += cyberpro.o i2c-old.o saa7111.o
++obj-$(CONFIG_VIDEO_LML33) += bt856.o bt819.o
+ obj-$(CONFIG_VIDEO_PMS) += pms.o
+ obj-$(CONFIG_VIDEO_PLANB) += planb.o
+ obj-$(CONFIG_VIDEO_VINO) += saa7191.o indycam.o vino.o
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/media/video/cyberpro.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,2091 @@
++/*
++ * CyberPro 2000 video capture driver for the Rebel.com NetWinder
++ *
++ * (C) 1999-2000 Russell King
++ *
++ *  Re-written from Rebel.com's vidcap driver.
++ *
++ * Architecture
++ * ------------
++ *  The NetWinder video capture consists of a SAA7111 video decoder chip
++ *  connected to the CyberPro feature bus.  The video data is captured to
++ *  the VGA memory, where the CyberPro can overlay (by chromakeying) the
++ *  data onto the VGA display.
++ *
++ *  The CyberPro also has some nifty features, including a second overlay
++ *  and picture in picture mode.  We do not currently use these features.
++ *
++ * Power Saving
++ * ------------
++ *  Please note that rev.5 NetWinders have the ability to hold the SAA7111
++ *  decoder chip into reset, which saves power.  The only time at which
++ *  this is done is when the driver is unloaded, which implies that this
++ *  is compiled as a module.
++ *
++ *  In this case, you will want the kernel to automatically load this
++ *  driver when required.  Place the following line in /etc/modules.conf
++ *  to enable this:
++ *
++ *   alias char-major-81-0 cyberpro
++ *
++ *  The relevant modules will be automatically loaded by modprobe on a
++ *  as and when needed basis.
++ *
++ * Capture resolution
++ * ------------------
++ *  The maximum useful capture resolution is:
++ *     625-line UK: 716x576
++ *     525-line US: ?
++ *
++ * Bugs
++ * ----
++ *  1. The CyberPro chip seems to be prone to randomly scribbling over VGA
++ *     memory [hopefully fixed with new capture enable/freeze stuff]
++ *  2. read()ing pauses video capture, and sometimes triggers bug 1.
++ *  3. mmap() is not supported (requires BM-DMA - see bug 4)
++ *  4. Really, we want to do scatter BM-DMA.  Is the CyberPro capable of this?
++ *     The Cyberpro seems to randomly scribble to various PCI addresses if you
++ *     transfer >16 words.
++ *  5. We shouldn't ignore O_NONBLOCK when reading a frame.
++ *  6. The incoming stream on the NetWinder is CCIR656, which is YUV422.
++ *     CyberPro docs also call the format we capture and overlay "YUV422",
++ *     but we actually seem to have Y, U, Y, V bytes (is this YUYV format?)
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/videodev.h>
++#include <linux/video_decoder.h>
++#include <linux/mm.h>
++#include <linux/i2c-old.h>
++#include <linux/spinlock.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/kmod.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/pgtable.h>
++#include <asm/pgalloc.h>
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("CyberPro v4l video grabber");
++MODULE_LICENSE("GPL");
++
++#include "../../video/cyber2000fb.h"
++
++/*
++ * These enable various experimental features.  Most of these
++ * are just plain broken or just don't work at the moment.
++ */
++/*
++ * Enable this if you want mmap() access. (see bug 4)
++ */
++#undef USE_MMAP
++
++/*
++ * Enable this if you want mmio access. (slow)
++ */
++#define USE_MMIO
++
++/*
++ * The V4L API is unclear whether VIDIOCSCAPTURE call is allowed while
++ * capture is running.  The default is to disallow the call.
++ *
++ * Define this if you do want to allow the call while capture is active.
++ */
++#undef	ALLOW_SCAPTURE_WHILE_CAP
++
++/*
++ * We capture two frames
++ */
++#define NR_FRAMES	2
++
++/*
++ * One frame of video is 202 pages, assuming YUV422 format, 716x576
++ */
++#define NR_PAGES	202
++
++struct src_info {
++	unsigned int	offset;		/* offset of source data	*/
++	unsigned int	x;		/* source x			*/
++	unsigned int	y;		/* source y			*/
++	unsigned int	width;		/* source width			*/
++	unsigned int	height;		/* source height		*/
++	unsigned int	format;		/* source format		*/
++};
++
++struct dst_info {
++	unsigned int	x;		/* destination x		*/
++	unsigned int	y;		/* destination y		*/
++	unsigned int	width;		/* destination width		*/
++	unsigned int	height;		/* destination height		*/
++	unsigned int	chromakey;	/* chromakey			*/
++	unsigned int	flags;		/* flags (eg, chromakey enable)	*/
++};
++
++struct cyberpro_vidinfo;
++
++struct win_info {
++	void (*init)(struct cyberpro_vidinfo *dp, struct win_info *wi);
++	void (*set_src)(struct cyberpro_vidinfo *dp, struct win_info *wi);
++	void (*set_win)(struct cyberpro_vidinfo *dp, struct win_info *wi);
++	void (*ctl)(struct cyberpro_vidinfo *dp, struct win_info *wi, int on_off);
++
++	/* public */
++	struct src_info	src;
++	struct dst_info	dst;
++
++	/* private */
++	unsigned short	vid_fifo_ctl;
++	unsigned char	vid_fmt;
++	unsigned char	vid_disp_ctl1;
++	unsigned char	vid_fifo_ctl1;
++	unsigned char	vid_misc_ctl1;
++};
++
++struct framebuf {
++	unsigned int		offset;		/* mmap offset for this frame	*/
++	unsigned int		status;
++#define FRAME_FREE	0
++#define FRAME_DONE	1
++#define FRAME_WAITING	2
++#define FRAME_GRABBING	3
++
++	/*
++	 * Bus-Master DMA stuff.  Note that we should
++	 * probably use the kiovec stuff instead.
++	 */
++	unsigned long		bus_addr[NR_PAGES];	/* list of pages		*/
++	struct page		*pages[NR_PAGES];
++	void			*buffer;
++	int dbg;
++};
++
++struct cyberpro_vidinfo {
++	struct video_device	*dev;
++	struct i2c_bus		*bus;
++	struct cyberpro_info	info;		/* host information		*/
++	unsigned char		*regs;
++	unsigned int		irq;		/* PCI interrupt number		*/
++
++	/* hardware configuration */
++	unsigned int		stream_fmt;	/* format of stream from decoder*/
++
++	/* software settings */
++	unsigned int		decoder:1;	/* decoder loaded		*/
++	unsigned int		interlace:1;	/* interlace			*/
++	unsigned int		buf_set:1;	/* VIDIOCSFBUF has been issued	*/
++	unsigned int		win_set:1;	/* VIDIOCSWIN has been issued 	*/
++	unsigned int		cap_active:1;	/* capture is active		*/
++	unsigned int		ovl_active:1;	/* overlay is active		*/
++	unsigned int		mmaped:1;	/* buffer is mmap()d		*/
++	unsigned int		unused:25;
++
++	unsigned int		users;		/* number of users		*/
++	unsigned long		cap_mem_offset;	/* capture framebuffer offset	*/
++	void *			buffer;		/* kernel capture buffer	*/
++	unsigned int		norm;		/* video standard		*/
++
++	struct video_capability	cap;		/* capabilities			*/
++	struct video_picture	pic;		/* current picture settings	*/
++	struct video_buffer	buf;		/* display parameters		*/
++	struct video_capture	capt;		/* video capture params		*/
++
++	struct win_info		*ovl;		/* overlay window set		*/
++	struct win_info		ext;		/* "Extended" window info	*/
++	struct win_info		v2;		/* "V2" window info		*/
++	struct win_info		x2;		/* "X2" window info		*/
++
++	unsigned int		bm_offset;	/* Cap memory bus master offset	*/
++	unsigned int		bm_index;	/* Cap page index		*/
++
++#ifdef USE_MMAP
++	unsigned int		frame_idx;	/* currently grabbing frame	*/
++	unsigned int		frame_size;
++	struct framebuf	frame[NR_FRAMES];
++	wait_queue_head_t	frame_wait;
++#endif
++
++	wait_queue_head_t	vbl_wait;
++
++	/*
++	 * cyberpro registers
++	 */
++	unsigned char	cap_mode1;
++	unsigned char	cap_mode2;
++	unsigned char	cap_miscctl;
++	unsigned char	vfac1;
++	unsigned char	vfac3;
++};
++
++/*
++ * Our access methods.
++ */
++#define cyberpro_writel(val,reg,dp)	writel(val, (dp)->regs + (reg))
++#define cyberpro_writew(val,reg,dp)	writew(val, (dp)->regs + (reg))
++#define cyberpro_writeb(val,reg,dp)	writeb(val, (dp)->regs + (reg))
++
++#define cyberpro_readb(reg,dp)	readb((dp)->regs + (reg))
++
++static inline void
++cyberpro_grphw(unsigned int reg, unsigned int val, struct cyberpro_vidinfo *dp)
++{
++	cyberpro_writew((reg & 255) | val << 8, 0x3ce, dp);
++}
++
++static void cyberpro_grphw8(unsigned int reg, unsigned int val, struct cyberpro_vidinfo *dp)
++{
++	cyberpro_grphw(reg, val, dp);
++}
++
++static unsigned char cyberpro_grphr8(int reg, struct cyberpro_vidinfo *dp)
++{
++	cyberpro_writeb(reg, 0x3ce, dp);
++	return cyberpro_readb(0x3cf, dp);
++}
++
++static void cyberpro_grphw16(int reg, unsigned int val, struct cyberpro_vidinfo *dp)
++{
++	cyberpro_grphw(reg, val, dp);
++	cyberpro_grphw(reg + 1, val >> 8, dp);
++}
++
++static void cyberpro_grphw24(int reg, unsigned int val, struct cyberpro_vidinfo *dp)
++{
++	cyberpro_grphw(reg, val, dp);
++	cyberpro_grphw(reg + 1, val >> 8, dp);
++	cyberpro_grphw(reg + 2, val >> 16, dp);
++}
++
++#if 0
++static void
++cyberpro_dbg_dump(void)
++{
++	int i;
++	unsigned char idx[] =
++		{ 0x30, 0x3e, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d,
++		  0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad };
++	printk(KERN_DEBUG);
++	for (i = 0; i < sizeof(idx); i++)
++		printk("%02x ", idx[i]);
++	printk("\n" KERN_DEBUG);
++	for (i = 0; i < sizeof(idx); i++)
++		printk("%02x ", cyberpro_grphr8(idx[i]));
++	printk("\n");
++}
++#endif
++
++/*
++ * On the NetWinder, we can put the SAA7111 to sleep by holding
++ * it in reset.
++ *
++ * Note: once we have initialised the SAA7111, we can't put it back to
++ * sleep and expect it to keep its settings.  Maybe a better solution
++ * is to register/de-register the i2c bus in open/release?
++ */
++static void
++decoder_sleep(int sleep)
++{
++#ifdef CONFIG_ARCH_NETWINDER
++	extern spinlock_t gpio_lock;
++
++	spin_lock_irq(&gpio_lock);
++	cpld_modify(CPLD_7111_DISABLE, sleep ? CPLD_7111_DISABLE : 0);
++	spin_unlock_irq(&gpio_lock);
++
++	if (!sleep) {
++		/*
++		 * wait 20ms for device to wake up
++		 */
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		schedule_timeout(HZ / 50);
++	}
++#endif
++}
++
++/* -------------------------------- I2C support ---------------------------- */
++
++#define I2C_DELAY	100
++
++static void
++cyberpro_i2c_setlines(struct i2c_bus *bus, int ctrl, int data)
++{
++	struct cyberpro_vidinfo *dp = bus->data;
++	int v;
++
++	v = (ctrl ? EXT_LATCH2_I2C_CLKEN : 0x00) | (data ? EXT_LATCH2_I2C_DATEN : 0x00);
++	cyberpro_grphw8(EXT_LATCH2, v, dp);
++
++	udelay(I2C_DELAY);
++}
++
++static int
++cyberpro_i2c_getdataline(struct i2c_bus *bus)
++{
++	struct cyberpro_vidinfo *dp = bus->data;
++	unsigned long flags;
++	int v;
++
++	save_flags(flags);
++	cli();
++
++	v = cyberpro_grphr8(EXT_LATCH2, dp);
++
++	restore_flags(flags);
++
++	return v & EXT_LATCH2_I2C_DAT ? 1 : 0;
++}
++
++static void
++cyberpro_i2c_attach(struct i2c_bus *bus, int id)
++{
++	struct cyberpro_vidinfo *dp = bus->data;
++	int zero = 0;
++
++	if (id == I2C_DRIVERID_VIDEODECODER) {
++		__u16 norm = dp->norm;
++		i2c_control_device(bus, id, DECODER_SET_NORM, &norm);
++		i2c_control_device(bus, id, DECODER_SET_PICTURE, &dp->pic);
++		i2c_control_device(bus, id, DECODER_ENABLE_OUTPUT, &zero);
++
++		dp->decoder = 1;
++	}
++}
++
++static void
++cyberpro_i2c_detach(struct i2c_bus *bus, int id)
++{
++	struct cyberpro_vidinfo *dp = bus->data;
++
++	if (id == I2C_DRIVERID_VIDEODECODER)
++		dp->decoder = 0;
++}
++
++static struct i2c_bus cyberpro_i2c_bus = {
++	name:			"",
++	id:			I2C_BUSID_CYBER2000,
++	bus_lock:		SPIN_LOCK_UNLOCKED,
++	attach_inform:		cyberpro_i2c_attach,
++	detach_inform:		cyberpro_i2c_detach,
++	i2c_setlines:		cyberpro_i2c_setlines,
++	i2c_getdataline:	cyberpro_i2c_getdataline,
++};
++
++/*------------------------- Extended Overlay Window -------------------------
++ * Initialise 1st overlay window (works)
++ */
++static void
++cyberpro_ext_init(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	wi->vid_fifo_ctl  = 0xf87c;
++	wi->vid_fmt       = EXT_VID_FMT_YUV422;
++	wi->vid_disp_ctl1 = EXT_VID_DISP_CTL1_VINTERPOL_OFF |
++			    EXT_VID_DISP_CTL1_NOCLIP;
++	wi->vid_fifo_ctl1 = EXT_VID_FIFO_CTL1_INTERLEAVE |
++			    EXT_VID_FIFO_CTL1_OE_HIGH;
++	wi->vid_misc_ctl1 = 0;
++
++	cyberpro_grphw8 (EXT_VID_DISP_CTL1,  wi->vid_disp_ctl1, dp);
++	cyberpro_grphw16(EXT_DDA_X_INIT,     0x0800, dp);
++	cyberpro_grphw16(EXT_DDA_Y_INIT,     0x0800, dp);
++	cyberpro_grphw16(EXT_VID_FIFO_CTL,   wi->vid_fifo_ctl, dp);
++	cyberpro_grphw8 (EXT_VID_FIFO_CTL1,  wi->vid_fifo_ctl1, dp);
++}
++
++/*
++ * Set the source parameters for the extended window
++ */
++static void
++cyberpro_ext_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	unsigned int phase, pitch;
++
++	pitch = (wi->src.width >> 2) & 0x0fff;
++	phase = (wi->src.width + 3) >> 2;
++
++	wi->vid_fmt &= ~7;
++	switch (wi->src.format) {
++	case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565;    break;
++	case VIDEO_PALETTE_RGB24:  wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break;
++	case VIDEO_PALETTE_RGB32:  wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break;
++	case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555;    break;
++	case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422;    break;
++	}
++
++	cyberpro_grphw24(EXT_MEM_START, wi->src.offset, dp);
++	cyberpro_grphw16(EXT_SRC_WIDTH, pitch | ((phase << 4) & 0xf000), dp);
++	cyberpro_grphw8 (EXT_SRC_WIN_WIDTH, phase, dp);
++	cyberpro_grphw8 (EXT_VID_FMT, wi->vid_fmt, dp);
++}
++
++/*
++ * Set overlay1 window
++ */
++static void
++cyberpro_ext_set_win(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	unsigned int xscale, yscale;
++	unsigned int xoff, yoff;
++
++	/*
++	 * Note: the offset does not appear to be influenced by
++	 * hardware scrolling.
++	 */
++	xoff = yoff = 0;
++
++	xoff += wi->dst.x;
++	yoff += wi->dst.y;
++
++	xscale = wi->src.width;
++
++	if (wi->dst.width >= wi->src.width * 2) {
++		wi->vid_fmt |= EXT_VID_FMT_DBL_H_PIX;
++		xscale *= 2;
++	} else {
++		wi->vid_fmt &= ~EXT_VID_FMT_DBL_H_PIX;
++	}
++
++	xscale = ((xscale - /*2*/0) * 4096) / wi->dst.width;
++	yscale = ((wi->src.height - /*2*/0) * 4096) / wi->dst.height;
++
++	cyberpro_grphw16(EXT_X_START, xoff, dp);
++	cyberpro_grphw16(EXT_X_END,   xoff + wi->dst.width, dp);
++	cyberpro_grphw16(EXT_Y_START, yoff, dp);
++	cyberpro_grphw16(EXT_Y_END,   yoff + wi->dst.height, dp);
++	cyberpro_grphw24(EXT_COLOUR_COMPARE, wi->dst.chromakey, dp);
++	cyberpro_grphw16(EXT_DDA_X_INC, xscale, dp);
++	cyberpro_grphw16(EXT_DDA_Y_INC, yscale, dp);
++	cyberpro_grphw8(EXT_VID_FMT, wi->vid_fmt, dp);
++
++	if (wi->dst.flags & VIDEO_WINDOW_CHROMAKEY)
++		wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_IGNORE_CCOMP;
++	else
++		wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_IGNORE_CCOMP;
++}
++
++/*
++ * Enable or disable the 1st overlay window.  Note that for anything
++ * useful to be displayed, we must have capture enabled.
++ */
++static void
++cyberpro_ext_ctl(struct cyberpro_vidinfo *dp, struct win_info *wi, int on)
++{
++	if (on)
++		wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_ENABLE_WINDOW;
++	else
++		wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_ENABLE_WINDOW;
++
++	cyberpro_grphw8(EXT_VID_DISP_CTL1, wi->vid_disp_ctl1, dp);
++}
++
++/*------------------------------- V2 Overlay Window -------------------------
++ * Initialise 2nd overlay window (guesswork)
++ */
++static void
++cyberpro_v2_init(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	wi->vid_fifo_ctl  = 0xf87c;
++	wi->vid_fmt       = EXT_VID_FMT_YUV422;
++	wi->vid_disp_ctl1 = EXT_VID_DISP_CTL1_VINTERPOL_OFF |
++			    EXT_VID_DISP_CTL1_NOCLIP;
++	wi->vid_fifo_ctl1 = 0x06;
++	wi->vid_misc_ctl1 = 0;
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp);
++	cyberpro_grphw8 (Y_V2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp);
++	/* No DDA init values */
++	cyberpro_grphw16(Y_V2_VID_FIFO_CTL,  wi->vid_fifo_ctl, dp);
++	cyberpro_grphw8 (Y_V2_VID_FIFO_CTL1, wi->vid_fifo_ctl1, dp);
++}
++
++/*
++ * Set the source parameters for the v2 window
++ */
++static void
++cyberpro_v2_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	unsigned int phase, pitch;
++
++	pitch = (wi->src.width >> 2) & 0x0fff;
++	phase = (wi->src.width + 3) >> 2;
++
++	wi->vid_fmt &= ~7;
++	switch (wi->src.format) {
++	case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565;    break;
++	case VIDEO_PALETTE_RGB24:  wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break;
++	case VIDEO_PALETTE_RGB32:  wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break;
++	case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555;    break;
++	case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422;    break;
++	}
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_X, dp);
++	cyberpro_grphw24(X_V2_VID_MEM_START, wi->src.offset, dp);
++	cyberpro_grphw16(X_V2_VID_SRC_WIDTH, pitch | ((phase << 4) & 0xf000), dp);
++	cyberpro_grphw8 (X_V2_VID_SRC_WIN_WIDTH, phase, dp);
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp);
++	cyberpro_grphw8(Y_V2_VID_FMT, wi->vid_fmt, dp);
++}
++
++/*
++ * Set v2 window
++ */
++static void
++cyberpro_v2_set_win(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	unsigned int xscale, yscale;
++	unsigned int xoff, yoff;
++
++	/*
++	 * Note: the offset does not appear to be influenced by
++	 * hardware scrolling.
++	 */
++	xoff = yoff = 0;
++
++	xoff += wi->dst.x;
++	yoff += wi->dst.y;
++
++	xscale = (wi->src.width  * 4096) / wi->dst.width;
++	yscale = (wi->src.height * 4096) / wi->dst.height;
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_X, dp);
++	cyberpro_grphw16(X_V2_X_START,	xoff, dp);
++	cyberpro_grphw16(X_V2_X_END,	xoff + wi->dst.width, dp);
++	cyberpro_grphw16(X_V2_Y_START,	yoff, dp);
++	cyberpro_grphw16(X_V2_Y_END,	yoff + wi->dst.height, dp);
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp);
++	cyberpro_grphw16(Y_V2_DDA_X_INC, xscale, dp);
++	cyberpro_grphw16(Y_V2_DDA_Y_INC, yscale, dp);
++}
++
++/*
++ * Enable or disable the 2nd overlay window.  Note that for anything
++ * useful to be displayed, we must have capture enabled.
++ */
++static void
++cyberpro_v2_ctl(struct cyberpro_vidinfo *dp, struct win_info *wi, int on)
++{
++	if (on)
++		wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_ENABLE_WINDOW;
++	else
++		wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_ENABLE_WINDOW;
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp);
++	cyberpro_grphw8(Y_V2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp);
++}
++
++/*--------------------------- X2 Overlay Window -----------------------------
++ * Initialise 3rd overlay window (guesswork)
++ */
++static void
++cyberpro_x2_init(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	wi->vid_fmt       = EXT_VID_FMT_YUV422;
++	wi->vid_disp_ctl1 = 0x40;
++	wi->vid_misc_ctl1 = 0;
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_K, dp);
++	cyberpro_grphw8 (K_X2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp);
++	cyberpro_grphw16(K_X2_DDA_X_INIT, 0x0800, dp);
++	cyberpro_grphw16(K_X2_DDA_Y_INIT, 0x0800, dp);
++}
++
++/*
++ * Set the source parameters for the x2 window
++ */
++static void
++cyberpro_x2_set_src(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	unsigned int phase, pitch;
++
++	pitch = (wi->src.width >> 2) & 0x0fff;
++	phase = (wi->src.width + 3) >> 2;
++
++	wi->vid_fmt &= ~7;
++	switch (wi->src.format) {
++	case VIDEO_PALETTE_RGB565: wi->vid_fmt |= EXT_VID_FMT_RGB565;    break;
++	case VIDEO_PALETTE_RGB24:  wi->vid_fmt |= EXT_VID_FMT_RGB888_24; break;
++	case VIDEO_PALETTE_RGB32:  wi->vid_fmt |= EXT_VID_FMT_RGB888_32; break;
++	case VIDEO_PALETTE_RGB555: wi->vid_fmt |= EXT_VID_FMT_RGB555;    break;
++	case VIDEO_PALETTE_YUV422: wi->vid_fmt |= EXT_VID_FMT_YUV422;    break;
++	}
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_J, dp);
++	cyberpro_grphw24(J_X2_VID_MEM_START, wi->src.offset, dp);
++	cyberpro_grphw16(J_X2_VID_SRC_WIDTH, pitch | ((phase << 4) & 0xf000), dp);
++	cyberpro_grphw8 (J_X2_VID_SRC_WIN_WIDTH, phase, dp);
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_K, dp);
++	cyberpro_grphw8(K_X2_VID_FMT, wi->vid_fmt, dp);
++}
++
++/*
++ * Set x2 window
++ */
++static void
++cyberpro_x2_set_win(struct cyberpro_vidinfo *dp, struct win_info *wi)
++{
++	unsigned int xscale, yscale;
++	unsigned int xoff, yoff;
++
++	/*
++	 * Note: the offset does not appear to be influenced by
++	 * hardware scrolling.
++	 */
++	xoff = yoff = 0;
++
++	xoff += wi->dst.x;
++	yoff += wi->dst.y;
++
++	xscale = (wi->src.width  * 4096) / wi->dst.width;
++	yscale = (wi->src.height * 4096) / wi->dst.height;
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_J, dp);
++	cyberpro_grphw16(J_X2_X_START,	xoff, dp);
++	cyberpro_grphw16(J_X2_X_END,	xoff + wi->dst.width, dp);
++	cyberpro_grphw16(J_X2_Y_START,	yoff, dp);
++	cyberpro_grphw16(J_X2_Y_END,	yoff + wi->dst.height, dp);
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_K, dp);
++	cyberpro_grphw16(K_X2_DDA_X_INC, xscale, dp);
++	cyberpro_grphw16(K_X2_DDA_Y_INC, yscale, dp);
++}
++
++/*
++ * Enable or disable the 3rd overlay window.  Note that for anything
++ * useful to be displayed, we must have capture enabled.
++ */
++static void
++cyberpro_x2_ctl(struct cyberpro_vidinfo *dp, struct win_info *wi, int on)
++{
++	if (on)
++		wi->vid_disp_ctl1 |= EXT_VID_DISP_CTL1_ENABLE_WINDOW;
++	else
++		wi->vid_disp_ctl1 &= ~EXT_VID_DISP_CTL1_ENABLE_WINDOW;
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_K, dp);
++	cyberpro_grphw8(K_X2_VID_DISP_CTL1, wi->vid_disp_ctl1, dp);
++}
++
++/* ------------------------------------------------------------------------- */
++
++#if 0
++static void reset_seq(struct cyberpro_vidinfo *dp)
++{
++	unsigned char ext_mem_ctl = cyberpro_grphr8(0x70, dp);
++
++	cyberpro_grphw8(ext_mem_ctl | 0x80, 0x70, dp);
++	cyberpro_grphw8(ext_mem_ctl, 0x70, dp);
++}
++#endif
++
++#ifdef USE_MMAP
++/*
++ * Buffer support
++ */
++static int
++cyberpro_alloc_frame_buffer(struct cyberpro_vidinfo *dp,
++			    struct framebuf *frame)
++{
++	unsigned long addr;
++	void *buffer;
++	int pgidx;
++
++	if (frame->buffer)
++		return 0;
++
++	/*
++	 * Allocate frame buffer
++	 */
++	buffer = vmalloc(NR_PAGES * PAGE_SIZE);
++
++	if (frame->buffer) {
++		vfree(buffer);
++		return 0;
++	}
++
++	if (!buffer)
++		return -ENOMEM;
++
++	printk("Buffer allocated @ %p [", buffer);
++
++	frame->buffer = buffer;
++	frame->dbg = 1;
++
++	/*
++	 * Don't leak information from the kernel.
++	 */
++	memset(buffer, 0x5a, NR_PAGES * PAGE_SIZE);
++
++	/*
++	 * Now, reserve all the pages, and calculate
++	 * each pages' bus address.
++	 */
++	addr = (unsigned long)buffer;
++	for (pgidx = 0; pgidx < NR_PAGES; pgidx++, addr += PAGE_SIZE) {
++		struct page *page;
++		pgd_t *pgd;
++		pmd_t *pmd;
++		pte_t *pte;
++
++		/*
++		 * The page should be present.  If not,
++		 * vmalloc has gone nuts.
++		 */
++		pgd = pgd_offset_k(addr);
++		if (pgd_none(*pgd))
++			BUG();
++		pmd = pmd_offset(pgd, addr);
++		if (pmd_none(*pmd))
++			BUG();
++		pte = pte_offset(pmd, addr);
++		if (!pte_present(*pte))
++			BUG();
++
++		page = pte_page(*pte);
++
++		frame->bus_addr[pgidx] = virt_to_bus((void *)page_address(page));
++		frame->pages[pgidx] = page;
++		SetPageReserved(page);
++
++		printk("%08lx (%08lx) ", page_address(page), frame->bus_addr[pgidx]);
++	}
++	printk("\n");
++
++	return 0;
++}
++
++static void
++cyberpro_frames_free_one(struct cyberpro_vidinfo *dp, struct framebuf *frame)
++{
++	void *buffer;
++	int pgidx;
++
++	frame->status = FRAME_FREE;
++	buffer = frame->buffer;
++	frame->buffer = NULL;
++
++	if (buffer) {
++		for (pgidx = 0; pgidx < NR_PAGES; pgidx++) {
++			frame->bus_addr[pgidx] = 0;
++			ClearPageReserved(frame->pages[pgidx]);
++			frame->pages[pgidx] = NULL;
++		}
++		vfree(buffer);
++	}
++}
++
++static void
++cyberpro_busmaster_frame(struct cyberpro_vidinfo *dp, struct framebuf *frame)
++{
++	unsigned long bus_addr;
++
++	bus_addr = frame->bus_addr[dp->bm_index];
++
++	if (frame->dbg) {
++		printk("Frame%d: %06x -> %08lx\n",
++			dp->frame_idx,
++			dp->bm_offset,
++			bus_addr);
++	}
++
++	cyber2000_outw(dp->bm_offset, BM_VID_ADDR_LOW);
++	cyber2000_outw(dp->bm_offset >> 16, BM_VID_ADDR_HIGH);
++
++	cyber2000_outw(bus_addr, BM_ADDRESS_LOW);
++	cyber2000_outw(bus_addr >> 16, BM_ADDRESS_HIGH);
++
++	/*
++	 * One page-full only
++	 */
++	cyber2000_outw(1023, BM_LENGTH);
++
++	/*
++	 * Load length
++	 */
++	cyber2000_outw(BM_CONTROL_INIT, BM_CONTROL);
++
++	/*
++	 * Enable transfer
++	 */
++	cyber2000_outw(BM_CONTROL_ENABLE|BM_CONTROL_IRQEN, BM_CONTROL);
++
++	dp->bm_offset += 1024;
++	dp->bm_index += 1;
++}
++
++static void cyberpro_busmaster_interrupt(struct cyberpro_vidinfo *dp)
++{
++	struct framebuf *frame = dp->frame + dp->frame_idx;
++
++	/*
++	 * Disable Busmaster operations
++	 */
++	cyber2000_outw(0, BM_CONTROL);
++
++	if (frame->status == FRAME_GRABBING) {
++		/*
++		 * We are still grabbing this frame to system
++		 * memory.  Transfer next page if there are
++		 * more, or else flag this frame as complete.
++		 */
++		if (dp->bm_index < NR_PAGES)
++			cyberpro_busmaster_frame(dp);
++		else {
++			unsigned int idx;
++
++			frame->status = FRAME_DONE;
++			frame->dbg = 0;
++
++			idx = dp->frame_idx + 1;
++			if (idx >= NR_FRAMES)
++				idx = 0;
++
++			dp->frame_idx = idx;
++
++			wake_up(&dp->frame_wait);
++		}
++	}
++}
++
++static void cyberpro_frames_vbl(struct cyberpro_vidinfo *dp, unsigned int stat)
++{
++	struct framebuf *frame = dp->frame + dp->frame_idx;
++
++	/*
++	 * No point capturing frames if the grabber isn't active.
++	 */
++	if (stat & EXT_ROM_UCB4GH_FREEZE)
++		return;
++
++	/*
++	 * If the next buffer is ready for grabbing,
++	 * set up the bus master registers for the
++	 * transfer.
++	 */
++	if (frame->status == FRAME_WAITING) {
++		frame->status = FRAME_GRABBING;
++
++		dp->bm_offset = dp->cap_mem_offset;
++		dp->bm_index  = 0;
++
++		cyberpro_busmaster_frame(dp, frame);
++	}
++}
++
++static void __init cyberpro_frames_init(struct cyberpro_vidinfo *dp)
++{
++	unsigned int offset, maxsize;
++	int i;
++
++	init_waitqueue_head(&dp->frame_wait);
++
++	maxsize = 2 * dp->cap.maxwidth * dp->cap.maxheight;
++	dp->frame_size = PAGE_ALIGN(maxsize);
++	dp->frame_idx = 0;
++
++	for (i = offset = 0; i < NR_FRAMES; i++) {
++		dp->frame[i].offset = offset;
++		dp->frame[i].status = FRAME_FREE;
++		offset += dp->frame_size;
++	}
++}
++
++static void cyberpro_frames_free(struct cyberpro_vidinfo *dp)
++{
++	int i;
++
++	dp->mmaped = 0;
++
++	/*
++	 * Free all frame buffers
++	 */
++	for (i = 0; i < NR_FRAMES; i++)
++		cyberpro_frames_free_one(dp, dp->frame + i);
++}
++
++#else
++#define cyberpro_frames_vbl(dp,stat) do { } while (0)
++#define cyberpro_frames_init(dp)     do { } while (0)
++#define cyberpro_frames_free(dp)     do { } while (0)
++#endif
++
++/*
++ * CyberPro Interrupts
++ * -------------------
++ *
++ *  We don't really know how to signal an IRQ clear to the chip.  However,
++ *  disabling and re-enabling the capture interrupt enable seems to do what
++ *  we want.
++ */
++static void cyberpro_interrupt(int nr, void *dev_id, struct pt_regs *regs)
++{
++	struct cyberpro_vidinfo *dp = dev_id;
++	unsigned char old_grphidx;
++	unsigned int status;
++
++	/*
++	 * Save old graphics index register
++	 */
++	old_grphidx = cyberpro_readb(0x3ce, dp);
++
++	status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp);
++
++	/*
++	 * Was it due to the Capture VSYNC?
++	 */
++	if (status & EXT_ROM_UCB4GH_INTSTAT) {
++		/*
++		 * Frob the IRQ enable bit to drop the request.
++		 */
++		cyberpro_grphw8(VFAC_CTL3, dp->vfac3 & ~VFAC_CTL3_CAP_IRQ, dp);
++		cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp);
++
++		cyberpro_frames_vbl(dp, status);
++		wake_up(&dp->vbl_wait);
++	}
++
++	/*
++	 * Restore graphics controller index
++	 */
++	cyberpro_writeb(old_grphidx, 0x3ce, dp);
++
++#ifdef USE_MMAP
++	/*
++	 * Do Bus-Master IRQ stuff
++	 */
++	if (cyber2000_inb(BM_CONTROL) & (1 << 7))
++		cyberpro_busmaster_interrupt(dp);
++#endif
++}
++
++static void cyberpro_capture(struct cyberpro_vidinfo *dp, int on)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned int status;
++
++	status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp);
++
++	add_wait_queue(&dp->vbl_wait, &wait);
++	set_current_state(TASK_UNINTERRUPTIBLE);
++
++	if (!!on ^ !(status & EXT_ROM_UCB4GH_FREEZE)) {
++		if (on) {
++			schedule_timeout(40 * HZ / 1000);
++			dp->vfac1 &= ~(VFAC_CTL1_FREEZE_CAPTURE|VFAC_CTL1_FREEZE_CAPTURE_SYNC);
++			cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp);
++
++			status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp);
++		} else {
++			dp->vfac1 |= VFAC_CTL1_FREEZE_CAPTURE_SYNC;
++			cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp);
++
++			status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp);
++			if (!(status & EXT_ROM_UCB4GH_FREEZE))
++				schedule_timeout(40 * HZ / 1000);
++		}
++	}
++
++	current->state = TASK_RUNNING;
++	remove_wait_queue(&dp->vbl_wait, &wait);
++}
++
++static void cyberpro_capture_one(struct cyberpro_vidinfo *dp)
++{
++	struct task_struct *tsk = current;
++	DECLARE_WAITQUEUE(wait, tsk);
++	unsigned int status;
++	unsigned long policy, rt_priority;
++
++	policy = tsk->policy;
++	rt_priority = tsk->rt_priority;
++
++	tsk->policy = SCHED_FIFO;
++	tsk->rt_priority = 1;
++
++	status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp);
++
++	add_wait_queue(&dp->vbl_wait, &wait);
++	set_current_state(TASK_UNINTERRUPTIBLE);
++
++	schedule_timeout(40 * HZ / 1000);
++	dp->vfac1 &= ~(VFAC_CTL1_FREEZE_CAPTURE|VFAC_CTL1_FREEZE_CAPTURE_SYNC);
++	cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp);
++
++	status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp);
++	set_current_state(TASK_UNINTERRUPTIBLE);
++	schedule_timeout(40 * HZ / 1000);
++	set_current_state(TASK_UNINTERRUPTIBLE);
++	schedule_timeout(40 * HZ / 1000);
++
++	dp->vfac1 |= VFAC_CTL1_FREEZE_CAPTURE_SYNC;
++	cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp);
++
++	set_current_state(TASK_UNINTERRUPTIBLE);
++	status = cyberpro_grphr8(EXT_ROM_UCB4GH, dp);
++
++	current->state = TASK_RUNNING;
++	remove_wait_queue(&dp->vbl_wait, &wait);
++
++	tsk->policy = policy;
++	tsk->rt_priority = rt_priority;
++}
++
++static void cyberpro_capture_set_win(struct cyberpro_vidinfo *dp)
++{
++	unsigned int xstart, xend, ystart, yend;
++
++	xstart = 4 + dp->capt.x;
++	xend   = xstart + dp->capt.width;
++
++	if (dp->cap_mode1 & EXT_CAP_MODE1_8BIT) {
++		/* 8-bit capture */
++		xstart *= 2;
++		xend   *= 2;
++	}
++
++	xstart -= 1;
++	xend   -= 1;
++
++	ystart = 18 + dp->capt.y;
++	yend   = ystart + dp->capt.height / 2;
++
++	cyberpro_grphw16(CAP_X_START, xstart, dp);
++	cyberpro_grphw16(CAP_X_END, xend + 1, dp);
++	cyberpro_grphw16(CAP_Y_START, ystart, dp);
++	cyberpro_grphw16(CAP_Y_END, yend + 2, dp);
++
++	/*
++	 * This should take account of capt.decimation
++	 */
++	cyberpro_grphw16(CAP_DDA_X_INIT, 0x0800, dp);
++	cyberpro_grphw16(CAP_DDA_X_INC, 0x1000, dp);
++	cyberpro_grphw16(CAP_DDA_Y_INIT, 0x0800, dp);
++	cyberpro_grphw16(CAP_DDA_Y_INC, 0x1000, dp);
++
++	cyberpro_grphw8(CAP_PITCH, dp->capt.width >> 2, dp);
++}
++
++static void cyberpro_set_interlace(struct cyberpro_vidinfo *dp)
++{
++	/*
++	 * set interlace mode
++	 */
++	if (dp->interlace) {
++		dp->vfac3 |= VFAC_CTL3_CAP_INTERLACE;
++		dp->cap_miscctl &= ~CAP_CTL_MISC_ODDEVEN;
++		dp->ovl->src.height = dp->capt.height;
++	} else {
++		dp->vfac3 &= ~VFAC_CTL3_CAP_INTERLACE;
++		dp->cap_miscctl |= CAP_CTL_MISC_ODDEVEN;
++		dp->ovl->src.height = dp->capt.height / 2;
++	}
++
++	cyberpro_grphw8(VFAC_CTL3,    dp->vfac3, dp);
++	cyberpro_grphw8(CAP_CTL_MISC, dp->cap_miscctl, dp);
++
++	dp->ovl->set_src(dp, dp->ovl);
++
++	if (dp->win_set)
++		dp->ovl->set_win(dp, dp->ovl);
++}
++
++/*
++ * Calculate and set the address of the capture buffer.  Note we
++ * also update the extended memory buffer for the overlay window.
++ *
++ *  base:         phys base address of display
++ *  width:        pixel width of display
++ *  height:       height of display
++ *  depth:        depth of display (8/16/24)
++ *  bytesperline: number of bytes on a line
++ *
++ * We place the capture buffer 16K after the screen.
++ */
++static int
++cyberpro_set_buffer(struct cyberpro_vidinfo *dp, struct video_buffer *b)
++{
++	unsigned long screensize, maxbufsz;
++
++	if (b->height <= 0 || b->width <= 0 || b->bytesperline <= 0)
++		return -EINVAL;
++
++	maxbufsz = dp->cap.maxwidth * dp->cap.maxheight * 2;
++	screensize = b->height * b->bytesperline + 16384;
++
++	if ((screensize + maxbufsz) >= dp->info.fb_size)
++		return -EINVAL;
++
++	dp->buf.base         = b->base;
++	dp->buf.width        = b->width;
++	dp->buf.height       = b->height;
++	dp->buf.depth        = b->depth;
++	dp->buf.bytesperline = b->bytesperline;
++	dp->cap_mem_offset   = screensize >> 2;
++
++	cyberpro_grphw24(CAP_MEM_START, dp->cap_mem_offset, dp);
++
++	/*
++	 * Setup the overlay source information.
++	 */
++	dp->ovl->src.offset = dp->cap_mem_offset;
++	dp->ovl->set_src(dp, dp->ovl);
++
++	return 0;
++}
++
++static void cyberpro_hw_init(struct cyberpro_vidinfo *dp)
++{
++	unsigned char old;
++
++	/*
++	 * Enable access to bus-master registers
++	 */
++	dp->info.enable_extregs(dp->info.info);
++
++	dp->vfac1 = VFAC_CTL1_PHILIPS |
++		    VFAC_CTL1_FREEZE_CAPTURE |
++		    VFAC_CTL1_FREEZE_CAPTURE_SYNC;
++	dp->vfac3 = VFAC_CTL3_CAP_IRQ;
++
++	dp->cap_miscctl = CAP_CTL_MISC_DISPUSED |
++			  CAP_CTL_MISC_SYNCTZOR |
++			  CAP_CTL_MISC_SYNCTZHIGH;
++
++	/*
++	 * Setup bus-master mode
++	 */
++	cyberpro_grphw8(BM_CTRL1, 0x88, dp);
++	cyberpro_grphw8(PCI_BM_CTL, PCI_BM_CTL_ENABLE, dp);
++	cyberpro_grphw8(BM_CTRL0, 0x44, dp);
++	cyberpro_grphw8(BM_CTRL1, 0x84, dp);
++
++	cyberpro_grphw24(CAP_MEM_START, 0, dp);
++
++	cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp);
++	cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp);
++	cyberpro_grphw8(VFAC_CTL2, 0, dp);
++
++	cyberpro_grphw8(REG_BANK, REG_BANK_Y, dp);
++	cyberpro_grphw8(EXT_TV_CTL, 0x80, dp);
++
++	cyberpro_grphw8(EXT_CAP_CTL1, 0x3f, dp);	/* disable PIP */
++	cyberpro_grphw8(EXT_CAP_CTL2, 0xc0 | EXT_CAP_CTL2_ODDFRAMEIRQ, dp);
++
++	/*
++	 * Configure capture mode to match the
++	 * external video processor format
++	 */
++	cyberpro_grphw8(EXT_CAP_MODE1, dp->cap_mode1, dp);
++	cyberpro_grphw8(EXT_CAP_MODE2, dp->cap_mode2, dp);
++
++	/* setup overlay */
++	cyberpro_grphw16(EXT_FIFO_CTL, 0x1010, dp);
++//	cyberpro_grphw16(EXT_FIFO_CTL, 0x1b0f, dp);
++
++	/*
++	 * Always reset the capture parameters on each open.
++	 */
++	dp->capt.x          = 0;
++	dp->capt.y          = 0;
++	dp->capt.width      = dp->cap.maxwidth;
++	dp->capt.height     = dp->cap.maxheight;
++	dp->capt.decimation = 0;
++	dp->capt.flags	    = 0;
++
++	cyberpro_capture_set_win(dp);
++
++	/*
++	 * Enable VAFC
++	 */
++	old = cyberpro_grphr8(EXT_LATCH1, dp);
++	cyberpro_grphw8(EXT_LATCH1, old | EXT_LATCH1_VAFC_EN, dp);
++
++	/*
++	 * Enable capture (we hope that VSYNC=1)
++	 */
++	dp->vfac1 |= VFAC_CTL1_CAPTURE;
++	cyberpro_grphw8(VFAC_CTL1, dp->vfac1, dp);
++
++	/*
++	 * The overlay source format is always the
++	 * same as the capture stream format.
++	 */
++	dp->ovl->src.width  = dp->capt.width;
++	dp->ovl->src.height = dp->capt.height;
++	dp->ovl->src.format = dp->stream_fmt;
++
++	/*
++	 * Initialise the overlay windows
++	 */
++	dp->ext.init(dp, &dp->ext);
++	dp->v2.init(dp, &dp->v2);
++	dp->x2.init(dp, &dp->x2);
++}
++
++static void cyberpro_deinit(struct cyberpro_vidinfo *dp)
++{
++	unsigned char old;
++
++	/*
++	 * Stop any bus-master activity
++	 */
++	cyberpro_writew(0, BM_CONTROL, dp);
++
++	/*
++	 * Shut down overlay
++	 */
++	if (dp->ovl_active)
++		dp->ovl->ctl(dp, dp->ovl, 0);
++	dp->ovl_active = 0;
++
++	/*
++	 * Shut down capture
++	 */
++	if (dp->cap_active)
++		cyberpro_capture(dp, 0);
++	dp->cap_active = 0;
++
++	/*
++	 * Disable all capture
++	 */
++	cyberpro_grphw8(VFAC_CTL1, 0, dp);
++
++	/*
++	 * Disable VAFC
++	 */
++	old = cyberpro_grphr8(EXT_LATCH1, dp);
++	cyberpro_grphw8(EXT_LATCH1, old & ~EXT_LATCH1_VAFC_EN, dp);
++
++	/*
++	 * Disable interrupt (this allows it to float)
++	 */
++	dp->vfac3 &= ~VFAC_CTL3_CAP_IRQ;
++	cyberpro_grphw8(VFAC_CTL3, dp->vfac3, dp);
++
++	/*
++	 * Switch off bus-master mode
++	 */
++	cyberpro_grphw8(PCI_BM_CTL, 0, dp);
++
++	/*
++	 * Disable access to bus-master registers
++	 */
++	dp->info.disable_extregs(dp->info.info);
++}
++
++static int cyberpro_grabber_open(struct video_device *dev, int flags)
++{
++	struct cyberpro_vidinfo *dp = dev->priv;
++	int ret, one = 1;
++
++	MOD_INC_USE_COUNT;
++
++	ret = -EBUSY;
++	if (flags || dp->users)
++		goto out;
++
++	dp->users += 1;
++
++	if (dp->users == 1) {
++		ret = request_irq(dp->irq, cyberpro_interrupt, SA_SHIRQ,
++				  dp->info.dev_name, dp);
++
++		if (ret) {
++			dp->users -= 1;
++			goto out;
++		}
++
++		/*
++		 * Initialise the VGA chip
++		 */
++		cyberpro_hw_init(dp);
++
++		/*
++		 * Enable the IRQ.  This allows the IRQ to work as expected
++		 * even if the IRQ line is missing the pull-up resistor.
++		 */
++		enable_irq(dp->irq);
++
++		i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER,
++				   DECODER_ENABLE_OUTPUT, &one);
++	}
++
++	ret = 0;
++out:
++	if (ret)
++		MOD_DEC_USE_COUNT;
++	return ret;
++}
++
++static void cyberpro_grabber_close(struct video_device *dev)
++{
++	struct cyberpro_vidinfo *dp = dev->priv;
++
++	if (dp->users == 1) {
++		int zero = 0;
++
++		/*
++		 * Disable the IRQ.  This prevents problems with missing
++		 * pull-up resistors on the PCI interrupt line.
++		 */
++		disable_irq(dp->irq);
++
++		cyberpro_frames_free(dp);
++
++		/*
++		 * Turn off the SAA7111 decoder
++		 */
++		i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER,
++				   DECODER_ENABLE_OUTPUT, &zero);
++
++		/*
++		 * Disable grabber
++		 */
++		cyberpro_deinit(dp);
++
++		free_irq(dp->irq, dp);
++	}
++
++	dp->users -= 1;
++
++	MOD_DEC_USE_COUNT;
++}
++
++/*
++ * Our general plan here is:
++ *  1. Set the CyberPro to perform a BM-DMA of one frame to this memory
++ *  2. Copy the frame to the userspace
++ *
++ * However, BM-DMA seems to be unreliable at the moment, especially on
++ * rev. 4 NetWinders.
++ */
++static long
++cyberpro_grabber_read(struct video_device *dev, char *buf,
++		      unsigned long count, int noblock)
++{
++	struct cyberpro_vidinfo *dp = dev->priv;
++	int ret = -EINVAL;
++
++#ifdef USE_MMIO
++	unsigned long maxbufsz = dp->capt.width * dp->capt.height * 2;
++	char *disp = dp->info.fb + (dp->cap_mem_offset << 2);
++
++	/*
++	 * If the buffer is mmap()'d, we shouldn't be using read()
++	 */
++	if (dp->mmaped)
++		return -EINVAL;
++
++	if (count > maxbufsz)
++		count = maxbufsz;
++
++	if (dp->cap_active)
++		cyberpro_capture(dp, 0);
++	else
++		cyberpro_capture_one(dp);
++
++	ret = (int)count;
++	if (copy_to_user(buf, disp, count))
++		ret = -EFAULT;
++
++	/*
++	 * unfreeze capture
++	 */
++	if (dp->cap_active)
++		cyberpro_capture(dp, 1);
++#endif
++
++	return ret;
++}
++
++/*
++ * We don't support writing to the grabber
++ * (In theory, we could allow writing to a separate region of VGA memory,
++ * and display this using the second overlay window.  This would allow us
++ * to do video conferencing for example).
++ */
++static long
++cyberpro_grabber_write(struct video_device *dev, const char *buf,
++		       unsigned long count, int noblock)
++{
++	return -EINVAL;
++}
++
++static int
++cyberpro_grabber_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
++{
++	struct cyberpro_vidinfo *dp = dev->priv;
++
++	switch (cmd) {
++	case VIDIOCGCAP:
++		return copy_to_user(arg, &dp->cap, sizeof(dp->cap))
++			? -EFAULT : 0;
++
++	case VIDIOCGCHAN:
++	{
++		struct video_channel chan;
++
++		chan.channel	= 0;
++		strcpy(chan.name, "Composite");
++		chan.tuners	= 0;
++		chan.flags	= 0;
++		chan.type	= VIDEO_TYPE_CAMERA;
++		chan.norm	= dp->norm;
++
++		return copy_to_user(arg, &chan, sizeof(chan)) ? -EFAULT : 0;
++	}
++
++	case VIDIOCGPICT:
++		return copy_to_user(arg, &dp->pic, sizeof(dp->pic))
++			? -EINVAL : 0;
++
++	case VIDIOCGWIN:
++	{
++		struct video_window win;
++
++		win.x         = dp->ovl->dst.x;
++		win.y         = dp->ovl->dst.y;
++		win.width     = dp->ovl->dst.width;
++		win.height    = dp->ovl->dst.height;
++		win.chromakey = dp->ovl->dst.chromakey;
++		win.flags     = VIDEO_WINDOW_CHROMAKEY |
++				(dp->interlace ? VIDEO_WINDOW_INTERLACE : 0);
++		win.clips     = NULL;
++		win.clipcount = 0;
++
++		return copy_to_user(arg, &win, sizeof(win))
++			? -EINVAL : 0;
++	}
++
++	case VIDIOCGFBUF:
++		return copy_to_user(arg, &dp->buf, sizeof(dp->buf))
++			? -EINVAL : 0;
++
++	case VIDIOCGUNIT:
++	{
++		struct video_unit unit;
++
++		unit.video    = dev->minor;
++		unit.vbi      = VIDEO_NO_UNIT;
++		unit.radio    = VIDEO_NO_UNIT;
++		unit.audio    = VIDEO_NO_UNIT;
++		unit.teletext = VIDEO_NO_UNIT;
++
++		return copy_to_user(arg, &unit, sizeof(unit))
++			? -EINVAL : 0;
++	}
++
++	case VIDIOCGCAPTURE:
++		return copy_to_user(arg, &dp->capt, sizeof(dp->capt))
++				? -EFAULT : 0;
++
++	case VIDIOCSCHAN:
++	{
++		struct video_decoder_capability vdc;
++		struct video_channel v;
++		int ok;
++
++		if (copy_from_user(&v, arg, sizeof(v)))
++			return -EFAULT;
++
++		if (v.channel != 0)
++			return -EINVAL;
++
++		i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER,
++				   DECODER_GET_CAPABILITIES, &vdc);
++
++		switch (v.norm) {
++		case VIDEO_MODE_PAL:
++			ok = vdc.flags & VIDEO_DECODER_PAL;
++			break;
++		case VIDEO_MODE_NTSC:
++			ok = vdc.flags & VIDEO_DECODER_NTSC;
++			break;
++		case VIDEO_MODE_AUTO:
++			ok = vdc.flags & VIDEO_DECODER_AUTO;
++			break;
++		default:
++			ok = 0;
++		}
++		if (!ok)
++			return -EINVAL;
++
++		dp->norm = v.norm;
++
++		i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER,
++				   DECODER_SET_NORM, &v.norm);
++
++		return 0;
++	}
++
++	case VIDIOCSPICT:
++	{
++		struct video_picture p;
++
++		if (copy_from_user(&p, arg, sizeof(p)))
++			return -EFAULT;
++
++		if (p.palette != dp->stream_fmt ||
++		    p.depth != 8)
++			return -EINVAL;
++
++		dp->pic = p;
++
++		/* p.depth sets the capture depth */
++		/* p.palette sets the capture palette */
++
++		i2c_control_device(dp->bus, I2C_DRIVERID_VIDEODECODER,
++				   DECODER_SET_PICTURE, &p);
++
++		return 0;
++	}
++
++	case VIDIOCSWIN:	/* set the size & position of the overlay window */
++	{
++		struct video_window w;
++		int diff;
++
++		if (!dp->buf_set)
++			return -EINVAL;
++
++		if (copy_from_user(&w, arg, sizeof(w)))
++			return -EFAULT;
++
++		if (w.clipcount)
++			return -EINVAL;
++
++		/*
++		 * Bound the overlay window by the size of the screen
++		 */
++		if (w.x < 0)
++			w.x = 0;
++		if (w.y < 0)
++			w.y = 0;
++
++		if (w.x > dp->buf.width)
++			w.x = dp->buf.width;
++		if (w.y > dp->buf.height)
++			w.y = dp->buf.height;
++
++		if (w.width < dp->capt.width)
++			w.width = dp->capt.width;
++		if (w.height < dp->capt.height)
++			w.height = dp->capt.height;
++
++		if (w.x + w.width > dp->buf.width)
++			w.width = dp->buf.width - w.x;
++		if (w.y + w.height > dp->buf.height)
++			w.height = dp->buf.height - w.y;
++
++		/*
++		 * We've tried to make the values fit, but
++		 * they just won't.
++		 */
++		if (w.width < dp->capt.width || w.height < dp->capt.height)
++			return -EINVAL;
++
++		diff = dp->ovl->dst.x != w.x ||
++		       dp->ovl->dst.y != w.y ||
++		       dp->ovl->dst.width != w.width  ||
++		       dp->ovl->dst.height != w.height ||
++		       dp->ovl->dst.chromakey != w.chromakey ||
++		       dp->ovl->dst.flags != w.flags;
++
++		if (!dp->win_set || diff) {
++			dp->ovl->dst.x         = w.x;
++			dp->ovl->dst.y         = w.y;
++			dp->ovl->dst.width     = w.width;
++			dp->ovl->dst.height    = w.height;
++			dp->ovl->dst.chromakey = w.chromakey;
++			dp->ovl->dst.flags     = w.flags;
++
++			if (dp->ovl_active)
++				dp->ovl->ctl(dp, dp->ovl, 0);
++
++			dp->ovl->set_win(dp, dp->ovl);
++
++			if (dp->ovl_active)
++				dp->ovl->ctl(dp, dp->ovl, 1);
++
++			diff = w.flags & VIDEO_WINDOW_INTERLACE ? 1 : 0;
++			if (!dp->win_set || dp->interlace != diff) {
++				dp->interlace = diff;
++				cyberpro_set_interlace(dp);
++			}
++		}
++
++		dp->win_set = 1;
++
++		return 0;
++	}
++
++	case VIDIOCSFBUF:	/* set frame buffer info */
++	{
++		struct video_buffer b;
++		int ret;
++
++		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
++			return -EPERM;
++
++		if (dp->cap_active)
++			return -EINVAL;
++
++		if (copy_from_user(&b, arg, sizeof(b)))
++			return -EFAULT;
++
++		ret = cyberpro_set_buffer(dp, &b);
++		if (ret == 0) {
++			dp->buf_set = 1;
++			dp->win_set = 0;
++		}
++
++		return ret;
++	}
++
++	case VIDIOCCAPTURE:
++	{
++		int on;
++
++		if (get_user(on, (int *)arg))
++			return -EFAULT;
++
++		if (( on &&  dp->ovl_active) ||
++		    (!on && !dp->ovl_active))
++			return 0;
++
++		if (on && (!dp->buf_set || !dp->win_set))
++			return -EINVAL;
++
++		cyberpro_capture(dp, on);
++		dp->cap_active = on;
++		dp->ovl->ctl(dp, dp->ovl, on);
++		dp->ovl_active = on;
++
++		return 0;
++	}
++
++#ifdef USE_MMAP
++	case VIDIOCSYNC:
++	{
++		DECLARE_WAITQUEUE(wait, current);
++		int buf;
++
++		/*
++		 * The buffer must have been mmaped
++		 * for this call to work.
++		 */
++		if (!dp->mmaped)
++			return -EINVAL;
++
++		if (get_user(buf, (int *)arg))
++			return -EFAULT;
++
++		if (buf < 0 || buf >= NR_FRAMES)
++			return -EINVAL;
++
++		switch (dp->frame[buf].status) {
++		case FRAME_FREE:
++			return -EINVAL;
++
++		case FRAME_WAITING:
++		case FRAME_GRABBING:
++			add_wait_queue(&dp->frame_wait, &wait);
++			while (1) {
++				set_current_state(TASK_INTERRUPTIBLE);
++				if (signal_pending(current))
++					break;
++				if (dp->frame[buf].status == FRAME_DONE)
++					break;
++				schedule();
++			}
++			set_current_state(TASK_RUNNING);
++			remove_wait_queue(&dp->frame_wait, &wait);
++			if (signal_pending(current))
++				return -EINTR;
++			/*FALLTHROUGH*/
++		case FRAME_DONE:
++			dp->frame[buf].status = FRAME_FREE;
++			break;
++		}
++		return 0;
++	}
++
++	case VIDIOCMCAPTURE:
++	{
++		struct video_mmap vmap;
++
++		/*
++		 * The buffer must have been mmaped
++		 * for this call to work.
++		 */
++		if (!dp->mmaped)
++			return -EINVAL;
++
++		if (copy_from_user(&vmap, arg, sizeof(vmap)))
++			return -EFAULT;
++
++		/*
++		 * We can only capture in our source format/size.
++		 */
++		if (vmap.frame  >= NR_FRAMES ||
++		    vmap.format != dp->stream_fmt ||
++		    vmap.width  != dp->capt.width ||
++		    vmap.height != dp->capt.height)
++			return -EINVAL;
++
++		if (dp->frame[vmap.frame].status == FRAME_WAITING ||
++		    dp->frame[vmap.frame].status == FRAME_GRABBING)
++			return -EBUSY;
++
++		dp->frame[vmap.frame].status = FRAME_WAITING;
++		return 0;
++	}
++
++	case VIDIOCGMBUF:
++	{
++		struct video_mbuf vmb;
++		unsigned int i;
++
++		vmb.frames = NR_FRAMES;
++		vmb.size   = dp->frame_size * NR_FRAMES;
++
++		for (i = 0; i < NR_FRAMES; i++)
++			vmb.offsets[i] = dp->frame[i].offset;
++
++		return copy_to_user(arg, &vmb, sizeof(vmb)) ? -EFAULT : 0;
++	}
++#endif
++
++	case VIDIOCSCAPTURE:
++	{
++		struct video_capture capt;
++
++#ifndef ALLOW_SCAPTURE_WHILE_CAP
++		if (dp->cap_active)
++			return -EINVAL;
++#endif
++
++		if (copy_from_user(&capt, arg, sizeof(capt)))
++			return -EFAULT;
++
++		if (capt.x < 0 || capt.width < 0 ||
++		    capt.y < 0 || capt.height < 0 ||
++		    capt.x + capt.width > dp->cap.maxwidth ||
++		    capt.y + capt.height > dp->cap.maxheight)
++			return -EINVAL;
++
++		/*
++		 * The capture width must be a multiple of 4
++		 */
++		if (dp->capt.width & 3)
++			return -EINVAL;
++
++		dp->capt.x = capt.x;
++		dp->capt.y = capt.y;
++		dp->capt.width = capt.width;
++		dp->capt.height = capt.height;
++#ifdef ALLOW_SCAPTURE_WHILE_CAP
++		if (dp->ovl_active)
++			dp->ovl->ctl(dp, dp->ovl, 0);
++		if (dp->cap_active)
++			cyberpro_capture(dp, 0);
++#endif
++		cyberpro_capture_set_win(dp);
++
++		/*
++		 * Update the overlay window information
++		 */
++		dp->ovl->src.width  = capt.width;
++		dp->ovl->src.height = capt.height;
++
++		dp->ovl->set_src(dp, dp->ovl);
++		if (dp->win_set)
++			dp->ovl->set_win(dp, dp->ovl);
++
++#ifdef ALLOW_SCAPTURE_WHILE_CAP
++		if (dp->cap_active)
++			cyberpro_capture(dp, 1);
++		if (dp->ovl_active)
++			dp->ovl->ctl(dp, dp->ovl, 1);
++#endif
++		return 0;
++	}
++
++	case VIDIOCGTUNER:	/* no tuner */
++	case VIDIOCSTUNER:
++		return -EINVAL;
++	}
++
++	return -EINVAL;
++}
++
++#ifdef USE_MMAP
++static int
++cyberpro_grabber_mmap(struct video_device *dev, const char *addr, unsigned long size)
++{
++	struct cyberpro_vidinfo *dp = dev->priv;
++	unsigned long vaddr = (unsigned long)addr;
++	pgprot_t prot;
++	int frame_idx, ret = -EINVAL;
++
++#if defined(__arm__)
++	prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_USER | L_PTE_WRITE | L_PTE_DIRTY);
++#elif defined(__i386__)
++	prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED);
++	if (boot_cpu_data.x86 > 3)
++		pgprot_val(prot) |= _PAGE_PCD;
++#else
++#error "Unsupported architecture"
++#endif
++
++	/*
++	 * The mmap() request must have the correct size.
++	 */
++	if (size != NR_FRAMES * dp->frame_size)
++		goto out;
++
++	/*
++	 * If it's already mapped, don't re-do
++	 */
++	if (dp->mmaped)
++		goto out;
++	dp->mmaped = 1;
++
++	/*
++	 * Map in each frame
++	 */
++	for (frame_idx = 0; frame_idx < NR_FRAMES; frame_idx++) {
++		struct framebuf *frame;
++		int pgidx;
++
++		frame = dp->frame + frame_idx;
++
++		ret = cyberpro_alloc_frame_buffer(dp, frame);
++
++		/*
++		 * If an error occurs, we can be lazy and leave what we've
++		 * been able to do.  Our release function will free any
++		 * allocated buffers, and do_mmap_pgoff() will zap any
++		 * inserted mappings.
++		 */
++		if (ret)
++			goto out2;
++
++		/*
++		 * Map in each page on a page by page basis.  This is just
++		 * a little on the inefficient side, but it's only run once.
++		 */
++		for (pgidx = 0; pgidx < NR_PAGES; pgidx++) {
++			unsigned long virt;
++
++			virt = page_address(frame->pages[pgidx]);
++
++			ret = remap_page_range(vaddr, virt_to_phys((void *)virt),
++					       PAGE_SIZE, prot);
++
++			if (ret)
++				goto out2;
++
++			vaddr += PAGE_SIZE;
++		}
++	}
++
++ out2:
++	if (ret)
++		dp->mmaped = 0;
++ out:
++	return ret;
++}
++#endif
++
++static int __init cyberpro_grabber_init_done(struct video_device *dev)
++{
++	struct cyberpro_vidinfo *dp;
++	struct cyberpro_info *info = dev->priv;
++	int ret;
++
++	dp = kmalloc(sizeof(*dp), GFP_KERNEL);
++	if (!dp)
++		return -ENOMEM;
++
++	memset(dp, 0, sizeof(*dp));
++
++	dev->priv		= dp;
++	dp->info		= *info;
++	dp->dev			= dev;
++	dp->bus			= &cyberpro_i2c_bus;
++	dp->regs		= info->regs;
++	dp->irq			= info->dev->irq;
++
++	strcpy(dp->cap.name, dev->name);
++	dp->cap.type		= dev->type;
++	dp->cap.channels	= 1;
++	dp->cap.audios		= 0;
++	dp->cap.minwidth	= 32;
++	dp->cap.maxwidth	= 716;
++	dp->cap.minheight	= 32;
++	dp->cap.maxheight	= 576;
++
++	dp->pic.brightness	= 32768;
++	dp->pic.hue		= 32768;
++	dp->pic.colour		= 32768;
++	dp->pic.contrast	= 32768;
++	dp->pic.whiteness	= 0;
++	dp->pic.depth		= 8;
++	dp->pic.palette		= VIDEO_PALETTE_YUV422;
++
++	/* dp->buf is setup by the user		*/
++	/* dp->cap_mem_offset setup by dp->buf	*/
++
++	dp->norm		= VIDEO_MODE_AUTO;
++
++	/*
++	 * The extended overlay window
++	 */
++	dp->ext.init		= cyberpro_ext_init;
++	dp->ext.set_src		= cyberpro_ext_set_src;
++	dp->ext.set_win		= cyberpro_ext_set_win;
++	dp->ext.ctl		= cyberpro_ext_ctl;
++
++	/*
++	 * The V2 overlay window
++	 */
++	dp->v2.init		= cyberpro_v2_init;
++	dp->v2.set_src		= cyberpro_v2_set_src;
++	dp->v2.set_win		= cyberpro_v2_set_win;
++	dp->v2.ctl		= cyberpro_v2_ctl;
++
++	/*
++	 * The X2 overlay window
++	 */
++	dp->x2.init		= cyberpro_x2_init;
++	dp->x2.set_src		= cyberpro_x2_set_src;
++	dp->x2.set_win		= cyberpro_x2_set_win;
++	dp->x2.ctl		= cyberpro_x2_ctl;
++
++	/*
++	 * Set the overlay window which we shall be using
++	 */
++	dp->ovl = &dp->ext;
++
++	dp->cap_mode1 = EXT_CAP_MODE1_ALTFIFO;
++
++	/*
++	 * Initialise hardware specific values.
++	 *  - CCIR656 8bit mode (YUV422 data)
++	 *  - Ignore Hgood signal
++	 *  - Invert Odd/Even field signal
++	 */
++	dp->cap_mode1 |= EXT_CAP_MODE1_CCIR656 | EXT_CAP_MODE1_8BIT;
++	dp->cap_mode2  = EXT_CAP_MODE2_FIXSONY | EXT_CAP_MODE2_DATEND |
++			 EXT_CAP_MODE2_CCIRINVOE;
++	dp->stream_fmt = VIDEO_PALETTE_YUV422;
++
++
++	init_waitqueue_head(&dp->vbl_wait);
++	cyberpro_frames_init(dp);
++
++	/*
++	 * wake up the decoder
++	 */
++	decoder_sleep(0);
++
++	dp->bus->data = dp;
++	strncpy(dp->bus->name, dev->name, sizeof(dp->bus->name));
++
++	pci_set_master(dp->info.dev);
++
++	ret = i2c_register_bus(dp->bus);
++
++	/*
++	 * If we successfully registered the bus, but didn't initialise
++	 * the decoder (because its driver is not present), request
++	 * that it is loaded.
++	 */
++	if (ret == 0 && !dp->decoder)
++		request_module("saa7111");
++
++	/*
++	 * If that didn't work, then we're out of luck.
++	 */
++	if (ret == 0 && !dp->decoder) {
++		i2c_unregister_bus(dp->bus);
++		ret = -ENXIO;
++	}
++
++	if (ret) {
++		kfree(dp);
++
++		/*
++		 * put the decoder back to sleep
++		 */
++		decoder_sleep(1);
++	}
++
++	return ret;
++}
++
++static struct video_device cyberpro_grabber = {
++	name:		"",
++	type:		VID_TYPE_CAPTURE   | VID_TYPE_OVERLAY |
++			VID_TYPE_CHROMAKEY | VID_TYPE_SCALES  |
++			VID_TYPE_SUBCAPTURE,
++	hardware:	0,
++	open:		cyberpro_grabber_open,
++	close:		cyberpro_grabber_close,
++	read:		cyberpro_grabber_read,
++	write:		cyberpro_grabber_write,
++	ioctl:		cyberpro_grabber_ioctl,
++#ifdef USE_MMAP
++	mmap:		cyberpro_grabber_mmap,
++#endif
++	initialize:	cyberpro_grabber_init_done,
++};
++
++int init_cyber2000fb_viddev(void)
++{
++	struct cyberpro_info info;
++
++	if (!cyber2000fb_attach(&info, 0))
++		return -ENXIO;
++
++	strncpy(cyberpro_grabber.name, info.dev_name, sizeof(cyberpro_grabber.name));
++
++	cyberpro_grabber.priv = &info;
++
++	return video_register_device(&cyberpro_grabber, VFL_TYPE_GRABBER, -1);
++}
++
++/*
++ * This can be cleaned up when the SAA7111 code is fixed.
++ */
++#ifdef MODULE
++static int __init cyberpro_init(void)
++{
++	disable_irq(35);
++	return init_cyber2000fb_viddev();
++}
++
++static void __exit cyberpro_exit(void)
++{
++	video_unregister_device(&cyberpro_grabber);
++	kfree(cyberpro_grabber.priv);
++	i2c_unregister_bus(&cyberpro_i2c_bus);
++
++	/*
++	 * put the decoder back to sleep
++	 */
++	decoder_sleep(1);
++
++	cyber2000fb_detach(0);
++}
++
++module_init(cyberpro_init);
++module_exit(cyberpro_exit);
++#endif
+--- linux-2.4.25/drivers/media/video/i2c-old.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/media/video/i2c-old.c	2004-03-31 17:15:09.000000000 +0200
+@@ -36,11 +36,20 @@
+ static struct i2c_driver *drivers[I2C_DRIVER_MAX];
+ static int bus_count = 0, driver_count = 0;
+ 
++extern int saa7111_init(void);
++extern int saa7185_init(void);
++extern int bt819_init(void);
++extern int bt856_init(void);
++
+ int i2c_init(void)
+ {
+ 	printk(KERN_INFO "i2c: initialized%s\n",
+ 		scan ? " (i2c bus scan enabled)" : "");
+ 
++#if defined(CONFIG_VIDEO_CYBERPRO)
++	saa7111_init();
++#endif
++
+ 	return 0;
+ }
+ 
+@@ -52,10 +61,10 @@
+ 	int i,j,ack=1;
+ 	unsigned char addr;
+ 	LOCK_FLAGS;
+-    
++
+ 	/* probe for device */
+ 	LOCK_I2C_BUS(bus);
+-	for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2) 
++	for (addr = driver->addr_l; addr <= driver->addr_h; addr += 2)
+ 	{
+ 		i2c_start(bus);
+ 		ack = i2c_sendbyte(bus,addr,0);
+@@ -87,8 +96,8 @@
+ 	device->addr = addr;
+ 
+ 	/* Attach */
+-	
+-	if (driver->attach(device)!=0) 
++
++	if (driver->attach(device)!=0)
+ 	{
+ 		kfree(device);
+ 		return;
+@@ -114,7 +123,7 @@
+ 	for (i = 0; i < I2C_DEVICE_MAX; i++)
+ 		if (device == device->driver->devices[i])
+ 			break;
+-	if (I2C_DEVICE_MAX == i) 
++	if (I2C_DEVICE_MAX == i)
+ 	{
+ 		printk(KERN_WARNING "i2c: detach_device #1: device not found: %s\n",
+ 			device->name);
+@@ -126,7 +135,7 @@
+ 	for (i = 0; i < I2C_DEVICE_MAX; i++)
+ 		if (device == device->bus->devices[i])
+ 			break;
+-	if (I2C_DEVICE_MAX == i) 
++	if (I2C_DEVICE_MAX == i)
+ 	{
+ 		printk(KERN_WARNING "i2c: detach_device #2: device not found: %s\n",
+ 		       device->name);
+@@ -158,19 +167,19 @@
+ 	busses[i] = bus;
+ 	bus_count++;
+ 	REGPRINT(printk("i2c: bus registered: %s\n",bus->name));
+-	
++
+ 	MOD_INC_USE_COUNT;
+ 
+-	if (scan) 
++	if (scan)
+ 	{
+ 		/* scan whole i2c bus */
+ 		LOCK_I2C_BUS(bus);
+-		for (i = 0; i < 256; i+=2) 
++		for (i = 0; i < 256; i+=2)
+ 		{
+ 			i2c_start(bus);
+ 			ack = i2c_sendbyte(bus,i,0);
+ 			i2c_stop(bus);
+-			if (!ack) 
++			if (!ack)
+ 			{
+ 				printk(KERN_INFO "i2c: scanning bus %s: found device at addr=0x%02x\n",
+ 					bus->name,i);
+@@ -198,20 +207,20 @@
+ 	for (i = 0; i < I2C_BUS_MAX; i++)
+ 		if (bus == busses[i])
+ 			break;
+-	if (I2C_BUS_MAX == i) 
++	if (I2C_BUS_MAX == i)
+ 	{
+ 		printk(KERN_WARNING "i2c: unregister_bus #1: bus not found: %s\n",
+ 			bus->name);
+ 		return -ENODEV;
+ 	}
+-	
++
+ 	MOD_DEC_USE_COUNT;
+-	
++
+ 	busses[i] = NULL;
+ 	bus_count--;
+ 	REGPRINT(printk("i2c: bus unregistered: %s\n",bus->name));
+ 
+-	return 0;    
++	return 0;
+ }
+ 
+ /* ----------------------------------------------------------------------- */
+@@ -231,9 +240,9 @@
+ 
+ 	drivers[i] = driver;
+ 	driver_count++;
+-	
++
+ 	MOD_INC_USE_COUNT;
+-	
++
+ 	REGPRINT(printk("i2c: driver registered: %s\n",driver->name));
+ 
+ 	/* Probe available busses */
+@@ -256,7 +265,7 @@
+ 	for (i = 0; i < I2C_DRIVER_MAX; i++)
+ 		if (driver == drivers[i])
+ 			break;
+-	if (I2C_DRIVER_MAX == i) 
++	if (I2C_DRIVER_MAX == i)
+ 	{
+ 		printk(KERN_WARNING "i2c: unregister_driver: driver not found: %s\n",
+ 			driver->name);
+@@ -264,7 +273,7 @@
+ 	}
+ 
+ 	MOD_DEC_USE_COUNT;
+-	
++
+ 	drivers[i] = NULL;
+ 	driver_count--;
+ 	REGPRINT(printk("i2c: driver unregistered: %s\n",driver->name));
+@@ -328,7 +337,7 @@
+ int i2c_ack(struct i2c_bus *bus)
+ {
+ 	int ack;
+-    
++
+ 	I2C_SET(bus,0,1);
+ 	I2C_SET(bus,1,1);
+ 	ack = I2C_GET(bus);
+@@ -339,7 +348,7 @@
+ int i2c_sendbyte(struct i2c_bus *bus,unsigned char data,int wait_for_ack)
+ {
+ 	int i, ack;
+-    
++
+ 	I2C_SET(bus,0,0);
+ 	for (i=7; i>=0; i--)
+ 		(data&(1<<i)) ? i2c_one(bus) : i2c_zero(bus);
+@@ -354,9 +363,9 @@
+ {
+ 	int i;
+ 	unsigned char data=0;
+-    
++
+ 	I2C_SET(bus,0,1);
+-	for (i=7; i>=0; i--) 
++	for (i=7; i>=0; i--)
+ 	{
+ 		I2C_SET(bus,1,1);
+ 		if (I2C_GET(bus))
+@@ -373,7 +382,7 @@
+ int i2c_read(struct i2c_bus *bus, unsigned char addr)
+ {
+ 	int ret;
+-    
++
+ 	if (bus->i2c_read)
+ 		return bus->i2c_read(bus, addr);
+ 
+--- linux-2.4.25/drivers/media/video/saa7111.c~2.4.25-vrs2.patch	2001-09-30 21:26:06.000000000 +0200
++++ linux-2.4.25/drivers/media/video/saa7111.c	2004-03-31 17:15:09.000000000 +0200
+@@ -20,9 +20,9 @@
+     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/init.h>
++#include <linux/module.h>
+ #include <linux/delay.h>
+ #include <linux/errno.h>
+ #include <linux/fs.h>
+@@ -149,7 +149,11 @@
+ 		0x0d, 0x00,	/* 0d - HUE=0 */
+ 		0x0e, 0x01,	/* 0e - CDTO=0, CSTD=0, DCCF=0, FCTC=0, CHBW=1 */
+ 		0x0f, 0x00,	/* 0f - reserved */
++#ifndef CONFIG_ARCH_NETWINDER
+ 		0x10, 0x48,	/* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
++#else
++		0x10, 0xc8,	/* 10 - OFTS=YUV-CCIR656, HDEL=0, VLRN=1, YDEL=0 */
++#endif
+ 		0x11, 0x1c,	/* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1, OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+ 		0x12, 0x00,	/* 12 - output control 2 */
+ 		0x13, 0x00,	/* 13 - output control 3 */
+--- linux-2.4.25/drivers/message/i2o/i2o_core.c~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/message/i2o/i2o_core.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1665,14 +1665,14 @@
+ 	}
+ 	memset(status, 0, 4);
+ 	
+-	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
+-	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
+-	msg[2]=core_context;
+-	msg[3]=0;
+-	msg[4]=0;
+-	msg[5]=0;
+-	msg[6]=virt_to_bus(status);
+-	msg[7]=0;	/* 64bit host FIXME */
++	writel(EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0, msg + 0);
++	writel(I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID, msg + 1);
++	writel(core_context, msg + 2);
++	writel(0, msg + 3);
++	writel(0, msg + 4);
++	writel(0, msg + 5);
++	writel(virt_to_bus(status), msg + 6);
++	writel(0, msg + 7);	/* 64bit host FIXME */
+ 
+ 	i2o_post_message(c,m);
+ 
+@@ -1781,15 +1781,15 @@
+ 		return -ETIMEDOUT;	
+ 	msg=(u32 *)(c->mem_offset+m);
+ 
+-	msg[0]=NINE_WORD_MSG_SIZE|SGL_OFFSET_0;
+-	msg[1]=I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID;
+-	msg[2]=core_context;
+-	msg[3]=0;
+-	msg[4]=0;
+-	msg[5]=0;
+-	msg[6]=virt_to_bus(c->status_block);
+-	msg[7]=0;   /* 64bit host FIXME */
+-	msg[8]=sizeof(i2o_status_block); /* always 88 bytes */
++	writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, msg + 0);
++	writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, msg + 1);
++	writel(core_context, msg + 2);
++	writel(0, msg + 3);
++	writel(0, msg + 4);
++	writel(0, msg + 5);
++	writel(virt_to_bus(c->status_block), msg + 6);
++	writel(0, msg + 7);   /* 64bit host FIXME */
++	writel(sizeof(i2o_status_block), msg + 8); /* always 88 bytes */
+ 
+ 	i2o_post_message(c,m);
+ 
+@@ -2193,15 +2193,15 @@
+ 	}
+ 	memset(status, 0, 4);
+ 
+-	msg[0]= EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6;
+-	msg[1]= I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID;
+-	msg[2]= core_context;
+-	msg[3]= 0x0106;				/* Transaction context */
+-	msg[4]= 4096;				/* Host page frame size */
++	writel(EIGHT_WORD_MSG_SIZE| TRL_OFFSET_6, msg + 0);
++	writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, msg + 1);
++	writel(core_context, msg + 2);
++	writel(0x0106, msg + 3);		/* Transaction context */
++	writel(PAGE_SIZE, msg + 4);		/* Host page frame size */
+ 	/* Frame size is in words. 256 bytes a frame for now */
+-	msg[5]= MSG_FRAME_SIZE<<16|0x80;	/* Outbound msg frame size in words and Initcode */
+-	msg[6]= 0xD0000004;			/* Simple SG LE, EOB */
+-	msg[7]= virt_to_bus(status);
++	writel(MSG_FRAME_SIZE<<16|0x80, msg + 5);/* Outbound msg frame size in words and Initcode */
++	writel(0xD0000004, msg + 6);		/* Simple SG LE, EOB */
++	writel(virt_to_bus(status), msg + 7);
+ 
+ 	i2o_post_message(c,m);
+ 	
+--- linux-2.4.25/drivers/message/i2o/i2o_pci.c~2.4.25-vrs2.patch	2002-11-29 00:53:13.000000000 +0100
++++ linux-2.4.25/drivers/message/i2o/i2o_pci.c	2004-03-31 17:15:09.000000000 +0200
+@@ -390,4 +390,4 @@
+ MODULE_PARM_DESC(dpt, "Set this if you want to drive DPT cards normally handled by dpt_i2o");
+ module_init(i2o_pci_core_attach);
+ module_exit(i2o_pci_core_detach);
+- 
+\ No newline at end of file
++ 
+--- linux-2.4.25/drivers/misc/Config.in~2.4.25-vrs2.patch	1999-12-26 00:04:56.000000000 +0100
++++ linux-2.4.25/drivers/misc/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -1,7 +1,17 @@
+ #
+-# Misc strange devices
++# MCP drivers
+ #
+ mainmenu_option next_comment
+-comment 'Misc devices'
++comment 'Multimedia Capabilities Port drivers'
++
++bool 'Multimedia drivers' CONFIG_MCP
++
++# Interface drivers
++dep_bool 'Support SA1100 MCP interface' CONFIG_MCP_SA1100 $CONFIG_MCP $CONFIG_ARCH_SA1100
++
++# Chip drivers
++dep_tristate 'Support for UCB1200 / UCB1300' CONFIG_MCP_UCB1200 $CONFIG_MCP
++dep_tristate '  Audio / Telephony interface support' CONFIG_MCP_UCB1200_AUDIO $CONFIG_MCP_UCB1200 $CONFIG_SOUND
++dep_tristate '  Touchscreen interface support' CONFIG_MCP_UCB1200_TS $CONFIG_MCP_UCB1200
+ 
+ endmenu
+--- linux-2.4.25/drivers/misc/Makefile~2.4.25-vrs2.patch	2000-12-29 23:07:22.000000000 +0100
++++ linux-2.4.25/drivers/misc/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -11,6 +11,14 @@
+ 
+ O_TARGET := misc.o
+ 
++export-objs			:= mcp-core.o mcp-sa1100.o ucb1x00-core.o
++
++obj-$(CONFIG_MCP)		+= mcp-core.o
++obj-$(CONFIG_MCP_SA1100)	+= mcp-sa1100.o
++obj-$(CONFIG_MCP_UCB1200)	+= ucb1x00-core.o
++obj-$(CONFIG_MCP_UCB1200_AUDIO)	+= ucb1x00-audio.o
++obj-$(CONFIG_MCP_UCB1200_TS)	+= ucb1x00-ts.o
++
+ include $(TOPDIR)/Rules.make
+ 
+ fastdep:
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/mcp-core.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,155 @@
++/*
++ *  linux/drivers/misc/mcp-core.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ * 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.
++ *
++ *  Generic MCP (Multimedia Communications Port) layer.  All MCP locking
++ *  is solely held within this file.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/smp.h>
++
++#include <asm/dma.h>
++#include <asm/system.h>
++
++#include "mcp.h"
++
++/**
++ *	mcp_set_telecom_divisor - set the telecom divisor
++ *	@mcp: MCP interface structure
++ *	@div: SIB clock divisor
++ *
++ *	Set the telecom divisor on the MCP interface.  The resulting
++ *	sample rate is SIBCLOCK/div.
++ */
++void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div)
++{
++	spin_lock_irq(&mcp->lock);
++	mcp->set_telecom_divisor(mcp, div);
++	spin_unlock_irq(&mcp->lock);
++}
++
++/**
++ *	mcp_set_audio_divisor - set the audio divisor
++ *	@mcp: MCP interface structure
++ *	@div: SIB clock divisor
++ *
++ *	Set the audio divisor on the MCP interface.
++ */
++void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div)
++{
++	spin_lock_irq(&mcp->lock);
++	mcp->set_audio_divisor(mcp, div);
++	spin_unlock_irq(&mcp->lock);
++}
++
++/**
++ *	mcp_reg_write - write a device register
++ *	@mcp: MCP interface structure
++ *	@reg: 4-bit register index
++ *	@val: 16-bit data value
++ *
++ *	Write a device register.  The MCP interface must be enabled
++ *	to prevent this function hanging.
++ */
++void mcp_reg_write(struct mcp *mcp, unsigned int reg, unsigned int val)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&mcp->lock, flags);
++	mcp->reg_write(mcp, reg, val);
++	spin_unlock_irqrestore(&mcp->lock, flags);
++}
++
++/**
++ *	mcp_reg_read - read a device register
++ *	@mcp: MCP interface structure
++ *	@reg: 4-bit register index
++ *
++ *	Read a device register and return its value.  The MCP interface
++ *	must be enabled to prevent this function hanging.
++ */
++unsigned int mcp_reg_read(struct mcp *mcp, unsigned int reg)
++{
++	unsigned long flags;
++	unsigned int val;
++
++	spin_lock_irqsave(&mcp->lock, flags);
++	val = mcp->reg_read(mcp, reg);
++	spin_unlock_irqrestore(&mcp->lock, flags);
++
++	return val;
++}
++
++/**
++ *	mcp_enable - enable the MCP interface
++ *	@mcp: MCP interface to enable
++ *
++ *	Enable the MCP interface.  Each call to mcp_enable will need
++ *	a corresponding call to mcp_disable to disable the interface.
++ */
++void mcp_enable(struct mcp *mcp)
++{
++	spin_lock_irq(&mcp->lock);
++	if (mcp->use_count++ == 0)
++		mcp->enable(mcp);
++	spin_unlock_irq(&mcp->lock);
++}
++
++/**
++ *	mcp_disable - disable the MCP interface
++ *	@mcp: MCP interface to disable
++ *
++ *	Disable the MCP interface.  The MCP interface will only be
++ *	disabled once the number of calls to mcp_enable matches the
++ *	number of calls to mcp_disable.
++ */
++void mcp_disable(struct mcp *mcp)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&mcp->lock, flags);
++	if (--mcp->use_count == 0)
++		mcp->disable(mcp);
++	spin_unlock_irqrestore(&mcp->lock, flags);
++}
++
++
++/*
++ * This needs re-working
++ */
++static struct mcp *mcp_if;
++
++struct mcp *mcp_get(void)
++{
++	return mcp_if;
++}
++
++int mcp_register(struct mcp *mcp)
++{
++	if (mcp_if)
++		return -EBUSY;
++	if (mcp->owner)
++		__MOD_INC_USE_COUNT(mcp->owner);
++	mcp_if = mcp;
++	return 0;
++}
++
++EXPORT_SYMBOL(mcp_set_telecom_divisor);
++EXPORT_SYMBOL(mcp_set_audio_divisor);
++EXPORT_SYMBOL(mcp_reg_write);
++EXPORT_SYMBOL(mcp_reg_read);
++EXPORT_SYMBOL(mcp_enable);
++EXPORT_SYMBOL(mcp_disable);
++EXPORT_SYMBOL(mcp_get);
++EXPORT_SYMBOL(mcp_register);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("Core multimedia communications port driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/mcp-sa1100.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,180 @@
++/*
++ *  linux/drivers/misc/mcp-sa1100.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ * 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.
++ *
++ *  SA1100 MCP (Multimedia Communications Port) driver.
++ *
++ *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/system.h>
++
++#include "mcp.h"
++
++static void
++mcp_sa1100_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
++{
++	unsigned int mccr0;
++
++	divisor /= 32;
++
++	mccr0 = Ser4MCCR0 & ~0x00007f00;
++	mccr0 |= divisor << 8;
++	Ser4MCCR0 = mccr0;
++}
++
++static void
++mcp_sa1100_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
++{
++	unsigned int mccr0;
++
++	divisor /= 32;
++
++	mccr0 = Ser4MCCR0 & ~0x0000007f;
++	mccr0 |= divisor;
++	Ser4MCCR0 = mccr0;
++}
++
++/*
++ * Write data to the device.  The bit should be set after 3 subframe
++ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
++ * We really should try doing something more productive while we
++ * wait.
++ */
++static void
++mcp_sa1100_write(struct mcp *mcp, unsigned int reg, unsigned int val)
++{
++	int ret = -ETIME;
++	int i;
++
++	Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
++
++	for (i = 0; i < 2; i++) {
++		udelay(mcp->rw_timeout);
++		if (Ser4MCSR & MCSR_CWC) {
++			ret = 0;
++			break;
++		}
++	}
++
++	if (ret < 0)
++		printk(KERN_WARNING "mcp: write timed out\n");
++}
++
++/*
++ * Read data from the device.  The bit should be set after 3 subframe
++ * times (each frame is 64 clocks).  We wait a maximum of 6 subframes.
++ * We really should try doing something more productive while we
++ * wait.
++ */
++static unsigned int
++mcp_sa1100_read(struct mcp *mcp, unsigned int reg)
++{
++	int ret = -ETIME;
++	int i;
++
++	Ser4MCDR2 = reg << 17 | MCDR2_Rd;
++
++	for (i = 0; i < 2; i++) {
++		udelay(mcp->rw_timeout);
++		if (Ser4MCSR & MCSR_CRC) {
++			ret = Ser4MCDR2 & 0xffff;
++			break;
++		}
++	}
++
++	if (ret < 0)
++		printk(KERN_WARNING "mcp: read timed out\n");
++
++	return ret;
++}
++
++static void mcp_sa1100_enable(struct mcp *mcp)
++{
++	Ser4MCSR = -1;
++	Ser4MCCR0 |= MCCR0_MCE;
++}
++
++static void mcp_sa1100_disable(struct mcp *mcp)
++{
++	Ser4MCCR0 &= ~MCCR0_MCE;
++}
++
++struct mcp mcp_sa1100 = {
++	owner:			THIS_MODULE,
++	lock:			SPIN_LOCK_UNLOCKED,
++	sclk_rate:		11981000,
++	dma_audio_rd:		DMA_Ser4MCP0Rd,
++	dma_audio_wr:		DMA_Ser4MCP0Wr,
++	dma_telco_rd:		DMA_Ser4MCP1Rd,
++	dma_telco_wr:		DMA_Ser4MCP1Wr,
++	set_telecom_divisor:	mcp_sa1100_set_telecom_divisor,
++	set_audio_divisor:	mcp_sa1100_set_audio_divisor,
++	reg_write:		mcp_sa1100_write,
++	reg_read:		mcp_sa1100_read,
++	enable:			mcp_sa1100_enable,
++	disable:		mcp_sa1100_disable,
++};
++
++/*
++ * This needs re-working
++ */
++static int mcp_sa1100_init(void)
++{
++	struct mcp *mcp = &mcp_sa1100;
++	int ret = -ENODEV;
++
++	if (machine_is_accelent_sa()    ||
++	    machine_is_adsbitsy()       || machine_is_assabet()        ||
++	    machine_is_cerf()           || machine_is_flexanet()       ||
++	    machine_is_freebird()       || machine_is_graphicsclient() ||
++	    machine_is_graphicsmaster() || machine_is_lart()           ||
++	    machine_is_omnimeter()      || machine_is_pfs168()         ||
++	    machine_is_shannon()        || machine_is_simpad()         ||
++	    machine_is_simputer()       || machine_is_yopy()) {
++		/*
++		 * Setup the PPC unit correctly.
++		 */
++		PPDR &= ~PPC_RXD4;
++		PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
++		PSDR |= PPC_RXD4;
++		PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
++		PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
++
++		Ser4MCSR = -1;
++		Ser4MCCR1 = 0;
++		Ser4MCCR0 = 0x00007f7f | MCCR0_ADM;
++
++		/*
++		 * Calculate the read/write timeout (us) from the bit clock
++		 * rate.  This is the period for 3 64-bit frames.  Always
++		 * round this time up.
++		 */
++		mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
++				  mcp->sclk_rate;
++
++		ret = mcp_register(mcp);
++	}
++
++	return ret;
++}
++
++module_init(mcp_sa1100_init);
++EXPORT_SYMBOL(mcp_sa1100_init);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/mcp.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,44 @@
++/*
++ *  linux/drivers/misc/mcp.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ */
++#ifndef MCP_H
++#define MCP_H
++
++struct mcp {
++	struct module	*owner;
++	spinlock_t	lock;
++	int		use_count;
++	unsigned int	sclk_rate;
++	unsigned int	rw_timeout;
++	dma_device_t	dma_audio_rd;
++	dma_device_t	dma_audio_wr;
++	dma_device_t	dma_telco_rd;
++	dma_device_t	dma_telco_wr;
++	void		(*set_telecom_divisor)(struct mcp *, unsigned int);
++	void		(*set_audio_divisor)(struct mcp *, unsigned int);
++	void		(*reg_write)(struct mcp *, unsigned int, unsigned int);
++	unsigned int	(*reg_read)(struct mcp *, unsigned int);
++	void		(*enable)(struct mcp *);
++	void		(*disable)(struct mcp *);
++};
++
++void mcp_set_telecom_divisor(struct mcp *, unsigned int);
++void mcp_set_audio_divisor(struct mcp *, unsigned int);
++void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
++unsigned int mcp_reg_read(struct mcp *, unsigned int);
++void mcp_enable(struct mcp *);
++void mcp_disable(struct mcp *);
++
++/* noddy implementation alert! */
++struct mcp *mcp_get(void);
++int mcp_register(struct mcp *);
++
++#define mcp_get_sclk_rate(mcp)	((mcp)->sclk_rate)
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00-audio.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,378 @@
++/*
++ *  linux/drivers/misc/ucb1x00-audio.c
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/slab.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/list.h>
++
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++
++#include "ucb1x00.h"
++
++#include "../drivers/sound/sa1100-audio.h"
++
++#define MAGIC	0x41544154
++
++struct ucb1x00_audio {
++	struct file_operations	fops;
++	struct file_operations	mops;
++	struct ucb1x00		*ucb;
++	audio_stream_t		output_stream;
++	audio_stream_t		input_stream;
++	audio_state_t		state;
++	unsigned int		rate;
++	int			dev_id;
++	int			mix_id;
++	unsigned int		daa_oh_bit;
++	unsigned int		telecom;
++	unsigned int		magic;
++	unsigned int		ctrl_a;
++	unsigned int		ctrl_b;
++
++	/* mixer info */
++	unsigned int		mod_cnt;
++	unsigned short		output_level;
++	unsigned short		input_level;
++};
++
++#define REC_MASK	(SOUND_MASK_VOLUME | SOUND_MASK_MIC)
++#define DEV_MASK	REC_MASK
++
++static int
++ucb1x00_mixer_ioctl(struct inode *ino, struct file *filp, uint cmd, ulong arg)
++{
++	struct ucb1x00_audio *ucba;
++	unsigned int val, gain;
++	int ret = 0;
++
++	ucba = list_entry(filp->f_op, struct ucb1x00_audio, mops);
++
++	if (_IOC_TYPE(cmd) != 'M')
++		return -EINVAL;
++
++	if (cmd == SOUND_MIXER_INFO) {
++		struct mixer_info mi;
++
++		strncpy(mi.id, "UCB1x00", sizeof(mi.id));
++		strncpy(mi.name, "Philips UCB1x00", sizeof(mi.name));
++		mi.modify_counter = ucba->mod_cnt;
++		return copy_to_user((void *)arg, &mi, sizeof(mi)) ? -EFAULT : 0;
++	}
++
++	if (_IOC_DIR(cmd) & _IOC_WRITE) {
++		unsigned int left, right;
++
++		ret = get_user(val, (unsigned int *)arg);
++		if (ret)
++			goto out;
++
++		left  = val & 255;
++		right = val >> 8;
++
++		if (left > 100)
++			left = 100;
++		if (right > 100)
++			right = 100;
++
++		gain = (left + right) / 2;
++
++		ret = -EINVAL;
++		if (!ucba->telecom) {
++			switch(_IOC_NR(cmd)) {
++			case SOUND_MIXER_VOLUME:
++				ucba->output_level = gain | gain << 8;
++				ucba->mod_cnt++;
++				ucba->ctrl_b = (ucba->ctrl_b & 0xff00) |
++					       ((gain * 31) / 100);
++				ucb1x00_reg_write(ucba->ucb, UCB_AC_B,
++						  ucba->ctrl_b);
++				ret = 0;
++				break;
++
++			case SOUND_MIXER_MIC:
++				ucba->input_level = gain | gain << 8;
++				ucba->mod_cnt++;
++				ucba->ctrl_a = (ucba->ctrl_a & 0x7f) |
++					       (((gain * 31) / 100) << 7);
++				ucb1x00_reg_write(ucba->ucb, UCB_AC_A,
++						  ucba->ctrl_a);
++				ret = 0;
++				break;
++			}
++		}
++	}
++
++	if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
++		switch (_IOC_NR(cmd)) {
++		case SOUND_MIXER_VOLUME:
++			val = ucba->output_level;
++			break;
++
++		case SOUND_MIXER_MIC:
++			val = ucba->input_level;
++			break;
++
++		case SOUND_MIXER_RECSRC:
++		case SOUND_MIXER_RECMASK:
++			val = ucba->telecom ? 0 : REC_MASK;
++			break;
++
++		case SOUND_MIXER_DEVMASK:
++			val = ucba->telecom ? 0 : DEV_MASK;
++			break;
++
++		case SOUND_MIXER_CAPS:
++		case SOUND_MIXER_STEREODEVS:
++			val = 0;
++			break;
++
++		default:
++			val = 0;
++			ret = -EINVAL;
++			break;
++		}
++
++		if (ret == 0)
++			ret = put_user(val, (int *)arg);
++	}
++ out:
++	return ret;
++}
++
++static int ucb1x00_audio_setrate(struct ucb1x00_audio *ucba, int rate)
++{
++	unsigned int div_rate = ucb1x00_clkrate(ucba->ucb) / 32;
++	unsigned int div;
++
++	div = (div_rate + (rate / 2)) / rate;
++	if (div < 6)
++		div = 6;
++	if (div > 127)
++		div = 127;
++
++	ucba->ctrl_a = (ucba->ctrl_a & ~0x7f) | div;
++
++	if (ucba->telecom) {
++		ucb1x00_reg_write(ucba->ucb, UCB_TC_B, 0);
++		ucb1x00_set_telecom_divisor(ucba->ucb, div * 32);
++		ucb1x00_reg_write(ucba->ucb, UCB_TC_A, ucba->ctrl_a);
++		ucb1x00_reg_write(ucba->ucb, UCB_TC_B, ucba->ctrl_b);
++	} else {
++		ucb1x00_reg_write(ucba->ucb, UCB_AC_B, 0);
++		ucb1x00_set_audio_divisor(ucba->ucb, div * 32);
++		ucb1x00_reg_write(ucba->ucb, UCB_AC_A, ucba->ctrl_a);
++		ucb1x00_reg_write(ucba->ucb, UCB_AC_B, ucba->ctrl_b);
++	}
++
++	ucba->rate = div_rate / div;
++
++	return ucba->rate;
++}
++
++static int ucb1x00_audio_getrate(struct ucb1x00_audio *ucba)
++{
++	return ucba->rate;
++}
++
++static void ucb1x00_audio_startup(void *data)
++{
++	struct ucb1x00_audio *ucba = data;
++
++	ucb1x00_enable(ucba->ucb);
++	ucb1x00_audio_setrate(ucba, ucba->rate);
++
++	ucb1x00_reg_write(ucba->ucb, UCB_MODE, UCB_MODE_DYN_VFLAG_ENA);
++
++	/*
++	 * Take off-hook
++	 */
++	if (ucba->daa_oh_bit)
++		ucb1x00_io_write(ucba->ucb, 0, ucba->daa_oh_bit);
++}
++
++static void ucb1x00_audio_shutdown(void *data)
++{
++	struct ucb1x00_audio *ucba = data;
++
++	/*
++	 * Place on-hook
++	 */
++	if (ucba->daa_oh_bit)
++		ucb1x00_io_write(ucba->ucb, ucba->daa_oh_bit, 0);
++
++	ucb1x00_reg_write(ucba->ucb, ucba->telecom ? UCB_TC_B : UCB_AC_B, 0);
++	ucb1x00_disable(ucba->ucb);
++}
++
++static int
++ucb1x00_audio_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++	struct ucb1x00_audio *ucba;
++	int val, ret = 0;
++
++	ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
++
++	/*
++	 * Make sure we have our magic number
++	 */
++	if (ucba->magic != MAGIC)
++		return -ENODEV;
++
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *)arg);
++		if (ret)
++			return ret;
++		if (val != 0)
++			return -EINVAL;
++		val = 0;
++		break;
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		val = 1;
++		break;
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (int *)arg);
++		if (ret)
++			return ret;
++		val = ucb1x00_audio_setrate(ucba, val);
++		break;
++
++	case SOUND_PCM_READ_RATE:
++		val = ucb1x00_audio_getrate(ucba);
++		break;
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		val = AFMT_S16_LE;
++		break;
++
++	default:
++		return ucb1x00_mixer_ioctl(inode, file, cmd, arg);
++	}
++
++	return put_user(val, (int *)arg);
++}
++
++static int ucb1x00_audio_open(struct inode *inode, struct file *file)
++{
++	struct ucb1x00_audio *ucba;
++
++	ucba = list_entry(file->f_op, struct ucb1x00_audio, fops);
++
++	return sa1100_audio_attach(inode, file, &ucba->state);
++}
++
++static struct ucb1x00_audio *ucb1x00_audio_alloc(struct ucb1x00 *ucb)
++{
++	struct ucb1x00_audio *ucba;
++
++	ucba = kmalloc(sizeof(*ucba), GFP_KERNEL);
++	if (ucba) {
++		memset(ucba, 0, sizeof(*ucba));
++
++		ucba->magic = MAGIC;
++		ucba->ucb = ucb;
++		ucba->fops.owner = THIS_MODULE;
++		ucba->fops.open  = ucb1x00_audio_open;
++		ucba->mops.owner = THIS_MODULE;
++		ucba->mops.ioctl = ucb1x00_mixer_ioctl;
++		ucba->state.output_stream = &ucba->output_stream;
++		ucba->state.input_stream = &ucba->input_stream;
++		ucba->state.data = ucba;
++		ucba->state.hw_init = ucb1x00_audio_startup;
++		ucba->state.hw_shutdown = ucb1x00_audio_shutdown;
++		ucba->state.client_ioctl = ucb1x00_audio_ioctl;
++
++		/* There is a bug in the StrongARM causes corrupt MCP data to be sent to
++		 * the codec when the FIFOs are empty and writes are made to the OS timer
++		 * match register 0. To avoid this we must make sure that data is always
++		 * sent to the codec.
++		 */
++		ucba->state.need_tx_for_rx = 1;
++
++		init_MUTEX(&ucba->state.sem);
++		ucba->rate = 8000;
++	}
++	return ucba;
++}
++
++static struct ucb1x00_audio *audio, *telecom;
++
++static int __init ucb1x00_audio_init(void)
++{
++	struct ucb1x00 *ucb = ucb1x00_get();
++	struct ucb1x00_audio *a;
++
++	if (!ucb)
++		return -ENODEV;
++
++	a = ucb1x00_audio_alloc(ucb);
++	if (a) {
++		a->state.input_dma  = ucb->mcp->dma_audio_rd;
++		a->state.input_id   = "UCB1x00 audio in";
++		a->state.output_dma = ucb->mcp->dma_audio_wr;
++		a->state.output_id  = "UCB1x00 audio out";
++		a->dev_id = register_sound_dsp(&a->fops, -1);
++		a->mix_id = register_sound_mixer(&a->mops, -1);
++		a->ctrl_a = 0;
++		a->ctrl_b = UCB_AC_B_IN_ENA|UCB_AC_B_OUT_ENA;
++		audio = a;
++	}
++
++	a = ucb1x00_audio_alloc(ucb);
++	if (a) {
++#if 0
++		a->daa_oh_bit = UCB_IO_8;
++
++		ucb1x00_enable(ucb);
++		ucb1x00_io_write(ucb, a->daa_oh_bit, 0);
++		ucb1x00_io_set_dir(ucb, UCB_IO_7 | UCB_IO_6, a->daa_oh_bit);
++		ucb1x00_disable(ucb);
++#endif
++
++		a->telecom = 1;
++		a->state.input_dma  = ucb->mcp->dma_telco_rd;
++		a->state.input_id   = "UCB1x00 telco in";
++		a->state.output_dma = ucb->mcp->dma_telco_wr;
++		a->state.output_id  = "UCB1x00 telco out";
++		a->dev_id = register_sound_dsp(&a->fops, -1);
++		a->mix_id = register_sound_mixer(&a->mops, -1);
++		a->ctrl_a = 0;
++		a->ctrl_b = UCB_TC_B_IN_ENA|UCB_TC_B_OUT_ENA;
++		telecom = a;
++	}
++
++	return 0;
++}
++
++static void __exit ucb1x00_audio_exit(void)
++{
++	unregister_sound_dsp(telecom->dev_id);
++	unregister_sound_dsp(audio->dev_id);
++	unregister_sound_mixer(telecom->mix_id);
++	unregister_sound_mixer(audio->mix_id);
++}
++
++module_init(ucb1x00_audio_init);
++module_exit(ucb1x00_audio_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 telecom/audio driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00-core.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,651 @@
++/*
++ *  linux/drivers/misc/ucb1x00-core.c
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  The UCB1x00 core driver provides basic services for handling IO,
++ *  the ADC, interrupts, and accessing registers.  It is designed
++ *  such that everything goes through this layer, thereby providing
++ *  a consistent locking methodology, as well as allowing the drivers
++ *  to be used on other non-MCP-enabled hardware platforms.
++ *
++ *  Note that all locks are private to this file.  Nothing else may
++ *  touch them.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/interrupt.h>
++#include <linux/pm.h>
++
++#include <asm/dma.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/arch/shannon.h>
++
++#include "ucb1x00.h"
++
++/**
++ *	ucb1x00_io_set_dir - set IO direction
++ *	@ucb: UCB1x00 structure describing chip
++ *	@in:  bitfield of IO pins to be set as inputs
++ *	@out: bitfield of IO pins to be set as outputs
++ *
++ *	Set the IO direction of the ten general purpose IO pins on
++ *	the UCB1x00 chip.  The @in bitfield has priority over the
++ *	@out bitfield, in that if you specify a pin as both input
++ *	and output, it will end up as an input.
++ *
++ *	ucb1x00_enable must have been called to enable the comms
++ *	before using this function.
++ *
++ *	This function takes a spinlock, disabling interrupts.
++ */
++void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int in, unsigned int out)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&ucb->io_lock, flags);
++	ucb->io_dir |= out;
++	ucb->io_dir &= ~in;
++
++	ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
++	spin_unlock_irqrestore(&ucb->io_lock, flags);
++}
++
++/**
++ *	ucb1x00_io_write - set or clear IO outputs
++ *	@ucb:   UCB1x00 structure describing chip
++ *	@set:   bitfield of IO pins to set to logic '1'
++ *	@clear: bitfield of IO pins to set to logic '0'
++ *
++ *	Set the IO output state of the specified IO pins.  The value
++ *	is retained if the pins are subsequently configured as inputs.
++ *	The @clear bitfield has priority over the @set bitfield -
++ *	outputs will be cleared.
++ *
++ *	ucb1x00_enable must have been called to enable the comms
++ *	before using this function.
++ *
++ *	This function takes a spinlock, disabling interrupts.
++ */
++void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int set, unsigned int clear)
++{
++	unsigned long flags;
++
++	spin_lock_irqsave(&ucb->io_lock, flags);
++	ucb->io_out |= set;
++	ucb->io_out &= ~clear;
++
++	ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
++	spin_unlock_irqrestore(&ucb->io_lock, flags);
++}
++
++/**
++ *	ucb1x00_io_read - read the current state of the IO pins
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Return a bitfield describing the logic state of the ten
++ *	general purpose IO pins.
++ *
++ *	ucb1x00_enable must have been called to enable the comms
++ *	before using this function.
++ *
++ *	This function does not take any semaphores or spinlocks.
++ */
++unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
++{
++	return ucb1x00_reg_read(ucb, UCB_IO_DATA);
++}
++
++/*
++ * UCB1300 data sheet says we must:
++ *  1. enable ADC	=> 5us (including reference startup time)
++ *  2. select input	=> 51*tsibclk  => 4.3us
++ *  3. start conversion	=> 102*tsibclk => 8.5us
++ * (tsibclk = 1/11981000)
++ * Period between SIB 128-bit frames = 10.7us
++ */
++
++/**
++ *	ucb1x00_adc_enable - enable the ADC converter
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Enable the ucb1x00 and ADC converter on the UCB1x00 for use.
++ *	Any code wishing to use the ADC converter must call this
++ *	function prior to using it.
++ *
++ *	This function takes the ADC semaphore to prevent two or more
++ *	concurrent uses, and therefore may sleep.  As a result, it
++ *	can only be called from process context, not interrupt
++ *	context.
++ *
++ *	You should release the ADC as soon as possible using
++ *	ucb1x00_adc_disable.
++ */
++void ucb1x00_adc_enable(struct ucb1x00 *ucb)
++{
++	down(&ucb->adc_sem);
++
++	ucb->adc_cr |= UCB_ADC_ENA;
++
++	ucb1x00_enable(ucb);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
++}
++
++/**
++ *	ucb1x00_adc_read - read the specified ADC channel
++ *	@ucb: UCB1x00 structure describing chip
++ *	@adc_channel: ADC channel mask
++ *	@sync: wait for syncronisation pulse.
++ *
++ *	Start an ADC conversion and wait for the result.  Note that
++ *	synchronised ADC conversions (via the ADCSYNC pin) must wait
++ *	until the trigger is asserted and the conversion is finished.
++ *
++ *	This function currently spins waiting for the conversion to
++ *	complete (2 frames max without sync).
++ *
++ *	If called for a synchronised ADC conversion, it may sleep
++ *	with the ADC semaphore held.
++ */
++unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync)
++{
++	unsigned int val;
++
++	if (sync)
++		adc_channel |= UCB_ADC_SYNC_ENA;
++
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr | adc_channel | UCB_ADC_START);
++
++	for (;;) {
++		val = ucb1x00_reg_read(ucb, UCB_ADC_DATA);
++		if (val & UCB_ADC_DAT_VAL)
++			break;
++		/* yield to other processes */
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(1);
++	}
++
++	return UCB_ADC_DAT(val);
++}
++
++/**
++ *	ucb1x00_adc_disable - disable the ADC converter
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Disable the ADC converter and release the ADC semaphore.
++ */
++void ucb1x00_adc_disable(struct ucb1x00 *ucb)
++{
++	ucb->adc_cr &= ~UCB_ADC_ENA;
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, ucb->adc_cr);
++	ucb1x00_disable(ucb);
++
++	up(&ucb->adc_sem);
++}
++
++#ifdef CONFIG_PM
++static int ucb1x00_pm (struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++	struct ucb1x00 *ucb = (struct ucb1x00 *)dev->data;
++	unsigned int isr;
++
++	if (rqst == PM_RESUME) {
++		ucb1x00_enable(ucb);
++		isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
++		ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++		ucb1x00_disable(ucb);
++	}
++
++	return 0;
++}
++#endif
++
++/*
++ * UCB1x00 Interrupt handling.
++ *
++ * The UCB1x00 can generate interrupts when the SIBCLK is stopped.
++ * Since we need to read an internal register, we must re-enable
++ * SIBCLK to talk to the chip.  We leave the clock running until
++ * we have finished processing all interrupts from the chip.
++ */
++static void ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
++{
++	struct ucb1x00 *ucb = devid;
++	struct ucb1x00_irq *irq;
++	unsigned int isr, i;
++
++	ucb1x00_enable(ucb);
++	isr = ucb1x00_reg_read(ucb, UCB_IE_STATUS);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, isr);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++	for (i = 0, irq = ucb->irq_handler; i < 16 && isr; i++, isr >>= 1, irq++)
++		if (isr & 1 && irq->fn)
++			irq->fn(i, irq->devid);
++	ucb1x00_disable(ucb);
++}
++
++/**
++ *	ucb1x00_hook_irq - hook a UCB1x00 interrupt
++ *	@ucb:   UCB1x00 structure describing chip
++ *	@idx:   interrupt index
++ *	@fn:    function to call when interrupt is triggered
++ *	@devid: device id to pass to interrupt handler
++ *
++ *	Hook the specified interrupt.  You can only register one handler
++ *	for each interrupt source.  The interrupt source is not enabled
++ *	by this function; use ucb1x00_enable_irq instead.
++ *
++ *	Interrupt handlers will be called with other interrupts enabled.
++ *
++ *	Returns zero on success, or one of the following errors:
++ *	 -EINVAL if the interrupt index is invalid
++ *	 -EBUSY if the interrupt has already been hooked
++ */
++int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid)
++{
++	struct ucb1x00_irq *irq;
++	int ret = -EINVAL;
++
++	if (idx < 16) {
++		irq = ucb->irq_handler + idx;
++		ret = -EBUSY;
++
++		spin_lock_irq(&ucb->lock);
++		if (irq->fn == NULL) {
++			irq->devid = devid;
++			irq->fn = fn;
++			ret = 0;
++		}
++		spin_unlock_irq(&ucb->lock);
++	}
++	return ret;
++}
++
++/**
++ *	ucb1x00_enable_irq - enable an UCB1x00 interrupt source
++ *	@ucb: UCB1x00 structure describing chip
++ *	@idx: interrupt index
++ *	@edges: interrupt edges to enable
++ *
++ *	Enable the specified interrupt to trigger on %UCB_RISING,
++ *	%UCB_FALLING or both edges.  The interrupt should have been
++ *	hooked by ucb1x00_hook_irq.
++ */
++void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
++{
++	unsigned long flags;
++
++	if (idx < 16) {
++		spin_lock_irqsave(&ucb->lock, flags);
++
++		ucb1x00_enable(ucb);
++		if (edges & UCB_RISING) {
++			ucb->irq_ris_enbl |= 1 << idx;
++			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
++		}
++		if (edges & UCB_FALLING) {
++			ucb->irq_fal_enbl |= 1 << idx;
++			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
++		}
++		ucb1x00_disable(ucb);
++		spin_unlock_irqrestore(&ucb->lock, flags);
++	}
++}
++
++/**
++ *	ucb1x00_disable_irq - disable an UCB1x00 interrupt source
++ *	@ucb: UCB1x00 structure describing chip
++ *	@edges: interrupt edges to disable
++ *
++ *	Disable the specified interrupt triggering on the specified
++ *	(%UCB_RISING, %UCB_FALLING or both) edges.
++ */
++void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges)
++{
++	unsigned long flags;
++
++	if (idx < 16) {
++		spin_lock_irqsave(&ucb->lock, flags);
++
++		ucb1x00_enable(ucb);
++		if (edges & UCB_RISING) {
++			ucb->irq_ris_enbl &= ~(1 << idx);
++			ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
++		}
++		if (edges & UCB_FALLING) {
++			ucb->irq_fal_enbl &= ~(1 << idx);
++			ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
++		}
++		ucb1x00_disable(ucb);
++		spin_unlock_irqrestore(&ucb->lock, flags);
++	}
++}
++
++/**
++ *	ucb1x00_free_irq - disable and free the specified UCB1x00 interrupt
++ *	@ucb: UCB1x00 structure describing chip
++ *	@idx: interrupt index
++ *	@devid: device id.
++ *
++ *	Disable the interrupt source and remove the handler.  devid must
++ *	match the devid passed when hooking the interrupt.
++ *
++ *	Returns zero on success, or one of the following errors:
++ *	 -EINVAL if the interrupt index is invalid
++ *	 -ENOENT if devid does not match
++ */
++int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid)
++{
++	struct ucb1x00_irq *irq;
++	int ret;
++
++	if (idx >= 16)
++		goto bad;
++
++	irq = ucb->irq_handler + idx;
++	ret = -ENOENT;
++
++	spin_lock_irq(&ucb->lock);
++	if (irq->devid == devid) {
++		ucb->irq_ris_enbl &= ~(1 << idx);
++		ucb->irq_fal_enbl &= ~(1 << idx);
++
++		ucb1x00_enable(ucb);
++		ucb1x00_reg_write(ucb, UCB_IE_RIS, ucb->irq_ris_enbl);
++		ucb1x00_reg_write(ucb, UCB_IE_FAL, ucb->irq_fal_enbl);
++		ucb1x00_disable(ucb);
++
++		irq->fn = NULL;
++		irq->devid = NULL;
++		ret = 0;
++	}
++	spin_unlock_irq(&ucb->lock);
++	return ret;
++
++bad:
++	printk(KERN_ERR "%s: freeing bad irq %d\n", __FUNCTION__, idx);
++	return -EINVAL;
++}
++
++/*
++ * Try to probe our interrupt, rather than relying on lots of
++ * hard-coded machine dependencies.  For reference, the expected
++ * IRQ mappings are:
++ *
++ *  	Machine		Default IRQ
++ *	adsbitsy	IRQ_GPCIN4
++ *	cerf		IRQ_GPIO_UCB1200_IRQ
++ *	flexanet	IRQ_GPIO_GUI
++ *	freebird	IRQ_GPIO_FREEBIRD_UCB1300_IRQ
++ *	graphicsclient	IRQ_GRAPHICSCLIENT_UCB1200
++ *	graphicsmaster	IRQ_GRAPHICSMASTER_UCB1200
++ *	lart		LART_IRQ_UCB1200
++ *	omnimeter	IRQ_GPIO23
++ *	pfs168		IRQ_GPIO_UCB1300_IRQ
++ *	simpad		IRQ_GPIO_UCB1300_IRQ
++ *	shannon		SHANNON_IRQ_GPIO_IRQ_CODEC
++ *	yopy		IRQ_GPIO_UCB1200_IRQ
++ */
++static int __init ucb1x00_detect_irq(struct ucb1x00 *ucb)
++{
++	unsigned long mask;
++
++	mask = probe_irq_on();
++	if (!mask)
++		return NO_IRQ;
++
++	/*
++	 * Enable the ADC interrupt.
++	 */
++	ucb1x00_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC);
++	ucb1x00_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++	/*
++	 * Cause an ADC interrupt.
++	 */
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START);
++
++	/*
++	 * Wait for the conversion to complete.
++	 */
++	while ((ucb1x00_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VAL) == 0);
++	ucb1x00_reg_write(ucb, UCB_ADC_CR, 0);
++
++	/*
++	 * Disable and clear interrupt.
++	 */
++	ucb1x00_reg_write(ucb, UCB_IE_RIS, 0);
++	ucb1x00_reg_write(ucb, UCB_IE_FAL, 0);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0xffff);
++	ucb1x00_reg_write(ucb, UCB_IE_CLEAR, 0);
++
++	/*
++	 * Read triggered interrupt.
++	 */
++	return probe_irq_off(mask);
++}
++
++/*
++ * This configures the UCB1x00 layer depending on the machine type
++ * we're running on.  The UCB1x00 drivers should not contain any
++ * machine dependencies.
++ *
++ * We can get rid of some of these dependencies by using existing
++ * facilities provided by the kernel - namely IRQ probing.  The
++ * machine specific files are expected to setup the IRQ levels on
++ * initialisation.  With any luck, we'll get rid of all the
++ * machine dependencies here.
++ */
++static int __init ucb1x00_configure(struct ucb1x00 *ucb)
++{
++	unsigned int irq_gpio_pin = 0;
++	int irq, default_irq = NO_IRQ;
++
++	if (machine_is_adsbitsy())
++		default_irq = IRQ_GPCIN4;
++
++//	if (machine_is_assabet())
++//		default_irq = IRQ_GPIO23;
++
++#ifdef CONFIG_SA1100_CERF
++	if (machine_is_cerf())
++		default_irq = IRQ_GPIO_UCB1200_IRQ;
++#endif
++#ifdef CONFIG_SA1100_FREEBIRD
++	if (machine_is_freebird())
++		default_irq = IRQ_GPIO_FREEBIRD_UCB1300_IRQ;
++#endif
++#if defined(CONFIG_SA1100_GRAPHICSCLIENT)
++//	if (machine_is_graphicsclient())
++//		default_irq = IRQ_GRAPHICSCLIENT_UCB1200;
++#endif
++#if defined(CONFIG_SA1100_GRAPICSMASTER)
++	if (machine_is_graphicsmaster())
++		default_irq = IRQ_GRAPHICSMASTER_UCB1200;
++#endif
++#ifdef CONFIG_SA1100_LART
++	if (machine_is_lart()) {
++		default_irq = LART_IRQ_UCB1200;
++		irq_gpio_pin = LART_GPIO_UCB1200;
++	}
++#endif
++	if (machine_is_omnimeter())
++		default_irq = IRQ_GPIO23;
++
++#ifdef CONFIG_SA1100_PFS168
++	if (machine_is_pfs168())
++		default_irq = IRQ_GPIO_UCB1300_IRQ;
++#endif
++#ifdef CONFIG_SA1100_SIMPAD
++	if (machine_is_simpad())
++		default_irq = IRQ_GPIO_UCB1300_IRQ;
++#endif
++#ifdef CONFIG_SA1100_SIMPUTER
++	if (machine_is_simputer()) {
++		default_irq = IRQ_GPIO_UCB1300_IRQ;
++		irq_gpio_pin = GPIO_UCB1300_IRQ;
++    }
++#endif
++	if (machine_is_shannon())
++		default_irq = SHANNON_IRQ_GPIO_IRQ_CODEC;
++#ifdef CONFIG_SA1100_YOPY
++	if (machine_is_yopy())
++		default_irq = IRQ_GPIO_UCB1200_IRQ;
++#endif
++#ifdef CONFIG_SA1100_ACCELENT
++	if (machine_is_accelent_sa()) {
++		ucb->irq = IRQ_GPIO_UCB1200_IRQ;
++		irq_gpio_pin = GPIO_UCB1200_IRQ;
++	}
++#endif
++
++	/*
++	 * Eventually, this will disappear.
++	 */
++	if (irq_gpio_pin)
++		set_GPIO_IRQ_edge(irq_gpio_pin, GPIO_RISING_EDGE);
++
++	irq = ucb1x00_detect_irq(ucb);
++	if (irq != NO_IRQ) {
++		if (default_irq != NO_IRQ && irq != default_irq)
++			printk(KERN_ERR "UCB1x00: probed IRQ%d != default IRQ%d\n",
++				irq, default_irq);
++		if (irq == default_irq)
++			printk(KERN_ERR "UCB1x00: probed IRQ%d correctly. "
++				"Please remove machine dependencies from "
++				"ucb1x00-core.c\n", irq);
++		ucb->irq = irq;
++	} else {
++		printk(KERN_ERR "UCB1x00: IRQ probe failed, using IRQ%d\n",
++			default_irq);
++		ucb->irq = default_irq;
++	}
++
++	return ucb->irq == NO_IRQ ? -ENODEV : 0;
++}
++
++struct ucb1x00 *my_ucb;
++
++/**
++ *	ucb1x00_get - get the UCB1x00 structure describing a chip
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Return the UCB1x00 structure describing a chip.
++ *
++ *	FIXME: Currently very noddy indeed, which currently doesn't
++ *	matter since we only support one chip.
++ */
++struct ucb1x00 *ucb1x00_get(void)
++{
++	return my_ucb;
++}
++
++static int __init ucb1x00_init(void)
++{
++	struct mcp *mcp;
++	unsigned int id;
++	int ret = -ENODEV;
++
++	mcp = mcp_get();
++	if (!mcp)
++		goto no_mcp;
++
++	mcp_enable(mcp);
++	id = mcp_reg_read(mcp, UCB_ID);
++
++	if (id != UCB_ID_1200 && id != UCB_ID_1300) {
++		printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
++		goto out;
++	}
++
++	my_ucb = kmalloc(sizeof(struct ucb1x00), GFP_KERNEL);
++	ret = -ENOMEM;
++	if (!my_ucb)
++		goto out;
++
++	if (machine_is_shannon()) {
++		/* reset the codec */
++		GPDR |= SHANNON_GPIO_CODEC_RESET;
++		GPCR = SHANNON_GPIO_CODEC_RESET;
++		GPSR = SHANNON_GPIO_CODEC_RESET;
++
++	}
++
++	memset(my_ucb, 0, sizeof(struct ucb1x00));
++
++	spin_lock_init(&my_ucb->lock);
++	spin_lock_init(&my_ucb->io_lock);
++	sema_init(&my_ucb->adc_sem, 1);
++
++	my_ucb->id  = id;
++	my_ucb->mcp = mcp;
++
++	ret = ucb1x00_configure(my_ucb);
++	if (ret)
++		goto out;
++
++	ret = request_irq(my_ucb->irq, ucb1x00_irq, 0, "UCB1x00", my_ucb);
++	if (ret) {
++		printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
++			my_ucb->irq, ret);
++		kfree(my_ucb);
++		my_ucb = NULL;
++		goto out;
++	}
++
++#ifdef CONFIG_PM
++	my_ucb->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ucb1x00_pm);
++	if (my_ucb->pmdev == NULL)
++		printk("ucb1x00: unable to register in PM.\n");
++	else
++		my_ucb->pmdev->data = my_ucb;
++#endif
++
++out:
++	mcp_disable(mcp);
++no_mcp:
++	return ret;
++}
++
++static void __exit ucb1x00_exit(void)
++{
++	free_irq(my_ucb->irq, my_ucb);
++	kfree(my_ucb);
++}
++
++module_init(ucb1x00_init);
++module_exit(ucb1x00_exit);
++
++EXPORT_SYMBOL(ucb1x00_get);
++
++EXPORT_SYMBOL(ucb1x00_io_set_dir);
++EXPORT_SYMBOL(ucb1x00_io_write);
++EXPORT_SYMBOL(ucb1x00_io_read);
++
++EXPORT_SYMBOL(ucb1x00_adc_enable);
++EXPORT_SYMBOL(ucb1x00_adc_read);
++EXPORT_SYMBOL(ucb1x00_adc_disable);
++
++EXPORT_SYMBOL(ucb1x00_hook_irq);
++EXPORT_SYMBOL(ucb1x00_free_irq);
++EXPORT_SYMBOL(ucb1x00_enable_irq);
++EXPORT_SYMBOL(ucb1x00_disable_irq);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 core driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00-ts.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,664 @@
++/*
++ *  linux/drivers/misc/ucb1x00-ts.c
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * 21-Jan-2002 <jco@ict.es> :
++ *
++ * Added support for synchronous A/D mode. This mode is useful to
++ * avoid noise induced in the touchpanel by the LCD, provided that
++ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
++ * It is important to note that the signal connected to the ADCSYNC
++ * pin should provide pulses even when the LCD is blanked, otherwise
++ * a pen touch needed to unblank the LCD will never be read.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/sched.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/pm.h>
++
++#include <asm/dma.h>
++#include <asm/semaphore.h>
++
++#include "ucb1x00.h"
++
++/*
++ * Define this if you want the UCB1x00 stuff to talk to the input layer
++ */
++#undef USE_INPUT
++
++#ifndef USE_INPUT
++
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/poll.h>
++
++/*
++ * This structure is nonsense - millisecs is not very useful
++ * since the field size is too small.  Also, we SHOULD NOT
++ * be exposing jiffies to user space directly.
++ */
++struct ts_event {
++	u16		pressure;
++	u16		x;
++	u16		y;
++	u16		pad;
++	struct timeval	stamp;
++};
++
++#define NR_EVENTS	16
++
++#else
++
++#include <linux/input.h>
++
++#endif
++
++struct ucb1x00_ts {
++#ifdef USE_INPUT
++	struct input_dev	idev;
++#endif
++	struct ucb1x00		*ucb;
++#ifdef CONFIG_PM
++	struct pm_dev		*pmdev;
++#endif
++
++	wait_queue_head_t	irq_wait;
++	struct semaphore	sem;
++	struct completion	init_exit;
++	struct task_struct	*rtask;
++	int			use_count;
++	u16			x_res;
++	u16			y_res;
++
++#ifndef USE_INPUT
++	struct fasync_struct	*fasync;
++	wait_queue_head_t	read_wait;
++	u8			evt_head;
++	u8			evt_tail;
++	struct ts_event		events[NR_EVENTS];
++#endif
++	int			restart:1;
++	int			adcsync:1;
++};
++
++static struct ucb1x00_ts ucbts;
++static int adcsync = UCB_NOSYNC;
++
++static int ucb1x00_ts_startup(struct ucb1x00_ts *ts);
++static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts);
++
++#ifndef USE_INPUT
++
++#define ucb1x00_ts_evt_pending(ts)	((volatile u8)(ts)->evt_head != (ts)->evt_tail)
++#define ucb1x00_ts_evt_get(ts)		((ts)->events + (ts)->evt_tail)
++#define ucb1x00_ts_evt_pull(ts)		((ts)->evt_tail = ((ts)->evt_tail + 1) & (NR_EVENTS - 1))
++#define ucb1x00_ts_evt_clear(ts)	((ts)->evt_head = (ts)->evt_tail = 0)
++
++static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
++{
++	int next_head;
++
++	next_head = (ts->evt_head + 1) & (NR_EVENTS - 1);
++	if (next_head != ts->evt_tail) {
++		ts->events[ts->evt_head].pressure = pressure;
++		ts->events[ts->evt_head].x = x;
++		ts->events[ts->evt_head].y = y;
++		do_gettimeofday(&ts->events[ts->evt_head].stamp);
++		ts->evt_head = next_head;
++
++		if (ts->fasync)
++			kill_fasync(&ts->fasync, SIGIO, POLL_IN);
++		wake_up_interruptible(&ts->read_wait);
++	}
++}
++
++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
++{
++	ucb1x00_ts_evt_add(ts, 0, 0, 0);
++}
++
++/*
++ * User space driver interface.
++ */
++static ssize_t
++ucb1x00_ts_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct ucb1x00_ts *ts = filp->private_data;
++	char *ptr = buffer;
++	int err = 0;
++
++	add_wait_queue(&ts->read_wait, &wait);
++	while (count >= sizeof(struct ts_event)) {
++		err = -ERESTARTSYS;
++		if (signal_pending(current))
++			break;
++
++		if (ucb1x00_ts_evt_pending(ts)) {
++			struct ts_event *evt = ucb1x00_ts_evt_get(ts);
++
++			err = copy_to_user(ptr, evt, sizeof(struct ts_event));
++			ucb1x00_ts_evt_pull(ts);
++
++			if (err)
++				break;
++
++			ptr += sizeof(struct ts_event);
++			count -= sizeof(struct ts_event);
++			continue;
++		}
++
++		set_current_state(TASK_INTERRUPTIBLE);
++		err = -EAGAIN;
++		if (filp->f_flags & O_NONBLOCK)
++			break;
++		schedule();
++	}
++	current->state = TASK_RUNNING;
++	remove_wait_queue(&ts->read_wait, &wait);
++ 
++	return ptr == buffer ? err : ptr - buffer;
++}
++
++static unsigned int ucb1x00_ts_poll(struct file *filp, poll_table *wait)
++{
++	struct ucb1x00_ts *ts = filp->private_data;
++	int ret = 0;
++
++	poll_wait(filp, &ts->read_wait, wait);
++	if (ucb1x00_ts_evt_pending(ts))
++		ret = POLLIN | POLLRDNORM;
++
++	return ret;
++}
++
++static int ucb1x00_ts_fasync(int fd, struct file *filp, int on)
++{
++	struct ucb1x00_ts *ts = filp->private_data;
++
++	return fasync_helper(fd, filp, on, &ts->fasync);
++}
++
++static int ucb1x00_ts_open(struct inode *inode, struct file *filp)
++{
++	struct ucb1x00_ts *ts = &ucbts;
++	int ret = 0;
++
++	ret = ucb1x00_ts_startup(ts);
++	if (ret == 0)
++		filp->private_data = ts;
++
++	return ret;
++}
++
++/*
++ * Release touchscreen resources.  Disable IRQs.
++ */
++static int ucb1x00_ts_release(struct inode *inode, struct file *filp)
++{
++	struct ucb1x00_ts *ts = filp->private_data;
++
++	down(&ts->sem);
++	ucb1x00_ts_fasync(-1, filp, 0);
++	ucb1x00_ts_shutdown(ts);
++	up(&ts->sem);
++
++	return 0;
++}
++
++static struct file_operations ucb1x00_fops = {
++	owner:		THIS_MODULE,
++	read:		ucb1x00_ts_read,
++	poll:		ucb1x00_ts_poll,
++	open:		ucb1x00_ts_open,
++	release:	ucb1x00_ts_release,
++	fasync:		ucb1x00_ts_fasync,
++};
++
++/*
++ * The official UCB1x00 touchscreen is a miscdevice:
++ *   10 char        Non-serial mice, misc features
++ *                   14 = /dev/touchscreen/ucb1x00  UCB 1x00 touchscreen
++ */
++static struct miscdevice ucb1x00_ts_dev = {
++	minor:	14,
++	name:	"touchscreen/ucb1x00",
++	fops:	&ucb1x00_fops,
++};
++
++static inline int ucb1x00_ts_register(struct ucb1x00_ts *ts)
++{
++	init_waitqueue_head(&ts->read_wait);
++	return misc_register(&ucb1x00_ts_dev);
++}
++
++static inline void ucb1x00_ts_deregister(struct ucb1x00_ts *ts)
++{
++	misc_deregister(&ucb1x00_ts_dev);
++}
++
++#else
++
++#define ucb1x00_ts_evt_clear(ts)	do { } while (0)
++
++static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
++{
++	input_report_abs(&ts->idev, ABS_X, x);
++	input_report_abs(&ts->idev, ABS_Y, y);
++	input_report_abs(&ts->idev, ABS_PRESSURE, pressure);
++}
++
++static int ucb1x00_ts_open(struct input_dev *idev)
++{
++	struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
++
++	return ucb1x00_ts_startup(ts);
++}
++
++static void ucb1x00_ts_close(struct input_dev *idev)
++{
++	struct ucb1x00_ts *ts = (struct ucb1x00_ts *)idev;
++
++	down(&ts->sem);
++	ucb1x00_ts_shutdown(ts);
++	up(&ts->sem);
++}
++
++static inline int ucb1x00_ts_register(struct ucb1x00_ts *ts)
++{
++	ts->idev.name      = "Touchscreen panel";
++	ts->idev.idproduct = ts->ucb->id;
++	ts->idev.open      = ucb1x00_ts_open;
++	ts->idev.close     = ucb1x00_ts_close;
++
++	__set_bit(EV_ABS, ts->idev.evbit);
++	__set_bit(ABS_X, ts->idev.absbit);
++	__set_bit(ABS_Y, ts->idev.absbit);
++	__set_bit(ABS_PRESSURE, ts->idev.absbit);
++
++	input_register_device(&ts->idev);
++
++	return 0;
++}
++
++static inline void ucb1x00_ts_deregister(struct ucb1x00_ts *ts)
++{
++	input_unregister_device(&ts->idev);
++}
++
++#endif
++
++/*
++ * Switch to interrupt mode.
++ */
++static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++			UCB_TS_CR_MODE_INT);
++}
++
++/*
++ * Switch to pressure mode, and read pressure.  We don't need to wait
++ * here, since both plates are being driven.
++ */
++static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++
++	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
++}
++
++/*
++ * Switch to X position mode and measure Y plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++	udelay(55);
++
++	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
++}
++
++/*
++ * Switch to Y position mode and measure X plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++	udelay(55);
++
++	return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
++}
++
++/*
++ * Switch to X plate resistance mode.  Set MX to ground, PX to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++/*
++ * Switch to Y plate resistance mode.  Set MY to ground, PY to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
++{
++	ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++			UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++			UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++	return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++/*
++ * This is a RT kernel thread that handles the ADC accesses
++ * (mainly so we can use semaphores in the UCB1200 core code
++ * to serialise accesses to the ADC).
++ */
++static int ucb1x00_thread(void *_ts)
++{
++	struct ucb1x00_ts *ts = _ts;
++	struct task_struct *tsk = current;
++	DECLARE_WAITQUEUE(wait, tsk);
++	int valid;
++
++	ts->rtask = tsk;
++
++	daemonize();
++	reparent_to_init();
++	strcpy(tsk->comm, "ktsd");
++	tsk->tty = NULL;
++	/*
++	 * We could run as a real-time thread.  However, thus far
++	 * this doesn't seem to be necessary.
++	 */
++//	tsk->policy = SCHED_FIFO;
++//	tsk->rt_priority = 1;
++
++	/* only want to receive SIGKILL */
++	spin_lock_irq(&tsk->sigmask_lock);
++	siginitsetinv(&tsk->blocked, sigmask(SIGKILL));
++	recalc_sigpending(tsk);
++	spin_unlock_irq(&tsk->sigmask_lock);
++
++	complete(&ts->init_exit);
++
++	valid = 0;
++
++	add_wait_queue(&ts->irq_wait, &wait);
++	for (;;) {
++		unsigned int x, y, p, val;
++		signed long timeout;
++
++		ts->restart = 0;
++
++		ucb1x00_adc_enable(ts->ucb);
++
++		x = ucb1x00_ts_read_xpos(ts);
++		y = ucb1x00_ts_read_ypos(ts);
++		p = ucb1x00_ts_read_pressure(ts);
++
++		/*
++		 * Switch back to interrupt mode.
++		 */
++		ucb1x00_ts_mode_int(ts);
++		ucb1x00_adc_disable(ts->ucb);
++
++		set_task_state(tsk, TASK_UNINTERRUPTIBLE);
++		schedule_timeout(HZ / 100);
++		if (signal_pending(tsk))
++			break;
++
++		ucb1x00_enable(ts->ucb);
++		val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
++
++		if (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)) {
++			set_task_state(tsk, TASK_INTERRUPTIBLE);
++
++			ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
++			ucb1x00_disable(ts->ucb);
++
++			/*
++			 * If we spat out a valid sample set last time,
++			 * spit out a "pen off" sample here.
++			 */
++			if (valid) {
++				ucb1x00_ts_event_release(ts);
++				valid = 0;
++			}
++
++			timeout = MAX_SCHEDULE_TIMEOUT;
++		} else {
++			ucb1x00_disable(ts->ucb);
++
++			/*
++			 * Filtering is policy.  Policy belongs in user
++			 * space.  We therefore leave it to user space
++			 * to do any filtering they please.
++			 */
++			if (!ts->restart) {
++				ucb1x00_ts_evt_add(ts, p, x, y);
++				valid = 1;
++			}
++
++			set_task_state(tsk, TASK_INTERRUPTIBLE);
++			timeout = HZ / 100;
++		}
++
++		schedule_timeout(timeout);
++		if (signal_pending(tsk))
++			break;
++	}
++
++	remove_wait_queue(&ts->irq_wait, &wait);
++
++	ts->rtask = NULL;
++	ucb1x00_ts_evt_clear(ts);
++	complete_and_exit(&ts->init_exit, 0);
++}
++
++/*
++ * We only detect touch screen _touches_ with this interrupt
++ * handler, and even then we just schedule our task.
++ */
++static void ucb1x00_ts_irq(int idx, void *id)
++{
++	struct ucb1x00_ts *ts = id;
++	ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
++	wake_up(&ts->irq_wait);
++}
++
++static int ucb1x00_ts_startup(struct ucb1x00_ts *ts)
++{
++	int ret = 0;
++
++	if (down_interruptible(&ts->sem))
++		return -EINTR;
++
++	if (ts->use_count++ != 0)
++		goto out;
++
++	if (ts->rtask)
++		panic("ucb1x00: rtask running?");
++
++	init_waitqueue_head(&ts->irq_wait);
++	ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
++	if (ret < 0)
++		goto out;
++
++	/*
++	 * If we do this at all, we should allow the user to
++	 * measure and read the X and Y resistance at any time.
++	 */
++	ucb1x00_adc_enable(ts->ucb);
++	ts->x_res = ucb1x00_ts_read_xres(ts);
++	ts->y_res = ucb1x00_ts_read_yres(ts);
++	ucb1x00_adc_disable(ts->ucb);
++
++	init_completion(&ts->init_exit);
++	ret = kernel_thread(ucb1x00_thread, ts, 0);
++	if (ret >= 0) {
++		wait_for_completion(&ts->init_exit);
++		ret = 0;
++	} else {
++		ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++	}
++
++ out:
++	if (ret)
++		ts->use_count--;
++	up(&ts->sem);
++	return ret;
++}
++
++/*
++ * Release touchscreen resources.  Disable IRQs.
++ */
++static void ucb1x00_ts_shutdown(struct ucb1x00_ts *ts)
++{
++	if (--ts->use_count == 0) {
++		if (ts->rtask) {
++			send_sig(SIGKILL, ts->rtask, 1);
++			wait_for_completion(&ts->init_exit);
++		}
++
++		ucb1x00_enable(ts->ucb);
++		ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++		ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
++		ucb1x00_disable(ts->ucb);
++	}
++}
++
++#ifdef CONFIG_PM
++static int ucb1x00_ts_pm (struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++	struct ucb1x00_ts *ts = (struct ucb1x00_ts *) (dev->data);
++
++	if (rqst == PM_RESUME && ts->rtask != NULL) {
++		/*
++		 * Restart the TS thread to ensure the
++		 * TS interrupt mode is set up again
++		 * after sleep.
++		 */
++		ts->restart = 1;
++		wake_up(&ts->irq_wait);
++	}
++	return 0;
++}
++#endif
++
++
++/*
++ * Initialisation.
++ */
++static int __init ucb1x00_ts_init(void)
++{
++	struct ucb1x00_ts *ts = &ucbts;
++
++	ts->ucb = ucb1x00_get();
++	if (!ts->ucb)
++		return -ENODEV;
++
++	ts->adcsync = adcsync;
++	init_MUTEX(&ts->sem);
++
++#ifdef CONFIG_PM
++	ts->pmdev = pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, ucb1x00_ts_pm);
++	if (ts->pmdev == NULL)
++		printk("ucb1x00_ts: unable to register in PM.\n");
++	else
++		ts->pmdev->data = ts;
++#endif
++	return ucb1x00_ts_register(ts);
++}
++
++static void __exit ucb1x00_ts_exit(void)
++{
++	struct ucb1x00_ts *ts = &ucbts;
++
++	ucb1x00_ts_deregister(ts);
++
++#ifdef CONFIG_PM
++	if (ts->pmdev)
++		pm_unregister(ts->pmdev);
++#endif
++}
++
++#ifndef MODULE
++
++/*
++ * Parse kernel command-line options.
++ *
++ * syntax : ucbts=[sync|nosync],...
++ */
++static int __init ucb1x00_ts_setup(char *str)
++{
++	char *p;
++
++	while ((p = strsep(&str, ",")) != NULL) {
++		if (strcmp(p, "sync") == 0)
++			adcsync = UCB_SYNC;
++	}
++
++	return 1;
++}
++
++__setup("ucbts=", ucb1x00_ts_setup);
++
++#else
++
++MODULE_PARM(adcsync, "i");
++MODULE_PARM_DESC(adcsync, "Enable use of ADCSYNC signal");
++
++#endif
++
++module_init(ucb1x00_ts_init);
++module_exit(ucb1x00_ts_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,232 @@
++/*
++ *  linux/drivers/misc/ucb1x00.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ */
++#ifndef UCB1200_H
++#define UCB1200_H
++
++#define UCB_IO_DATA	0x00
++#define UCB_IO_DIR	0x01
++
++#define UCB_IO_0		(1 << 0)
++#define UCB_IO_1		(1 << 1)
++#define UCB_IO_2		(1 << 2)
++#define UCB_IO_3		(1 << 3)
++#define UCB_IO_4		(1 << 4)
++#define UCB_IO_5		(1 << 5)
++#define UCB_IO_6		(1 << 6)
++#define UCB_IO_7		(1 << 7)
++#define UCB_IO_8		(1 << 8)
++#define UCB_IO_9		(1 << 9)
++
++#define UCB_IE_RIS	0x02
++#define UCB_IE_FAL	0x03
++#define UCB_IE_STATUS	0x04
++#define UCB_IE_CLEAR	0x04
++#define UCB_IE_ADC		(1 << 11)
++#define UCB_IE_TSPX		(1 << 12)
++#define UCB_IE_TSMX		(1 << 13)
++#define UCB_IE_TCLIP		(1 << 14)
++#define UCB_IE_ACLIP		(1 << 15)
++
++#define UCB_IRQ_TSPX		12
++
++#define UCB_TC_A	0x05
++#define UCB_TC_A_LOOP		(1 << 7)	/* UCB1200 */
++#define UCB_TC_A_AMPL		(1 << 7)	/* UCB1300 */
++
++#define UCB_TC_B	0x06
++#define UCB_TC_B_VOICE_ENA	(1 << 3)
++#define UCB_TC_B_CLIP		(1 << 4)
++#define UCB_TC_B_ATT		(1 << 6)
++#define UCB_TC_B_SIDE_ENA	(1 << 11)
++#define UCB_TC_B_MUTE		(1 << 13)
++#define UCB_TC_B_IN_ENA		(1 << 14)
++#define UCB_TC_B_OUT_ENA	(1 << 15)
++
++#define UCB_AC_A	0x07
++#define UCB_AC_B	0x08
++#define UCB_AC_B_LOOP		(1 << 8)
++#define UCB_AC_B_MUTE		(1 << 13)
++#define UCB_AC_B_IN_ENA		(1 << 14)
++#define UCB_AC_B_OUT_ENA	(1 << 15)
++
++#define UCB_TS_CR	0x09
++#define UCB_TS_CR_TSMX_POW	(1 << 0)
++#define UCB_TS_CR_TSPX_POW	(1 << 1)
++#define UCB_TS_CR_TSMY_POW	(1 << 2)
++#define UCB_TS_CR_TSPY_POW	(1 << 3)
++#define UCB_TS_CR_TSMX_GND	(1 << 4)
++#define UCB_TS_CR_TSPX_GND	(1 << 5)
++#define UCB_TS_CR_TSMY_GND	(1 << 6)
++#define UCB_TS_CR_TSPY_GND	(1 << 7)
++#define UCB_TS_CR_MODE_INT	(0 << 8)
++#define UCB_TS_CR_MODE_PRES	(1 << 8)
++#define UCB_TS_CR_MODE_POS	(2 << 8)
++#define UCB_TS_CR_BIAS_ENA	(1 << 11)
++#define UCB_TS_CR_TSPX_LOW	(1 << 12)
++#define UCB_TS_CR_TSMX_LOW	(1 << 13)
++
++#define UCB_ADC_CR	0x0a
++#define UCB_ADC_SYNC_ENA	(1 << 0)
++#define UCB_ADC_VREFBYP_CON	(1 << 1)
++#define UCB_ADC_INP_TSPX	(0 << 2)
++#define UCB_ADC_INP_TSMX	(1 << 2)
++#define UCB_ADC_INP_TSPY	(2 << 2)
++#define UCB_ADC_INP_TSMY	(3 << 2)
++#define UCB_ADC_INP_AD0		(4 << 2)
++#define UCB_ADC_INP_AD1		(5 << 2)
++#define UCB_ADC_INP_AD2		(6 << 2)
++#define UCB_ADC_INP_AD3		(7 << 2)
++#define UCB_ADC_EXT_REF		(1 << 5)
++#define UCB_ADC_START		(1 << 7)
++#define UCB_ADC_ENA		(1 << 15)
++
++#define UCB_ADC_DATA	0x0b
++#define UCB_ADC_DAT_VAL		(1 << 15)
++#define UCB_ADC_DAT(x)		(((x) & 0x7fe0) >> 5)
++
++#define UCB_ID		0x0c
++#define UCB_ID_1200		0x1004
++#define UCB_ID_1300		0x1005
++
++#define UCB_MODE	0x0d
++#define UCB_MODE_DYN_VFLAG_ENA	(1 << 12)
++#define UCB_MODE_AUD_OFF_CAN	(1 << 13)
++
++#include "mcp.h"
++
++struct ucb1x00;
++
++struct ucb1x00_irq {
++	void *devid;
++	void (*fn)(int, void *);
++};
++
++struct ucb1x00 {
++	spinlock_t		lock;
++	struct mcp		*mcp;
++	struct pm_dev		*pmdev;
++	unsigned int		irq;
++	struct semaphore	adc_sem;
++	spinlock_t		io_lock;
++	u16			id;
++	u16			io_dir;
++	u16			io_out;
++	u16			adc_cr;
++	u16			irq_fal_enbl;
++	u16			irq_ris_enbl;
++	struct ucb1x00_irq	irq_handler[16];
++};
++
++/**
++ *	ucb1x00_clkrate - return the UCB1x00 SIB clock rate
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Return the SIB clock rate in Hz.
++ */
++static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
++{
++	return mcp_get_sclk_rate(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_enable - enable the UCB1x00 SIB clock
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Enable the SIB clock.  This can be called multiple times.
++ */
++static inline void ucb1x00_enable(struct ucb1x00 *ucb)
++{
++	mcp_enable(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_disable - disable the UCB1x00 SIB clock
++ *	@ucb: UCB1x00 structure describing chip
++ *
++ *	Disable the SIB clock.  The SIB clock will only be disabled
++ *	when the number of ucb1x00_enable calls match the number of
++ *	ucb1x00_disable calls.
++ */
++static inline void ucb1x00_disable(struct ucb1x00 *ucb)
++{
++	mcp_disable(ucb->mcp);
++}
++
++/**
++ *	ucb1x00_reg_write - write a UCB1x00 register
++ *	@ucb: UCB1x00 structure describing chip
++ *	@reg: UCB1x00 4-bit register index to write
++ *	@val: UCB1x00 16-bit value to write
++ *
++ *	Write the UCB1x00 register @reg with value @val.  The SIB
++ *	clock must be running for this function to return.
++ */
++static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
++{
++	mcp_reg_write(ucb->mcp, reg, val);
++}
++
++/**
++ *	ucb1x00_reg_read - read a UCB1x00 register
++ *	@ucb: UCB1x00 structure describing chip
++ *	@reg: UCB1x00 4-bit register index to write
++ *
++ *	Read the UCB1x00 register @reg and return its value.  The SIB
++ *	clock must be running for this function to return.
++ */
++static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
++{
++	return mcp_reg_read(ucb->mcp, reg);
++}
++/**
++ *	ucb1x00_set_audio_divisor - 
++ *	@ucb: UCB1x00 structure describing chip
++ *	@div: SIB clock divisor
++ */
++static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++	mcp_set_audio_divisor(ucb->mcp, div);
++}
++
++/**
++ *	ucb1x00_set_telecom_divisor -
++ *	@ucb: UCB1x00 structure describing chip
++ *	@div: SIB clock divisor
++ */
++static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++	mcp_set_telecom_divisor(ucb->mcp, div);
++}
++
++struct ucb1x00 *ucb1x00_get(void);
++
++void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
++void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
++unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
++
++#define UCB_NOSYNC	(0)
++#define UCB_SYNC	(1)
++
++unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
++void ucb1x00_adc_enable(struct ucb1x00 *ucb);
++void ucb1x00_adc_disable(struct ucb1x00 *ucb);
++
++/*
++ * Which edges of the IRQ do you want to control today?
++ */
++#define UCB_RISING	(1 << 0)
++#define UCB_FALLING	(1 << 1)
++
++int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
++void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
++
++#endif
+--- linux-2.4.25/drivers/mtd/chips/cfi_probe.c~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/mtd/chips/cfi_probe.c	2004-03-31 17:15:09.000000000 +0200
+@@ -65,6 +65,10 @@
+ 		return 0;
+ 	}
+ 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
++
++	/* some devices don't respond to 0xF0, so send 0xFF to be sure */
++	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
++
+ 	cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
+ 
+ 	if (!qry_present(map,base,cfi))
+@@ -84,6 +88,8 @@
+ 			/* Eep. This chip also had the QRY marker. 
+ 			 * Is it an alias for the new one? */
+ 			cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
++			/* some devices don't respond to 0xF0, so send 0xFF to be sure */
++			cfi_send_gen_cmd(0xFF, 0, chips[i].start, map, cfi, cfi->device_type, NULL);
+ 
+ 			/* If the QRY marker goes away, it's an alias */
+ 			if (!qry_present(map, chips[i].start, cfi)) {
+@@ -96,7 +102,8 @@
+ 			 * too and if it's the same, assume it's an alias. */
+ 			/* FIXME: Use other modes to do a proper check */
+ 			cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+-			
++			/* some devices don't respond to 0xF0, so send 0xFF to be sure */
++			cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
+ 			if (qry_present(map, base, cfi)) {
+ 				printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
+ 				       map->name, base, chips[i].start);
+@@ -119,6 +126,10 @@
+ 	/* Put it back into Read Mode */
+ 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ 
++	/* some devices don't respond to 0xF0, so send 0xFF to be sure */
++	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
++
++
+ 	printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n",
+ 	       map->name, cfi->interleave, cfi->device_type*8, base,
+ 	       map->buswidth*8);
+@@ -165,6 +176,20 @@
+ 	cfi->cfiq->InterfaceDesc = le16_to_cpu(cfi->cfiq->InterfaceDesc);
+ 	cfi->cfiq->MaxBufWriteSize = le16_to_cpu(cfi->cfiq->MaxBufWriteSize);
+ 
++	/*
++	 * ST screwed up the CFI interface for buffer writes on their parts,
++	 * so this needs to be fixed up by hand here.
++         *
++         * A possible enhancment is that instead of just reverting back
++         * to word write (as this does), we could use the ST specific double
++         * word write instead.
++	 */
++
++	if (cfi_read_query(map,base) == 0x20){
++	  cfi->cfiq->BufWriteTimeoutTyp = 0;
++	  cfi->cfiq->BufWriteTimeoutMax = 0;
++	}
++
+ #ifdef DEBUG_CFI
+ 	/* Dump the information therein */
+ 	print_cfi_ident(cfi->cfiq);
+@@ -182,6 +207,9 @@
+ 	/* Put it back into Read Mode */
+ 	cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
+ 
++	/* some devices don't respond to 0xF0, so send 0xFF to be sure */
++	cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
++
+ 	return 1;
+ }
+ 
+--- linux-2.4.25/drivers/mtd/devices/Config.in~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/mtd/devices/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -17,6 +17,15 @@
+ if [ "$CONFIG_SA1100_LART" = "y" ]; then
+    dep_tristate '  28F160xx flash driver for LART' CONFIG_MTD_LART $CONFIG_MTD
+ fi
++if [ "$CONFIG_ARCH_MX1ADS" = "y" ]; then
++   dep_tristate '  SyncFlash driver for MX1ADS' CONFIG_MTD_SYNCFLASH $CONFIG_MTD
++fi
++if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
++   dep_tristate '  AT91RM9200 DataFlash support' CONFIG_MTD_AT91_DATAFLASH $CONFIG_MTD
++   if [ "$CONFIG_MTD_AT91_DATAFLASH" = "y" -o "$CONFIG_MTD_AT91_DATAFLASH" = "m" ]; then
++      bool '     Enable DataFlash card?   ' CONFIG_MTD_AT91_DATAFLASH_CARD
++   fi
++fi
+ dep_tristate '  Test driver using RAM' CONFIG_MTD_MTDRAM $CONFIG_MTD
+ if [ "$CONFIG_MTD_MTDRAM" = "y" -o "$CONFIG_MTD_MTDRAM" = "m" ]; then
+    int 'MTDRAM device size in KiB' CONFIG_MTDRAM_TOTAL_SIZE 4096
+--- linux-2.4.25/drivers/mtd/devices/Makefile~2.4.25-vrs2.patch	2002-11-29 00:53:13.000000000 +0100
++++ linux-2.4.25/drivers/mtd/devices/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -21,6 +21,7 @@
+ obj-$(CONFIG_MTD_MS02NV)	+= ms02-nv.o
+ obj-$(CONFIG_MTD_MTDRAM)	+= mtdram.o
+ obj-$(CONFIG_MTD_LART)		+= lart.o
++obj-$(CONFIG_MTD_SYNCFLASH)	+= syncflash.o
+ obj-$(CONFIG_MTD_BLKMTD)	+= blkmtd.o
+ 
+ include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mtd/devices/syncflash.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,615 @@
++/*
++ * MTD driver for Micron SyncFlash flash memory.
++ *
++ * Author: Jon McClintock <jonm@bluemug.com>
++ *
++ * Based loosely upon the LART flash driver, authored by Abraham vd Merwe
++ * <abraham@2d3d.co.za>.
++ *
++ * Copyright 2003, Blue Mug, Inc. for Motorola, Inc.
++ *
++ * This code is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * References:
++ *
++ * 	[1] Micron SyncFlash homepage
++ * 		- http://www.syncflash.com/
++ *
++ * 	[2] MT28S4M16LC -- 4Mx16 SyncFlash memory datasheet
++ * 		- http://syncflash.com/pdfs/datasheets/mt28s4m16lc_6.pdf
++ *
++ * 	[3] MTD internal API documentation
++ * 		- http://www.linux-mtd.infradead.org/tech/
++ *
++ * Limitations:
++ *
++ * 	Even though this driver is written for Micron SyncFlash, it is quite
++ * 	specific to the Motorola MX1 ADS development board.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/version.h>
++#include <linux/errno.h>
++#include <linux/mtd/mtd.h>
++#include <asm/io.h>
++
++/* partition support */
++#define HAVE_PARTITIONS
++#ifdef HAVE_PARTITIONS
++#include <linux/mtd/partitions.h>
++#endif
++
++#ifndef CONFIG_ARCH_MX1ADS
++#error The SyncFlash driver currently only supports the MX1 ADS platform.
++#endif
++
++/*
++ * General flash configuration parameters.
++ */
++#define BUSWIDTH		4
++#define FLASH_BLOCKSIZE		(256 * 1024 * BUSWIDTH)
++#define FLASH_NUMBLOCKS		16
++
++#define BUSWIDTH		4
++#define FLASH_ADDRESS		IO_ADDRESS(MX1ADS_FLASH_BASE)
++
++#define FLASH_MANUFACTURER	0x002C002C
++#define FLASH_DEVICE_ID		0x00D300D3
++
++/*
++ * The size and extent of the bootloader in flash.
++ */
++#define NUM_BOOTLOADER_BLOCKS	1
++#define BOOTLOADER_START	0x00000000
++#define BOOTLOADER_LEN		(NUM_BOOTLOADER_BLOCKS * FLASH_BLOCKSIZE)
++
++/*
++ * The size and extent of the kernel in flash.
++ */
++#define NUM_KERNEL_BLOCKS	1
++#define KERNEL_START		(BOOTLOADER_START + BOOTLOADER_LEN)
++#define KERNEL_LEN		(NUM_KERNEL_BLOCKS * FLASH_BLOCKSIZE)
++
++/* File system */
++#define NUM_FILESYSTEM_BLOCKS	14
++#define FILESYSTEM_START	(KERNEL_START + KERNEL_LEN)
++#define FILESYSTEM_LEN		(NUM_FILESYSTEM_BLOCKS * FLASH_BLOCKSIZE)
++
++
++/*
++ * SDRAM controller register location and values. These are very specific
++ * to the MX1.
++ */
++#define SDRAMC_REGISTER		IO_ADDRESS(0x00221004)
++
++/*
++ * This the mask we use to get the start of a block from a given address.
++ */
++#define BLOCK_MASK	(0xFFF00000)
++
++/*
++ * This is the A10 address line of the SyncFlash; it's used to initiate
++ * a precharge command.
++ */
++#define SYNCFLASH_A10	(0x00100000)
++
++/*
++ * SDRAM controller MODE settings.
++ */
++#define CMD_NORMAL	(0x81020300)			/* Normal Mode */
++#define CMD_PREC	(CMD_NORMAL + 0x10000000)	/* Precharge command */
++#define CMD_AUTO	(CMD_NORMAL + 0x20000000)	/* Auto refresh */
++#define CMD_LMR		(CMD_NORMAL + 0x30000000)	/* Load Mode Register */
++#define CMD_LCR		(CMD_NORMAL + 0x60000000)	/* LCR Command */
++#define CMD_PROGRAM	(CMD_NORMAL + 0x70000000)	/* SyncFlash Program */
++
++/*
++ * SyncFlash LCR Commands adjusted for the DBMX1 AHB internal address bus .
++ */
++#define LCR_READ_STATUS		(0x0001C000)	/* 0x70 */
++#define LCR_READ_CONFIG		(0x00024000)	/* 0x90 */
++#define LCR_ERASE_CONFIRM	(0x00008000)	/* 0x20 */
++#define LCR_ERASE_NVMODE	(0x0000C000)	/* 0x30 */
++#define LCR_PROG_NVMODE		(0x00028000)	/* 0xA0 */
++#define LCR_SR_CLEAR		(0x00014000)	/* 0x50 */
++
++/*
++ * Status register bits
++ */
++#define SR_VPS_ERROR		(1 << 8)	/* Power-Up status error */
++#define SR_ISM_READY		(1 << 7)	/* State machine isn't busy */
++#define SR_ERASE_ERROR		(1 << 5)	/* Erase/Unprotect error */
++#define SR_PROGRAM_ERROR	(1 << 4)	/* Program/Protect error */
++#define SR_DEVICE_PROTECTED	(1 << 3)	/* Device is protected */
++#define SR_ISM_STATUS_H		(1 << 2)	/* Bank ISM status, high bit */
++#define SR_ISM_STATUS_L		(1 << 1)	/* Bank ISM status, low bit */
++#define SR_DEVICE_ISM_STATUS	(1 << 0)	/* ISM is device-level */
++
++#define SR_ERROR		(SR_VPS_ERROR|SR_ERASE_ERROR|SR_PROGRAM_ERROR|SR_DEVICE_PROTECTED)
++
++#define STATUS_VALUE(a)		((a) | ((a) << 16))
++
++/*
++ * Device configuration register offsets
++ */
++#define DC_MANUFACTURER		(0 * BUSWIDTH)
++#define DC_DEVICE_ID		(1 * BUSWIDTH)
++#define DC_BLOCK_PROTECT	(2 * BUSWIDTH)
++#define DC_DEVICE_PROTECT	(3 * BUSWIDTH)
++
++#define FL_WORD(addr) (*(volatile unsigned long*)(addr))
++
++static char module_name[] = "syncflash";
++
++inline __u8 read8 (__u32 offset)
++{
++	return *(volatile __u8 *) (FLASH_ADDRESS + offset);
++}
++
++inline __u32 read32 (__u32 offset)
++{
++	return *(volatile __u32 *) (FLASH_ADDRESS + offset);
++}
++
++inline void write32 (__u32 x,__u32 offset)
++{
++	*(volatile __u32 *) (FLASH_ADDRESS + offset) = x;
++}
++
++static __u32 read_device_configuration_register(__u32 reg_number)
++{
++	__u32 tmp;
++
++	/* Setup the SDRAM controller to issue an LCR command. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_LCR;
++
++	/* Perform a read to issue the Read Device Configuration Command. */
++	tmp = read32(LCR_READ_CONFIG);
++
++	/* Return the SDRAM controller to normal mode. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL;
++
++	/* Return the value of the specified register. */
++	tmp = read32(reg_number);
++
++	return tmp;
++}
++
++/*
++ * Get the status of the flash devices.
++ */
++static __u32 flash_read_status()
++{
++	__u32 status, tmp;
++
++	/* Enter the SyncFlash Program READ/WRITE mode. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_PROGRAM;
++
++	/* Read the status register. */
++	status = read32(LCR_READ_STATUS);
++
++	/* Clear the status register. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_LCR;
++	tmp = read32(LCR_SR_CLEAR);
++
++	/* Return to Normal mode. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL;
++
++	return status;
++}
++
++/*
++ * Loop until both write state machines are ready.
++ */
++static __u32 flash_status_wait()
++{
++	__u32 status;
++	do {
++		status = flash_read_status();
++	} while ((status & STATUS_VALUE(SR_ISM_READY)) !=
++			STATUS_VALUE(SR_ISM_READY));
++	return status;
++}
++
++/*
++ * Loop until the Write State machine is ready, then do a full error
++ * check.  Clear status and leave the flash in Read Array mode; return
++ * 0 for no error, -1 for error.
++ */
++static int flash_status_full_check()
++{
++	__u32 status;
++
++	status = flash_status_wait() & STATUS_VALUE(SR_ERROR);
++	return status ? -EIO : 0;
++}
++
++/*
++ * Return the flash to the normal mode.
++ */
++static void flash_normal_mode()
++{
++	__u32 tmp;
++
++	/* First issue a precharge all command. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_PREC;
++	tmp = read32(SYNCFLASH_A10);
++
++	/* Now place the SDRAM controller in Normal mode. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL;
++}
++
++/*
++ * Probe for SyncFlash memory on MX1ADS board.
++ *
++ * Returns 1 if we found SyncFlash memory, 0 otherwise.
++ */
++static int flash_probe (void)
++{
++	__u32 manufacturer, device_id;
++
++	/* For some reason, the first read doesn't work, so we do it
++	 * twice. */
++	manufacturer = read_device_configuration_register(DC_MANUFACTURER);
++	manufacturer = read_device_configuration_register(DC_MANUFACTURER);
++	device_id = read_device_configuration_register(DC_DEVICE_ID);
++
++	printk("SyncFlash probe: manufacturer 0x%08lx, device_id 0x%08lx\n",
++		manufacturer, device_id);
++	return (manufacturer == FLASH_MANUFACTURER &&
++		device_id == FLASH_DEVICE_ID);
++}
++
++/*
++ * Erase one block of flash memory at offset ``offset'' which is any
++ * address within the block which should be erased.
++ *
++ * Returns 0 if successful, -1 otherwise.
++ */
++static inline int erase_block (__u32 offset)
++{
++	__u32 tmp;
++
++	/* Mask off the lower bits of the address to get the first address
++	 * in the flash block. */
++	offset &= (__u32)BLOCK_MASK;
++
++	/* Perform a read and precharge of the bank before the LCR|ACT|WRIT
++	 * sequence to avoid the inadvertent precharge command occurring
++	 * during the LCR_ACT_WRIT sequence. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL;
++	tmp = read32(offset);
++	FL_WORD(SDRAMC_REGISTER) = CMD_PREC;
++	tmp = read32(offset);
++
++	/* Now start the actual erase. */
++
++	/* LCR|ACT|WRIT sequence */
++	FL_WORD(SDRAMC_REGISTER) = CMD_LCR;
++	write32(0, offset + LCR_ERASE_CONFIRM);
++
++	/* Return to normal mode to issue the erase confirm. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_NORMAL;
++	write32(0xD0D0D0D0, offset);
++
++	if (flash_status_full_check()) {
++		printk (KERN_WARNING "%s: erase error at address 0x%.8x.\n",
++			module_name, offset);
++		return (-1);
++	}
++
++	flash_normal_mode();
++
++	return 0;
++}
++
++static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
++{
++	__u32 addr,len;
++	int i,first;
++
++	/* sanity checks */
++	if (instr->addr + instr->len > mtd->size) return (-EINVAL);
++
++	/*
++	 * check that both start and end of the requested erase are
++	 * aligned with the erasesize at the appropriate addresses.
++	 *
++	 * skip all erase regions which are ended before the start of
++	 * the requested erase. Actually, to save on the calculations,
++	 * we skip to the first erase region which starts after the
++	 * start of the requested erase, and then go back one.
++	 */
++	for (i = 0; (i < mtd->numeraseregions) &&
++		    (instr->addr >= mtd->eraseregions[i].offset); i++) ;
++	i--;
++
++	/*
++	 * ok, now i is pointing at the erase region in which this
++	 * erase request starts. Check the start of the requested
++	 * erase range is aligned with the erase size which is in
++	 * effect here.
++	 */
++	if (instr->addr & (mtd->eraseregions[i].erasesize - 1))
++		return (-EINVAL);
++
++	/* Remember the erase region we start on */
++	first = i;
++
++	/*
++	 * next, check that the end of the requested erase is aligned
++	 * with the erase region at that address.
++	 *
++	 * as before, drop back one to point at the region in which
++	 * the address actually falls
++	 */
++	for (;
++	     (i < mtd->numeraseregions) &&
++	     ((instr->addr + instr->len) >= mtd->eraseregions[i].offset) ;
++	     i++) ;
++	i--;
++
++	/* is the end aligned on a block boundary? */
++	if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1))
++		return (-EINVAL);
++
++	addr = instr->addr;
++	len = instr->len;
++
++	i = first;
++
++	/* now erase those blocks */
++	while (len)
++	{
++		if (erase_block (addr))
++		{
++			instr->state = MTD_ERASE_FAILED;
++			return (-EIO);
++		}
++
++		addr += mtd->eraseregions[i].erasesize;
++		len -= mtd->eraseregions[i].erasesize;
++
++		if (addr == (mtd->eraseregions[i].offset +
++				(mtd->eraseregions[i].erasesize *
++				 mtd->eraseregions[i].numblocks)))
++			i++;
++	}
++
++	instr->state = MTD_ERASE_DONE;
++	if (instr->callback) instr->callback (instr);
++
++	return (0);
++}
++
++static int flash_read (struct mtd_info *mtd, loff_t from,
++		       size_t len, size_t *retlen, u_char *buf)
++{
++	/* Sanity checks. */
++	if (!len) return (0);
++	if (from + len > mtd->size) return (-EINVAL);
++
++	/* Ensure that we are in normal mode. */
++	flash_normal_mode();
++
++	/* We always read len bytes. */
++	*retlen = len;
++
++	/* first, we read bytes until we reach a dword boundary */
++	if (from & (BUSWIDTH - 1))
++	{
++		int gap = BUSWIDTH - (from & (BUSWIDTH - 1));
++		while (len && gap--) *buf++ = read8(from++), len--;
++	}
++
++	/* now we read dwords until we reach a non-dword boundary */
++	while (len >= BUSWIDTH)
++	{
++		*((__u32 *) buf) = read32(from);
++
++		buf += BUSWIDTH;
++		from += BUSWIDTH;
++		len -= BUSWIDTH;
++	}
++
++	/* top up the last unaligned bytes */
++	if (len & (BUSWIDTH - 1))
++		while (len--) *buf++ = read8(from++);
++
++	return (0);
++}
++
++/*
++ * Write one dword ``x'' to flash memory at offset ``offset''. ``offset''
++ * must be 32 bits, i.e. it must be on a dword boundary.
++ *
++ * Returns 0 if successful, -1 otherwise.
++ */
++static int flash_write_dword(__u32 offset, __u32 x)
++{
++	__u32 tmp;
++
++	/* First issue a precharge all command. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_PREC;
++	tmp = read32(SYNCFLASH_A10);
++
++	/* Enter the SyncFlash programming mode. */
++	FL_WORD(SDRAMC_REGISTER) = CMD_PROGRAM;
++	write32(x, offset);
++
++	/* Wait for the write to complete. */
++	flash_status_wait();
++
++	/* Return to normal mode. */
++	flash_normal_mode();
++
++	return 0;
++}
++
++static int flash_write (struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const u_char *buf)
++{
++	__u8 tmp[4];
++	int i,n;
++
++	*retlen = 0;
++
++	/* Sanity checks */
++	if (!len) return (0);
++	if (to + len > mtd->size) return (-EINVAL);
++
++	/* First, we write a 0xFF.... padded byte until we reach a
++	 * dword boundary. */
++	if (to & (BUSWIDTH - 1))
++	{
++		__u32 aligned = to & ~(BUSWIDTH - 1);
++		int gap = to - aligned;
++
++		i = n = 0;
++
++		while (gap--) tmp[i++] = 0xFF;
++		while (len && i < BUSWIDTH) tmp[i++] = buf[n++], len--;
++		while (i < BUSWIDTH) tmp[i++] = 0xFF;
++
++		if (flash_write_dword(aligned, *((__u32 *) tmp)))
++			return (-EIO);
++
++		to += n;
++		buf += n;
++		*retlen += n;
++	}
++
++	/* Now we write dwords until we reach a non-dword boundary. */
++	while (len >= BUSWIDTH)
++	{
++		if (flash_write_dword (to,*((__u32 *) buf))) return (-EIO);
++
++		to += BUSWIDTH;
++		buf += BUSWIDTH;
++		*retlen += BUSWIDTH;
++		len -= BUSWIDTH;
++	}
++
++	/* Top up the last unaligned bytes, padded with 0xFF.... */
++	if (len & (BUSWIDTH - 1))
++	{
++		i = n = 0;
++
++		while (len--) tmp[i++] = buf[n++];
++		while (i < BUSWIDTH) tmp[i++] = 0xFF;
++
++		if (flash_write_dword (to,*((__u32 *) tmp))) return (-EIO);
++
++		*retlen += n;
++	}
++
++	return flash_status_full_check();
++}
++
++
++
++#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
++
++static struct mtd_info mtd;
++
++static struct mtd_erase_region_info erase_regions[] =
++{
++	/* flash blocks */
++	{
++		offset: 	0x00000000,
++		erasesize: 	FLASH_BLOCKSIZE,
++		numblocks: 	FLASH_NUMBLOCKS
++	},
++};
++
++#ifdef HAVE_PARTITIONS
++static struct mtd_partition syncflash_partitions[] =
++{
++   /* bootloader */
++   {
++	       name: "bootloader",
++	     offset: BOOTLOADER_START,
++	       size: BOOTLOADER_LEN,
++	 mask_flags: 0
++   },
++   /* Kernel */
++   {
++	       name: "kernel",
++	     offset: KERNEL_START,			/* MTDPART_OFS_APPEND */
++	       size: KERNEL_LEN,
++	 mask_flags: 0
++   },
++   /* file system */
++   {
++	       name: "file system",
++	     offset: FILESYSTEM_START,			/* MTDPART_OFS_APPEND */
++	       size: FILESYSTEM_LEN,			/* MTDPART_SIZ_FULL */
++	 mask_flags: 0
++   }
++};
++#endif
++
++int __init syncflash_init (void)
++{
++	int result;
++
++	memset (&mtd,0,sizeof (mtd));
++
++	printk ("MTD driver for Micron SyncFlash.\n");
++	printk ("%s: Probing for SyncFlash on MX1ADS...\n",module_name);
++
++	if (!flash_probe ())
++	{
++		printk (KERN_WARNING "%s: Found no SyncFlash devices\n",
++			module_name);
++		return (-ENXIO);
++	}
++
++	printk ("%s: Found a SyncFlash device.\n",module_name);
++
++	mtd.name = module_name;
++	mtd.type = MTD_NORFLASH;
++	mtd.flags = MTD_CAP_NORFLASH;
++	mtd.size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS;
++
++	mtd.erasesize = FLASH_BLOCKSIZE;
++	mtd.numeraseregions = NB_OF(erase_regions);
++	mtd.eraseregions = erase_regions;
++
++	mtd.module = THIS_MODULE;
++
++	mtd.erase = flash_erase;
++	mtd.read = flash_read;
++	mtd.write = flash_write;
++
++#ifndef HAVE_PARTITIONS
++	result = add_mtd_device(&mtd);
++#else
++	result = add_mtd_partitions(&mtd,
++				    syncflash_partitions,
++				    NB_OF(syncflash_partitions));
++#endif
++
++	return (result);
++}
++
++void __exit syncflash_exit (void)
++{
++#ifndef HAVE_PARTITIONS
++	del_mtd_device (&mtd);
++#else
++	del_mtd_partitions (&mtd);
++#endif
++}
++
++module_init (syncflash_init);
++module_exit (syncflash_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jon McClintock <jonm@bluemug.com>");
++MODULE_DESCRIPTION("MTD driver for Micron MT28S4M16LC SyncFlash on MX1ADS board");
++
++
+--- linux-2.4.25/drivers/mtd/maps/Config.in~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/mtd/maps/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -81,10 +81,10 @@
+    dep_tristate '  CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
+    dep_tristate '  CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
+    dep_tristate '  CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
+-   dep_tristate '  CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI  $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+-   dep_tristate '  CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
++   dep_tristate '  CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_FORTUNET
++   dep_tristate '  CFI Flash device mapped on Epxa' CONFIG_MTD_EPXA $CONFIG_MTD_CFI  $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+    dep_tristate '  NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
+-   dep_tristate '  CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
++   dep_tristate '  CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_ARCH_EDB7212 $CONFIG_MTD_CFI
+    dep_tristate '  JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
+    dep_tristate '  JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE  $CONFIG_ARCH_CEIVA
+ fi
+--- linux-2.4.25/drivers/mtd/maps/Makefile~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/mtd/maps/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -3,11 +3,7 @@
+ #
+ # $Id$
+ 
+-BELOW25		:= $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/)
+-
+-ifeq ($(BELOW25),y)
+ O_TARGET	:= mapslink.o
+-endif
+ 
+ # Chip mappings
+ obj-$(CONFIG_MTD_CDB89712)	+= cdb89712.o
+@@ -17,7 +13,7 @@
+ obj-$(CONFIG_MTD_DC21285)	+= dc21285.o
+ obj-$(CONFIG_MTD_DILNETPC)	+= dilnetpc.o
+ obj-$(CONFIG_MTD_ELAN_104NC)	+= elan-104nc.o
+-obj-$(CONFIG_MTD_EPXA10DB)	+= epxa10db-flash.o
++obj-$(CONFIG_MTD_EPXA)		+= epxa-flash.o
+ obj-$(CONFIG_MTD_IQ80310)	+= iq80310.o
+ obj-$(CONFIG_MTD_L440GX)	+= l440gx.o
+ obj-$(CONFIG_MTD_AMD76XROM)	+= amd76xrom.o
+@@ -29,9 +25,9 @@
+ obj-$(CONFIG_MTD_OCTAGON)	+= octagon-5066.o
+ ifneq ($(CONFIG_MTD_PHYSMAP),n)
+   ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8)
+-    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap64.o 
++    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap64.o
+   else
+-    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o 
++    obj-$(CONFIG_MTD_PHYSMAP)	+= physmap.o
+   endif
+ endif
+ obj-$(CONFIG_MTD_PNC2000)	+= pnc2000.o
+@@ -39,6 +35,9 @@
+ obj-$(CONFIG_MTD_RPXLITE)	+= rpxlite.o
+ obj-$(CONFIG_MTD_TQM8XXL)	+= tqm8xxl.o
+ obj-$(CONFIG_MTD_SA1100)	+= sa1100-flash.o
++ifeq ($(CONFIG_ASSABET_NEPONSET),y)
++  obj-$(CONFIG_MTD_SA1100)	+= neponset-flash.o
++endif
+ obj-$(CONFIG_MTD_SBC_GXX)	+= sbc_gxx.o
+ obj-$(CONFIG_MTD_SC520CDP)	+= sc520cdp.o
+ obj-$(CONFIG_MTD_NETSC520)	+= netsc520.o
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mtd/maps/epxa-flash.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,234 @@
++/*
++ * Flash memory access on EPXA based devices
++ *
++ * (C) 2000 Nicolas Pitre <nico@cam.org>
++ *  Copyright (C) 2001 Altera Corporation
++ *  Copyright (C) 2001 Red Hat, Inc.
++ *
++ * $Id$
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <asm/io.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/hardware.h>
++#ifdef CONFIG_EPXA10DB
++#define BOARD_NAME "EPXA10DB"
++#else
++#define BOARD_NAME "EPXA1DB"
++#endif
++
++static int nr_parts = 0;
++static struct mtd_partition *parts;
++
++static struct mtd_info *mymtd;
++
++extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
++static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++
++static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
++{
++	return __raw_readb(map->map_priv_1 + ofs);
++}
++
++static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
++{
++	return __raw_readw(map->map_priv_1 + ofs);
++}
++
++static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
++{
++	return __raw_readl(map->map_priv_1 + ofs);
++}
++
++static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++	memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++	__raw_writeb(d, map->map_priv_1 + adr);
++	mb();
++}
++
++static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++	__raw_writew(d, map->map_priv_1 + adr);
++	mb();
++}
++
++static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++	__raw_writel(d, map->map_priv_1 + adr);
++	mb();
++}
++
++static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++	memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++static struct map_info epxa_map = {
++	.name      = "EPXA flash",
++	.size      = FLASH_SIZE,
++	.buswidth  = 2,
++	.read8     = epxa_read8,
++	.read16    = epxa_read16,
++	.read32    = epxa_read32,
++	.copy_from = epxa_copy_from,
++	.write8    = epxa_write8,
++	.write16   = epxa_write16,
++	.write32   = epxa_write32,
++	.copy_to   = epxa_copy_to
++};
++
++static int __init epxa_mtd_init(void)
++{
++	int i;
++
++	printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
++	epxa_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_START, FLASH_SIZE);
++	if (!epxa_map.map_priv_1) {
++		printk("Failed to ioremap %s flash\n",BOARD_NAME);
++		return -EIO;
++	}
++
++	mymtd = do_map_probe("cfi_probe", &epxa_map);
++	if (!mymtd) {
++		iounmap((void *)epxa_map.map_priv_1);
++		return -ENXIO;
++	}
++
++	mymtd->module = THIS_MODULE;
++
++	/* Unlock the flash device. */
++	if(mymtd->unlock){
++		for (i=0; i<mymtd->numeraseregions;i++){
++			int j;
++			for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
++				mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
++			}
++		}
++	}
++
++#ifdef CONFIG_MTD_REDBOOT_PARTS
++	nr_parts = parse_redboot_partitions(mymtd, &parts);
++
++	if (nr_parts > 0) {
++		add_mtd_partitions(mymtd, parts, nr_parts);
++		return 0;
++	}
++#endif
++#ifdef CONFIG_MTD_AFS_PARTS
++	nr_parts = parse_afs_partitions(mymtd, &parts);
++
++	if (nr_parts > 0) {
++		add_mtd_partitions(mymtd, parts, nr_parts);
++		return 0;
++	}
++#endif
++
++	/* No recognised partitioning schemes found - use defaults */
++	nr_parts = epxa_default_partitions(mymtd, &parts);
++	if (nr_parts > 0) {
++		add_mtd_partitions(mymtd, parts, nr_parts);
++		return 0;
++	}
++
++	/* If all else fails... */
++	add_mtd_device(mymtd);
++	return 0;
++}
++
++static void __exit epxa_mtd_cleanup(void)
++{
++	if (mymtd) {
++		if (nr_parts)
++			del_mtd_partitions(mymtd);
++		else
++			del_mtd_device(mymtd);
++		map_destroy(mymtd);
++	}
++	if (epxa_map.map_priv_1) {
++		iounmap((void *)epxa_map.map_priv_1);
++		epxa_map.map_priv_1 = 0;
++	}
++}
++
++
++/*
++ * This will do for now, once we decide which bootldr we're finally
++ * going to use then we'll remove this function and do it properly
++ *
++ * Partions are currently (as offsets from base of flash):
++ * 0x00000000 - 0x003FFFFF - bootloader (!)
++ * 0x00400000 - 0x00FFFFFF - Flashdisk
++ */
++
++static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
++{
++	struct mtd_partition *parts;
++	int ret;
++	int npartitions = 0;
++	char *names;
++	const char *name = "jffs";
++
++	printk("Using default partitions for %s\n",BOARD_NAME);
++	npartitions=1;
++	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name)+1, GFP_KERNEL);
++	if (!parts) {
++		ret = -ENOMEM;
++		goto out;
++	}
++	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
++
++	names = (char *)&parts[npartitions];
++	parts[0].name = names;
++	names += strlen(name) + 1;
++	strcpy(parts[0].name, name);
++
++#ifdef CONFIG_EPXA10DB_R2
++	parts[0].size       = FLASH_SIZE-0x00400000;
++	parts[0].offset     = 0x00400000;
++#elif defined CONFIG_EPXA10DB_R3
++	parts[0].size       = 0x00800000;
++	parts[0].offset     = 0x00800000;
++#else
++	parts[0].size       = FLASH_SIZE-0x00180000;
++	parts[0].offset     = 0x00180000;
++#endif
++	ret = npartitions;
++
++ out:
++	*pparts = parts;
++	return ret;
++}
++
++
++module_init(epxa_mtd_init);
++module_exit(epxa_mtd_cleanup);
++
++MODULE_AUTHOR("Clive Davies");
++MODULE_DESCRIPTION("Altera epxa mtd flash map");
++MODULE_LICENSE("GPL");
+--- linux-2.4.25/drivers/mtd/maps/epxa10db-flash.c~2.4.25-vrs2.patch
++++ linux-2.4.25/drivers/mtd/maps/epxa10db-flash.c
+-/*
+- * Flash memory access on EPXA based devices
+- *
+- * (C) 2000 Nicolas Pitre <nico@cam.org>
+- *  Copyright (C) 2001 Altera Corporation
+- *  Copyright (C) 2001 Red Hat, Inc.
+- *
+- * $Id$ 
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * This program is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-#include <linux/types.h>
+-#include <linux/kernel.h>
+-#include <asm/io.h>
+-#include <linux/mtd/mtd.h>
+-#include <linux/mtd/map.h>
+-#include <linux/mtd/partitions.h>
+-
+-#include <asm/hardware.h>
+-#ifdef CONFIG_EPXA10DB
+-#define BOARD_NAME "EPXA10DB"
+-#else
+-#define BOARD_NAME "EPXA1DB"
+-#endif
+-
+-static int nr_parts = 0;
+-static struct mtd_partition *parts;
+-
+-static struct mtd_info *mymtd;
+-
+-extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
+-static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+-
+-static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
+-{
+-	return __raw_readb(map->map_priv_1 + ofs);
+-}
+-
+-static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
+-{
+-	return __raw_readw(map->map_priv_1 + ofs);
+-}
+-
+-static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
+-{
+-	return __raw_readl(map->map_priv_1 + ofs);
+-}
+-
+-static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+-{
+-	memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
+-}
+-
+-static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
+-{
+-	__raw_writeb(d, map->map_priv_1 + adr);
+-	mb();
+-}
+-
+-static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
+-{
+-	__raw_writew(d, map->map_priv_1 + adr);
+-	mb();
+-}
+-
+-static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
+-{
+-	__raw_writel(d, map->map_priv_1 + adr);
+-	mb();
+-}
+-
+-static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+-{
+-	memcpy_toio((void *)(map->map_priv_1 + to), from, len);
+-}
+-
+-
+-
+-static struct map_info epxa_map = {
+-	name:		"EPXA flash",
+-	size:		FLASH_SIZE,
+-	buswidth:	2,
+-	read8:		epxa_read8,
+-	read16:		epxa_read16,
+-	read32:		epxa_read32,
+-	copy_from:	epxa_copy_from,
+-	write8:		epxa_write8,
+-	write16:	epxa_write16,
+-	write32:	epxa_write32,
+-	copy_to:	epxa_copy_to
+-};
+-
+-
+-static int __init epxa_mtd_init(void)
+-{
+-	int i;
+-	
+-	printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
+-	epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+-	if (!epxa_map.map_priv_1) {
+-		printk("Failed to ioremap %s flash\n",BOARD_NAME);
+-		return -EIO;
+-	}
+-
+-	mymtd = do_map_probe("cfi_probe", &epxa_map);
+-	if (!mymtd) {
+-		iounmap((void *)epxa_map.map_priv_1);
+-		return -ENXIO;
+-	}
+-
+-	mymtd->module = THIS_MODULE;
+-
+-	/* Unlock the flash device. */
+-	if(mymtd->unlock){
+-		for (i=0; i<mymtd->numeraseregions;i++){
+-			int j;
+-			for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
+-				mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
+-			}
+-		}
+-	}
+-
+-#ifdef CONFIG_MTD_REDBOOT_PARTS
+-	nr_parts = parse_redboot_partitions(mymtd, &parts);
+-
+-	if (nr_parts > 0) {
+-		add_mtd_partitions(mymtd, parts, nr_parts);
+-		return 0;
+-	}
+-#endif
+-#ifdef CONFIG_MTD_AFS_PARTS
+-	nr_parts = parse_afs_partitions(mymtd, &parts);
+-
+-	if (nr_parts > 0) {
+-		add_mtd_partitions(mymtd, parts, nr_parts);
+-		return 0;
+-	}
+-#endif
+-
+-	/* No recognised partitioning schemes found - use defaults */
+-	nr_parts = epxa_default_partitions(mymtd, &parts);
+-	if (nr_parts > 0) {
+-		add_mtd_partitions(mymtd, parts, nr_parts);
+-		return 0;
+-	}
+-
+-	/* If all else fails... */
+-	add_mtd_device(mymtd);
+-	return 0;
+-}
+-
+-static void __exit epxa_mtd_cleanup(void)
+-{
+-	if (mymtd) {
+-		if (nr_parts)
+-			del_mtd_partitions(mymtd);
+-		else
+-			del_mtd_device(mymtd);
+-		map_destroy(mymtd);
+-	}
+-	if (epxa_map.map_priv_1) {
+-		iounmap((void *)epxa_map.map_priv_1);
+-		epxa_map.map_priv_1 = 0;
+-	}
+-}
+-
+-
+-/* 
+- * This will do for now, once we decide which bootldr we're finally 
+- * going to use then we'll remove this function and do it properly
+- *
+- * Partions are currently (as offsets from base of flash):
+- * 0x00000000 - 0x003FFFFF - bootloader (!)
+- * 0x00400000 - 0x00FFFFFF - Flashdisk
+- */
+-
+-static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+-{
+-	struct mtd_partition *parts;
+-	int ret, i;
+-	int npartitions = 0;
+-	char *names; 
+-	const char *name = "jffs";
+-
+-	printk("Using default partitions for %s\n",BOARD_NAME);
+-	npartitions=1;
+-	parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+-	memzero(parts,npartitions*sizeof(*parts)+strlen(name));
+-	if (!parts) {
+-		ret = -ENOMEM;
+-		goto out;
+-	}
+-	i=0;
+-	names = (char *)&parts[npartitions];	
+-	parts[i].name = names;
+-	names += strlen(name) + 1;
+-	strcpy(parts[i].name, name);
+-
+-#ifdef CONFIG_EPXA10DB
+-	parts[i].size = FLASH_SIZE-0x00400000;
+-	parts[i].offset = 0x00400000;
+-#else
+-	parts[i].size = FLASH_SIZE-0x00180000;
+-	parts[i].offset = 0x00180000;
+-#endif
+-
+- out:
+-	*pparts = parts;
+-	return npartitions;
+-}
+-
+-
+-module_init(epxa_mtd_init);
+-module_exit(epxa_mtd_cleanup);
+-
+-MODULE_AUTHOR("Clive Davies");
+-MODULE_DESCRIPTION("Altera epxa mtd flash map");
+-MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/mtd/maps/neponset-flash.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,109 @@
++/*
++ * Flash memory access on SA11x0 based devices
++ * 
++ * (C) 2000 Nicolas Pitre <nico@cam.org>
++ * 
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/arch/assabet.h>
++
++static __u8 read8(struct map_info *map, unsigned long ofs)
++{
++	return readb(map->map_priv_1 + ofs);
++}
++
++static __u16 read16(struct map_info *map, unsigned long ofs)
++{
++	return readw(map->map_priv_1 + ofs);
++}
++
++static __u32 read32(struct map_info *map, unsigned long ofs)
++{
++	return readl(map->map_priv_1 + ofs);
++}
++
++static void copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
++{
++	memcpy_fromio(to, map->map_priv_1 + from, len);
++}
++
++static void write8(struct map_info *map, __u8 d, unsigned long adr)
++{
++	writeb(d, map->map_priv_1 + adr);
++}
++
++static void write16(struct map_info *map, __u16 d, unsigned long adr)
++{
++	writew(d, map->map_priv_1 + adr);
++}
++
++static void write32(struct map_info *map, __u32 d, unsigned long adr)
++{
++	writel(d, map->map_priv_1 + adr);
++}
++
++static void copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
++{
++	memcpy_toio(map->map_priv_1 + to, from, len);
++}
++
++#define MAX_SZ (32 * 1024 * 1024)
++
++static struct map_info neponset_map = {
++	name:		"Neponset",
++	size:		MAX_SZ,
++	buswidth:	4,
++	read8:		read8,
++	read16:		read16,
++	read32:		read32,
++	copy_from:	copy_from,
++	write8:		write8,
++	write16:	write16,
++	write32:	write32,
++	copy_to:	copy_to,
++};
++
++extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++
++static struct mtd_info *neponset_mtd;
++
++int __init neponset_mtd_init(void)
++{
++	if (!machine_is_assabet() || !machine_has_neponset())
++		return -ENODEV;
++
++	neponset_map.map_priv_1 = (unsigned int)ioremap(0x08000000, MAX_SZ);
++	if (!neponset_map.map_priv_1)
++		return -ENOMEM;
++
++	neponset_mtd = do_map_probe("cfi_probe", &neponset_map);
++	if (!neponset_mtd)
++		return -ENXIO;
++	neponset_mtd->module = THIS_MODULE;
++	add_mtd_device(neponset_mtd);
++	return 0;
++}
++
++static void __exit neponset_mtd_cleanup(void)
++{
++	if (neponset_mtd)
++		map_destroy(neponset_mtd);
++	if (neponset_map.map_priv_1)
++		iounmap((void *)neponset_map.map_priv_1);
++}
++
++module_init(neponset_mtd_init);
++module_exit(neponset_mtd_cleanup);
+--- linux-2.4.25/drivers/mtd/maps/sa1100-flash.c~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/mtd/maps/sa1100-flash.c	2004-03-31 17:15:09.000000000 +0200
+@@ -97,6 +97,32 @@
+  * entries.  Thanks.
+  */
+ 
++#ifdef CONFIG_SA1100_ADSAGC
++#define ADSAGC_FLASH_SIZE		0x02000000
++static struct mtd_partition adsagc_partitions[] = {
++	{
++		name:		"bootROM",
++		size:		0x80000,
++		offset:		0,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	}, {
++		name:		"zImage",
++		size:		0x100000,
++		offset:		MTDPART_OFS_APPEND,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	}, {
++		name:		"ramdisk.gz",
++		size:		0x300000,
++		offset:		MTDPART_OFS_APPEND,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	}, {
++		name:		"User FS",
++		size:		MTDPART_SIZ_FULL,
++		offset:		MTDPART_OFS_APPEND,
++	}
++};
++#endif
++
+ #ifdef CONFIG_SA1100_ADSBITSY
+ #define ADSBITSY_FLASH_SIZE		0x02000000
+ static struct mtd_partition adsbitsy_partitions[] = {
+@@ -123,6 +149,32 @@
+ };
+ #endif
+ 
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++#define ADSBITSYPLUS_FLASH_SIZE		0x02000000
++static struct mtd_partition adsbitsyplus_partitions[] = {
++	{
++		name:		"bootROM",
++		size:		0x80000,
++		offset:		0,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	}, {
++		name:		"zImage",
++		size:		0x100000,
++		offset:		MTDPART_OFS_APPEND,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	}, {
++		name:		"ramdisk.gz",
++		size:		0x300000,
++		offset:		MTDPART_OFS_APPEND,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	}, {
++		name:		"User FS",
++		size:		MTDPART_SIZ_FULL,
++		offset:		MTDPART_OFS_APPEND,
++	}
++};
++#endif
++
+ #ifdef CONFIG_SA1100_ASSABET
+ /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
+ #define ASSABET4_FLASH_SIZE		0x00400000
+@@ -438,7 +490,7 @@
+ #endif
+ 
+ #ifdef CONFIG_SA1100_GRAPHICSMASTER
+-#define GRAPHICSMASTER_FLASH_SIZE	0x01000000
++#define GRAPHICSMASTER_FLASH_SIZE	0x02000000
+ static struct mtd_partition graphicsmaster_partitions[] = {
+ 	{
+ 		name:		"zImage",
+@@ -507,6 +559,38 @@
+ }
+ #endif
+ 
++#ifdef CONFIG_SA1100_HACKKIT
++#define HACKKIT_FLASH_SIZE		0x01000000
++static struct mtd_partition hackkit_partitions[] = {
++	{
++		name:		"BLOB",
++		size:		0x00040000,
++		offset:		0x00000000,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	}, {
++		name:		"config",
++		size:		0x00040000,
++		offset:		MTDPART_OFS_APPEND,
++	}, {
++		name:		"kernel",
++		size:		0x00100000,
++		offset:		MTDPART_OFS_APPEND,
++	}, {
++		name:		"initrd",
++		size:		0x00180000,
++		offset:		MTDPART_OFS_APPEND,
++	}, {
++		name:		"rootfs",
++		size:		0x700000,
++		offset:		MTDPART_OFS_APPEND,
++	}, {
++		name:		"data",
++		size:		MTDPART_SIZ_FULL,
++		offset:		MTDPART_OFS_APPEND,
++	}
++};
++#endif
++
+ #ifdef CONFIG_SA1100_HUW_WEBPANEL
+ #define HUW_WEBPANEL_FLASH_SIZE		0x01000000
+ static struct mtd_partition huw_webpanel_partitions[] = {
+@@ -555,12 +639,12 @@
+ 		offset:		0x00540000,
+ 	}, {
+ 		name:		"JORNADA720 usr local",
+-		size:		0  /* will expand to the end of the flash */
++		size:		0,  /* will expand to the end of the flash */
+ 		offset:		0x00d00000,
+ 	}
+ };
+ 
+-static void jornada720_set_vpp(int vpp)
++static void jornada720_set_vpp(struct map_info *map, int vpp)
+ {
+ 	if (vpp)
+ 		PPSR |= 0x80;
+@@ -571,6 +655,27 @@
+ 
+ #endif
+ 
++#ifdef CONFIG_SA1100_NANOENGINE
++/* nanoEngine has one 28F320B3B Flash part in bank 0: */
++#define NANOENGINE_FLASH_SIZE		0x00400000
++static struct mtd_partition nanoengine_partitions[] = {
++	{
++		name:		"nanoEngine boot firmware and parameter table",
++		size:		0x00010000,  /* 32K */
++		offset:		0x00000000,
++		mask_flags:	MTD_WRITEABLE,  /* force read-only */
++	},{
++		name:		"kernel/initrd reserved",
++		size:		0x002f0000,
++		offset:		0x00010000,
++	},{
++		name:		"experimental filesystem allocation",
++		size:		0x00100000,
++		offset:		0x00300000,
++	}
++};
++#endif
++
+ #ifdef CONFIG_SA1100_PANGOLIN
+ #define PANGOLIN_FLASH_SIZE		0x04000000
+ static struct mtd_partition pangolin_partitions[] = {
+@@ -699,6 +804,32 @@
+ };
+ #endif /* CONFIG_SA1100_SIMPAD */
+ 
++#ifdef CONFIG_SA1100_SIMPUTER
++#define SIMPUTER_FLASH_SIZE 0x02000000
++static struct mtd_partition simputer_partitions[] = {
++	{
++		name:		"blob+logo",
++		offset:		0,
++		size:		0x00040000
++	},
++	{
++		name:		"kernel",
++		offset:		MTDPART_OFS_APPEND,
++		size:		0x000C0000
++	},
++	{
++		name:		"/(cramfs)",
++		offset:		MTDPART_OFS_APPEND,
++		size:		0x00200000
++	},
++	{
++		name:		"/usr/local(jffs2)",
++		offset:		MTDPART_OFS_APPEND,
++		size:		MTDPART_SIZ_FULL /* expand till the end */
++	}
++};
++#endif
++
+ #ifdef CONFIG_SA1100_STORK
+ #define STORK_FLASH_SIZE		0x02000000
+ static struct mtd_partition stork_partitions[] = {
+@@ -766,7 +897,7 @@
+ #endif
+ 
+ extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+-extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
++extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+ 
+ static struct mtd_partition *parsed_parts;
+ static struct mtd_info *mymtd;
+@@ -787,6 +918,14 @@
+ 	 */
+ 	part_type = "static";
+ 
++#ifdef CONFIG_SA1100_ADSAGC
++	if (machine_is_adsagc()) {
++		parts = adsagc_partitions;
++		nb_parts = ARRAY_SIZE(adsagc_partitions);
++		sa1100_map.size = ADSAGC_FLASH_SIZE;
++		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
++	}
++#endif
+ #ifdef CONFIG_SA1100_ADSBITSY
+ 	if (machine_is_adsbitsy()) {
+ 		parts = adsbitsy_partitions;
+@@ -795,6 +934,14 @@
+ 		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
+ 	}
+ #endif
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++	if (machine_is_adsbitsyplus()) {
++		parts = adsbitsyplus_partitions;
++		nb_parts = ARRAY_SIZE(adsbitsyplus_partitions);
++		sa1100_map.size = ADSBITSYPLUS_FLASH_SIZE;
++		sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4;
++	}
++#endif
+ #ifdef CONFIG_SA1100_ASSABET
+ 	if (machine_is_assabet()) {
+ 		parts = assabet_partitions;
+@@ -869,6 +1016,13 @@
+ 		sa1100_map.set_vpp = h3600_set_vpp;
+ 	}
+ #endif
++#ifdef CONFIG_SA1100_HACKKIT
++	if (machine_is_hackkit()) {
++		parts = hackkit_partitions;
++		nb_parts = ARRAY_SIZE(hackkit_partitions);
++		sa1100_map.size = HACKKIT_FLASH_SIZE;
++	}
++#endif
+ #ifdef CONFIG_SA1100_HUW_WEBPANEL
+ 	if (machine_is_huw_webpanel()) {
+ 		parts = huw_webpanel_partitions;
+@@ -884,6 +1038,13 @@
+ 		sa1100_map.set_vpp = jornada720_set_vpp;
+ 	}
+ #endif
++#ifdef CONFIG_SA1100_NANOENGINE
++	if (machine_is_nanoengine()) {
++		parts = nanoengine_partitions;
++		nb_parts = ARRAY_SIZE(nanoengine_partitions);
++		sa1100_map.size = NANOENGINE_FLASH_SIZE;
++	}
++#endif
+ #ifdef CONFIG_SA1100_PANGOLIN
+ 	if (machine_is_pangolin()) {
+ 		parts = pangolin_partitions;
+@@ -919,6 +1080,13 @@
+ 		sa1100_map.size = SIMPAD_FLASH_SIZE;
+ 	}
+ #endif
++#ifdef CONFIG_SA1100_SIMPUTER
++	if (machine_is_simputer()) {
++		parts = simputer_partitions;
++		nb_parts = ARRAY_SIZE(simputer_partitions);
++		sa1100_map.size = SIMPUTER_FLASH_SIZE;
++	}
++#endif
+ #ifdef CONFIG_SA1100_STORK
+ 	if (machine_is_stork()) {
+ 		parts = stork_partitions;
+@@ -953,7 +1121,9 @@
+ 	 * specific machine settings might have been set above.
+ 	 */
+ 	printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
+-	mymtd = do_map_probe("cfi_probe", &sa1100_map);
++	mymtd = do_map_probe("jedec_probe", &sa1100_map);
++	if (!mymtd)
++		mymtd = do_map_probe("cfi_probe", &sa1100_map);
+ 	ret = -ENXIO;
+ 	if (!mymtd)
+ 		goto out_err;
+--- linux-2.4.25/drivers/net/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/net/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -30,9 +30,15 @@
+       if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+          source drivers/acorn/net/Config.in
+       fi
++      if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
++         tristate '  AT91RM9200 Ethernet support' CONFIG_AT91_ETHER
++         if [ "$CONFIG_AT91_ETHER" = "y" -o "$CONFIG_AT91_ETHER" = "m" ]; then
++            bool '      RMII interface?   ' CONFIG_AT91_ETHER_RMII
++         fi
++      fi
+    fi
+    if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then
+-	tristate ' Altera Ether00 support' CONFIG_ETHER00
++	tristate '  Altera Ether00 support' CONFIG_ETHER00
+    fi
+    if [ "$CONFIG_PPC" = "y" ]; then
+       dep_tristate '  MACE (Power Mac ethernet) support' CONFIG_MACE $CONFIG_ALL_PPC
+--- linux-2.4.25/drivers/net/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/net/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -243,6 +243,7 @@
+ # non-drivers/net drivers who want mii lib
+ obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o
+ obj-$(CONFIG_USB_USBNET) += mii.o
++obj-$(CONFIG_AT91_ETHER) += mii.o
+ 
+ ifeq ($(CONFIG_ARCH_ACORN),y)
+ mod-subdirs	+= ../acorn/net
+@@ -267,4 +268,3 @@
+ 
+ rcpci.o: $(rcpci-objs)
+ 	$(LD) -r -o $@ $(rcpci-objs)
+-
+--- linux-2.4.25/drivers/net/am79c961a.c~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/net/am79c961a.c	2004-03-31 17:15:09.000000000 +0200
+@@ -54,25 +54,36 @@
+ #ifdef __arm__
+ static void write_rreg(u_long base, u_int reg, u_int val)
+ {
+-	__asm__("str%?h	%1, [%2]	@ NET_RAP
+-		str%?h	%0, [%2, #-4]	@ NET_RDP
+-		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
++	__asm__("str%?h	%1, [%2]	@ NET_RAP\n\t"
++		"str%?h	%0, [%2, #-4]	@ NET_RDP"
++		: : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
+ }
+ 
+ static inline unsigned short read_rreg(u_long base_addr, u_int reg)
+ {
+ 	unsigned short v;
+-	__asm__("str%?h	%1, [%2]	@ NET_RAP
+-		ldr%?h	%0, [%2, #-4]	@ NET_RDP
+-		" : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
++	__asm__("str%?h	%1, [%2]	@ NET_RAP\n\t"
++		"ldr%?h	%0, [%2, #-4]	@ NET_RDP"
++		: "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
+ 	return v;
+ }
+ 
+ static inline void write_ireg(u_long base, u_int reg, u_int val)
+ {
+-	__asm__("str%?h	%1, [%2]	@ NET_RAP
+-		str%?h	%0, [%2, #8]	@ NET_IDP
+-		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
++	__asm__("str%?h	%1, [%2]	@ NET_RAP\n\t"
++		"str%?h	%0, [%2, #8]	@ NET_IDP"
++		: : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
++}
++
++static inline unsigned short read_ireg(u_long base_addr, u_int reg)
++{
++	u_short v;
++	__asm__(
++	"str%?h	%1, [%2]	@ NAT_RAP\n\t"
++	"str%?h	%0, [%2, #8]	@ NET_IDP\n\t"
++	: "=r" (v)
++	: "r" (reg), "r" (ISAIO_BASE + 0x0464));
++	return v;
+ }
+ 
+ #define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
+@@ -91,16 +102,16 @@
+ 	}
+ 	while (length > 8) {
+ 		unsigned int tmp, tmp2;
+-		__asm__ __volatile__("
+-			ldm%?ia	%1!, {%2, %3}
+-			str%?h	%2, [%0], #4
+-			mov%?	%2, %2, lsr #16
+-			str%?h	%2, [%0], #4
+-			str%?h	%3, [%0], #4
+-			mov%?	%3, %3, lsr #16
+-			str%?h	%3, [%0], #4
+-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
+-		  : "0" (offset), "1" (buf));
++		__asm__ __volatile__(
++			"ldm%?ia	%1!, {%2, %3}\n\t"
++			"str%?h	%2, [%0], #4\n\t"
++			"mov%?	%2, %2, lsr #16\n\t"
++			"str%?h	%2, [%0], #4\n\t"
++			"str%?h	%3, [%0], #4\n\t"
++			"mov%?	%3, %3, lsr #16\n\t"
++			"str%?h	%3, [%0], #4"
++		: "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
++		: "0" (offset), "1" (buf));
+ 		length -= 8;
+ 	}
+ 	while (length > 0) {
+@@ -118,36 +129,36 @@
+ 	length = (length + 1) & ~1;
+ 	if ((int)buf & 2) {
+ 		unsigned int tmp;
+-		__asm__ __volatile__("
+-			ldr%?h	%2, [%0], #4
+-			str%?b	%2, [%1], #1
+-			mov%?	%2, %2, lsr #8
+-			str%?b	%2, [%1], #1
+-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
++		__asm__ __volatile__(
++			"ldr%?h	%2, [%0], #4\n\t"
++			"str%?b	%2, [%1], #1\n\t"
++			"mov%?	%2, %2, lsr #8\n\t"
++			"str%?b	%2, [%1], #1"
++		: "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
+ 		length -= 2;
+ 	}
+ 	while (length > 8) {
+ 		unsigned int tmp, tmp2, tmp3;
+-		__asm__ __volatile__("
+-			ldr%?h	%2, [%0], #4
+-			ldr%?h	%3, [%0], #4
+-			orr%?	%2, %2, %3, lsl #16
+-			ldr%?h	%3, [%0], #4
+-			ldr%?h	%4, [%0], #4
+-			orr%?	%3, %3, %4, lsl #16
+-			stm%?ia	%1!, {%2, %3}
+-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
+-		  : "0" (offset), "1" (buf));
++		__asm__ __volatile__(
++			"ldr%?h	%2, [%0], #4\n\t"
++			"ldr%?h	%3, [%0], #4\n\t"
++			"orr%?	%2, %2, %3, lsl #16\n\t"
++			"ldr%?h	%3, [%0], #4\n\t"
++			"ldr%?h	%4, [%0], #4\n\t"
++			"orr%?	%3, %3, %4, lsl #16\n\t"
++			"stm%?ia	%1!, {%2, %3}"
++		: "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
++		: "0" (offset), "1" (buf));
+ 		length -= 8;
+ 	}
+ 	while (length > 0) {
+ 		unsigned int tmp;
+-		__asm__ __volatile__("
+-			ldr%?h	%2, [%0], #4
+-			str%?b	%2, [%1], #1
+-			mov%?	%2, %2, lsr #8
+-			str%?b	%2, [%1], #1
+-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
++		__asm__ __volatile__(
++			"ldr%?h	%2, [%0], #4\n\t"
++			"str%?b	%2, [%1], #1\n\t"
++			"mov%?	%2, %2, lsr #8\n\t"
++			"str%?b	%2, [%1], #1"
++		: "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
+ 		length -= 2;
+ 	}
+ }
+@@ -254,9 +265,27 @@
+ 	write_rreg (dev->base_addr, BASERXH, 0);
+ 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+ 	write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
++	write_rreg (dev->base_addr, CSR4, CSR4_APAD_XMIT|CSR4_MFCOM|CSR4_RCVCCOM|CSR4_TXSTRTM|CSR4_JABM);
+ 	write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
+ }
+ 
++static void am79c961_timer(unsigned long data)
++{
++	struct net_device *dev = (struct net_device *)data;
++	struct dev_priv *priv = (struct dev_priv *)dev->priv;
++	unsigned int lnkstat, carrier;
++
++	lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
++	carrier = netif_carrier_ok(dev);
++
++	if (lnkstat && !carrier)
++		netif_carrier_on(dev);
++	else if (!lnkstat && carrier)
++		netif_carrier_off(dev);
++
++	mod_timer(&priv->timer, jiffies + 5*HZ);
++}
++
+ /*
+  * Open/initialize the board.
+  */
+@@ -274,6 +303,11 @@
+ 
+ 	am79c961_init_for_open(dev);
+ 
++	netif_carrier_off(dev);
++
++	priv->timer.expires = jiffies;
++	add_timer(&priv->timer);
++
+ 	netif_start_queue(dev);
+ 
+ 	return 0;
+@@ -288,7 +322,10 @@
+ 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ 	unsigned long flags;
+ 
++	del_timer_sync(&priv->timer);
++
+ 	netif_stop_queue(dev);
++	netif_carrier_off(dev);
+ 
+ 	spin_lock_irqsave(priv->chip_lock, flags);
+ 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+@@ -413,15 +450,6 @@
+ 	unsigned int hdraddr, bufaddr;
+ 	unsigned int head;
+ 	unsigned long flags;
+-	
+-	/* FIXME: I thought the 79c961 could do padding - RMK ??? */
+-	if(length < ETH_ZLEN)
+-	{
+-		skb = skb_padto(skb, ETH_ZLEN);
+-		if(skb == NULL)
+-			return 0;
+-		length = ETH_ZLEN;
+-	}
+ 
+ 	head = priv->txhead;
+ 	hdraddr = priv->txhdr + (head << 3);
+@@ -431,7 +459,7 @@
+ 		head = 0;
+ 
+ 	am_writebuffer (dev, bufaddr, skb->data, length);
+-	am_writeword (dev, hdraddr + 4, -length);
++	am_writeword (dev, hdraddr + 4, -skb->len);
+ 	am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
+ 	priv->txhead = head;
+ 
+@@ -448,6 +476,8 @@
+ 	if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
+ 		netif_stop_queue(dev);
+ 
++	priv->stats.tx_bytes += skb->len;
++
+ 	dev_kfree_skb(skb);
+ 
+ 	return 0;
+@@ -520,6 +550,7 @@
+ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
+ {
+ 	do {
++		signed short len;
+ 		u_int hdraddr;
+ 		u_int status;
+ 
+@@ -555,6 +586,8 @@
+ 			continue;
+ 		}
+ 		priv->stats.tx_packets ++;
++		len = am_readword (dev, hdraddr + 4);
++		priv->stats.tx_bytes += -len;
+ 	} while (priv->txtail != priv->txhead);
+ 
+ 	netif_wake_queue(dev);
+@@ -565,17 +598,23 @@
+ {
+ 	struct net_device *dev = (struct net_device *)dev_id;
+ 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+-	u_int status;
++	u_int status, n = 100;
+ 
+-	status = read_rreg(dev->base_addr, CSR0);
+-	write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
++	do {
++		status = read_rreg(dev->base_addr, CSR0);
++		write_rreg(dev->base_addr, CSR0, status &
++			   (CSR0_IENA|CSR0_TINT|CSR0_RINT|
++			    CSR0_MERR|CSR0_MISS|CSR0_CERR|CSR0_BABL));
+ 
+-	if (status & CSR0_RINT)
+-		am79c961_rx(dev, priv);
+-	if (status & CSR0_TINT)
+-		am79c961_tx(dev, priv);
+-	if (status & CSR0_MISS)
+-		priv->stats.rx_dropped ++;
++		if (status & CSR0_RINT)
++			am79c961_rx(dev, priv);
++		if (status & CSR0_TINT)
++			am79c961_tx(dev, priv);
++		if (status & CSR0_MISS)
++			priv->stats.rx_dropped ++;
++		if (status & CSR0_CERR)
++			mod_timer(&priv->timer, jiffies);
++	} while (--n && status & (CSR0_RINT | CSR0_TINT));
+ }
+ 
+ /*
+@@ -587,10 +626,10 @@
+ {
+ 	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+ 
+-	spin_lock_irq(priv->chip_lock);
++	spin_lock_irq(&priv->chip_lock);
+ 	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+ 	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
+-	spin_unlock_irq(priv->chip_lock);
++	spin_unlock_irq(&priv->chip_lock);
+ 
+ 	am79c961_ramtest(dev, 0x66);
+ 	am79c961_ramtest(dev, 0x99);
+@@ -655,6 +694,11 @@
+ 		printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+ 	}
+ 
++	spin_lock_init(&priv->chip_lock);
++	init_timer(&priv->timer);
++	priv->timer.data = (unsigned long)dev;
++	priv->timer.function = am79c961_timer;
++
+ 	if (am79c961_hw_init(dev))
+ 		goto release;
+ 
+--- linux-2.4.25/drivers/net/am79c961a.h~2.4.25-vrs2.patch	2000-09-19 00:15:22.000000000 +0200
++++ linux-2.4.25/drivers/net/am79c961a.h	2004-03-31 17:15:09.000000000 +0200
+@@ -58,6 +58,18 @@
+ #define CSR3_BABLM	0x4000
+ #define CSR3_MASKALL	0x5F00
+ 
++#define CSR4		4
++#define CSR4_JABM	0x0001
++#define CSR4_JAB	0x0002
++#define CSR4_TXSTRTM	0x0004
++#define CSR4_TXSTRT	0x0008
++#define CSR4_RCVCCOM	0x0010
++#define CSR4_RCVCCO	0x0020
++#define CSR4_MFCOM	0x0100
++#define CSR4_MFCO	0x0200
++#define CSR4_ASTRP_RCV	0x0400
++#define CSR4_APAD_XMIT	0x0800
++
+ #define CTRL1		5
+ #define CTRL1_SPND	0x0001
+ 
+@@ -93,6 +105,8 @@
+ #define SIZERXR		76
+ #define SIZETXR		78
+ 
++#define CSR_MFC		112
++
+ #define RMD_ENP		0x0100
+ #define RMD_STP		0x0200
+ #define RMD_CRC		0x0800
+@@ -112,6 +126,9 @@
+ #define TST_UFLO	0x4000
+ #define TST_BUFF	0x8000
+ 
++#define ISALED0		0x0004
++#define ISALED0_LNKST	0x8000
++
+ struct dev_priv {
+     struct net_device_stats stats;
+     unsigned long	rxbuffer[RX_BUFFERS];
+@@ -123,6 +140,7 @@
+     unsigned long	rxhdr;
+     unsigned long	txhdr;
+     spinlock_t		chip_lock;
++    struct timer_list	timer;
+ };
+ 
+ extern int	am79c961_probe (struct net_device *dev);
+--- linux-2.4.25/drivers/net/cirrus.c~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/net/cirrus.c	2004-03-31 17:15:09.000000000 +0200
+@@ -75,6 +75,7 @@
+ typedef struct {
+ 	struct net_device_stats stats;
+ 	u16 txlen;
++	u16 txafter;	/* Default is After5 (0) */
+ } cirrus_t;
+ 
+ typedef struct {
+@@ -230,13 +231,19 @@
+ 	cirrus_t *priv = (cirrus_t *) dev->priv;
+ 	u16 status;
+ 
++	/* Tx start must be done with irq disabled
++	 * else status can be wrong */
++	disable_irq (dev->irq);
++
+ 	netif_stop_queue (dev);
+ 
+-	cirrus_write (dev,PP_TxCMD,TxStart (After5));
++	cirrus_write (dev,PP_TxCMD,TxStart (priv->txafter));
+ 	cirrus_write (dev,PP_TxLength,skb->len);
+ 
+ 	status = cirrus_read (dev,PP_BusST);
+ 
++	enable_irq (dev->irq);
++
+ 	if ((status & TxBidErr)) {
+ 		printk (KERN_WARNING "%s: Invalid frame size %d!\n",dev->name,skb->len);
+ 		priv->stats.tx_errors++;
+@@ -249,7 +256,6 @@
+ 		printk (KERN_WARNING "%s: Transmit buffer not free!\n",dev->name);
+ 		priv->stats.tx_errors++;
+ 		priv->txlen = 0;
+-		/* FIXME: store skb and send it in interrupt handler */
+ 		return (1);
+ 	}
+ 
+@@ -310,11 +316,18 @@
+ 			}
+ 			if ((RegContent (status) & TxUnderrun)) {
+ 				priv->stats.tx_errors++;
+-				priv->stats.tx_fifo_errors++;
++				/* Shift start tx, if underruns come too often */
++				switch (priv->stats.tx_fifo_errors++) {
++				case 3: priv->txafter = After381; break;
++				case 6: priv->txafter = After1021; break;
++				case 9: priv->txafter = AfterAll; break;
++				}
++			}
++			/* Wakeup only for tx events ! */
++			if ((RegContent (status) & (TxUnderrun | Rdy4Tx))) {
++				priv->txlen = 0;
++				netif_wake_queue (dev);
+ 			}
+-			/* FIXME: if Rdy4Tx, transmit last sent packet (if any) */
+-			priv->txlen = 0;
+-			netif_wake_queue (dev);
+ 			break;
+ 
+ 		case TxCOL:
+@@ -428,7 +441,7 @@
+ 	else
+ 		cirrus_clear (dev,PP_RxCTL,PromiscuousA);
+ 
+-	if ((dev->flags & IFF_ALLMULTI) && dev->mc_list)
++	if ((dev->flags & IFF_ALLMULTI) || dev->mc_list)
+ 		cirrus_set (dev,PP_RxCTL,MulticastA);
+ 	else
+ 		cirrus_clear (dev,PP_RxCTL,MulticastA);
+--- linux-2.4.25/drivers/net/cs89x0.c~2.4.25-vrs2.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/net/cs89x0.c	2004-03-31 17:15:09.000000000 +0200
+@@ -115,6 +115,7 @@
+ 
+ */
+ 
++#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
+ #include <linux/types.h>
+@@ -427,18 +428,18 @@
+ 	/* if they give us an odd I/O address, then do ONE write to
+            the address port, to get it back to address zero, where we
+            expect to find the EISA signature word. An IO with a base of 0x3
+-	   will skip the test for the ADD_PORT. */
++ 	   will skip the test for the ADD_PORT. */
+ 	if (ioaddr & 1) {
+ 		if (net_debug > 1)
+ 			printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr);
+-	        if ((ioaddr & 2) != 2)
++ 	        if ((ioaddr & 2) != 2)
+ 	        	if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) {
+ 				printk(KERN_ERR "%s: bad signature 0x%x\n",
+ 					dev->name, inw((ioaddr & ~3)+ ADD_PORT));
+ 		        	retval = -ENODEV;
+ 				goto out2;
+ 			}
+-		ioaddr &= ~3;
++ 		ioaddr &= ~3;
+ 		outw(PP_ChipID, ioaddr + ADD_PORT);
+ 	}
+ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
+@@ -446,7 +447,7 @@
+ 	if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) {
+ 		printk(KERN_ERR "%s: incorrect signature 0x%x\n",
+ 			dev->name, inw(ioaddr + DATA_PORT));
+-  		retval = -ENODEV;
++		retval = -ENODEV;
+   		goto out2;
+ 	}
+ 
+@@ -477,7 +478,7 @@
+ 	       dev->base_addr);
+ 
+ 	reset_chip(dev);
+-   
++
+         /* Here we read the current configuration of the chip. If there
+ 	   is no Extended EEPROM then the idea is to not disturb the chip
+ 	   configuration, it should have been correctly setup by automatic
+--- linux-2.4.25/drivers/net/ether00.c~2.4.25-vrs2.patch	2003-06-13 16:51:34.000000000 +0200
++++ linux-2.4.25/drivers/net/ether00.c	2004-03-31 17:15:09.000000000 +0200
+@@ -38,6 +38,7 @@
+ #include <asm/arch/ether00.h>
+ #include <asm/arch/tdkphy.h>
+ 
++static int ether00_get_ethernet_address(struct net_device* dev);
+ 
+ MODULE_AUTHOR("Clive Davies");
+ MODULE_DESCRIPTION("Altera Ether00 IP core driver");
+@@ -734,8 +735,11 @@
+ 	int result,tmp;
+ 	struct net_priv* priv;
+ 
+-	if (!is_valid_ether_addr(dev->dev_addr))
+-		return -EINVAL;
++	if (!ether00_get_ethernet_address(dev)){
++	  printk("%s: Invalid ethernet MAC address.  Please set using "
++		 "ifconfig\n", dev->name);
++	  return -EINVAL;
++	}
+ 
+ 	dev->base_addr=(unsigned int)ioremap_nocache(base,SZ_4K);
+ 
+@@ -906,10 +910,9 @@
+ }
+ 
+ 
+-static void ether00_get_ethernet_address(struct net_device* dev)
++static int ether00_get_ethernet_address(struct net_device* dev)
+ {
+ 	struct mtd_info *mymtd=NULL;
+-	int i;
+ 	size_t retlen;
+ 
+ 	/*
+@@ -926,11 +929,7 @@
+ #ifdef CONFIG_ARCH_CAMELOT
+ #ifdef CONFIG_MTD
+ 	/* get the mtd_info structure for the first mtd device*/
+-	for(i=0;i<MAX_MTD_DEVICES;i++){
+-		mymtd=get_mtd_device(NULL,i);
+-		if(!mymtd||!strcmp(mymtd->name,"EPXA10DB flash"))
+-			break;
+-	}
++	mymtd=get_mtd_device(NULL,0);
+ 
+ 	if(!mymtd || !mymtd->read_user_prot_reg){
+ 		printk(KERN_WARNING "%s: Failed to read MAC address from flash\n",dev->name);
+@@ -947,9 +946,7 @@
+ #endif
+ #endif
+ 
+-	if (!is_valid_ether_addr(dev->dev_addr))
+-		printk("%s: Invalid ethernet MAC address.  Please set using "
+-			"ifconfig\n", dev->name);
++	return (is_valid_ether_addr(dev->dev_addr));
+ 
+ }
+ 
+@@ -966,8 +963,6 @@
+ 	dev->tx_timeout=ether00_tx_timeout;
+ 	dev->watchdog_timeo=TX_TIMEOUT;
+ 
+-	ether00_get_ethernet_address(dev);
+-
+ 	SET_MODULE_OWNER(dev);
+ 	return 0;
+ }
+--- linux-2.4.25/drivers/net/irda/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/net/irda/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -40,7 +40,7 @@
+ dep_tristate 'VIA IrCC (Experimental)' CONFIG_VIA_IRCC_FIR $CONFIG_IRDA
+ fi
+ if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+-   dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA
++   dep_tristate 'SA1100 Internal IR' CONFIG_SA1100_FIR $CONFIG_IRDA $CONFIG_EXPERIMENTAL
+ fi
+ 
+ endmenu
+--- linux-2.4.25/drivers/net/irda/sa1100_ir.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/net/irda/sa1100_ir.c	2004-03-31 17:15:09.000000000 +0200
+@@ -38,11 +38,7 @@
+ 
+ #include <asm/arch/assabet.h>
+ 
+-#ifndef CONFIG_SA1100_H3600
+-#define clr_h3600_egpio(x)	do { } while (0)
+-#define set_h3600_egpio(x)	do { } while (0)
+-#endif
+-
++/* Yopy wants fixing */
+ #ifndef GPIO_IRDA_FIR
+ #define GPIO_IRDA_FIR		(0)
+ #endif
+@@ -174,8 +170,8 @@
+ 
+ 		if (machine_is_assabet())
+ 			ASSABET_BCR_clear(ASSABET_BCR_IRDA_FSEL);
+-		if (machine_is_h3600())
+-			clr_h3600_egpio(EGPIO_H3600_IR_FSEL);
++		if (machine_is_h3xxx())
++			clr_h3600_egpio(IPAQ_EGPIO_IR_FSEL);
+ 		if (machine_is_yopy())
+ 			PPSR &= ~GPIO_IRDA_FIR;
+ 
+@@ -199,8 +195,8 @@
+ 
+ 		if (machine_is_assabet())
+ 			ASSABET_BCR_set(ASSABET_BCR_IRDA_FSEL);
+-		if (machine_is_h3600())
+-			set_h3600_egpio(EGPIO_H3600_IR_FSEL);
++		if (machine_is_h3xxx())
++			set_h3600_egpio(IPAQ_EGPIO_IR_FSEL);
+ 		if (machine_is_yopy())
+ 			PPSR |= GPIO_IRDA_FIR;
+ 
+@@ -246,10 +242,7 @@
+ static inline int
+ sa1100_irda_set_power_h3600(struct sa1100_irda *si, unsigned int state)
+ {
+-	if (state)
+-		set_h3600_egpio(EGPIO_H3600_IR_ON);
+-	else
+-		clr_h3600_egpio(EGPIO_H3600_IR_ON);
++	assign_h3600_egpio( IPAQ_EGPIO_IR_ON, state );
+ 	return 0;
+ }
+ 
+@@ -283,7 +276,7 @@
+ 
+ 	if (machine_is_assabet())
+ 		ret = sa1100_irda_set_power_assabet(si, state);
+-	if (machine_is_h3600())
++	if (machine_is_h3xxx())
+ 		ret = sa1100_irda_set_power_h3600(si, state);
+ 	if (machine_is_yopy())
+ 		ret = sa1100_irda_set_power_yopy(si, state);
+@@ -727,11 +720,6 @@
+ 	netif_wake_queue(dev);
+ }
+ 
+-/*
+- * Note that we will never build up a backlog of frames; the protocol is a
+- * half duplex protocol which basically means we transmit a frame, we
+- * receive a frame, we transmit the next frame etc.
+- */
+ static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ 	struct sa1100_irda *si = dev->priv;
+@@ -758,6 +746,8 @@
+ 	}
+ 
+ 	if (!IS_FIR(si)) {
++		netif_stop_queue(dev);
++
+ 		si->tx_buff.data = si->tx_buff.head;
+ 		si->tx_buff.len  = async_wrap_skb(skb, si->tx_buff.data,
+ 						  si->tx_buff.truesize);
+--- linux-2.4.25/drivers/net/irda/w83977af_ir.c~2.4.25-vrs2.patch	2002-11-29 00:53:13.000000000 +0100
++++ linux-2.4.25/drivers/net/irda/w83977af_ir.c	2004-03-31 17:15:09.000000000 +0200
+@@ -205,7 +205,7 @@
+ 
+ 	/* FIXME: The HP HDLS-1100 does not support 1152000! */
+ 	self->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
+-		IR_115200|IR_576000|IR_1152000|(IR_4000000 << 8);
++		IR_115200/*|IR_576000|IR_1152000|(IR_4000000 << 8)*/;
+ 
+ 	/* The HP HDLS-1100 needs 1 ms according to the specs */
+ 	self->qos.min_turn_time.bits = qos_mtt_bits;
+@@ -1341,7 +1341,7 @@
+ 	case SIOCSBANDWIDTH: /* Set bandwidth */
+ 		if (!capable(CAP_NET_ADMIN)) {
+ 			ret = -EPERM;
+-			goto out;
++			break;
+ 		}
+ 		w83977af_change_speed(self, irq->ifr_baudrate);
+ 		break;
+--- linux-2.4.25/drivers/net/smc9194.c~2.4.25-vrs2.patch	2003-06-13 16:51:35.000000000 +0200
++++ linux-2.4.25/drivers/net/smc9194.c	2004-03-31 17:15:09.000000000 +0200
+@@ -12,8 +12,8 @@
+  .   AUI/TP selection  ( mine has 10Base2/10BaseT select )
+  .
+  . Arguments:
+- . 	io		 = for the base address
+- .	irq	 = for the IRQ
++ . 	io     = for the base address
++ .	irq    = for the IRQ
+  .	ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 )
+  .
+  . author:
+@@ -51,12 +51,21 @@
+  .				 allocation
+  .      08/20/00  Arnaldo Melo   fix kfree(skb) in smc_hardware_send_packet
+  .      12/15/00  Christian Jullien fix "Warning: kfree_skb on hard IRQ"
++ .	06/23/01  Russell King   Separate out IO functions for different bus
++ .				 types.
++ .				 Use dev->name instead of CARDNAME for printk
++ .				 Add ethtool support, full duplex support
++ .				 Add LAN91C96 support.
+  .      11/08/01 Matt Domsch     Use common crc32 function
+  ----------------------------------------------------------------------------*/
+ 
++#define DRV_NAME	"smc9194"
++#define DRV_VERSION	"0.15"
++
+ static const char version[] =
+-	"smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n";
++	DRV_NAME ".c:v" DRV_VERSION " 12/15/00 by Erik Stahlman (erik@vt.edu)\n";
+ 
++#include <linux/config.h>
+ #include <linux/module.h>
+ #include <linux/version.h>
+ #include <linux/kernel.h>
+@@ -69,16 +78,26 @@
+ #include <linux/in.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
++#include <linux/delay.h>
+ #include <linux/init.h>
+ #include <linux/crc32.h>
+-#include <asm/bitops.h>
+-#include <asm/io.h>
+ #include <linux/errno.h>
++#include <linux/ethtool.h>
+ 
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/skbuff.h>
+ 
++#include <asm/bitops.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++
++#ifdef CONFIG_ARCH_SA1100
++#include <asm/hardware.h>
++#include <asm/arch/assabet.h>
++#endif
++
+ #include "smc9194.h"
+ /*------------------------------------------------------------------------
+  .
+@@ -152,29 +171,27 @@
+  -------------------------------------------------------------------------*/
+ #define CARDNAME "SMC9194"
+ 
++static const char *chip_ids[15] = { 
++	NULL,
++	NULL,
++	NULL,
++	"SMC91C90/91C92",	/* 3 */
++	"SMC91C94/91C96",	/* 4 */
++	"SMC91C95",		/* 5 */
++	NULL,
++	"SMC91C100",		/* 7 */
++	"SMC91C100FD",		/* 8 */
++	NULL,
++	NULL,
++	NULL, 
++	NULL,
++	NULL,
++	NULL
++};
+ 
+-/* store this information for the driver.. */
+-struct smc_local {
+-	/*
+- 	   these are things that the kernel wants me to keep, so users
+-	   can find out semi-useless statistics of how well the card is
+-	   performing
+- 	*/
+-	struct net_device_stats stats;
+-
+-	/*
+-	   If I have to wait until memory is available to send
+-	   a packet, I will store the skbuff here, until I get the
+-	   desired memory.  Then, I'll send it out and free it.
+-	*/
+-	struct sk_buff * saved_skb;
+-
+-	/*
+- 	 . This keeps track of how many packets that I have
+- 	 . sent out.  When an TX_EMPTY interrupt comes, I know
+-	 . that all of these have been sent.
+-	*/
+-	int	packets_waiting;
++static const char * interfaces[2] = {
++	"TP",
++	"AUI"
+ };
+ 
+ 
+@@ -202,6 +219,11 @@
+ static int smc_open(struct net_device *dev);
+ 
+ /*
++ . This handles the ethtool interface
++*/
++static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
++
++/*
+  . Our watchdog timed out. Called by the networking layer
+ */
+ static void smc_timeout(struct net_device *dev);
+@@ -217,11 +239,11 @@
+  . This routine allows the proc file system to query the driver's
+  . statistics.
+ */
+-static struct net_device_stats * smc_query_statistics( struct net_device *dev);
++static struct net_device_stats * smc_query_statistics(struct net_device *dev);
+ 
+ /*
+- . Finally, a call to set promiscuous mode ( for TCPDUMP and related
+- . programs ) and multicast modes.
++ . Finally, a call to set promiscuous mode (for TCPDUMP and related
++ . programs) and multicast modes.
+ */
+ static void smc_set_multicast_list(struct net_device *dev);
+ 
+@@ -240,12 +262,12 @@
+  . This is a separate procedure to handle the receipt of a packet, to
+  . leave the interrupt code looking slightly cleaner
+ */
+-static inline void smc_rcv( struct net_device *dev );
++static inline void smc_rcv(struct net_device *dev);
+ /*
+  . This handles a TX interrupt, which is only called when an error
+  . relating to a packet is sent.
+ */
+-static inline void smc_tx( struct net_device * dev );
++static inline void smc_tx(struct net_device * dev);
+ 
+ /*
+  ------------------------------------------------------------
+@@ -261,39 +283,287 @@
+ */
+ static int smc_probe(struct net_device *dev, int ioaddr);
+ 
+-/*
+- . A rather simple routine to print out a packet for debugging purposes.
+-*/
+-#if SMC_DEBUG > 2
+-static void print_packet( byte *, int );
+-#endif
+-
+-#define tx_done(dev) 1
+-
+ /* this is called to actually send the packet to the chip */
+-static void smc_hardware_send_packet( struct net_device * dev );
++static void smc_hardware_send_packet(struct net_device * dev);
+ 
+ /* Since I am not sure if I will have enough room in the chip's ram
+  . to store the packet, I call this routine, which either sends it
+  . now, or generates an interrupt when the card is ready for the
+  . packet */
+-static int  smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev );
++static int smc_wait_to_send_packet(struct sk_buff * skb, struct net_device *dev);
+ 
+ /* this does a soft reset on the device */
+-static void smc_reset( int ioaddr );
++static void smc_reset(struct net_device *dev);
+ 
+ /* Enable Interrupts, Receive, and Transmit */
+-static void smc_enable( int ioaddr );
++static void smc_enable(struct net_device *dev);
+ 
+ /* this puts the device in an inactive state */
+-static void smc_shutdown( int ioaddr );
++static void smc_shutdown(struct net_device *dev);
+ 
+ /* This routine will find the IRQ of the driver if one is not
+  . specified in the input to the device.  */
+-static int smc_findirq( int ioaddr );
++static int smc_findirq(struct net_device *dev);
+ 
++#ifndef CONFIG_ASSABET_NEPONSET
+ /*
+- . Function: smc_reset( int ioaddr )
++ * These functions allow us to handle IO addressing as we wish - this
++ * ethernet controller can be connected to a variety of busses.  Some
++ * busses do not support 16 bit or 32 bit transfers.  --rmk
++ */
++static inline u8 smc_inb(u_int base, u_int reg)
++{
++	return inb(base + reg);
++}
++
++static inline u16 smc_inw(u_int base, u_int reg)
++{
++	return inw(base + reg);
++}
++
++static inline void smc_ins(u_int base, u_int reg, u8 *data, u_int len)
++{
++	u_int port = base + reg;
++#ifdef USE_32_BIT
++	/* QUESTION:  Like in the TX routine, do I want
++	   to send the DWORDs or the bytes first, or some
++	   mixture.  A mixture might improve already slow PIO
++	   performance  */
++	PRINTK3((" Reading %d dwords (and %d bytes) \n",
++		len >> 2, len & 3));
++	insl(port, data, len >> 2);
++	/* read the left over bytes */
++	insb(port, data + (len & ~3), len & 3);
++#else
++	PRINTK3((" Reading %d words and %d byte(s) \n",
++		len >> 1, len & 1));
++	insw(port, data, len >> 1);
++	if (len & 1) {
++		data += len & ~1;
++		*data = inb(port);
++	}
++#endif
++}
++
++static inline void smc_outb(u8 val, u_int base, u_int reg)
++{
++	outb(val, base + reg);
++}
++
++static inline void smc_outw(u16 val, u_int base, u_int reg)
++{
++	outw(val, base + reg);
++}
++
++static inline void smc_outl(u32 val, u_int base, u_int reg)
++{
++	u_int port = base + reg;
++#ifdef USE_32_BIT
++	outl(val, port);
++#else
++	outw(val, port);
++	outw(val >> 16, port);
++#endif
++}
++
++static inline void smc_outs(u_int base, u_int reg, u8 *data, u_int len)
++{
++	u_int port = base + reg;
++#ifdef USE_32_BIT
++	if (len & 2) {
++		outsl(port, data, len >> 2);
++		outw(*((word *)(data + (len & ~3))), port);
++	}
++	else
++		outsl(port, data, len >> 2);
++#else
++	outsw(port, data, len >> 1);
++#endif
++}
++
++
++/*-------------------------------------------------------------------------
++ .  I define some macros to make it easier to do somewhat common
++ . or slightly complicated, repeated tasks. 
++ --------------------------------------------------------------------------*/
++
++/* select a register bank, 0 to 3  */
++
++#define SMC_SELECT_BANK(x)				\
++	{						\
++		smc_outw(x, ioaddr, BANK_SELECT);	\
++	} 
++
++/* define a small delay for the reset */
++#define SMC_DELAY()					\
++	{						\
++		smc_inw(ioaddr, RCR);			\
++		smc_inw(ioaddr, RCR);			\
++		smc_inw(ioaddr, RCR);			\
++	}
++
++/* this enables an interrupt in the interrupt mask register */
++#define SMC_ENABLE_INT(x)				\
++	{						\
++		byte mask;				\
++		mask = smc_inb(ioaddr, INT_MASK);	\
++		mask |= (x);				\
++		smc_outb(mask, ioaddr, INT_MASK);	\
++	}
++
++/* this sets the absolutel interrupt mask */
++#define SMC_SET_INT(x)					\
++	{						\
++		smc_outw((x), INT_MASK);		\
++	}
++
++#else
++
++#undef SMC_IO_EXTENT
++#define SMC_IO_EXTENT	(16 << 2)
++
++/*
++ * These functions allow us to handle IO addressing as we wish - this
++ * ethernet controller can be connected to a variety of busses.  Some
++ * busses do not support 16 bit or 32 bit transfers.  --rmk
++ */
++static inline u8 smc_inb(u_int base, u_int reg)
++{
++	u_int port = base + reg * 4;
++
++	return readb(port);
++}
++
++static inline u16 smc_inw(u_int base, u_int reg)
++{
++	u_int port = base + reg * 4;
++
++	return readb(port) | readb(port + 4) << 8;
++}
++
++static inline void smc_ins(u_int base, u_int reg, u8 *data, u_int len)
++{
++	u_int port = base + reg * 4;
++
++	insb(port, data, len);
++}
++
++static inline void smc_outb(u8 val, u_int base, u_int reg)
++{
++	u_int port = base + reg * 4;
++
++	writeb(val, port);
++}
++
++static inline void smc_outw(u16 val, u_int base, u_int reg)
++{
++	u_int port = base + reg * 4;
++
++	writeb(val, port);
++	writeb(val >> 8, port + 4);
++}
++
++static inline void smc_outl(u32 val, u_int base, u_int reg)
++{
++	u_int port = base + reg * 4;
++
++	writeb(val, port);
++	writeb(val >> 8, port + 4);
++	writeb(val >> 16, port + 8);
++	writeb(val >> 24, port + 12);
++}
++
++static inline void smc_outs(u_int base, u_int reg, u8 *data, u_int len)
++{
++	u_int port = base + reg * 4;
++
++	outsb(port, data, len & ~1);
++}
++
++/*-------------------------------------------------------------------------
++ .  I define some macros to make it easier to do somewhat common
++ . or slightly complicated, repeated tasks. 
++ --------------------------------------------------------------------------*/
++
++/* select a register bank, 0 to 3  */
++
++#define SMC_SELECT_BANK(x)				\
++	{						\
++		smc_outb(x, ioaddr, BANK_SELECT);	\
++	} 
++
++/* define a small delay for the reset */
++#define SMC_DELAY()					\
++	{						\
++		smc_inb(ioaddr, RCR);			\
++		smc_inb(ioaddr, RCR);			\
++		smc_inb(ioaddr, RCR);			\
++	}
++
++/* this enables an interrupt in the interrupt mask register */
++#define SMC_ENABLE_INT(x)				\
++	{						\
++		byte mask;				\
++		mask = smc_inb(ioaddr, INT_MASK);	\
++		mask |= (x);				\
++		smc_outb(mask, ioaddr, INT_MASK);	\
++	}
++
++/* this sets the absolutel interrupt mask */
++#define SMC_SET_INT(x)					\
++	{						\
++		smc_outb((x), ioaddr, INT_MASK);	\
++	}
++
++#endif
++
++/*
++ . A rather simple routine to print out a packet for debugging purposes.
++*/
++#if SMC_DEBUG > 2
++static void print_packet(byte * buf, int length)
++{
++	int i;
++	int remainder;
++	int lines;
++
++	printk("Packet of length %d \n", length);
++	lines = length / 16;
++	remainder = length % 16;
++
++	for (i = 0; i < lines ; i ++) {
++		int cur;
++
++		for (cur = 0; cur < 8; cur ++) {
++			byte a, b;
++
++			a = *(buf ++);
++			b = *(buf ++);
++			printk("%02x%02x ", a, b);
++		}
++		printk("\n");
++	}
++	for (i = 0; i < remainder/2 ; i++) {
++		byte a, b;
++
++		a = *(buf ++);
++		b = *(buf ++);
++		printk("%02x%02x ", a, b);
++	}
++	if (remainder & 1) {
++		byte a;
++
++		a = *buf++;
++		printk("%02x", a);
++	}
++	printk("\n");
++}
++#else
++#define print_packet(buf,len) do { } while (0)
++#endif
++
++/*
++ . Function: smc_reset(struct net_device *dev)
+  . Purpose:
+  .  	This sets the SMC91xx chip to its normal state, hopefully from whatever
+  . 	mess that any other DOS driver has put it in.
+@@ -309,36 +579,37 @@
+  .	5.  clear all interrupts
+  .
+ */
+-static void smc_reset( int ioaddr )
++static void smc_reset(struct net_device *dev)
+ {
++	u_int ioaddr = dev->base_addr;
++
+ 	/* This resets the registers mostly to defaults, but doesn't
+ 	   affect EEPROM.  That seems unnecessary */
+-	SMC_SELECT_BANK( 0 );
+-	outw( RCR_SOFTRESET, ioaddr + RCR );
++	SMC_SELECT_BANK(0);
++	smc_outw(RCR_SOFTRESET, ioaddr, RCR);
+ 
+ 	/* this should pause enough for the chip to be happy */
+-	SMC_DELAY( );
++	SMC_DELAY();
+ 
+ 	/* Set the transmit and receive configuration registers to
+ 	   default values */
+-	outw( RCR_CLEAR, ioaddr + RCR );
+-	outw( TCR_CLEAR, ioaddr + TCR );
++	smc_outw(RCR_CLEAR, ioaddr, RCR);
++	smc_outw(TCR_CLEAR, ioaddr, TCR);
+ 
+ 	/* set the control register to automatically
+ 	   release successfully transmitted packets, to make the best
+ 	   use out of our limited memory */
+-	SMC_SELECT_BANK( 1 );
+-	outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL );
++	SMC_SELECT_BANK(1);
++	smc_outw(smc_inw(ioaddr, CONTROL) | CTL_AUTO_RELEASE, ioaddr, CONTROL);
+ 
+ 	/* Reset the MMU */
+-	SMC_SELECT_BANK( 2 );
+-	outw( MC_RESET, ioaddr + MMU_CMD );
++	SMC_SELECT_BANK(2);
++	smc_outw(MC_RESET, ioaddr, MMU_CMD);
+ 
+ 	/* Note:  It doesn't seem that waiting for the MMU busy is needed here,
+ 	   but this is a place where future chipsets _COULD_ break.  Be wary
+  	   of issuing another MMU command right after this */
+-
+-	outb( 0, ioaddr + INT_MASK );
++	SMC_SET_INT(0);
+ }
+ 
+ /*
+@@ -349,20 +620,21 @@
+  .	2.  Enable the receiver
+  .	3.  Enable interrupts
+ */
+-static void smc_enable( int ioaddr )
++static void smc_enable(struct net_device *dev)
+ {
+-	SMC_SELECT_BANK( 0 );
++	u_int ioaddr = dev->base_addr;
++	SMC_SELECT_BANK(0);
+ 	/* see the header file for options in TCR/RCR NORMAL*/
+-	outw( TCR_NORMAL, ioaddr + TCR );
+-	outw( RCR_NORMAL, ioaddr + RCR );
++	smc_outw(TCR_NORMAL, ioaddr, TCR);
++	smc_outw(RCR_NORMAL, ioaddr, RCR);
+ 
+ 	/* now, enable interrupts */
+-	SMC_SELECT_BANK( 2 );
+-	outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK );
++	SMC_SELECT_BANK(2);
++	SMC_SET_INT(SMC_INTERRUPT_MASK);
+ }
+ 
+ /*
+- . Function: smc_shutdown
++ . Function: smc_shutdown(struct net_device *dev)
+  . Purpose:  closes down the SMC91xxx chip.
+  . Method:
+  .	1. zero the interrupt mask
+@@ -375,26 +647,28 @@
+  .	the manual says that it will wake up in response to any I/O requests
+  .	in the register space.   Empirical results do not show this working.
+ */
+-static void smc_shutdown( int ioaddr )
++static void smc_shutdown(struct net_device *dev)
+ {
++	u_int ioaddr = dev->base_addr;
++
+ 	/* no more interrupts for me */
+-	SMC_SELECT_BANK( 2 );
+-	outb( 0, ioaddr + INT_MASK );
++	SMC_SELECT_BANK(2);
++	SMC_SET_INT(0);
+ 
+ 	/* and tell the card to stay away from that nasty outside world */
+-	SMC_SELECT_BANK( 0 );
+-	outb( RCR_CLEAR, ioaddr + RCR );
+-	outb( TCR_CLEAR, ioaddr + TCR );
++	SMC_SELECT_BANK(0);
++	smc_outb(RCR_CLEAR, ioaddr, RCR);
++	smc_outb(TCR_CLEAR, ioaddr, TCR);
+ #if 0
+ 	/* finally, shut the chip down */
+-	SMC_SELECT_BANK( 1 );
+-	outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL  );
++	SMC_SELECT_BANK(1);
++	smc_outw(smc_inw(ioaddr, CONTROL), CTL_POWERDOWN, ioaddr, CONTROL);
+ #endif
+ }
+ 
+ 
+ /*
+- . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
++ . Function: smc_setmulticast(int ioaddr, int count, dev_mc_list * adds)
+  . Purpose:
+  .    This sets the internal hardware table to filter out unwanted multicast
+  .    packets before they take up memory.
+@@ -411,26 +685,28 @@
+ */
+ 
+ 
+-static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) {
++static void smc_setmulticast(struct net_device *dev, int count, struct dev_mc_list * addrs)
++{
++	u_int ioaddr = dev->base_addr;
+ 	int			i;
+-	unsigned char		multicast_table[ 8 ];
++	unsigned char		multicast_table[8];
+ 	struct dev_mc_list	* cur_addr;
+ 	/* table for flipping the order of 3 bits */
+ 	unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+ 
+ 	/* start with a table of all zeros: reject all */
+-	memset( multicast_table, 0, sizeof( multicast_table ) );
++	memset(multicast_table, 0, sizeof(multicast_table));
+ 
+ 	cur_addr = addrs;
+-	for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next  ) {
++	for (i = 0; i < count ; i ++, cur_addr = cur_addr->next) {
+ 		int position;
+ 
+ 		/* do we have a pointer here? */
+-		if ( !cur_addr )
++		if (!cur_addr)
+ 			break;
+ 		/* make sure this is a multicast address - shouldn't this
+ 		   be a given if we have it here ? */
+-		if ( !( *cur_addr->dmi_addr & 1 ) )
++		if (!(*cur_addr->dmi_addr & 1))
+ 			continue;
+ 
+ 		/* only use the low order bits */
+@@ -442,15 +718,15 @@
+ 
+ 	}
+ 	/* now, the table can be loaded into the chipset */
+-	SMC_SELECT_BANK( 3 );
++	SMC_SELECT_BANK(3);
+ 
+-	for ( i = 0; i < 8 ; i++ ) {
+-		outb( multicast_table[i], ioaddr + MULTICAST1 + i );
++	for (i = 0; i < 8 ; i++) {
++		smc_outb(multicast_table[i], ioaddr, MULTICAST1 + i);
+ 	}
+ }
+ 
+ /*
+- . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * )
++ . Function: smc_wait_to_send_packet(struct sk_buff * skb, struct net_device *)
+  . Purpose:
+  .    Attempt to allocate memory for a packet, if chip-memory is not
+  .    available, then tell the card to generate an interrupt when it
+@@ -465,10 +741,10 @@
+  . o 	(NO): Enable interrupts and let the interrupt handler deal with it.
+  . o	(YES):Send it now.
+ */
+-static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev )
++static int smc_wait_to_send_packet(struct sk_buff * skb, struct net_device * dev)
+ {
+ 	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+-	unsigned short ioaddr 	= dev->base_addr;
++	u_int ioaddr	 	= dev->base_addr;
+ 	word 			length;
+ 	unsigned short 		numPages;
+ 	word			time_out;
+@@ -477,15 +753,16 @@
+ 	/* Well, I want to send the packet.. but I don't know
+ 	   if I can send it right now...  */
+ 
+-	if ( lp->saved_skb) {
++	if (lp->saved_skb) {
+ 		/* THIS SHOULD NEVER HAPPEN. */
+ 		lp->stats.tx_aborted_errors++;
+-		printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
++		printk("%s: Bad Craziness - sent packet while busy.\n",
++			dev->name);
+ 		return 1;
+ 	}
+ 
+ 	length = skb->len;
+-
++		
+ 	if(length < ETH_ZLEN)
+ 	{
+ 		skb = skb_padto(skb, ETH_ZLEN);
+@@ -497,18 +774,18 @@
+ 		length = ETH_ZLEN;
+ 	}
+ 	lp->saved_skb = skb;
+-		
++
+ 	/*
+ 	** The MMU wants the number of pages to be the number of 256 bytes
+-	** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
++	** 'pages', minus 1 (since a packet can't ever have 0 pages :))
+ 	**
+ 	** Pkt size for allocating is data length +6 (for additional status words,
+ 	** length and ctl!) If odd size last byte is included in this header.
+ 	*/
+-	numPages =  ((length & 0xfffe) + 6) / 256;
++	numPages = ((length & 0xfffe) + 6) / 256;
+ 
+-	if (numPages > 7 ) {
+-		printk(CARDNAME": Far too big packet error. \n");
++	if (numPages > 7) {
++		printk("%s: Far too big packet error.\n", dev->name);
+ 		/* freeing the packet is a good thing here... but should
+ 		 . any packets of this size get down here?   */
+ 		dev_kfree_skb (skb);
+@@ -517,12 +794,13 @@
+ 		netif_wake_queue(dev);
+ 		return 0;
+ 	}
++
+ 	/* either way, a packet is waiting now */
+ 	lp->packets_waiting++;
+ 
+ 	/* now, try to allocate the memory */
+-	SMC_SELECT_BANK( 2 );
+-	outw( MC_ALLOC | numPages, ioaddr + MMU_CMD );
++	SMC_SELECT_BANK(2);
++	smc_outw(MC_ALLOC | numPages, ioaddr, MMU_CMD);
+ 	/*
+  	. Performance Hack
+ 	.
+@@ -539,21 +817,21 @@
+ 	do {
+ 		word	status;
+ 
+-		status = inb( ioaddr + INTERRUPT );
+-		if ( status & IM_ALLOC_INT ) {
++		status = smc_inb(ioaddr, INTERRUPT);
++		if (status & IM_ALLOC_INT) {
+ 			/* acknowledge the interrupt */
+-			outb( IM_ALLOC_INT, ioaddr + INTERRUPT );
+-  			break;
++			smc_outb(IM_ALLOC_INT, ioaddr, INTERRUPT);
++			break;
+ 		}
+-   	} while ( -- time_out );
++ 	} while (-- time_out);
+ 
+-   	if ( !time_out ) {
++ 	if (!time_out) {
+ 		/* oh well, wait until the chip finds memory later */
+-		SMC_ENABLE_INT( IM_ALLOC_INT );
+-      		PRINTK2((CARDNAME": memory allocation deferred. \n"));
++		SMC_ENABLE_INT(IM_ALLOC_INT);
++		PRINTK2(("%s: memory allocation deferred.\n", dev->name));
+ 		/* it's deferred, but I'll handle it later */
+-      		return 0;
+-   	}
++		return 0;
++ 	}
+ 	/* or YES! I can send the packet now.. */
+ 	smc_hardware_send_packet(dev);
+ 	netif_wake_queue(dev);
+@@ -561,46 +839,46 @@
+ }
+ 
+ /*
+- . Function:  smc_hardware_send_packet(struct net_device * )
++ . Function:  smc_hardware_send_packet(struct net_device *)
+  . Purpose:
+  .	This sends the actual packet to the SMC9xxx chip.
+  .
+  . Algorithm:
+  . 	First, see if a saved_skb is available.
+- .		( this should NOT be called if there is no 'saved_skb'
++ .		(this should NOT be called if there is no 'saved_skb'
+  .	Now, find the packet number that the chip allocated
+  .	Point the data pointers at it in memory
+  .	Set the length word in the chip's memory
+  .	Dump the packet to chip memory
+- .	Check if a last byte is needed ( odd length packet )
++ .	Check if a last byte is needed (odd length packet)
+  .		if so, set the control flag right
+  . 	Tell the card to send it
+  .	Enable the transmit interrupt, so I know if it failed
+  . 	Free the kernel data if I actually sent it.
+ */
+-static void smc_hardware_send_packet( struct net_device * dev )
++static void smc_hardware_send_packet(struct net_device *dev)
+ {
+ 	struct smc_local *lp = (struct smc_local *)dev->priv;
+-	byte	 		packet_no;
+-	struct sk_buff * 	skb = lp->saved_skb;
+-	word			length;
+-	unsigned short		ioaddr;
+-	byte			* buf;
+-
+-	ioaddr = dev->base_addr;
++	struct sk_buff *skb = lp->saved_skb;
++	word length, lastword;
++	u_int ioaddr = dev->base_addr;
++	byte packet_no;
++	byte *buf;
+ 
+-	if ( !skb ) {
+-		PRINTK((CARDNAME": In XMIT with no packet to send \n"));
++	if (!skb) {
++		PRINTK(("%s: In XMIT with no packet to send\n", dev->name));
+ 		return;
+ 	}
++
+ 	length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ 	buf = skb->data;
+ 
+ 	/* If I get here, I _know_ there is a packet slot waiting for me */
+-	packet_no = inb( ioaddr + PNR_ARR + 1 );
+-	if ( packet_no & 0x80 ) {
++	packet_no = smc_inb(ioaddr, PNR_ARR + 1);
++	if (packet_no & 0x80) {
+ 		/* or isn't there?  BAD CHIP! */
+-		printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
++		printk(KERN_DEBUG "%s: Memory allocation failed.\n",
++			dev->name);
+ 		dev_kfree_skb_any(skb);
+ 		lp->saved_skb = NULL;
+ 		netif_wake_queue(dev);
+@@ -608,26 +886,19 @@
+ 	}
+ 
+ 	/* we have a packet address, so tell the card to use it */
+-	outb( packet_no, ioaddr + PNR_ARR );
++	smc_outb(packet_no, ioaddr, PNR_ARR);
+ 
+ 	/* point to the beginning of the packet */
+-	outw( PTR_AUTOINC , ioaddr + POINTER );
++	smc_outw(PTR_AUTOINC, ioaddr, POINTER);
+ 
+-   	PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length ));
+-#if SMC_DEBUG > 2
+-	print_packet( buf, length );
+-#endif
++ 	PRINTK3(("%s: Trying to xmit packet of length %x\n",
++		dev->name, length));
+ 
+-	/* send the packet length ( +6 for status, length and ctl byte )
+- 	   and the status word ( set to zeros ) */
+-#ifdef USE_32_BIT
+-	outl(  (length +6 ) << 16 , ioaddr + DATA_1 );
+-#else
+-	outw( 0, ioaddr + DATA_1 );
+-	/* send the packet length ( +6 for status words, length, and ctl*/
+-	outb( (length+6) & 0xFF,ioaddr + DATA_1 );
+-	outb( (length+6) >> 8 , ioaddr + DATA_1 );
+-#endif
++	print_packet(buf, length);
++
++	/* send the packet length (+6 for status, length and ctl byte)
++ 	   and the status word (set to zeros) */
++	smc_outl((length + 6) << 16, ioaddr, DATA_1);
+ 
+ 	/* send the actual data
+ 	 . I _think_ it's faster to send the longs first, and then
+@@ -636,32 +907,22 @@
+  	 . a good idea to check which is optimal?  But that could take
+ 	 . almost as much time as is saved?
+ 	*/
+-#ifdef USE_32_BIT
+-	if ( length & 0x2  ) {
+-		outsl(ioaddr + DATA_1, buf,  length >> 2 );
+-		outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1);
+-	}
+-	else
+-		outsl(ioaddr + DATA_1, buf,  length >> 2 );
+-#else
+-	outsw(ioaddr + DATA_1 , buf, (length ) >> 1);
+-#endif
+-	/* Send the last byte, if there is one.   */
++	smc_outs(ioaddr, DATA_1, buf, length);
+ 
+-	if ( (length & 1) == 0 ) {
+-		outw( 0, ioaddr + DATA_1 );
+-	} else {
+-		outb( buf[length -1 ], ioaddr + DATA_1 );
+-		outb( 0x20, ioaddr + DATA_1);
+-	}
++	/* Send the last byte, if there is one.   */
++	if ((length & 1) == 0)
++		lastword = 0;
++	else
++		lastword = 0x2000 | buf[length - 1];
++	smc_outw(lastword, ioaddr, DATA_1);
+ 
+ 	/* enable the interrupts */
+-	SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) );
++	SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT);
+ 
+ 	/* and let the chipset deal with it */
+-	outw( MC_ENQUEUE , ioaddr + MMU_CMD );
++	smc_outw(MC_ENQUEUE, ioaddr, MMU_CMD);
+ 
+-	PRINTK2((CARDNAME": Sent packet of length %d \n",length));
++	PRINTK2(("%s: Sent packet of length %d\n", dev->name, length));
+ 
+ 	lp->saved_skb = NULL;
+ 	dev_kfree_skb_any (skb);
+@@ -676,7 +937,7 @@
+ 
+ /*-------------------------------------------------------------------------
+  |
+- | smc_init( struct net_device * dev )
++ | smc_init(struct net_device * dev)
+  |   Input parameters:
+  |	dev->base_addr == 0, try to find all possible locations
+  |	dev->base_addr == 1, return failure code
+@@ -691,6 +952,65 @@
+ */
+ int __init smc_init(struct net_device *dev)
+ {
++	int ret = -ENODEV;
++#if defined(CONFIG_ASSABET_NEPONSET)
++	if (machine_is_assabet() && machine_has_neponset()) {
++		unsigned int *addr;
++		unsigned char ecor;
++		unsigned long flags;
++
++		NCR_0 |= NCR_ENET_OSC_EN;
++		dev->irq = IRQ_NEPONSET_SMC9196;
++
++		/*
++		 * Map the attribute space.  This is overkill, but clean.
++		 */
++		addr = ioremap(0x18000000 + (1 << 25), 64 * 1024 * 4);
++		if (!addr)
++			return -ENOMEM;
++
++		/*
++		 * Reset the device.  We must disable IRQs around this.
++		 */
++		local_irq_save(flags);
++		ecor = readl(addr + ECOR) & ~ECOR_RESET;
++		writel(ecor | ECOR_RESET, addr + ECOR);
++		udelay(100);
++
++		/*
++		 * The device will ignore all writes to the enable bit while
++		 * reset is asserted, even if the reset bit is cleared in the
++		 * same write.  Must clear reset first, then enable the device.
++		 */
++		writel(ecor, addr + ECOR);
++		writel(ecor | ECOR_ENABLE, addr + ECOR);
++
++		/*
++		 * Force byte mode.
++		 */
++		writel(readl(addr + ECSR) | ECSR_IOIS8, addr + ECSR);
++		local_irq_restore(flags);
++
++		iounmap(addr);
++
++		/*
++		 * Wait for the chip to wake up.
++		 */
++		mdelay(1);
++
++		/*
++		 * Map the real registers.
++		 */
++		addr = ioremap(0x18000000, 8 * 1024);
++		if (!addr)
++			return -ENOMEM;
++
++		ret = smc_probe(dev, (int)addr);
++		if (ret)
++			iounmap(addr);
++	}
++
++#elif defined(CONFIG_ISA)
+ 	int i;
+ 	int base_addr = dev->base_addr;
+ 
+@@ -708,7 +1028,8 @@
+ 			return 0;
+ 
+ 	/* couldn't find anything */
+-	return -ENODEV;
++#endif
++	return ret;
+ }
+ 
+ /*----------------------------------------------------------------------
+@@ -718,10 +1039,11 @@
+  . interrupt, so an auto-detect routine can detect it, and find the IRQ,
+  ------------------------------------------------------------------------
+ */
+-int __init smc_findirq( int ioaddr )
++int __init smc_findirq(struct net_device *dev)
+ {
+ 	int	timeout = 20;
+ 	unsigned long cookie;
++	u_int ioaddr = dev->base_addr;
+ 
+ 
+ 	/* I have to do a STI() here, because this is called from
+@@ -737,26 +1059,25 @@
+ 	 * when done.
+ 	 */
+ 
+-
++	/* enable ALLOCation interrupts ONLY. */
+ 	SMC_SELECT_BANK(2);
+-	/* enable ALLOCation interrupts ONLY */
+-	outb( IM_ALLOC_INT, ioaddr + INT_MASK );
++	SMC_SET_INT(IM_ALLOC_INT);
+ 
+ 	/*
+  	 . Allocate 512 bytes of memory.  Note that the chip was just
+ 	 . reset so all the memory is available
+ 	*/
+-	outw( MC_ALLOC | 1, ioaddr + MMU_CMD );
++	smc_outw(MC_ALLOC | 1, ioaddr, MMU_CMD);
+ 
+ 	/*
+ 	 . Wait until positive that the interrupt has been generated
+ 	*/
+-	while ( timeout ) {
++	while (timeout) {
+ 		byte	int_status;
+ 
+-		int_status = inb( ioaddr + INTERRUPT );
++		int_status = smc_inb(ioaddr, INTERRUPT);
+ 
+-		if ( int_status & IM_ALLOC_INT )
++		if (int_status & IM_ALLOC_INT)
+ 			break;		/* got the interrupt */
+ 		timeout--;
+ 	}
+@@ -775,7 +1096,7 @@
+ 	SMC_DELAY();
+ 
+ 	/* and disable all interrupts again */
+-	outb( 0, ioaddr + INT_MASK );
++	SMC_SET_INT(0);
+ 
+ 	/* clear hardware interrupts again, because that's how it
+ 	   was when I was called... */
+@@ -785,8 +1106,87 @@
+ 	return probe_irq_off(cookie);
+ }
+ 
++static int __init smc_probe_chip(struct net_device *dev, int ioaddr)
++{
++	unsigned int temp;
++
++	/* First, see if the high byte is 0x33 */
++	temp = smc_inw(ioaddr, BANK_SELECT);
++	if ((temp & 0xFF00) != 0x3300)
++		return -ENODEV;
++
++	/* The above MIGHT indicate a device, but I need to write to further
++ 	   test this.  */
++	smc_outw(0, ioaddr, BANK_SELECT);
++	temp = smc_inw(ioaddr, BANK_SELECT);
++	if ((temp & 0xFF00) != 0x3300)
++		return -ENODEV;
++
++#ifndef CONFIG_ASSABET_NEPONSET
++	/* well, we've already written once, so hopefully another time won't
++ 	   hurt.  This time, I need to switch the bank register to bank 1,
++	   so I can access the base address register */
++	SMC_SELECT_BANK(1);
++	temp = smc_inw(ioaddr, BASE);
++	if (ioaddr != (temp >> 3 & 0x3E0)) {
++		printk("%s: IOADDR %x doesn't match configuration (%x)."
++			"Probably not a SMC chip\n", dev->name,
++			ioaddr, (base_address_register >> 3) & 0x3E0);
++		/* well, the base address register didn't match.  Must not have
++		   been a SMC chip after all. */
++		return -ENODEV;
++	}
++#endif
++
++	return 0;
++}
++
++/*
++ . If dev->irq is 0, then the device has to be banged on to see
++ . what the IRQ is.
++ .
++ . This banging doesn't always detect the IRQ, for unknown reasons.
++ . a workaround is to reset the chip and try again.
++ .
++ . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
++ . be what is requested on the command line.   I don't do that, mostly
++ . because the card that I have uses a non-standard method of accessing
++ . the IRQs, and because this _should_ work in most configurations.
++ .
++ . Specifying an IRQ is done with the assumption that the user knows
++ . what (s)he is doing.  No checking is done!!!!
++ .
++*/
++static int __init smc_probe_irq(struct net_device *dev)
++{
++	if (dev->irq < 2) {
++		int	trials;
++
++		trials = 3;
++		while (trials--) {
++			dev->irq = smc_findirq(dev);
++			if (dev->irq)
++				break;
++			/* kick the card and try again */
++			smc_reset(dev);
++		}
++	}
++	if (dev->irq == 0) {
++		printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",
++			dev->name);
++		return -ENODEV;
++	}
++
++	/*
++	 * Some machines (eg, PCs) need to cannonicalize their IRQs.
++	 */
++	dev->irq = irq_cannonicalize(dev->irq);
++
++	return 0;
++}
++
+ /*----------------------------------------------------------------------
+- . Function: smc_probe( int ioaddr )
++ . Function: smc_probe(struct net_device *dev, int ioaddr)
+  .
+  . Purpose:
+  .	Tests to see if a given ioaddr points to an SMC9xxx chip.
+@@ -816,16 +1216,14 @@
+ */
+ static int __init smc_probe(struct net_device *dev, int ioaddr)
+ {
++	struct smc_local *smc;
+ 	int i, memory, retval;
+ 	static unsigned version_printed;
+-	unsigned int bank;
+ 
+ 	const char *version_string;
+-	const char *if_string;
+ 
+ 	/* registers */
+ 	word revision_register;
+-	word base_address_register;
+ 	word configuration_register;
+ 	word memory_info_register;
+ 	word memory_cfg_register;
+@@ -834,44 +1232,24 @@
+ 	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))
+ 		return -EBUSY;
+ 
+-	/* First, see if the high byte is 0x33 */
+-	bank = inw( ioaddr + BANK_SELECT );
+-	if ( (bank & 0xFF00) != 0x3300 ) {
+-		retval = -ENODEV;
+-		goto err_out;
+-	}
+-	/* The above MIGHT indicate a device, but I need to write to further
+- 	 	test this.  */
+-	outw( 0x0, ioaddr + BANK_SELECT );
+-	bank = inw( ioaddr + BANK_SELECT );
+-	if ( (bank & 0xFF00 ) != 0x3300 ) {
+-		retval = -ENODEV;
+-		goto err_out;
+-	}
+-	/* well, we've already written once, so hopefully another time won't
+- 	   hurt.  This time, I need to switch the bank register to bank 1,
+-	   so I can access the base address register */
+-	SMC_SELECT_BANK(1);
+-	base_address_register = inw( ioaddr + BASE );
+-	if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) )  {
+-		printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)."
+-			"Probably not a SMC chip\n",
+-			ioaddr, base_address_register >> 3 & 0x3E0 );
+-		/* well, the base address register didn't match.  Must not have
+-		   been a SMC chip after all. */
+-		retval = -ENODEV;
++	/*
++	 * Do the basic probes.
++	 */
++	retval = smc_probe_chip(dev, ioaddr);
++	if (retval)
+ 		goto err_out;
+-	}
+ 
+ 	/*  check if the revision register is something that I recognize.
+ 	    These might need to be added to later, as future revisions
+ 	    could be added.  */
+ 	SMC_SELECT_BANK(3);
+-	revision_register  = inw( ioaddr + REVISION );
+-	if ( !chip_ids[ ( revision_register  >> 4 ) & 0xF  ] ) {
++	revision_register = smc_inw(ioaddr, REVISION);
++	version_string = chip_ids[(revision_register >> 4) & 15];
++	if (!version_string) {
+ 		/* I don't recognize this chip, so... */
+-		printk(CARDNAME ": IO %x: Unrecognized revision register:"
+-			" %x, Contact author. \n", ioaddr, revision_register );
++		printk("%s: IO %x: unrecognized revision register: %x, "
++			"contact author.\n", dev->name, ioaddr,
++			revision_register);
+ 
+ 		retval = -ENODEV;
+ 		goto err_out;
+@@ -882,138 +1260,122 @@
+ 	   against the hardware address, or do some other tests. */
+ 
+ 	if (version_printed++ == 0)
+-		printk("%s", version);
++		printk(KERN_INFO "%s", version);
+ 
+ 	/* fill in some of the fields */
+ 	dev->base_addr = ioaddr;
+ 
+ 	/*
+- 	 . Get the MAC address ( bank 1, regs 4 - 9 )
++ 	 . Get the MAC address (bank 1, regs 4 - 9)
+ 	*/
+-	SMC_SELECT_BANK( 1 );
+-	for ( i = 0; i < 6; i += 2 ) {
++	SMC_SELECT_BANK(1);
++	for (i = 0; i < 6; i += 2) {
+ 		word	address;
+ 
+-		address = inw( ioaddr + ADDR0 + i  );
+-		dev->dev_addr[ i + 1] = address >> 8;
+-		dev->dev_addr[ i ] = address & 0xFF;
++		address = smc_inw(ioaddr, ADDR0 + i);
++		dev->dev_addr[i + 1] = address >> 8;
++		dev->dev_addr[i] = address & 0xFF;
+ 	}
+ 
++	if (!is_valid_ether_addr(dev->dev_addr))
++		printk("%s: Invalid ethernet MAC address.  Please set using "
++			"ifconfig\n", dev->name);
++
+ 	/* get the memory information */
+ 
+-	SMC_SELECT_BANK( 0 );
+-	memory_info_register = inw( ioaddr + MIR );
+-	memory_cfg_register  = inw( ioaddr + MCR );
+-	memory = ( memory_cfg_register >> 9 )  & 0x7;  /* multiplier */
+-	memory *= 256 * ( memory_info_register & 0xFF );
++	SMC_SELECT_BANK(0);
++	memory_info_register = smc_inw(ioaddr, MIR);
++	memory_cfg_register = smc_inw(ioaddr, MCR);
++	memory = (memory_cfg_register >> 9) & 0x7;  /* multiplier */
++	memory *= 256 * (memory_info_register & 0xFF);
++
++	/* now, reset the chip, and put it into a known state */
++	smc_reset(dev);
+ 
+ 	/*
+-	 Now, I want to find out more about the chip.  This is sort of
+- 	 redundant, but it's cleaner to have it in both, rather than having
+- 	 one VERY long probe procedure.
+-	*/
+-	SMC_SELECT_BANK(3);
+-	revision_register  = inw( ioaddr + REVISION );
+-	version_string = chip_ids[ ( revision_register  >> 4 ) & 0xF  ];
+-	if ( !version_string ) {
+-		/* I shouldn't get here because this call was done before.... */
+-		retval = -ENODEV;
++	 * Ok, now that we have everything in a
++	 * sane state, probe for the interrupt.
++	 */
++	retval = smc_probe_irq(dev);
++	if (retval)
+ 		goto err_out;
+-	}
+ 
+-	/* is it using AUI or 10BaseT ? */
+-	if ( dev->if_port == 0 ) {
+-		SMC_SELECT_BANK(1);
+-		configuration_register = inw( ioaddr + CONFIG );
+-		if ( configuration_register & CFG_AUI_SELECT )
+-			dev->if_port = 2;
+-		else
+-			dev->if_port = 1;
++	/* Initialize the private structure. */
++	if (dev->priv == NULL) {
++		dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL);
++		if (dev->priv == NULL) {
++			retval = -ENOMEM;
++			goto err_out;
++		}
+ 	}
+-	if_string = interfaces[ dev->if_port - 1 ];
+ 
+-	/* now, reset the chip, and put it into a known state */
+-	smc_reset( ioaddr );
++	smc = dev->priv;
++
++	/* set the private data to zero by default */
++	memset(smc, 0, sizeof(struct smc_local));
+ 
+ 	/*
+-	 . If dev->irq is 0, then the device has to be banged on to see
+-	 . what the IRQ is.
+- 	 .
+-	 . This banging doesn't always detect the IRQ, for unknown reasons.
+-	 . a workaround is to reset the chip and try again.
+-	 .
+-	 . Interestingly, the DOS packet driver *SETS* the IRQ on the card to
+-	 . be what is requested on the command line.   I don't do that, mostly
+-	 . because the card that I have uses a non-standard method of accessing
+-	 . the IRQs, and because this _should_ work in most configurations.
+-	 .
+-	 . Specifying an IRQ is done with the assumption that the user knows
+-	 . what (s)he is doing.  No checking is done!!!!
+- 	 .
+-	*/
+-	if ( dev->irq < 2 ) {
+-		int	trials;
++	 * Get the interface characteristics.
++	 * is it using AUI or 10BaseT ?
++	 */
++	switch (dev->if_port) {
++	case IF_PORT_10BASET:
++		smc->port = PORT_TP;
++		break;
+ 
+-		trials = 3;
+-		while ( trials-- ) {
+-			dev->irq = smc_findirq( ioaddr );
+-			if ( dev->irq )
+-				break;
+-			/* kick the card and try again */
+-			smc_reset( ioaddr );
++	case IF_PORT_AUI:
++		smc->port = PORT_AUI;
++		break;
++
++	default:
++		SMC_SELECT_BANK(1);
++		configuration_register = smc_inw(ioaddr, CONFIG);
++		if (configuration_register & CFG_AUI_SELECT) {
++			dev->if_port = IF_PORT_AUI;
++			smc->port = PORT_AUI;
++		} else {
++			dev->if_port = IF_PORT_10BASET;
++			smc->port = PORT_TP;
+ 		}
+-	}
+-	if (dev->irq == 0 ) {
+-		printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n");
+-		retval = -ENODEV;
+-		goto err_out;
++		break;
+ 	}
+ 
+-	/* now, print out the card info, in a short format.. */
++	/* all interfaces are half-duplex by default */
++	smc->duplex = DUPLEX_HALF;
+ 
+-	printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name,
+-		version_string, revision_register & 0xF, ioaddr, dev->irq,
+-		if_string, memory );
++	/* now, print out the card info, in a short format.. */
++	printk("%s: %s (rev %d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name,
++		version_string, revision_register & 15, ioaddr, dev->irq,
++		interfaces[smc->port], memory);
+ 	/*
+ 	 . Print the Ethernet address
+ 	*/
+ 	printk("ADDR: ");
+ 	for (i = 0; i < 5; i++)
+-		printk("%2.2x:", dev->dev_addr[i] );
+-	printk("%2.2x \n", dev->dev_addr[5] );
+-
+-
+-	/* Initialize the private structure. */
+-	if (dev->priv == NULL) {
+-		dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL);
+-		if (dev->priv == NULL) {
+-			retval = -ENOMEM;
+-			goto err_out;
+-		}
+-	}
+-	/* set the private data to zero by default */
+-	memset(dev->priv, 0, sizeof(struct smc_local));
++		printk("%2.2x:", dev->dev_addr[i]);
++	printk("%2.2x\n", dev->dev_addr[5]);
+ 
+ 	/* Fill in the fields of the device structure with ethernet values. */
+ 	ether_setup(dev);
+ 
+ 	/* Grab the IRQ */
+-      	retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
+-      	if (retval) {
++	retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev);
++	if (retval) {
+ 		printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
+ 			dev->irq, retval);
+ 		kfree(dev->priv);
+ 		dev->priv = NULL;
+-  	  	goto err_out;
+-      	}
++		goto err_out;
++	}
+ 
+-	dev->open		        = smc_open;
+-	dev->stop		        = smc_close;
+-	dev->hard_start_xmit    	= smc_wait_to_send_packet;
+-	dev->tx_timeout		    	= smc_timeout;
+-	dev->watchdog_timeo		= HZ/20;
+-	dev->get_stats			= smc_query_statistics;
+-	dev->set_multicast_list 	= smc_set_multicast_list;
++	dev->open		= smc_open;
++	dev->stop		= smc_close;
++	dev->hard_start_xmit	= smc_wait_to_send_packet;
++	dev->tx_timeout 	= smc_timeout;
++	dev->watchdog_timeo	= HZ/20;
++	dev->get_stats		= smc_query_statistics;
++	dev->set_multicast_list = smc_set_multicast_list;
++	dev->do_ioctl		= smc_ioctl;
+ 
+ 	return 0;
+ 
+@@ -1022,42 +1384,43 @@
+ 	return retval;
+ }
+ 
+-#if SMC_DEBUG > 2
+-static void print_packet( byte * buf, int length )
++/*
++ * This is responsible for setting the chip appropriately
++ * for the interface type.  This should only be called while
++ * the interface is up and running.
++ */
++static void smc_set_port(struct net_device *dev)
+ {
+-#if 0
+-	int i;
+-	int remainder;
+-	int lines;
+-
+-	printk("Packet of length %d \n", length );
+-	lines = length / 16;
+-	remainder = length % 16;
+-
+-	for ( i = 0; i < lines ; i ++ ) {
+-		int cur;
++	struct smc_local *smc = dev->priv;
++	u_int ioaddr = dev->base_addr;
++	u_int val;
+ 
+-		for ( cur = 0; cur < 8; cur ++ ) {
+-			byte a, b;
++	SMC_SELECT_BANK(1);
++	val = smc_inw(ioaddr, CONFIG);
++	switch (smc->port) {
++	case PORT_TP:
++		val &= ~CFG_AUI_SELECT;
++		break;
+ 
+-			a = *(buf ++ );
+-			b = *(buf ++ );
+-			printk("%02x%02x ", a, b );
+-		}
+-		printk("\n");
++	case PORT_AUI:
++		val |= CFG_AUI_SELECT;
++		break;
+ 	}
+-	for ( i = 0; i < remainder/2 ; i++ ) {
+-		byte a, b;
++	smc_outw(val, ioaddr, CONFIG);
+ 
+-		a = *(buf ++ );
+-		b = *(buf ++ );
+-		printk("%02x%02x ", a, b );
++	SMC_SELECT_BANK(0);
++	val = smc_inw(ioaddr, TCR);
++	switch (smc->duplex) {
++	case DUPLEX_HALF:
++		val &= ~TCR_FDSE;
++		break;
++
++	case DUPLEX_FULL:
++		val |= TCR_FDSE;
++		break;
+ 	}
+-	printk("\n");
+-#endif
++	smc_outw(val, ioaddr, TCR);
+ }
+-#endif
+-
+ 
+ /*
+  * Open and Initialize the board
+@@ -1067,48 +1430,141 @@
+  */
+ static int smc_open(struct net_device *dev)
+ {
+-	int	ioaddr = dev->base_addr;
++	struct smc_local *smc = dev->priv;
++	u_int ioaddr = dev->base_addr;
++	int i;
+ 
+-	int	i;	/* used to set hw ethernet address */
++	/*
++	 * Check that the address is valid.  If its not, refuse
++	 * to bring the device up.  The user must specify an
++	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
++	 */
++	if (!is_valid_ether_addr(dev->dev_addr))
++		return -EINVAL;
+ 
+ 	/* clear out all the junk that was put here before... */
+-	memset(dev->priv, 0, sizeof(struct smc_local));
++	smc->saved_skb = NULL;
++	smc->packets_waiting = 0;
+ 
+ 	/* reset the hardware */
+-
+-	smc_reset( ioaddr );
+-	smc_enable( ioaddr );
++	smc_reset(dev);
++	smc_enable(dev);
+ 
+ 	/* Select which interface to use */
+-
+-	SMC_SELECT_BANK( 1 );
+-	if ( dev->if_port == 1 ) {
+-		outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT,
+-			ioaddr + CONFIG );
+-	}
+-	else if ( dev->if_port == 2 ) {
+-		outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT,
+-			ioaddr + CONFIG );
+-	}
++	smc_set_port(dev);
+ 
+ 	/*
+-  		According to Becker, I have to set the hardware address
++		According to Becker, I have to set the hardware address
+ 		at this point, because the (l)user can set it with an
+ 		ioctl.  Easily done...
+ 	*/
+-	SMC_SELECT_BANK( 1 );
+-	for ( i = 0; i < 6; i += 2 ) {
++	SMC_SELECT_BANK(1);
++	for (i = 0; i < 6; i += 2) {
+ 		word	address;
+ 
+-		address = dev->dev_addr[ i + 1 ] << 8 ;
+-		address  |= dev->dev_addr[ i ];
+-		outw( address, ioaddr + ADDR0 + i );
++		address = dev->dev_addr[i + 1] << 8 ;
++		address |= dev->dev_addr[i];
++		smc_outw(address, ioaddr, ADDR0 + i);
+ 	}
+ 	
+ 	netif_start_queue(dev);
+ 	return 0;
+ }
+ 
++/*
++ * This is our template.  Fill the rest in at run-time
++ */
++static const struct ethtool_cmd ecmd_template = {
++	supported:	SUPPORTED_10baseT_Half |
++			SUPPORTED_10baseT_Full |
++			SUPPORTED_TP |
++			SUPPORTED_AUI,
++	speed:		SPEED_10,
++	autoneg:	AUTONEG_DISABLE,
++	maxtxpkt:	1,
++	maxrxpkt:	1,
++	transceiver:	XCVR_INTERNAL,
++};
++
++static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
++{
++	struct smc_local *smc = dev->priv;
++	u32 etcmd;
++	int ret = -EINVAL;
++
++	if (cmd != SIOCETHTOOL)
++		return -EOPNOTSUPP;
++
++	if (get_user(etcmd, (u32 *)rq->ifr_data))
++		return -EFAULT;
++
++	switch (etcmd) {
++	case ETHTOOL_GSET: {
++		struct ethtool_cmd ecmd = ecmd_template;
++
++		ecmd.cmd = etcmd;
++		ecmd.port = smc->port;
++		ecmd.duplex = smc->duplex;
++
++		ret = copy_to_user(rq->ifr_data, &ecmd, sizeof(ecmd))
++				? -EFAULT : 0;
++		break;
++	}
++
++	case ETHTOOL_SSET: {
++		struct ethtool_cmd ecmd;
++
++		ret = -EPERM;
++		if (!capable(CAP_NET_ADMIN))
++			break;
++
++		ret = -EFAULT;
++		if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd)))
++			break;
++
++		/*
++		 * Sanity-check the arguments.
++		 */
++		ret = -EINVAL;
++		if (ecmd.autoneg != AUTONEG_DISABLE)
++			break;
++		if (ecmd.speed != SPEED_10)
++			break;
++		if (ecmd.duplex != DUPLEX_HALF && ecmd.duplex != DUPLEX_FULL)
++			break;
++		if (ecmd.port != PORT_TP && ecmd.port != PORT_AUI)
++			break;
++
++		smc->port   = ecmd.port;
++		smc->duplex = ecmd.duplex;
++
++		if (netif_running(dev))
++			smc_set_port(dev);
++
++		ret = 0;
++		break;
++	}
++
++	case ETHTOOL_GDRVINFO: {
++		struct ethtool_drvinfo edrv;
++
++		memset(&edrv, 0, sizeof(edrv));
++
++		edrv.cmd = etcmd;
++		strcpy(edrv.driver, DRV_NAME);
++		strcpy(edrv.version, DRV_VERSION);
++		sprintf(edrv.bus_info, "ISA:%8.8lx:%d",
++			dev->base_addr, dev->irq);
++
++		ret = copy_to_user(rq->ifr_data, &edrv, sizeof(edrv))
++				? -EFAULT : 0;
++		break;
++	}
++	}
++
++	return ret;
++}
++
+ /*--------------------------------------------------------
+  . Called by the kernel to send a packet out into the void
+  . of the net.  This routine is largely based on
+@@ -1120,12 +1576,10 @@
+ {
+ 	/* If we get here, some higher level has decided we are broken.
+ 	   There should really be a "kick me" function call instead. */
+-	printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n",
+-		tx_done(dev) ? "IRQ conflict" :
+-		"network cable problem");
++	printk(KERN_WARNING "%s: transmit timed out\n", dev->name);
+ 	/* "kick" the adaptor */
+-	smc_reset( dev->base_addr );
+-	smc_enable( dev->base_addr );
++	smc_reset(dev);
++	smc_enable(dev);
+ 	dev->trans_start = jiffies;
+ 	/* clear anything saved */
+ 	((struct smc_local *)dev->priv)->saved_skb = NULL;
+@@ -1145,10 +1599,10 @@
+  .
+  ---------------------------------------------------------------------*/
+ 
+-static void smc_interrupt(int irq, void * dev_id,  struct pt_regs * regs)
++static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+ {
+ 	struct net_device *dev 	= dev_id;
+-	int ioaddr 		= dev->base_addr;
++	u_int ioaddr 		= dev->base_addr;
+ 	struct smc_local *lp 	= (struct smc_local *)dev->priv;
+ 
+ 	byte	status;
+@@ -1161,45 +1615,45 @@
+ 
+ 
+ 
+-	PRINTK3((CARDNAME": SMC interrupt started \n"));
++	PRINTK3(("%s: SMC interrupt started\n", dev->name));
+ 
+-	saved_bank = inw( ioaddr + BANK_SELECT );
++	saved_bank = smc_inw(ioaddr, BANK_SELECT);
+ 
+ 	SMC_SELECT_BANK(2);
+-	saved_pointer = inw( ioaddr + POINTER );
++	saved_pointer = smc_inw(ioaddr, POINTER);
+ 
+-	mask = inb( ioaddr + INT_MASK );
++	mask = smc_inb(ioaddr, INT_MASK);
+ 	/* clear all interrupts */
+-	outb( 0, ioaddr + INT_MASK );
++	SMC_SET_INT(0);
+ 
+ 
+ 	/* set a timeout value, so I don't stay here forever */
+ 	timeout = 4;
+ 
+-	PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask ));
++	PRINTK2((KERN_WARNING "%s: MASK IS %x\n", dev->name, mask));
+ 	do {
+ 		/* read the status flag, and mask it */
+-		status = inb( ioaddr + INTERRUPT ) & mask;
+-		if (!status )
++		status = smc_inb(ioaddr, INTERRUPT) & mask;
++		if (!status)
+ 			break;
+ 
+-		PRINTK3((KERN_WARNING CARDNAME
+-			": Handling interrupt status %x \n", status ));
++		PRINTK3((KERN_WARNING "%s: handling interrupt status %x\n",
++			dev->name, status));
+ 
+ 		if (status & IM_RCV_INT) {
+ 			/* Got a packet(s). */
+-			PRINTK2((KERN_WARNING CARDNAME
+-				": Receive Interrupt\n"));
++			PRINTK2((KERN_WARNING "%s: receive interrupt\n",
++				dev->name));
+ 			smc_rcv(dev);
+-		} else if (status & IM_TX_INT ) {
+-			PRINTK2((KERN_WARNING CARDNAME
+-				": TX ERROR handled\n"));
++		} else if (status & IM_TX_INT) {
++			PRINTK2((KERN_WARNING "%s: TX ERROR handled\n",
++				dev->name));
+ 			smc_tx(dev);
+-			outb(IM_TX_INT, ioaddr + INTERRUPT );
+-		} else if (status & IM_TX_EMPTY_INT ) {
++			smc_outb(IM_TX_INT, ioaddr, INTERRUPT);
++		} else if (status & IM_TX_EMPTY_INT) {
+ 			/* update stats */
+-			SMC_SELECT_BANK( 0 );
+-			card_stats = inw( ioaddr + COUNTER );
++			SMC_SELECT_BANK(0);
++			card_stats = smc_inw(ioaddr, COUNTER);
+ 			/* single collisions */
+ 			lp->stats.collisions += card_stats & 0xF;
+ 			card_stats >>= 4;
+@@ -1208,60 +1662,63 @@
+ 
+ 			/* these are for when linux supports these statistics */
+ 
+-			SMC_SELECT_BANK( 2 );
+-			PRINTK2((KERN_WARNING CARDNAME
+-				": TX_BUFFER_EMPTY handled\n"));
+-			outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
++			SMC_SELECT_BANK(2);
++			PRINTK2((KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n",
++				dev->name));
++			smc_outb(IM_TX_EMPTY_INT, ioaddr, INTERRUPT);
+ 			mask &= ~IM_TX_EMPTY_INT;
+ 			lp->stats.tx_packets += lp->packets_waiting;
+ 			lp->packets_waiting = 0;
+ 
+-		} else if (status & IM_ALLOC_INT ) {
+-			PRINTK2((KERN_DEBUG CARDNAME
+-				": Allocation interrupt \n"));
++		} else if (status & IM_ALLOC_INT) {
++			PRINTK2((KERN_DEBUG "%s: Allocation interrupt\n",
++				dev->name));
+ 			/* clear this interrupt so it doesn't happen again */
+ 			mask &= ~IM_ALLOC_INT;
+ 
+-			smc_hardware_send_packet( dev );
++			smc_hardware_send_packet(dev);
+ 
+ 			/* enable xmit interrupts based on this */
+-			mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );
++			mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
+ 
+ 			/* and let the card send more packets to me */
+ 			netif_wake_queue(dev);
+ 			
+-			PRINTK2((CARDNAME": Handoff done successfully.\n"));
+-		} else if (status & IM_RX_OVRN_INT ) {
++			PRINTK2(("%s: Handoff done successfully.\n",
++				dev->name));
++		} else if (status & IM_RX_OVRN_INT) {
+ 			lp->stats.rx_errors++;
+ 			lp->stats.rx_fifo_errors++;
+-			outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
+-		} else if (status & IM_EPH_INT ) {
+-			PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
+-		} else if (status & IM_ERCV_INT ) {
+-			PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n"));
+-			outb( IM_ERCV_INT, ioaddr + INTERRUPT );
++			smc_outb(IM_RX_OVRN_INT, ioaddr, INTERRUPT);
++		} else if (status & IM_EPH_INT) {
++			PRINTK(("%s: UNSUPPORTED: EPH INTERRUPT\n",
++				dev->name));
++		} else if (status & IM_ERCV_INT) {
++			PRINTK(("%s: UNSUPPORTED: ERCV INTERRUPT\n",
++				dev->name));
++			smc_outb(IM_ERCV_INT, ioaddr, INTERRUPT);
+ 		}
+-	} while ( timeout -- );
++	} while (timeout --);
+ 
+ 
+ 	/* restore state register */
+-	SMC_SELECT_BANK( 2 );
+-	outb( mask, ioaddr + INT_MASK );
++	SMC_SELECT_BANK(2);
++	SMC_SET_INT(mask);
+ 
+-	PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask ));
+-	outw( saved_pointer, ioaddr + POINTER );
++	PRINTK3((KERN_WARNING "%s: MASK is now %x\n", dev->name, mask));
++	smc_outw(saved_pointer, ioaddr, POINTER);
+ 
+-	SMC_SELECT_BANK( saved_bank );
++	SMC_SELECT_BANK(saved_bank);
+ 
+-	PRINTK3((CARDNAME ": Interrupt done\n"));
++	PRINTK3(("%s: Interrupt done\n", dev->name));
+ 	return;
+ }
+ 
+ /*-------------------------------------------------------------
+  .
+- . smc_rcv -  receive a packet from the card
++ . smc_rcv - receive a packet from the card
+  .
+- . There is ( at least ) a packet waiting to be read from
++ . There is (at least) a packet waiting to be read from
+  . chip-memory.
+  .
+  . o Read the status
+@@ -1272,55 +1729,57 @@
+ static void smc_rcv(struct net_device *dev)
+ {
+ 	struct smc_local *lp = (struct smc_local *)dev->priv;
+-	int 	ioaddr = dev->base_addr;
++	u_int 	ioaddr = dev->base_addr;
+ 	int 	packet_number;
+ 	word	status;
+ 	word	packet_length;
+ 
+ 	/* assume bank 2 */
+ 
+-	packet_number = inw( ioaddr + FIFO_PORTS );
++	packet_number = smc_inw(ioaddr, FIFO_PORTS);
+ 
+-	if ( packet_number & FP_RXEMPTY ) {
++	if (packet_number & FP_RXEMPTY) {
+ 		/* we got called , but nothing was on the FIFO */
+-		PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO. \n"));
++		PRINTK(("%s: WARNING: smc_rcv with nothing on FIFO.\n",
++			dev->name));
+ 		/* don't need to restore anything */
+ 		return;
+ 	}
+ 
+ 	/*  start reading from the start of the packet */
+-	outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER );
++	smc_outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr, POINTER);
+ 
+ 	/* First two words are status and packet_length */
+-	status 		= inw( ioaddr + DATA_1 );
+-	packet_length 	= inw( ioaddr + DATA_1 );
++	status 		= smc_inw(ioaddr, DATA_1);
++	packet_length 	= smc_inw(ioaddr, DATA_1);
+ 
+ 	packet_length &= 0x07ff;  /* mask off top bits */
+ 
+-	PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length ));
++	PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length));
+ 	/*
+ 	 . the packet length contains 3 extra words :
+ 	 . status, length, and an extra word with an odd byte .
+ 	*/
+ 	packet_length -= 6;
+ 
+-	if ( !(status & RS_ERRORS ) ){
++	if (!(status & RS_ERRORS)){
+ 		/* do stuff to make a new packet */
+ 		struct sk_buff  * skb;
+ 		byte		* data;
+ 
+ 		/* read one extra byte */
+-		if ( status & RS_ODDFRAME )
++		if (status & RS_ODDFRAME)
+ 			packet_length++;
+ 
+ 		/* set multicast stats */
+-		if ( status & RS_MULTICAST )
++		if (status & RS_MULTICAST)
+ 			lp->stats.multicast++;
+ 
+-		skb = dev_alloc_skb( packet_length + 5);
++		skb = dev_alloc_skb(packet_length + 5);
+ 
+-		if ( skb == NULL ) {
+-			printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
++		if (skb == NULL) {
++			printk(KERN_NOTICE "%s: Low memory, packet dropped.\n",
++				dev->name);
+ 			lp->stats.rx_dropped++;
+ 			goto done;
+ 		}
+@@ -1330,36 +1789,15 @@
+ 		 ! in the worse case
+ 		*/
+ 
+-		skb_reserve( skb, 2 );   /* 16 bit alignment */
++		skb_reserve(skb, 2);   /* 16 bit alignment */
+ 
+ 		skb->dev = dev;
+-		data = skb_put( skb, packet_length);
++		data = skb_put(skb, packet_length);
+ 
+-#ifdef USE_32_BIT
+-		/* QUESTION:  Like in the TX routine, do I want
+-		   to send the DWORDs or the bytes first, or some
+-		   mixture.  A mixture might improve already slow PIO
+-		   performance  */
+-		PRINTK3((" Reading %d dwords (and %d bytes) \n",
+-			packet_length >> 2, packet_length & 3 ));
+-		insl(ioaddr + DATA_1 , data, packet_length >> 2 );
+-		/* read the left over bytes */
+-		insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC),
+-			packet_length & 0x3  );
+-#else
+-		PRINTK3((" Reading %d words and %d byte(s) \n",
+-			(packet_length >> 1 ), packet_length & 1 ));
+-		insw(ioaddr + DATA_1 , data, packet_length >> 1);
+-		if ( packet_length & 1 ) {
+-			data += packet_length & ~1;
+-			*(data++) = inb( ioaddr + DATA_1 );
+-		}
+-#endif
+-#if	SMC_DEBUG > 2
+-			print_packet( data, packet_length );
+-#endif
++		smc_ins(ioaddr, DATA_1, data, packet_length);
++		print_packet(data, packet_length);
+ 
+-		skb->protocol = eth_type_trans(skb, dev );
++		skb->protocol = eth_type_trans(skb, dev);
+ 		netif_rx(skb);
+ 		dev->last_rx = jiffies;
+ 		lp->stats.rx_packets++;
+@@ -1368,15 +1806,17 @@
+ 		/* error ... */
+ 		lp->stats.rx_errors++;
+ 
+-		if ( status & RS_ALGNERR )  lp->stats.rx_frame_errors++;
+-		if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
++		if (status & RS_ALGNERR)
++			lp->stats.rx_frame_errors++;
++		if (status & (RS_TOOSHORT | RS_TOOLONG))
+ 			lp->stats.rx_length_errors++;
+-		if ( status & RS_BADCRC)	lp->stats.rx_crc_errors++;
++		if (status & RS_BADCRC)
++			lp->stats.rx_crc_errors++;
+ 	}
+ 
+ done:
+ 	/*  error or good, tell the card to get rid of this packet */
+-	outw( MC_RELEASE, ioaddr + MMU_CMD );
++	smc_outw(MC_RELEASE, ioaddr, MMU_CMD);
+ }
+ 
+ 
+@@ -1389,62 +1829,64 @@
+  . Algorithm:
+  .	Save pointer and packet no
+  .	Get the packet no from the top of the queue
+- .	check if it's valid ( if not, is this an error??? )
++ .	check if it's valid (if not, is this an error???)
+  .	read the status word
+  .	record the error
+- .	( resend?  Not really, since we don't want old packets around )
++ .	(resend?  Not really, since we don't want old packets around)
+  .	Restore saved values
+  ************************************************************************/
+-static void smc_tx( struct net_device * dev )
++static void smc_tx(struct net_device * dev)
+ {
+-	int	ioaddr = dev->base_addr;
++	u_int ioaddr = dev->base_addr;
+ 	struct smc_local *lp = (struct smc_local *)dev->priv;
+ 	byte saved_packet;
+ 	byte packet_no;
+ 	word tx_status;
+ 
+ 
+-	/* assume bank 2  */
++	/* assume bank 2 */
+ 
+-	saved_packet = inb( ioaddr + PNR_ARR );
+-	packet_no = inw( ioaddr + FIFO_PORTS );
++	saved_packet = smc_inb(ioaddr, PNR_ARR);
++	packet_no = smc_inw(ioaddr, FIFO_PORTS);
+ 	packet_no &= 0x7F;
+ 
+ 	/* select this as the packet to read from */
+-	outb( packet_no, ioaddr + PNR_ARR );
++	smc_outb(packet_no, ioaddr, PNR_ARR);
+ 
+ 	/* read the first word from this packet */
+-	outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER );
++	smc_outw(PTR_AUTOINC | PTR_READ, ioaddr, POINTER);
+ 
+-	tx_status = inw( ioaddr + DATA_1 );
+-	PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status ));
++	tx_status = smc_inw(ioaddr, DATA_1);
++	PRINTK3(("%s: TX DONE STATUS: %4x\n", dev->name, tx_status));
+ 
+ 	lp->stats.tx_errors++;
+-	if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;
+-	if ( tx_status & TS_LATCOL  ) {
+-		printk(KERN_DEBUG CARDNAME
+-			": Late collision occurred on last xmit.\n");
++	if (tx_status & TS_LOSTCAR)
++		lp->stats.tx_carrier_errors++;
++	if (tx_status & TS_LATCOL) {
++		printk(KERN_DEBUG "%s: Late collision occurred on "
++			"last xmit.\n", dev->name);
+ 		lp->stats.tx_window_errors++;
+ 	}
+ #if 0
+-		if ( tx_status & TS_16COL ) { ... }
++		if (tx_status & TS_16COL) { ... }
+ #endif
+ 
+-	if ( tx_status & TS_SUCCESS ) {
+-		printk(CARDNAME": Successful packet caused interrupt \n");
++	if (tx_status & TS_SUCCESS) {
++		printk("%s: Successful packet caused interrupt\n",
++			dev->name);
+ 	}
+ 	/* re-enable transmit */
+-	SMC_SELECT_BANK( 0 );
+-	outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR );
++	SMC_SELECT_BANK(0);
++	smc_outw(smc_inw(ioaddr, TCR) | TCR_ENABLE, ioaddr, TCR);
+ 
+ 	/* kill the packet */
+-	SMC_SELECT_BANK( 2 );
+-	outw( MC_FREEPKT, ioaddr + MMU_CMD );
++	SMC_SELECT_BANK(2);
++	smc_outw(MC_FREEPKT, ioaddr, MMU_CMD);
+ 
+ 	/* one less packet waiting for me */
+ 	lp->packets_waiting--;
+ 
+-	outb( saved_packet, ioaddr + PNR_ARR );
++	smc_outb(saved_packet, ioaddr, PNR_ARR);
+ 	return;
+ }
+ 
+@@ -1460,7 +1902,7 @@
+ {
+ 	netif_stop_queue(dev);
+ 	/* clear everything */
+-	smc_shutdown( dev->base_addr );
++	smc_shutdown(dev);
+ 
+ 	/* Update the statistics here. */
+ 	return 0;
+@@ -1481,16 +1923,16 @@
+  .
+  . This routine will, depending on the values passed to it,
+  . either make it accept multicast packets, go into
+- . promiscuous mode ( for TCPDUMP and cousins ) or accept
++ . promiscuous mode (for TCPDUMP and cousins) or accept
+  . a select set of multicast packets
+ */
+ static void smc_set_multicast_list(struct net_device *dev)
+ {
+-	short ioaddr = dev->base_addr;
++	u_int ioaddr = dev->base_addr;
+ 
+ 	SMC_SELECT_BANK(0);
+-	if ( dev->flags & IFF_PROMISC )
+-		outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR );
++	if (dev->flags & IFF_PROMISC)
++		smc_outw(smc_inw(ioaddr, RCR) | RCR_PROMISC, ioaddr, RCR);
+ 
+ /* BUG?  I never disable promiscuous mode if multicasting was turned on.
+    Now, I turn off promiscuous mode, but I don't do anything to multicasting
+@@ -1502,34 +1944,34 @@
+ 	   checked before the table is
+ 	*/
+ 	else if (dev->flags & IFF_ALLMULTI)
+-		outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR );
++		smc_outw(smc_inw(ioaddr, RCR) | RCR_ALMUL, ioaddr, RCR);
+ 
+ 	/* We just get all multicast packets even if we only want them
+ 	 . from one source.  This will be changed at some future
+ 	 . point. */
+-	else if (dev->mc_count )  {
++	else if (dev->mc_count) {
+ 		/* support hardware multicasting */
+ 
+ 		/* be sure I get rid of flags I might have set */
+-		outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
+-			ioaddr + RCR );
++		smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL),
++			ioaddr, RCR);
+ 		/* NOTE: this has to set the bank, so make sure it is the
+ 		   last thing called.  The bank is set to zero at the top */
+-		smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
++		smc_setmulticast(dev, dev->mc_count, dev->mc_list);
+ 	}
+-	else  {
+-		outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
+-			ioaddr + RCR );
++	else {
++		smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL),
++			ioaddr, RCR);
+ 
+ 		/*
+ 		  since I'm disabling all multicast entirely, I need to
+ 		  clear the multicast list
+ 		*/
+-		SMC_SELECT_BANK( 3 );
+-		outw( 0, ioaddr + MULTICAST1 );
+-		outw( 0, ioaddr + MULTICAST2 );
+-		outw( 0, ioaddr + MULTICAST3 );
+-		outw( 0, ioaddr + MULTICAST4 );
++		SMC_SELECT_BANK(3);
++		smc_outw(0, ioaddr, MULTICAST1);
++		smc_outw(0, ioaddr, MULTICAST2);
++		smc_outw(0, ioaddr, MULTICAST3);
++		smc_outw(0, ioaddr, MULTICAST4);
+ 	}
+ }
+ 
+@@ -1550,21 +1992,26 @@
+ 
+ int init_module(void)
+ {
+-	int result;
+-
+ 	if (io == 0)
+-		printk(KERN_WARNING
+-		CARDNAME": You shouldn't use auto-probing with insmod!\n" );
++		printk(KERN_WARNING CARDNAME
++			": You shouldn't use auto-probing with insmod!\n");
++
++	/*
++	 * Note: dev->if_port has changed to be 2.4 compliant.
++	 * We keep the ifport insmod parameter the same though.
++	 */
++	switch (ifport) {
++	case 1: devSMC9194.if_port = IF_PORT_10BASET;	break;
++	case 2: devSMC9194.if_port = IF_PORT_AUI;	break;
++	default: devSMC9194.if_port = 0;		break;
++	}
+ 
+ 	/* copy the parameters from insmod into the device structure */
+ 	devSMC9194.base_addr = io;
+ 	devSMC9194.irq       = irq;
+-	devSMC9194.if_port	= ifport;
+-	devSMC9194.init   	= smc_init;
+-	if ((result = register_netdev(&devSMC9194)) != 0)
+-		return result;
++	devSMC9194.init      = smc_init;
+ 
+-	return 0;
++	return register_netdev(&devSMC9194);
+ }
+ 
+ void cleanup_module(void)
+--- linux-2.4.25/drivers/net/smc9194.h~2.4.25-vrs2.patch	2001-09-08 21:13:55.000000000 +0200
++++ linux-2.4.25/drivers/net/smc9194.h	2004-03-31 17:15:09.000000000 +0200
+@@ -63,10 +63,11 @@
+ 
+ #define	TCR 		0    	/* transmit control register */
+ #define TCR_ENABLE	0x0001	/* if this is 1, we can transmit */ 
++#define	TCR_PAD_ENABLE	0x0080	/* pads short packets to 64 bytes */
++#define	TCR_MON_CNS	0x0400	/* monitors the carrier status */
+ #define TCR_FDUPLX    	0x0800  /* receive packets sent out */
+ #define TCR_STP_SQET	0x1000	/* stop transmitting if Signal quality error */
+-#define	TCR_MON_CNS	0x0400	/* monitors the carrier status */
+-#define	TCR_PAD_ENABLE	0x0080	/* pads short packets to 64 bytes */
++#define TCR_FDSE	0x8000	/* full duplex, switched ethernet */
+ 
+ #define	TCR_CLEAR	0	/* do NOTHING */
+ /* the normal settings for the TCR register : */ 
+@@ -107,7 +108,10 @@
+ #define	CTL_CR_ENABLE		0x40
+ #define	CTL_TE_ENABLE		0x0020
+ #define CTL_AUTO_RELEASE	0x0800
+-#define	CTL_EPROM_ACCESS	0x0003 /* high if Eprom is being read */
++#define CTL_EPROM_SELECT	0x0004
++#define CTL_EPROM_RELOAD	0x0002
++#define CTL_EPROM_STORE		0x0001
++#define	CTL_EPROM_ACCESS	(CTL_EPROM_RELOAD | CTL_EPROM_STORE) /* high if Eprom is being read */
+ 
+ /* BANK 2 */
+ #define MMU_CMD		0
+@@ -130,7 +134,6 @@
+ #define PTR_READ	0x2000
+ #define	PTR_RCV		0x8000
+ #define	PTR_AUTOINC 	0x4000
+-#define PTR_AUTO_INC	0x0040
+ 
+ #define	DATA_1		8
+ #define	DATA_2		10
+@@ -162,17 +165,6 @@
+ #define CHIP_9195	5
+ #define CHIP_91100	7
+ 
+-static const char * chip_ids[ 15 ] =  { 
+-	NULL, NULL, NULL, 
+-	/* 3 */ "SMC91C90/91C92",
+-	/* 4 */ "SMC91C94",
+-	/* 5 */ "SMC91C95",
+-	NULL,
+-	/* 7 */ "SMC91C100", 
+-	/* 8 */ "SMC91C100FD", 
+-	NULL, NULL, NULL, 
+-	NULL, NULL, NULL};  
+-
+ /* 
+  . Transmit status bits 
+ */
+@@ -192,40 +184,20 @@
+ #define RS_MULTICAST	0x0001
+ #define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT) 
+ 
+-static const char * interfaces[ 2 ] = { "TP", "AUI" };
+-
+-/*-------------------------------------------------------------------------
+- .  I define some macros to make it easier to do somewhat common
+- . or slightly complicated, repeated tasks. 
+- --------------------------------------------------------------------------*/
+-
+-/* select a register bank, 0 to 3  */
+-
+-#define SMC_SELECT_BANK(x)  { outw( x, ioaddr + BANK_SELECT ); } 
+-
+-/* define a small delay for the reset */
+-#define SMC_DELAY() { inw( ioaddr + RCR );\
+-			inw( ioaddr + RCR );\
+-			inw( ioaddr + RCR );  }
+-
+-/* this enables an interrupt in the interrupt mask register */
+-#define SMC_ENABLE_INT(x) {\
+-		unsigned char mask;\
+-		SMC_SELECT_BANK(2);\
+-		mask = inb( ioaddr + INT_MASK );\
+-		mask |= (x);\
+-		outb( mask, ioaddr + INT_MASK ); \
+-}
+-
+-/* this disables an interrupt from the interrupt mask register */
++/*
++ * SMC91C96 ethernet config and status registers.
++ * These are in the "attribute" space.
++ */
++#define ECOR		0x8000
++#define ECOR_RESET	0x80
++#define ECOR_LEVEL_IRQ	0x40
++#define ECOR_WR_ATTRIB	0x04
++#define ECOR_ENABLE	0x01
+ 
+-#define SMC_DISABLE_INT(x) {\
+-		unsigned char mask;\
+-		SMC_SELECT_BANK(2);\
+-		mask = inb( ioaddr + INT_MASK );\
+-		mask &= ~(x);\
+-		outb( mask, ioaddr + INT_MASK ); \
+-}
++#define ECSR		0x8002
++#define ECSR_IOIS8	0x20
++#define ECSR_PWRDWN	0x04
++#define ECSR_INT	0x02
+ 
+ /*----------------------------------------------------------------------
+  . Define the interrupts that I want to receive from the card
+@@ -237,5 +209,36 @@
+  --------------------------------------------------------------------------*/
+ #define SMC_INTERRUPT_MASK   (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) 
+ 
++/* store this information for the driver.. */
++struct smc_local {
++	/*
++ 	   these are things that the kernel wants me to keep, so users
++	   can find out semi-useless statistics of how well the card is
++	   performing
++ 	*/
++	struct net_device_stats stats;
++
++	/*
++	   If I have to wait until memory is available to send
++	   a packet, I will store the skbuff here, until I get the
++	   desired memory.  Then, I'll send it out and free it.
++	*/
++	struct sk_buff * saved_skb;
++
++	/*
++ 	 . This keeps track of how many packets that I have
++ 	 . sent out.  When an TX_EMPTY interrupt comes, I know
++	 . that all of these have been sent.
++	*/
++	int	packets_waiting;
++
++	/*
++	 . Interface status.  These correspond to the parameters
++	 . in the ethtool_cmd structure.
++	*/
++	u8	duplex;
++	u8	port;
++};
++
+ #endif  /* _SMC_9194_H_ */
+ 
+--- linux-2.4.25/drivers/parport/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/parport/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -27,7 +27,8 @@
+       dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA $CONFIG_PARPORT_PC $CONFIG_HOTPLUG
+    fi
+    if [ "$CONFIG_ARM" = "y" ]; then
+-      dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
++      dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT $CONFIG_ARCH_ARC
++      dep_tristate '  Accelent SA1110 IDP' CONFIG_PARPORT_IDP $CONFIG_PARPORT $CONFIG_SA1100_ACCELENT
+    fi
+    if [ "$CONFIG_AMIGA" = "y" ]; then
+       dep_tristate '  Amiga builtin port' CONFIG_PARPORT_AMIGA $CONFIG_PARPORT
+--- linux-2.4.25/drivers/parport/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/parport/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -29,6 +29,7 @@
+ obj-$(CONFIG_PARPORT_ATARI)	+= parport_atari.o
+ obj-$(CONFIG_PARPORT_SUNBPP)	+= parport_sunbpp.o
+ obj-$(CONFIG_PARPORT_GSC)	+= parport_gsc.o
++obj-$(CONFIG_PARPORT_IDP)	+= parport_idp.o
+ obj-$(CONFIG_PARPORT_IP22)	+= parport_ip22.o
+ 
+ include $(TOPDIR)/Rules.make
+--- linux-2.4.25/drivers/parport/init.c~2.4.25-vrs2.patch	2002-11-29 00:53:14.000000000 +0100
++++ linux-2.4.25/drivers/parport/init.c	2004-03-31 17:15:09.000000000 +0200
+@@ -164,6 +164,9 @@
+ #ifdef CONFIG_PARPORT_SUNBPP
+ 	parport_sunbpp_init();
+ #endif
++#ifdef CONFIG_PARPORT_IDP
++	parport_idp_init();
++#endif
+ 	return 0;
+ }
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/parport/parport_idp.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,247 @@
++/* Low-level polled-mode parallel port routines for the Accelent IDP
++ *
++ * Author: Rich Dulabahn <rich@accelent.com>
++ *
++ * Inspiration taken from parport_amiga.c and parport_atari.c.
++ *
++ * To use, under menuconfig:
++ *   1)  Turn on <*> Accelent IDP under Parallel port setup
++ *   2)  Turn on <*> Parallel printer support under Character devices
++ *
++ * This will give you parport0 configured as /dev/lp0
++ *
++ * To make the correct /dev/lp* entries, enter /dev and type this:
++ *
++ * mknod lp0 c 6 0
++ * mknod lp1 c 6 1
++ * mknod lp2 c 6 2
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/parport.h>
++#include <asm/hardware.h>
++
++/*
++ * Parallel data port is port H, data
++ * Parallel data direction is port H, direction
++ * Control port is port I, data, lowest 4 bits
++ * Status port is port G, data, upper 5 bits
++ */
++
++#define INPUTPOWERHANDLER		0
++/* masks */
++#define CONTROL_MASK			0x0f
++#define STATUS_MASK			0xf8
++
++#undef DEBUG
++
++#ifdef DEBUG
++#define DPRINTK  printk
++#else
++#define DPRINTK(stuff...)
++#endif
++
++static struct parport *this_port = NULL;
++
++static unsigned char
++parport_idp_read_data(struct parport *p)
++{
++	unsigned char c;
++
++	c = IDP_FPGA_PORTH_DATA;
++	DPRINTK("read_data:0x%x\n",c);
++	return c;
++}
++
++static void
++parport_idp_write_data(struct parport *p, unsigned char data)
++{
++	IDP_FPGA_PORTH_DATA = data;
++	DPRINTK("write_data:0x%x\n",data);
++}
++
++static unsigned char
++parport_idp_read_control(struct parport *p)
++{
++	unsigned char c;
++
++	c = IDP_FPGA_PORTI_DATA & CONTROL_MASK;
++	DPRINTK("read_control:0x%x\n",c);
++	return c;
++}
++
++static void
++parport_idp_write_control(struct parport *p, unsigned char control)
++{
++	unsigned int temp;
++
++	temp = IDP_FPGA_PORTH_DATA;
++	temp &= ~CONTROL_MASK;
++	IDP_FPGA_PORTI_DATA = (temp | (control & CONTROL_MASK));
++DPRINTK("write_control:0x%x\n",control);
++}
++
++static unsigned char
++parport_idp_frob_control(struct parport *p, unsigned char mask,
++			   unsigned char val)
++{
++	unsigned char c;
++
++/* From the parport-lowlevel.txt file...*/
++/* This is equivalent to reading from the control register, masking out
++the bits in mask, exclusive-or'ing with the bits in val, and writing
++the result to the control register. */
++
++/* Easy enough, right? */
++
++	c = parport_idp_read_control(p);
++	parport_idp_write_control(p, (c & ~mask) ^ val);
++	DPRINTK("frob_control:0x%x\n",c);
++	return c;
++}
++
++static unsigned char
++parport_idp_read_status(struct parport *p)
++{
++	unsigned char c;
++
++	c = IDP_FPGA_PORTG_DATA & STATUS_MASK;
++	c ^= 0x80;  /* toggle S7 bit, active low */
++	DPRINTK("read_status:0x%x\n",c);
++	return c;
++}
++
++static void
++parport_idp_init_state(struct pardevice *d, struct parport_state *s)
++{
++}
++
++static void
++parport_idp_save_state(struct parport *p, struct parport_state *s)
++{
++}
++
++static void
++parport_idp_restore_state(struct parport *p, struct parport_state *s)
++{
++}
++
++static void
++parport_idp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++}
++
++static void
++parport_idp_enable_irq(struct parport *p)
++{
++}
++
++static void
++parport_idp_disable_irq(struct parport *p)
++{
++}
++
++static void
++parport_idp_data_forward(struct parport *p)
++{
++	IDP_FPGA_PORTH_DIR = 0x00; /* 0 sets to output */
++	DPRINTK("data_forward:0x%x\n",0);
++}
++
++static void
++parport_idp_data_reverse(struct parport *p)
++{
++	IDP_FPGA_PORTH_DIR = 0xff; /* and 1 sets to input */
++	DPRINTK("data_reverse:0x%x\n",0xff);
++}
++
++static void
++parport_idp_inc_use_count(void)
++{
++	MOD_INC_USE_COUNT;
++}
++
++static void
++parport_idp_dec_use_count(void)
++{
++	MOD_DEC_USE_COUNT;
++}
++
++static struct parport_operations parport_idp_ops = {
++	parport_idp_write_data,
++	parport_idp_read_data,
++
++	parport_idp_write_control,
++	parport_idp_read_control,
++	parport_idp_frob_control,
++
++	parport_idp_read_status,
++
++	parport_idp_enable_irq,
++	parport_idp_disable_irq,
++
++	parport_idp_data_forward,
++	parport_idp_data_reverse,
++
++	parport_idp_init_state,
++	parport_idp_save_state,
++	parport_idp_restore_state,
++
++	parport_idp_inc_use_count,
++	parport_idp_dec_use_count,
++
++	parport_ieee1284_epp_write_data,
++	parport_ieee1284_epp_read_data,
++	parport_ieee1284_epp_write_addr,
++	parport_ieee1284_epp_read_addr,
++
++	parport_ieee1284_ecp_write_data,
++	parport_ieee1284_ecp_read_data,
++	parport_ieee1284_ecp_write_addr,
++
++	parport_ieee1284_write_compat,
++	parport_ieee1284_read_nibble,
++	parport_ieee1284_read_byte,
++};
++
++
++int __init
++parport_idp_init(void)
++{
++	struct parport *p;
++
++	p = parport_register_port((unsigned long)0,PARPORT_IRQ_NONE,PARPORT_DMA_NONE,&parport_idp_ops);
++
++	if (!p) return 0;  /* return 0 on failure */
++
++	this_port=p;
++	printk("%s: Accelent IDP parallel port registered.\n", p->name);
++	parport_proc_register(p);
++	parport_announce_port(p);
++
++	return 1;
++}
++
++#ifdef MODULE
++
++MODULE_AUTHOR("Rich Dulabahn");
++MODULE_DESCRIPTION("Parport Driver for Accelent IDP");
++MODULE_SUPPORTED_DEVICE("Accelent IDP builtin Parallel Port");
++MODULE_LICENSE("GPL");
++
++int
++init_module(void)
++{
++	return parport_idp_init() ? 0 : -ENODEV;
++}
++
++void
++cleanup_module(void)
++{
++	parport_proc_unregister(this_port);
++	parport_unregister_port(this_port);
++}
++#endif
++
+--- linux-2.4.25/drivers/pci/Makefile~2.4.25-vrs2.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/pci/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -13,7 +13,7 @@
+ 
+ export-objs := pci.o
+ 
+-obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o
++obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o bridge.o 
+ obj-$(CONFIG_PROC_FS) += proc.o
+ 
+ ifndef CONFIG_SPARC64
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pci/bridge.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,149 @@
++
++/*
++ *	Copyright (c) 2001 Red Hat, Inc. All rights reserved.
++ *
++ *	This software may be freely redistributed under the terms
++ * 	of the GNU public license.
++ * 
++ *	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.
++ *
++ * 	Author: Arjan van de Ven <arjanv@redhat.com>
++ *
++ */
++
++
++/*
++ * Generic PCI driver for PCI bridges for powermanagement purposes
++ *
++ */
++
++#include <linux/config.h> 
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++
++static struct pci_device_id bridge_pci_table[] __devinitdata = {
++        {/* handle all PCI bridges */
++	class:          ((PCI_CLASS_BRIDGE_PCI << 8) | 0x00),
++	class_mask:     ~0,
++	vendor:         PCI_ANY_ID,
++	device:         PCI_ANY_ID,
++	subvendor:      PCI_ANY_ID,
++	subdevice:      PCI_ANY_ID,
++	},
++        {0,},
++};
++
++static int bridge_probe(struct pci_dev *pdev, const struct pci_device_id *id);
++static int pci_bridge_save_state_bus(struct pci_bus *bus, int force);
++int pci_generic_resume_compare(struct pci_dev *pdev);
++
++int pci_bridge_force_restore = 0;
++
++
++
++
++static int __init bridge_setup(char *str)
++{
++	if (!strcmp(str,"force"))
++		pci_bridge_force_restore = 1;
++	else if (!strcmp(str,"noforce"))
++		pci_bridge_force_restore = 0;
++	return 0;
++}
++
++__setup("resume=",bridge_setup);
++
++
++static int pci_bridge_save_state_bus(struct pci_bus *bus, int force)
++{
++	struct list_head *list;
++	int error = 0;
++
++	list_for_each(list, &bus->children) {
++		error = pci_bridge_save_state_bus(pci_bus_b(list),force);
++		if (error) return error;
++	}
++	list_for_each(list, &bus->devices) {
++		pci_generic_suspend_save(pci_dev_b(list),0);
++	}
++	return 0;
++}
++
++
++static int pci_bridge_restore_state_bus(struct pci_bus *bus, int force)
++{
++	struct list_head *list;
++	int error = 0;
++	static int printed_warning=0;
++
++	list_for_each(list, &bus->children) {
++		error = pci_bridge_restore_state_bus(pci_bus_b(list),force);
++		if (error) return error;
++	}
++	list_for_each(list, &bus->devices) {
++		if (force)
++			pci_generic_resume_restore(pci_dev_b(list));
++		else {
++			error = pci_generic_resume_compare(pci_dev_b(list));
++			if (error && !printed_warning++) { 
++				printk(KERN_WARNING "resume warning: bios doesn't restore PCI state properly\n");
++				printk(KERN_WARNING "resume warning: if resume failed, try booting with resume=force\n");
++			}
++			if (error)
++				return error;
++		}
++	}
++	return 0;
++}
++
++static int bridge_suspend(struct pci_dev *dev, u32 force)
++{
++	pci_generic_suspend_save(dev,force);
++	if (dev->subordinate)
++		pci_bridge_save_state_bus(dev->subordinate,force);
++	return 0;
++}
++
++static int bridge_resume(struct pci_dev *dev)
++{
++
++	pci_generic_resume_restore(dev);
++	if (dev->subordinate)
++		pci_bridge_restore_state_bus(dev->subordinate,pci_bridge_force_restore);
++	return 0;
++}
++
++
++MODULE_DEVICE_TABLE(pci, bridge_pci_table);
++static struct pci_driver bridge_ops = {
++        name:           "PCI Bridge",   
++        id_table:       bridge_pci_table,
++        probe:          bridge_probe,    
++        suspend: 	bridge_suspend,
++        resume: 	bridge_resume
++};
++
++static int __devinit bridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
++{
++	return 0;
++}
++
++static int __init bridge_init(void) 
++{
++        pci_register_driver(&bridge_ops);
++        return 0;
++}
++
++static void __exit bridge_exit(void)
++{
++        pci_unregister_driver(&bridge_ops);
++} 
++
++
++module_init(bridge_init)
++module_exit(bridge_exit)
++
+--- linux-2.4.25/drivers/pci/pci.c~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/pci/pci.c	2004-03-31 17:15:09.000000000 +0200
+@@ -359,6 +359,48 @@
+ 	return 0;
+ }
+ 
++int 
++pci_compare_state(struct pci_dev *dev, u32 *buffer)
++{
++	int i;
++	unsigned int temp;
++
++	if (buffer) {
++		for (i = 0; i < 16; i++) {
++			pci_read_config_dword(dev,i*4,&temp);
++			if (temp!=buffer[i])
++				return 1;
++		}
++	}
++	return 0;
++}
++
++int pci_generic_suspend_save(struct pci_dev *pdev, u32 state)
++{
++	if (pdev)
++		pci_save_state(pdev,pdev->saved_state);
++	return 0;
++}
++
++int pci_generic_resume_restore(struct pci_dev *pdev)
++{
++	if (pdev)
++		pci_restore_state(pdev,pdev->saved_state);
++	return 0;		
++}
++
++int pci_generic_resume_compare(struct pci_dev *pdev)
++{
++	int retval=0;
++	if (pdev)
++		retval = pci_compare_state(pdev,pdev->saved_state);
++	return retval;		
++}
++
++EXPORT_SYMBOL(pci_generic_suspend_save);
++EXPORT_SYMBOL(pci_generic_resume_restore);
++EXPORT_SYMBOL(pci_generic_resume_compare);
++
+ /**
+  * pci_enable_device_bars - Initialize some of a device for use
+  * @dev: PCI device to be initialized
+--- linux-2.4.25/drivers/pci/setup-bus.c~2.4.25-vrs2.patch	2003-06-13 16:51:35.000000000 +0200
++++ linux-2.4.25/drivers/pci/setup-bus.c	2004-03-31 17:15:09.000000000 +0200
+@@ -12,6 +12,8 @@
+ /*
+  * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+  *	     PCI-PCI bridges cleanup, sorted resource allocation.
++ * May 2001, Russell King <rmk@arm.linux.org.uk>
++ *           Allocate prefetchable memory regions where available.
+  * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
+  *	     Converted to allocation in 3 passes, which gives
+  *	     tighter packing. Prefetchable range support.
+@@ -160,8 +162,10 @@
+ 	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+ 
+ 	/* Check if we have VGA behind the bridge.
+-	   Enable ISA in either case (FIXME!). */
+-	l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ? 0x0c : 0x04;
++	   Enable ISA in either case. */
++	l = (bus->resource[0]->flags & IORESOURCE_BUS_HAS_VGA) ?
++		PCI_BRIDGE_CTL_VGA | PCI_BRIDGE_CTL_NO_ISA :
++		PCI_BRIDGE_CTL_NO_ISA;
+ 	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, l);
+ }
+ 
+--- linux-2.4.25/drivers/pcmcia/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -14,21 +14,19 @@
+ 
+ tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+ if [ "$CONFIG_PCMCIA" != "n" ]; then
++   # yes, I really mean the following...
++   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then
++      define_bool CONFIG_PCMCIA_PROBE y
++   fi
+    if [ "$CONFIG_PCI" != "n" ]; then
+       bool '  CardBus support' CONFIG_CARDBUS
+    fi
++   dep_bool '  i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI
++   bool '  i82365 compatible bridge support' CONFIG_I82365
+    bool '  Databook TCIC host bridge support' CONFIG_TCIC
+    if [ "$CONFIG_HD64465" = "y" ]; then
+       dep_tristate '  HD64465 host bridge support' CONFIG_HD64465_PCMCIA $CONFIG_PCMCIA
+    fi
+-   dep_bool '  i82092 compatible bridge support' CONFIG_I82092 $CONFIG_PCI
+-   bool '  i82365 compatible bridge support' CONFIG_I82365
+-   if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+-      dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_PCMCIA
+-   fi
+-   if [ "$CONFIG_8xx" = "y" ]; then
+-      dep_tristate '  M8xx support' CONFIG_PCMCIA_M8XX $CONFIG_PCMCIA
+-   fi
+    if [ "$CONFIG_SOC_AU1X00" = "y" ]; then
+       dep_tristate '  Au1x00 PCMCIA support' CONFIG_PCMCIA_AU1X00 $CONFIG_PCMCIA 
+       if [ "$CONFIG_PCMCIA_AU1X00" != "n" ]; then
+@@ -44,5 +42,9 @@
+       dep_tristate '  NEC VRC4173 CARDU support' CONFIG_PCMCIA_VRC4173 $CONFIG_PCMCIA
+    fi
+ fi
++if [ "$CONFIG_ARM" = "y" ]; then
++   dep_tristate '  CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA
++   dep_tristate '  SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA
++fi
+ 
+ endmenu
+--- linux-2.4.25/drivers/pcmcia/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -65,15 +65,18 @@
+ au1000_ss-objs-$(CONFIG_PCMCIA_DB1X00)		+= au1000_db1x00.o
+ au1000_ss-objs-$(CONFIG_PCMCIA_XXS1500) 	+= au1000_xxs1500.o
+ 
++obj-$(CONFIG_PCMCIA_CLPS6700)	+= clps6700.o
+ obj-$(CONFIG_PCMCIA_SA1100)	+= sa1100_cs.o
+-obj-$(CONFIG_PCMCIA_M8XX)	+= m8xx_pcmcia.o
+ obj-$(CONFIG_PCMCIA_SIBYTE)	+= sibyte_generic.o
+ 
+ sa1100_cs-objs-y				:= sa1100_generic.o
++sa1100_cs-objs-$(CONFIG_SA1100_ADSAGC)		+= sa1100_graphicsmaster.o sa1111_generic.o
+ sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSY)	+= sa1100_adsbitsy.o sa1111_generic.o
++sa1100_cs-objs-$(CONFIG_SA1100_ADSBITSYPLUS)	+= sa1100_adsbitsyplus.o sa1111_generic.o
+ sa1100_cs-objs-$(CONFIG_SA1100_ASSABET)		+= sa1100_assabet.o
+ sa1100_cs-objs-$(CONFIG_ASSABET_NEPONSET)	+= sa1100_neponset.o sa1111_generic.o
+ sa1100_cs-objs-$(CONFIG_SA1100_BADGE4)		+= sa1100_badge4.o sa1111_generic.o
++sa1100_cs-objs-$(CONFIG_SA1100_CONSUS)		+= sa1100_neponset.o sa1111_generic.o
+ sa1100_cs-objs-$(CONFIG_SA1100_CERF)		+= sa1100_cerf.o
+ sa1100_cs-objs-$(CONFIG_SA1100_FLEXANET)	+= sa1100_flexanet.o
+ sa1100_cs-objs-$(CONFIG_SA1100_FREEBIRD)	+= sa1100_freebird.o
+--- linux-2.4.25/drivers/pcmcia/cistpl.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/cistpl.c	2004-03-31 17:15:09.000000000 +0200
+@@ -286,7 +286,7 @@
+ 	s->cis_mem.flags &= ~MAP_ACTIVE;
+ 	s->ss_entry->set_mem_map(s->sock, &s->cis_mem);
+ 	if (!(s->cap.features & SS_CAP_STATIC_MAP))
+-	    release_mem_region(s->cis_mem.sys_start, s->cap.map_size);
++	    release_mem_resource(s->cis_mem.sys_start, s->cap.map_size);
+ 	bus_iounmap(s->cap.bus, s->cis_virt);
+ 	s->cis_mem.sys_start = 0;
+ 	s->cis_virt = NULL;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/clps6700.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,498 @@
++/*
++ *  linux/drivers/pcmcia/clps6700.c
++ *
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * 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/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/proc_fs.h>
++#include <linux/spinlock.h>
++#include <linux/init.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/page.h>
++
++#include <asm/arch/syspld.h>
++#include <asm/hardware/clps7111.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/ss.h>
++
++#include "clps6700.h"
++
++#define DEBUG
++
++MODULE_AUTHOR("Russell King");
++MODULE_DESCRIPTION("CL-PS6700 PCMCIA socket driver");
++
++#define NR_CLPS6700	2
++
++struct clps6700_skt {
++	u_int			nr;
++	u_int			physbase;
++	u_int			regbase;
++	u_int			pmr;
++	u_int			cpcr;
++	u_int			cpcr_3v3;
++	u_int			cpcr_5v0;
++	u_int			cur_pmr;
++	u_int			cur_cicr;
++	u_int			cur_pcimr;
++	u_int			cur_cpcr;
++	void			(*handler)(void *, u_int);
++	void			*handler_info;
++
++	u_int			ev_pending;
++	spinlock_t		ev_lock;
++};
++
++static struct clps6700_skt *skts[NR_CLPS6700];
++
++static int clps6700_sock_init(u_int sock)
++{
++	struct clps6700_skt *skt = skts[sock];
++
++	skt->cur_cicr  = 0;
++	skt->cur_pmr   = skt->pmr;
++	skt->cur_pcimr = 0;
++	skt->cur_cpcr  = skt->cpcr;
++
++#ifdef DEBUG
++	printk("skt%d: sock_init()\n", sock);
++#endif
++
++	__raw_writel(skt->cur_pmr,	skt->regbase + PMR);
++	__raw_writel(skt->cur_cpcr,	skt->regbase + CPCR);
++	__raw_writel(0x01f8,		skt->regbase + SICR);
++	__raw_writel(0x0000,		skt->regbase + DMACR);
++	__raw_writel(skt->cur_cicr,	skt->regbase + CICR);
++	__raw_writel(0x1f00,		skt->regbase + CITR0A);
++	__raw_writel(0x0000,		skt->regbase + CITR0B);
++	__raw_writel(0x1f00,		skt->regbase + CITR1A);
++	__raw_writel(0x0000,		skt->regbase + CITR1B);
++	__raw_writel(skt->cur_pcimr,	skt->regbase + PCIMR);
++
++	/*
++	 * Enable Auto Idle Mode in PM register
++	 */
++	__raw_writel(-1,		skt->regbase + PCIRR1);
++	__raw_writel(-1,		skt->regbase + PCIRR2);
++	__raw_writel(-1,		skt->regbase + PCIRR3);
++
++	return 0;
++}
++
++static int clps6700_suspend(u_int sock)
++{
++	return 0;
++}
++
++static int clps6700_register_callback(u_int sock, void (*handler)(void *, u_int), void *info)
++{
++	struct clps6700_skt *skt = skts[sock];
++
++#ifdef DEBUG
++	printk("skt%d: register_callback: %p (%p)\n", sock, handler, info);
++#endif
++
++	skt->handler_info = info;
++	skt->handler = handler;
++
++	return 0;
++}
++
++static int clps6700_inquire_socket(u_int sock, socket_cap_t *cap)
++{
++	cap->features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP | SS_CAP_MEM_ALIGN;
++	cap->irq_mask = 0;		/* available IRQs for this socket */
++	cap->map_size = PAGE_SIZE;	/* minimum mapping size */
++	cap->pci_irq  = 0;		/* PCI interrupt number */
++	cap->cb_dev   = NULL;
++	cap->bus      = NULL;
++	return 0;
++}
++
++static int __clps6700_get_status(struct clps6700_skt *skt)
++{
++	unsigned int v, val;
++
++	v = __raw_readl(skt->regbase + PCIILR);
++	val = 0;
++	if ((v & (PCM_CD1 | PCM_CD2)) == 0)
++		val |= SS_DETECT;
++	if ((v & (PCM_BVD2 | PCM_BVD1)) == PCM_BVD1)
++		val |= SS_BATWARN;
++	if ((v & PCM_BVD2) == 0)
++		val |= SS_BATDEAD;
++
++	if (v & PCM_RDYL)
++		val |= SS_READY;
++	if (v & PCM_VS1)
++		val |= SS_3VCARD;
++	if (v & PCM_VS2)
++		val |= SS_XVCARD;
++
++#ifdef DEBUG
++	printk("skt%d: PCIILR: %08x -> (%s %s %s %s %s %s)\n",
++		skt->nr, v,
++		val & SS_READY   ? "rdy" : "---",
++		val & SS_DETECT  ? "det" : "---",
++		val & SS_BATWARN ? "bw"  : "--",
++		val & SS_BATDEAD ? "bd"  : "--",
++		val & SS_3VCARD  ? "3v"  : "--",
++		val & SS_XVCARD  ? "xv"  : "--");
++#endif
++	return val;
++}
++
++static int clps6700_get_status(u_int sock, u_int *valp)
++{
++	struct clps6700_skt *skt = skts[sock];
++
++	*valp = __clps6700_get_status(skt);
++
++	return 0; /* not used! */
++}
++
++static int clps6700_get_socket(u_int sock, socket_state_t *state)
++{
++	return -EINVAL;
++}
++
++static int clps6700_set_socket(u_int sock, socket_state_t *state)
++{
++	struct clps6700_skt *skt = skts[sock];
++	unsigned long flags;
++	u_int cpcr = skt->cur_cpcr, pmr = skt->cur_pmr, cicr = skt->cur_cicr;
++	u_int pcimr = 0;
++
++	cicr &= ~(CICR_ENABLE | CICR_RESET | CICR_IOMODE);
++
++	if (state->flags & SS_PWR_AUTO)
++		pmr |= PMR_DCAR | PMR_PDCR;
++
++	/*
++	 * Note! We must NOT assert the Card Enable bit until reset has
++	 * been de-asserted.  Some cards indicate not ready, which then
++	 * hangs our next access.  (Bug in CLPS6700?)
++	 */
++	if (state->flags & SS_RESET)
++		cicr |= CICR_RESET | CICR_RESETOE;
++	else if (state->flags & SS_OUTPUT_ENA)
++		cicr |= CICR_ENABLE;
++
++	if (state->flags & SS_IOCARD) {
++		cicr |= CICR_IOMODE;
++
++/*		if (state->csc_mask & SS_STSCHG)*/
++	} else {
++		if (state->csc_mask & SS_BATDEAD)
++			pcimr |= PCM_BVD2;
++		if (state->csc_mask & SS_BATWARN)
++			pcimr |= PCM_BVD1;
++		if (state->csc_mask & SS_READY)
++			pcimr |= PCM_RDYL;
++	}
++
++	if (state->csc_mask & SS_DETECT)
++		pcimr |= PCM_CD1 | PCM_CD2;
++
++	switch (state->Vcc) {
++	case 0:				break;
++	case 33: cpcr |= skt->cpcr_3v3; pmr |= PMR_CPE; break;
++	case 50: cpcr |= skt->cpcr_5v0; pmr |= PMR_CPE; break;
++	default: return -EINVAL;
++	}
++
++#ifdef DEBUG
++	printk("skt%d: PMR: %04x, CPCR: %04x, CICR: %04x PCIMR: %04x "
++		"(Vcc = %d, flags = %c%c%c%c, csc = %c%c%c%c%c)\n",
++		sock, pmr, cpcr, cicr, pcimr, state->Vcc,
++		state->flags & SS_RESET      ? 'r' : '-',
++		state->flags & SS_PWR_AUTO   ? 'p' : '-',
++		state->flags & SS_IOCARD     ? 'i' : '-',
++		state->flags & SS_OUTPUT_ENA ? 'o' : '-',
++		state->csc_mask & SS_STSCHG  ? 's' : '-',
++		state->csc_mask & SS_BATDEAD ? 'd' : '-',
++		state->csc_mask & SS_BATWARN ? 'w' : '-',
++		state->csc_mask & SS_READY   ? 'r' : '-',
++		state->csc_mask & SS_DETECT  ? 'c' : '-');
++#endif
++
++	save_flags_cli(flags);
++
++	if (skt->cur_cpcr != cpcr) {
++		skt->cur_cpcr = cpcr;
++		__raw_writel(skt->cur_cpcr, skt->regbase + CPCR);
++	}
++
++	if (skt->cur_pmr != pmr) {
++		skt->cur_pmr = pmr;
++		__raw_writel(skt->cur_pmr, skt->regbase + PMR);
++	}
++	if (skt->cur_pcimr != pcimr) {
++		skt->cur_pcimr = pcimr;
++		__raw_writel(skt->cur_pcimr, skt->regbase + PCIMR);
++	}
++	if (skt->cur_cicr != cicr) {
++		skt->cur_cicr = cicr;
++		__raw_writel(skt->cur_cicr, skt->regbase + CICR);
++	}
++
++	restore_flags(flags);
++
++	return 0;
++}
++
++static int clps6700_get_io_map(u_int sock, struct pccard_io_map *io)
++{
++	return -EINVAL;
++}
++
++static int clps6700_set_io_map(u_int sock, struct pccard_io_map *io)
++{
++	printk("skt%d: iomap: %d: speed %d, flags %X start %X stop %X\n",
++		sock, io->map, io->speed, io->flags, io->start, io->stop);
++	return 0;
++}
++
++static int clps6700_get_mem_map(u_int sock, struct pccard_mem_map *mem)
++{
++	return -EINVAL;
++}
++
++/*
++ * Set the memory map attributes for this socket.  (ie, mem->speed)
++ * Note that since we have SS_CAP_STATIC_MAP set, we don't need to do
++ * any mapping here at all; we just need to return the address (suitable
++ * for ioremap) to map the requested space in mem->sys_start.
++ *
++ * flags & MAP_ATTRIB indicates whether we want attribute space.
++ */
++static int clps6700_set_mem_map(u_int sock, struct pccard_mem_map *mem)
++{
++	struct clps6700_skt *skt = skts[sock];
++	u_int off;
++
++	printk("skt%d: memmap: %d: speed %d, flags %X start %lX stop %lX card %X\n",
++		sock, mem->map, mem->speed, mem->flags, mem->sys_start,
++		mem->sys_stop, mem->card_start);
++
++	if (mem->flags & MAP_ATTRIB)
++		off = CLPS6700_ATTRIB_BASE;
++	else
++		off = CLPS6700_MEM_BASE;
++
++	mem->sys_start  = skt->physbase + off;
++	mem->sys_start += mem->card_start;
++
++	return 0;
++}
++
++static void clps6700_proc_setup(u_int sock, struct proc_dir_entry *base)
++{
++}
++
++static struct pccard_operations clps6700_operations = {
++	init:			clps6700_sock_init,
++	suspend:		clps6700_suspend,
++	register_callback:	clps6700_register_callback,
++	inquire_socket:		clps6700_inquire_socket,
++	get_status:		clps6700_get_status,
++	get_socket:		clps6700_get_socket,
++	set_socket:		clps6700_set_socket,
++	get_io_map:		clps6700_get_io_map,
++	set_io_map:		clps6700_set_io_map,
++	get_mem_map:		clps6700_get_mem_map,
++	set_mem_map:		clps6700_set_mem_map,
++	proc_setup:		clps6700_proc_setup
++};
++
++static void clps6700_bh(void *dummy)
++{
++	int i;
++
++	for (i = 0; i < NR_CLPS6700; i++) {
++		struct clps6700_skt *skt = skts[i];
++		unsigned long flags;
++		u_int events;
++
++		if (!skt)
++			continue;
++
++		/*
++		 * Note!  We must read the pending event state
++		 * with interrupts disabled, otherwise we race
++		 * with our own interrupt routine!
++		 */
++		spin_lock_irqsave(&skt->ev_lock, flags);
++		events = skt->ev_pending;
++		skt->ev_pending = 0;
++		spin_unlock_irqrestore(&skt->ev_lock, flags);	
++
++		if (skt->handler && events)
++			skt->handler(skt->handler_info, events);
++	}
++}
++
++static struct tq_struct clps6700_task = {
++	routine:	clps6700_bh
++};
++
++static void clps6700_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct clps6700_skt *skt = dev_id;
++	u_int val, events;
++
++	val = __raw_readl(skt->regbase + PCISR);
++	if (!val)
++		return;
++
++	__raw_writel(val, skt->regbase + PCICR);
++
++	events = 0;
++	if (val & (PCM_CD1 | PCM_CD2))
++		events |= SS_DETECT;
++	if (val & PCM_BVD1)
++		events |= SS_BATWARN;
++	if (val & PCM_BVD2)
++		events |= SS_BATDEAD;
++	if (val & PCM_RDYL)
++		events |= SS_READY;
++
++	spin_lock(&skt->ev_lock);
++	skt->ev_pending |= events;
++	spin_unlock(&skt->ev_lock);
++	schedule_task(&clps6700_task);
++}
++
++static int __init clps6700_init_skt(int nr)
++{
++	struct clps6700_skt *skt;
++	int ret;
++
++	skt = kmalloc(sizeof(struct clps6700_skt), GFP_KERNEL);
++	if (!skt)
++		return -ENOMEM;
++
++	memset(skt, 0, sizeof(struct clps6700_skt));
++
++	spin_lock_init(&skt->ev_lock);
++
++	skt->nr       = nr;
++	skt->physbase = nr ? CS5_PHYS_BASE : CS4_PHYS_BASE;
++	skt->pmr      = PMR_AUTOIDLE | PMR_MCPE | PMR_CDWEAK;
++	skt->cpcr     = CPCR_PDIR(PCTL1|PCTL0);
++	skt->cpcr_3v3 = CPCR_PON(PCTL0);
++	skt->cpcr_5v0 = CPCR_PON(PCTL0);	/* we only do 3v3 */
++
++	skt->cur_pmr  = skt->pmr;
++
++	skt->regbase = (u_int)ioremap(skt->physbase + CLPS6700_REG_BASE,
++					CLPS6700_REG_SIZE);
++	ret = -ENOMEM;
++	if (!skt->regbase)
++		goto err_free;
++
++	skts[nr] = skt;
++
++	ret = request_irq(IRQ_EINT3, clps6700_interrupt,
++			  SA_SHIRQ, "pcmcia", skt);
++
++	if (ret) {
++		printk(KERN_ERR "clps6700: unable to grab irq%d (%d)\n",
++		       IRQ_EINT3, ret);
++		goto err_unmap;
++	}
++	return 0;
++
++err_unmap:
++	iounmap((void *)skt->regbase);
++err_free:
++	kfree(skt);
++	skts[nr] = NULL;
++	return ret;
++}
++
++static void clps6700_free_resources(void)
++{
++	int i;
++
++	for (i = NR_CLPS6700; i >= 0; i--) {
++		struct clps6700_skt *skt = skts[i];
++
++		skts[i] = NULL;
++		if (skt == NULL)
++			continue;
++
++		free_irq(IRQ_EINT3, skt);
++		if (skt->regbase) {
++			__raw_writel(skt->pmr,  skt->regbase + PMR);
++			__raw_writel(skt->cpcr, skt->regbase + CPCR);
++			__raw_writel(0,         skt->regbase + CICR);
++			__raw_writel(0,         skt->regbase + PCIMR);
++		}
++		iounmap((void *)skt->regbase);
++		kfree(skt);
++	}
++}
++
++static int __init clps6700_init(void)
++{
++	unsigned int v;
++	int err, nr;
++
++	PLD_CF = 0;
++	v = clps_readl(SYSCON2) | SYSCON2_PCCARD1 | SYSCON2_PCCARD2;
++	clps_writel(v, SYSCON2);
++	v = clps_readl(SYSCON1) | SYSCON1_EXCKEN;
++	clps_writel(v, SYSCON1);
++
++	for (nr = 0; nr < NR_CLPS6700; nr++) {
++		err = clps6700_init_skt(nr);
++		if (err)
++			goto free;
++	}
++
++	err = register_ss_entry(nr, &clps6700_operations);
++	if (err)
++		goto free;
++
++	return 0;
++
++free:
++	clps6700_free_resources();
++	/*
++	 * An error occurred.  Unmap and free all CLPS6700
++	 */
++	return err;
++}
++
++static void __exit clps6700_exit(void)
++{
++	unregister_ss_entry(&clps6700_operations);
++	clps6700_free_resources();
++}
++
++module_init(clps6700_init);
++module_exit(clps6700_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/clps6700.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,85 @@
++#define PCISR	0x0000		/* PC Card Interrupt Status Register		*/
++#define PCIMR	0x0400		/* PC Card Interrupt Mask Register		*/
++#define PCICR	0x0800		/* PC Card Interrupt Clear Register		*/
++#define PCIOSR	0x0c00		/* PC Card Interrupt Output Select Regsiter	*/
++#define PCIRR1	0x1000		/* PC Card Interrupt Reserved Register 1	*/
++#define PCIRR2	0x1400		/* PC Card Interrupt Reserved Register 2	*/
++#define PCIRR3	0x1800		/* PC Card Interrupt Reserved Register 3	*/
++#define PCIILR	0x1c00		/* PC Card Interrupt Input Level Register	*/
++#define SICR	0x2000		/* System Interface Configuration Register	*/
++#define CICR	0x2400		/* Card Interface Configuration Register	*/
++#define PMR	0x2800		/* Power Management Register			*/
++#define CPCR	0x2c00		/* Card Power Control Register			*/
++#define CITR0A	0x3000		/* Card Interface Timing Register 0A		*/
++#define CITR0B	0x3400		/* Card Interface Timing Register 0B		*/
++#define CITR1A	0x3800		/* Card Interface Timing Register 1A		*/
++#define CITR1B	0x3c00		/* Card Interface Timing Register 1B		*/
++#define DMACR	0x4000		/* DMA Control Register				*/
++#define DIR	0x4400		/* Device Information Register			*/
++
++#define CLPS6700_ATTRIB_BASE	0x00000000
++#define CLPS6700_IO_BASE	0x04000000
++#define CLPS6700_MEM_BASE	0x08000000
++#define CLPS6700_REG_BASE	0x0c000000
++#define CLPS6700_REG_SIZE	0x00005000
++
++
++#define PMR_AUTOIDLE	(1 << 0)	/* auto idle mode			*/
++#define PMR_FORCEIDLE	(1 << 1)	/* force idle mode			*/
++#define PMR_PDCS	(1 << 2)	/* Power down card on standby		*/
++#define PMR_PDCR	(1 << 3)	/* Power down card on removal		*/
++#define PMR_DCAR	(1 << 4)	/* Disable card access on removal	*/
++#define PMR_CPE		(1 << 5)	/* Card power enable			*/
++#define PMR_MCPE	(1 << 6)	/* Monitor card power enable		*/
++#define PMR_PDREQLSEL	(1 << 7)	/* If set, PDREQL is a GPIO pin		*/
++#define PMR_DISSTBY	(1 << 8)	/* Disable standby			*/
++#define PMR_ACCSTBY	(1 << 9)	/* Complete card accesses before standby*/
++#define PMR_CDUNPROT	(0 << 10)	/* Card detect inputs unprotected	*/
++#define PMR_CDPROT	(1 << 10)	/* Card detect inputs protected		*/
++#define PMR_CDWEAK	(2 << 10)	/* Weak pullup except in standby	*/
++#define PMR_CDWEAKAL	(3 << 10)	/* Weak pullup				*/
++
++#define CPCR_PON(x)	((x)&7)		/* PCTL[2:0] value when PMR_CPE = 1	*/
++#define CPCR_POFF(x)	(((x)&7)<<3)	/* PCTL[2:0] value when PMR_CPE = 0	*/
++#define CPCR_PDIR(x)	(((x)&7)<<6)	/* PCTL[2:0] direction			*/
++#define CPCR_CON(x)	(((x)&1)<<9)	/* GPIO value when PMR_CPE = 1		*/
++#define CPCR_COFF(x)	(((x)&1)<<10)	/* GPIO value when PMR_CPE = 0		*/
++#define CPCR_CDIR(x)	(((x)&1)<<11)	/* GPIO direction (PMR_PDREQLSEL = 1)	*/
++#define CPCR_VS(x)	(((x)&3)<<12)	/* VS[2:1] output value			*/
++#define CPCR_VSDIR(x)	(((x)&3)<<14)	/* VS[2:1] direction			*/
++
++#define PCTL0		(1 << 0)
++#define PCTL1		(1 << 1)
++#define PCTL2		(1 << 2)
++
++#define CICR_ASRTMR1	(1 << 0)	/* Timer 1 select for attribute read	*/
++#define CICR_ASWTMR1	(1 << 1)	/* Timer 1 select for attribute write	*/
++#define CICR_IOSRTMR1	(1 << 2)	/* Timer 1 select for IO read		*/
++#define CICR_IOSWTMR1	(1 << 3)	/* Timer 1 select for IO write		*/
++#define CICR_MEMSRTMR1	(1 << 4)	/* Timer 1 select for memory read	*/
++#define CICR_MEMSWTMR1	(1 << 5)	/* Timer 1 select for memory write	*/
++#define CICR_AUTOIOSZ	(1 << 6)	/* Auto size I/O accesses		*/
++#define CICR_CAW	(1 << 7)	/* Card access width			*/
++#define CICR_IOMODE	(1 << 8)	/* IO mode select			*/
++#define CICR_ENABLE	(1 << 10)	/* Card enable				*/
++#define CICR_RESETOE	(1 << 11)	/* Card reset output enable		*/
++#define CICR_RESET	(1 << 12)	/* Card reset				*/
++
++
++#define RD_FAIL		(1 << 14)
++#define WR_FAIL		(1 << 13)
++#define IDLE		(1 << 12)
++
++#define FFOTHLD		(1 << 11)
++#define PCM_RDYL	(1 << 10)
++#define PCM_WP		(1 << 9)
++#define PCTL		(1 << 8)
++
++#define PDREQ_L		(1 << 6)
++#define PCM_VS2		(1 << 5)
++#define PCM_VS1		(1 << 4)
++
++#define PCM_CD2		(1 << 3)
++#define PCM_CD1		(1 << 2)
++#define PCM_BVD2	(1 << 1)
++#define PCM_BVD1	(1 << 0)
+--- linux-2.4.25/drivers/pcmcia/cs.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/cs.c	2004-03-31 17:15:09.000000000 +0200
+@@ -3,7 +3,7 @@
+     Kernel Card Services -- core services
+ 
+     cs.c 1.271 2000/10/02 20:27:49
+-    
++
+     The contents of this file are subject to the Mozilla Public
+     License Version 1.1 (the "License"); you may not use this file
+     except in compliance with the License. You may obtain a copy of
+@@ -28,7 +28,7 @@
+     and other provisions required by the GPL.  If you do not delete
+     the provisions above, a recipient may use your version of this
+     file under either the MPL or the GPL.
+-    
++
+ ======================================================================*/
+ 
+ #include <linux/module.h>
+@@ -92,7 +92,7 @@
+ MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+ MODULE_DESCRIPTION("Linux Kernel Card Services " CS_RELEASE
+ 		   "\n  options:" OPTIONS);
+-MODULE_LICENSE("Dual MPL/GPL");	  
++MODULE_LICENSE("Dual MPL/GPL");
+ 
+ #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+ 
+@@ -123,7 +123,7 @@
+ static const char *version =
+ "cs.c 1.279 2001/10/13 00:08:28 (David Hinds)";
+ #endif
+- 
++
+ /*====================================================================*/
+ 
+ socket_state_t dead_socket = {
+@@ -299,7 +299,7 @@
+ 
+     Low-level PC Card interface drivers need to register with Card
+     Services using these calls.
+-    
++
+ ======================================================================*/
+ 
+ static int setup_socket(socket_info_t *);
+@@ -331,7 +331,7 @@
+     s->use_bus_pm = use_bus_pm;
+     s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
+     spin_lock_init(&s->lock);
+-    
++
+     for (i = 0; i < sockets; i++)
+ 	if (socket_table[i] == NULL) break;
+     socket_table[i] = s;
+@@ -365,7 +365,7 @@
+     for (ns = 0; ns < nsock; ns++) {
+ 	pcmcia_register_socket (ns, ss_entry, 0);
+     }
+-    
++
+     return 0;
+ } /* register_ss_entry */
+ 
+@@ -457,7 +457,7 @@
+ static void shutdown_socket(socket_info_t *s)
+ {
+     client_t **c;
+-    
++
+     DEBUG(1, "cs: shutdown_socket(%p)\n", s);
+ 
+     /* Blank out the socket state */
+@@ -561,7 +561,7 @@
+     have several causes: card insertion, a call to reset_socket, or
+     recovery from a suspend/resume cycle.  Unreset_socket() sends
+     a CS event that matches the cause of the reset.
+-    
++
+ ======================================================================*/
+ 
+ static void reset_socket(socket_info_t *s)
+@@ -616,7 +616,7 @@
+ 	    s->state &= ~SOCKET_SETUP_PENDING;
+ 	} else {
+ 	    send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+-	    if (s->reset_handle) { 
++	    if (s->reset_handle) {
+ 		    s->reset_handle->event_callback_args.info = NULL;
+ 		    EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
+ 			  CS_EVENT_PRI_LOW);
+@@ -631,7 +631,7 @@
+     valid clients.  Parse_events() interprets the event bits from
+     a card status change report.  Do_shutdown() handles the high
+     priority stuff associated with a card removal.
+-    
++
+ ======================================================================*/
+ 
+ static int send_event(socket_info_t *s, event_t event, int priority)
+@@ -641,7 +641,7 @@
+     DEBUG(1, "cs: send_event(sock %d, event %d, pri %d)\n",
+ 	  s->sock, event, priority);
+     ret = 0;
+-    for (; client; client = client->next) { 
++    for (; client; client = client->next) {
+ 	if (client->state & (CLIENT_UNBOUND|CLIENT_STALE))
+ 	    continue;
+ 	if (client->EventMask & event) {
+@@ -675,10 +675,17 @@
+ static void parse_events(void *info, u_int events)
+ {
+     socket_info_t *s = info;
++
+     if (events & SS_DETECT) {
+ 	int status;
+ 
+ 	get_socket_status(s, &status);
++
++	/*
++	 * If our socket state indicates that a card is present and
++	 * either the socket has not been suspended (for some reason)
++	 * or the card has been removed, shut down the socket first.
++	 */
+ 	if ((s->state & SOCKET_PRESENT) &&
+ 	    (!(s->state & SOCKET_SUSPEND) ||
+ 	     !(status & SS_DETECT)))
+@@ -716,7 +723,7 @@
+ 
+     This does not comply with the latest PC Card spec for handling
+     power management events.
+-    
++
+ ======================================================================*/
+ 
+ void pcmcia_suspend_socket (socket_info_t *s)
+@@ -773,7 +780,7 @@
+ /*======================================================================
+ 
+     Special stuff for managing IO windows, because they are scarce.
+-    
++
+ ======================================================================*/
+ 
+ static int alloc_io_space(socket_info_t *s, u_int attr, ioaddr_t *base,
+@@ -862,7 +869,7 @@
+     Access_configuration_register() reads and writes configuration
+     registers in attribute memory.  Memory window 0 is reserved for
+     this and the tuple reading services.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_access_configuration_register(client_handle_t handle,
+@@ -872,7 +879,7 @@
+     config_t *c;
+     int addr;
+     u_char val;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     s = SOCKET(handle);
+@@ -890,7 +897,7 @@
+ 	return CS_CONFIGURATION_LOCKED;
+ 
+     addr = (c->ConfigBase + reg->Offset) >> 1;
+-    
++
+     switch (reg->Action) {
+     case CS_READ:
+ 	read_cis_mem(s, 1, addr, 1, &val);
+@@ -913,7 +920,7 @@
+     It is normally called by Driver Services after it has identified
+     a newly inserted card.  An instance of that driver will then be
+     eligible to register as a client of this socket.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_bind_device(bind_req_t *req)
+@@ -949,23 +956,23 @@
+     region.  It is normally called by Driver Services after it has
+     identified a memory device type.  An instance of the corresponding
+     driver will then be able to register to control this region.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_bind_mtd(mtd_bind_t *req)
+ {
+     socket_info_t *s;
+     memory_handle_t region;
+-    
++
+     if (CHECK_SOCKET(req->Socket))
+ 	return CS_BAD_SOCKET;
+     s = SOCKET(req);
+-    
++
+     if (req->Attributes & REGION_TYPE_AM)
+ 	region = s->a_region;
+     else
+ 	region = s->c_region;
+-    
++
+     while (region) {
+ 	if (region->info.CardOffset == req->CardOffset) break;
+ 	region = region->info.next;
+@@ -973,7 +980,7 @@
+     if (!region || (region->mtd != NULL))
+ 	return CS_BAD_OFFSET;
+     strncpy(region->dev_info, (char *)req->dev_info, DEV_NAME_LEN);
+-    
++
+     DEBUG(1, "cs: bind_mtd(): attr 0x%x, offset 0x%x, dev %s\n",
+ 	  req->Attributes, req->CardOffset, (char *)req->dev_info);
+     return CS_SUCCESS;
+@@ -988,7 +995,7 @@
+     memory_handle_t region;
+     u_long flags;
+     int i, sn;
+-    
++
+     DEBUG(1, "cs: deregister_client(%p)\n", handle);
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+@@ -1007,7 +1014,7 @@
+ 	for (region = s->c_region; region; region = region->info.next)
+ 	    if (region->mtd == handle) region->mtd = NULL;
+     }
+-    
++
+     sn = handle->Socket; s = socket_table[sn];
+ 
+     if ((handle->state & CLIENT_STALE) ||
+@@ -1032,7 +1039,7 @@
+ 
+     if (--s->real_clients == 0)
+         register_callback(s, NULL, NULL);
+-    
++
+     return CS_SUCCESS;
+ } /* deregister_client */
+ 
+@@ -1043,7 +1050,7 @@
+ {
+     socket_info_t *s;
+     config_t *c;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     s = SOCKET(handle);
+@@ -1055,7 +1062,7 @@
+ 	    return CS_BAD_ARGS;
+     } else
+ 	config->Function = handle->Function;
+-    
++
+ #ifdef CONFIG_CARDBUS
+     if (s->state & SOCKET_CARDBUS) {
+ 	u_char fn = config->Function;
+@@ -1076,16 +1083,16 @@
+ 	return CS_SUCCESS;
+     }
+ #endif
+-    
++
+     c = (s->config != NULL) ? &s->config[config->Function] : NULL;
+-    
++
+     if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+ 	config->Attributes = 0;
+ 	config->Vcc = s->socket.Vcc;
+ 	config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+ 	return CS_SUCCESS;
+     }
+-    
++
+     /* !!! This is a hack !!! */
+     memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
+     config->Attributes |= CONF_VALID_CLIENT;
+@@ -1099,14 +1106,14 @@
+     config->NumPorts2 = c->io.NumPorts2;
+     config->Attributes2 = c->io.Attributes2;
+     config->IOAddrLines = c->io.IOAddrLines;
+-    
++
+     return CS_SUCCESS;
+ } /* get_configuration_info */
+ 
+ /*======================================================================
+ 
+     Return information about this version of Card Services.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_get_card_services_info(servinfo_t *info)
+@@ -1124,7 +1131,7 @@
+ 
+     Note that get_first_client() *does* recognize the Socket field
+     in the request structure.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_get_first_client(client_handle_t *handle, client_req_t *req)
+@@ -1239,7 +1246,7 @@
+ 
+     Get the current socket state bits.  We don't support the latched
+     SocketState yet: I haven't seen any point for it.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
+@@ -1247,7 +1254,7 @@
+     socket_info_t *s;
+     config_t *c;
+     int val;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     s = SOCKET(handle);
+@@ -1263,7 +1270,7 @@
+ 	return CS_NO_CARD;
+     if (s->state & SOCKET_SETUP_PENDING)
+ 	status->CardState |= CS_EVENT_CARD_INSERTION;
+-    
++
+     /* Get info from the PRR, if necessary */
+     if (handle->Function == BIND_FN_ALL) {
+ 	if (status->Function && (status->Function >= s->functions))
+@@ -1309,7 +1316,7 @@
+ /*======================================================================
+ 
+     Change the card address of an already open memory window.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
+@@ -1338,7 +1345,7 @@
+ /*======================================================================
+ 
+     Modify a locked socket configuration
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_modify_configuration(client_handle_t handle,
+@@ -1346,7 +1353,7 @@
+ {
+     socket_info_t *s;
+     config_t *c;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     s = SOCKET(handle); c = CONFIG(handle);
+@@ -1354,7 +1361,7 @@
+ 	return CS_NO_CARD;
+     if (!(c->state & CONFIG_LOCKED))
+ 	return CS_CONFIGURATION_LOCKED;
+-    
++
+     if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+ 	if (mod->Attributes & CONF_ENABLE_IRQ) {
+ 	    c->Attributes |= CONF_ENABLE_IRQ;
+@@ -1406,7 +1413,7 @@
+ 	win->ctl.flags |= MAP_USE_WAIT;
+     win->ctl.speed = req->AccessSpeed;
+     set_mem_map(win->sock, &win->ctl);
+-    
++
+     return CS_SUCCESS;
+ } /* modify_window */
+ 
+@@ -1416,7 +1423,7 @@
+     caller with a socket.  The driver must have already been bound
+     to a socket with bind_device() -- in fact, bind_device()
+     allocates the client structure that will be used.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
+@@ -1424,7 +1431,7 @@
+     client_t *client;
+     socket_info_t *s;
+     socket_t ns;
+-    
++
+     /* Look for unbound client with matching dev_info */
+     client = NULL;
+     for (ns = 0; ns < sockets; ns++) {
+@@ -1464,7 +1471,7 @@
+ 
+     if (s->state & SOCKET_CARDBUS)
+ 	client->state |= CLIENT_CARDBUS;
+-    
++
+     if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
+ 	(client->Function != BIND_FN_ALL)) {
+ 	cistpl_longlink_mfc_t mfc;
+@@ -1479,7 +1486,7 @@
+ 		return CS_OUT_OF_RESOURCE;
+ 	memset(s->config, 0, sizeof(config_t) * s->functions);
+     }
+-    
++
+     DEBUG(1, "cs: register_client(): client 0x%p, sock %d, dev %s\n",
+ 	  client, client->Socket, client->dev_info);
+     if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
+@@ -1501,13 +1508,13 @@
+     pccard_io_map io = { 0, 0, 0, 0, 1 };
+     socket_info_t *s;
+     int i;
+-    
++
+     if (CHECK_HANDLE(handle) ||
+ 	!(handle->state & CLIENT_CONFIG_LOCKED))
+ 	return CS_BAD_HANDLE;
+     handle->state &= ~CLIENT_CONFIG_LOCKED;
+     s = SOCKET(handle);
+-    
++
+ #ifdef CONFIG_CARDBUS
+     if (handle->state & CLIENT_CARDBUS) {
+ 	cb_disable(s);
+@@ -1515,7 +1522,7 @@
+ 	return CS_SUCCESS;
+     }
+ #endif
+-    
++
+     if (!(handle->state & CLIENT_STALE)) {
+ 	config_t *c = CONFIG(handle);
+ 	if (--(s->lock_count) == 0) {
+@@ -1536,7 +1543,7 @@
+ 	    }
+ 	c->state &= ~CONFIG_LOCKED;
+     }
+-    
++
+     return CS_SUCCESS;
+ } /* release_configuration */
+ 
+@@ -1547,25 +1554,25 @@
+     the actual socket configuration, so if the client is "stale", we
+     don't bother checking the port ranges against the current socket
+     values.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_release_io(client_handle_t handle, io_req_t *req)
+ {
+     socket_info_t *s;
+-    
++
+     if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
+ 	return CS_BAD_HANDLE;
+     handle->state &= ~CLIENT_IO_REQ;
+     s = SOCKET(handle);
+-    
++
+ #ifdef CONFIG_CARDBUS
+     if (handle->state & CLIENT_CARDBUS) {
+ 	cb_release(s);
+ 	return CS_SUCCESS;
+     }
+ #endif
+-    
++
+     if (!(handle->state & CLIENT_STALE)) {
+ 	config_t *c = CONFIG(handle);
+ 	if (c->state & CONFIG_LOCKED)
+@@ -1581,7 +1588,7 @@
+     release_io_space(s, req->BasePort1, req->NumPorts1);
+     if (req->NumPorts2)
+ 	release_io_space(s, req->BasePort2, req->NumPorts2);
+-    
++
+     return CS_SUCCESS;
+ } /* release_io */
+ 
+@@ -1594,7 +1601,7 @@
+ 	return CS_BAD_HANDLE;
+     handle->state &= ~CLIENT_IRQ_REQ;
+     s = SOCKET(handle);
+-    
++
+     if (!(handle->state & CLIENT_STALE)) {
+ 	config_t *c = CONFIG(handle);
+ 	if (c->state & CONFIG_LOCKED)
+@@ -1608,16 +1615,16 @@
+ 	    s->irq.AssignedIRQ = 0;
+ 	}
+     }
+-    
++
+     if (req->Attributes & IRQ_HANDLE_PRESENT) {
+ 	bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance);
+     }
+ 
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+     if (req->AssignedIRQ != s->cap.pci_irq)
+ 	undo_irq(req->Attributes, req->AssignedIRQ);
+ #endif
+-    
++
+     return CS_SUCCESS;
+ } /* cs_release_irq */
+ 
+@@ -1626,7 +1633,7 @@
+ int pcmcia_release_window(window_handle_t win)
+ {
+     socket_info_t *s;
+-    
++
+     if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ 	return CS_BAD_HANDLE;
+     s = win->sock;
+@@ -1640,11 +1647,11 @@
+ 
+     /* Release system memory */
+     if(!(s->cap.features & SS_CAP_STATIC_MAP))
+-	release_mem_region(win->base, win->size);
++	release_mem_resource(win->base, win->size);
+     win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+ 
+     win->magic = 0;
+-    
++
+     return CS_SUCCESS;
+ } /* release_window */
+ 
+@@ -1658,13 +1665,13 @@
+     socket_info_t *s;
+     config_t *c;
+     pccard_io_map iomap;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     i = handle->Socket; s = socket_table[i];
+     if (!(s->state & SOCKET_PRESENT))
+ 	return CS_NO_CARD;
+-    
++
+ #ifdef CONFIG_CARDBUS
+     if (handle->state & CLIENT_CARDBUS) {
+ 	if (!(req->IntType & INT_CARDBUS))
+@@ -1677,7 +1684,7 @@
+ 	return CS_SUCCESS;
+     }
+ #endif
+-    
++
+     if (req->IntType & INT_CARDBUS)
+ 	return CS_UNSUPPORTED_MODE;
+     c = CONFIG(handle);
+@@ -1692,9 +1699,9 @@
+     s->socket.Vpp = req->Vpp1;
+     if (set_socket(s, &s->socket))
+ 	return CS_BAD_VPP;
+-    
++
+     c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
+-    
++
+     /* Pick memory or I/O card, DMA mode, interrupt */
+     c->IntType = req->IntType;
+     c->Attributes = req->Attributes;
+@@ -1712,7 +1719,7 @@
+ 	s->socket.io_irq = 0;
+     set_socket(s, &s->socket);
+     s->lock_count++;
+-    
++
+     /* Set up CIS configuration registers */
+     base = c->ConfigBase = req->ConfigBase;
+     c->Present = c->CardValues = req->Present;
+@@ -1757,7 +1764,7 @@
+ 	u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+ 	write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
+     }
+-    
++
+     /* Configure I/O windows */
+     if (c->state & CONFIG_IO_REQ) {
+ 	iomap.speed = io_speed;
+@@ -1779,24 +1786,24 @@
+ 		s->io[i].Config++;
+ 	    }
+     }
+-    
++
+     c->state |= CONFIG_LOCKED;
+     handle->state |= CLIENT_CONFIG_LOCKED;
+     return CS_SUCCESS;
+ } /* request_configuration */
+ 
+ /*======================================================================
+-  
++
+     Request_io() reserves ranges of port addresses for a socket.
+     I have not implemented range sharing or alias addressing.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_request_io(client_handle_t handle, io_req_t *req)
+ {
+     socket_info_t *s;
+     config_t *c;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     s = SOCKET(handle);
+@@ -1855,7 +1862,7 @@
+     hooked, we don't guarantee that an irq will still be available
+     when the configuration is locked.  Now that I think about it,
+     there might be a way to fix this using a dummy handler.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
+@@ -1863,7 +1870,7 @@
+     socket_info_t *s;
+     config_t *c;
+     int ret = CS_IN_USE, irq = 0;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     s = SOCKET(handle);
+@@ -1875,7 +1882,7 @@
+     if (c->state & CONFIG_IRQ_REQ)
+ 	return CS_IN_USE;
+ 
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+     if (s->irq.AssignedIRQ != 0) {
+ 	/* If the interrupt is already assigned, it must match */
+ 	irq = s->irq.AssignedIRQ;
+@@ -1909,7 +1916,7 @@
+ 
+     if (req->Attributes & IRQ_HANDLE_PRESENT) {
+ 	if (bus_request_irq(s->cap.bus, irq, req->Handler,
+-			    ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || 
++			    ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+ 			     (s->functions > 1) ||
+ 			     (irq == s->cap.pci_irq)) ? SA_SHIRQ : 0,
+ 			    handle->dev_info, req->Instance))
+@@ -1919,7 +1926,7 @@
+     c->irq.Attributes = req->Attributes;
+     s->irq.AssignedIRQ = req->AssignedIRQ = irq;
+     s->irq.Config++;
+-    
++
+     c->state |= CONFIG_IRQ_REQ;
+     handle->state |= CLIENT_IRQ_REQ;
+     return CS_SUCCESS;
+@@ -1938,7 +1945,7 @@
+     window_t *win;
+     u_long align;
+     int w;
+-    
++
+     if (CHECK_HANDLE(*handle))
+ 	return CS_BAD_HANDLE;
+     s = SOCKET(*handle);
+@@ -2005,7 +2012,7 @@
+     /* Return window handle */
+     req->Base = win->ctl.sys_start;
+     *wh = win;
+-    
++
+     return CS_SUCCESS;
+ } /* request_window */
+ 
+@@ -2014,14 +2021,14 @@
+     I'm not sure which "reset" function this is supposed to use,
+     but for now, it uses the low-level interface's reset, not the
+     CIS register.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
+ {
+     int i, ret;
+     socket_info_t *s;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     i = handle->Socket; s = socket_table[i];
+@@ -2049,14 +2056,14 @@
+ 
+     These shut down or wake up a socket.  They are sort of user
+     initiated versions of the APM suspend and resume actions.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
+ {
+     int i;
+     socket_info_t *s;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     i = handle->Socket; s = socket_table[i];
+@@ -2077,7 +2084,7 @@
+ {
+     int i;
+     socket_info_t *s;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     i = handle->Socket; s = socket_table[i];
+@@ -2095,7 +2102,7 @@
+ /*======================================================================
+ 
+     These handle user requests to eject or insert a card.
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_eject_card(client_handle_t handle, client_req_t *req)
+@@ -2103,7 +2110,7 @@
+     int i, ret;
+     socket_info_t *s;
+     u_long flags;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     i = handle->Socket; s = socket_table[i];
+@@ -2119,9 +2126,9 @@
+     spin_lock_irqsave(&s->lock, flags);
+     do_shutdown(s);
+     spin_unlock_irqrestore(&s->lock, flags);
+-    
++
+     return CS_SUCCESS;
+-    
++
+ } /* eject_card */
+ 
+ int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
+@@ -2129,7 +2136,7 @@
+     int i, status;
+     socket_info_t *s;
+     u_long flags;
+-    
++
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+     i = handle->Socket; s = socket_table[i];
+@@ -2157,7 +2164,7 @@
+ 
+     Maybe this should send a CS_EVENT_CARD_INSERTION event if we
+     haven't sent one to this client yet?
+-    
++
+ ======================================================================*/
+ 
+ int pcmcia_set_event_mask(client_handle_t handle, eventmask_t *mask)
+@@ -2189,7 +2196,7 @@
+ 	printk(KERN_NOTICE);
+     else
+ 	printk(KERN_NOTICE "%s: ", handle->dev_info);
+-    
++
+     for (i = 0; i < SERVICE_COUNT; i++)
+ 	if (service_table[i].key == err->func) break;
+     if (i < SERVICE_COUNT)
+@@ -2347,13 +2354,13 @@
+     default:
+ 	return CS_UNSUPPORTED_FUNCTION; break;
+     }
+-    
++
+ } /* CardServices */
+ 
+ /*======================================================================
+ 
+     OS-specific module glue goes here
+-    
++
+ ======================================================================*/
+ /* in alpha order */
+ EXPORT_SYMBOL(pcmcia_access_configuration_register);
+@@ -2450,4 +2457,3 @@
+ module_exit(exit_pcmcia_cs);
+ 
+ /*====================================================================*/
+-
+--- linux-2.4.25/drivers/pcmcia/ds.c~2.4.25-vrs2.patch	2001-11-12 18:39:01.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/ds.c	2004-03-31 17:15:09.000000000 +0200
+@@ -55,6 +55,7 @@
+ #include <pcmcia/bulkmem.h>
+ #include <pcmcia/cistpl.h>
+ #include <pcmcia/ds.h>
++#include <linux/devfs_fs_kernel.h>
+ 
+ /*====================================================================*/
+ 
+@@ -880,6 +881,8 @@
+ EXPORT_SYMBOL(register_pccard_driver);
+ EXPORT_SYMBOL(unregister_pccard_driver);
+ 
++static devfs_handle_t devfs_handle;
++
+ /*====================================================================*/
+ 
+ int __init init_pcmcia_ds(void)
+@@ -957,8 +960,13 @@
+     if (i == -EBUSY)
+ 	printk(KERN_NOTICE "unable to find a free device # for "
+ 	       "Driver Services\n");
+-    else
++    else {
+ 	major_dev = i;
++	devfs_handle = devfs_register(NULL, "pcmcia", DEVFS_FL_DEFAULT,
++				      major_dev, 0,
++				      S_IFCHR | S_IRUSR | S_IWUSR,
++				      &ds_fops, NULL);
++    }
+ 
+ #ifdef CONFIG_PROC_FS
+     if (proc_pccard)
+@@ -983,7 +991,9 @@
+ 	remove_proc_entry("drivers", proc_pccard);
+ #endif
+     if (major_dev != -1)
+-	unregister_chrdev(major_dev, "pcmcia");
++	devfs_unregister_chrdev(major_dev, "pcmcia");
++	devfs_unregister(devfs_handle);
++
+     for (i = 0; i < sockets; i++)
+ 	pcmcia_deregister_client(socket_table[i].handle);
+     sockets = 0;
+--- linux-2.4.25/drivers/pcmcia/i82365.c~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/i82365.c	2004-03-31 17:15:09.000000000 +0200
+@@ -28,7 +28,7 @@
+     and other provisions required by the GPL.  If you do not delete
+     the provisions above, a recipient may use your version of this
+     file under either the MPL or the GPL.
+-    
++
+ ======================================================================*/
+ 
+ #include <linux/module.h>
+@@ -65,6 +65,15 @@
+ #include "ricoh.h"
+ #include "o2micro.h"
+ 
++#ifdef CONFIG_ARCH_EBSA110
++#define I365_MASK		(1 << 6)
++#define SOCKIRQ2REG(sock,irq)	((irq) ? ((sock) ? 3 : 4) : 0)
++#define REG2SOCKIRQ(sock,reg)	(6)
++#else
++#define SOCKIRQ2REG(sock,irq)	(irq)
++#define REG2SOCKIRQ(sock,reg)	(reg)
++#endif
++
+ #ifdef PCMCIA_DEBUG
+ static int pc_debug = PCMCIA_DEBUG;
+ MODULE_PARM(pc_debug, "i");
+@@ -173,13 +182,15 @@
+ } socket_info_t;
+ 
+ /* Where we keep track of our sockets... */
+-static int sockets = 0;
+-static socket_info_t socket[8] = {
+-    { 0, }, /* ... */
+-};
++static int sockets /* = 0 */;
++static socket_info_t socket[8] /* = {
++    { 0, },
++} */;
+ 
+ /* Default ISA interrupt mask */
++#ifndef I365_MASK
+ #define I365_MASK	0xdeb8	/* irq 15,14,12,11,10,9,7,5,4,3 */
++#endif
+ 
+ static int grab_irq;
+ static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED;
+@@ -303,7 +314,7 @@
+ 
+     The VIA controllers also use these routines, as they are mostly
+     Cirrus lookalikes, without the timing registers.
+-    
++
+ ======================================================================*/
+ 
+ #define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
+@@ -389,7 +400,7 @@
+     Code to save and restore global state information for Vadem VG468
+     and VG469 controllers, and to set and report global configuration
+     options.
+-    
++
+ ======================================================================*/
+ 
+ static void vg46x_get_state(u_short s)
+@@ -411,7 +422,7 @@
+ static u_int __init vg46x_set_opts(u_short s, char *buf)
+ {
+     vg46x_state_t *p = &socket[s].state.vg46x;
+-    
++
+     flip(p->ctl, VG468_CTL_ASYNC, async_clock);
+     flip(p->ema, VG469_MODE_CABLE, cable_mode);
+     if (p->ctl & VG468_CTL_ASYNC)
+@@ -436,7 +447,7 @@
+ /*======================================================================
+ 
+     Generic routines to get and set controller options
+-    
++
+ ======================================================================*/
+ 
+ static void get_bridge_state(u_short s)
+@@ -489,7 +500,7 @@
+ /*======================================================================
+ 
+     Interrupt testing code, for ISA and PCI interrupts
+-    
++
+ ======================================================================*/
+ 
+ static volatile u_int irq_hits;
+@@ -517,7 +528,7 @@
+     }
+ 
+     /* Generate one interrupt */
+-    i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (irq << 4));
++    i365_set(sock, I365_CSCINT, I365_CSC_DETECT | (SOCKIRQ2REG(sock, irq) << 4));
+     i365_bset(sock, I365_GENCTL, I365_CTL_SW_IRQ);
+     udelay(1000);
+ 
+@@ -526,7 +537,7 @@
+     /* mask all interrupts */
+     i365_set(sock, I365_CSCINT, 0);
+     DEBUG(2, "    hits = %d\n", irq_hits);
+-    
++
+     return (irq_hits != 1);
+ }
+ 
+@@ -540,7 +551,7 @@
+     /* Don't probe level-triggered interrupts -- reserved for PCI */
+     mask0 &= ~(inb(PIC) | (inb(PIC+1) << 8));
+ #endif
+-    
++
+     if (do_scan) {
+ 	set_bridge_state(sock);
+ 	i365_set(sock, I365_CSCINT, 0);
+@@ -551,7 +562,7 @@
+ 	    if ((mask1 & (1 << i)) && (test_irq(sock, i) != 0))
+ 		mask1 ^= (1 << i);
+     }
+-    
++
+     printk(KERN_INFO "    ISA irqs (");
+     if (mask1) {
+ 	printk("scanned");
+@@ -565,12 +576,12 @@
+ 	if (!cs_irq && (poll_interval == 0)) poll_interval = HZ;
+     }
+     printk(") = ");
+-    
++
+     for (i = 0; i < 16; i++)
+ 	if (mask1 & (1<<i))
+ 	    printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
+     if (mask1 == 0) printk("none!");
+-    
++
+     return mask1;
+ }
+ 
+@@ -598,14 +609,14 @@
+     /* Use the next free entry in the socket table */
+     socket[sockets].ioaddr = port;
+     socket[sockets].psock = sock;
+-    
++
+     /* Wake up a sleepy Cirrus controller */
+     if (wakeup) {
+ 	i365_bclr(sockets, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
+ 	/* Pause at least 50 ms */
+ 	mdelay(50);
+     }
+-    
++
+     if ((val = i365_get(sockets, I365_IDENT)) & 0x70)
+ 	return -1;
+     switch (val) {
+@@ -618,7 +629,7 @@
+     case 0x88: case 0x89: case 0x8a:
+ 	type = IS_IBM; break;
+     }
+-    
++
+     /* Check for Vadem VG-468 chips */
+     outb(0x0e, port);
+     outb(0x37, port);
+@@ -633,7 +644,7 @@
+     val = i365_get(sockets, RF5C_CHIP_ID);
+     if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
+ 	type = IS_RF5Cx96;
+-    
++
+     /* Check for Cirrus CL-PD67xx chips */
+     i365_set(sockets, PD67_CHIP_INFO, 0);
+     val = i365_get(sockets, PD67_CHIP_INFO);
+@@ -655,14 +666,14 @@
+     bound to a (non PC Card) Linux driver.  We leave these alone.
+ 
+     We make an exception for cards that seem to be serial devices.
+-    
++
+ ======================================================================*/
+ 
+ static int __init is_alive(u_short sock)
+ {
+     u_char stat;
+     u_short start, stop;
+-    
++
+     stat = i365_get(sock, I365_STATUS);
+     start = i365_get_pair(sock, I365_IO(0)+I365_W_START);
+     stop = i365_get_pair(sock, I365_IO(0)+I365_W_STOP);
+@@ -697,7 +708,7 @@
+ 
+     base = sockets-ns;
+     if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365");
+-    
++
+     if (base == 0) printk("\n");
+     printk(KERN_INFO "  %s", pcic[type].name);
+     printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x",
+@@ -713,7 +724,7 @@
+     mask &= I365_MASK & set_bridge_opts(base, ns);
+     /* Scan for ISA interrupts */
+     mask = isa_scan(base, mask);
+-        
++
+     /* Poll if only two interrupts available */
+     if (!poll_interval) {
+ 	u_int tmp = (mask & 0xff20);
+@@ -735,15 +746,15 @@
+ 	    printk(" status change on irq %d\n", cs_irq);
+ 	}
+     }
+-    
++
+     if (!isa_irq) {
+ 	if (poll_interval == 0)
+ 	    poll_interval = HZ;
+ 	printk(" polling interval = %d ms\n",
+ 	       poll_interval * 1000 / HZ);
+-	
++
+     }
+-    
++
+     /* Update socket interrupt information, capabilities */
+     for (i = 0; i < ns; i++) {
+ 	t[i].cap.features |= SS_CAP_PCCARD;
+@@ -866,12 +877,12 @@
+ 		events = pending_events[i];
+ 		pending_events[i] = 0;
+ 		spin_unlock_irq(&pending_event_lock);
+-		/* 
+-		SS_DETECT events need a small delay here. The reason for this is that 
++		/*
++		SS_DETECT events need a small delay here. The reason for this is that
+ 		the "is there a card" electronics need time to see the card after the
+-		"we have a card coming in" electronics have seen it. 
++		"we have a card coming in" electronics have seen it.
+ 		*/
+-		if (events & SS_DETECT) 
++		if (events & SS_DETECT)
+ 			mdelay(4);
+ 		if (socket[i].handler)
+ 			socket[i].handler(socket[i].info, events);
+@@ -890,7 +901,7 @@
+     int i, j, csc;
+     u_int events, active;
+     u_long flags = 0;
+-    
++
+     DEBUG(4, "i82365: pcic_interrupt(%d)\n", irq);
+ 
+     for (j = 0; j < 20; j++) {
+@@ -906,20 +917,20 @@
+ 		continue;
+ 	    }
+ 	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+-	    
+-	    
++
++
+ 	    /* Several sockets will send multiple "new card detected"
+-	       events in rapid succession. However, the rest of the pcmcia expects 
++	       events in rapid succession. However, the rest of the pcmcia expects
+ 	       only one such event. We just ignore these events by having a
+                timeout */
+ 
+ 	    if (events) {
+-	    	if ((jiffies - last_detect_jiffies)<(HZ/20)) 
++	    	if ((jiffies - last_detect_jiffies)<(HZ/20))
+ 	    		events = 0;
+ 	    	last_detect_jiffies = jiffies;
+-	    	
++
+ 	    }
+-	
++
+ 	    if (i365_get(i, I365_INTCTL) & I365_PC_IOCARD)
+ 		events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+ 	    else {
+@@ -980,11 +991,11 @@
+ static int i365_get_status(u_short sock, u_int *value)
+ {
+     u_int status;
+-    
++
+     status = i365_get(sock, I365_STATUS);
+     *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
+ 	? SS_DETECT : 0;
+-	
++
+     if (i365_get(sock, I365_INTCTL) & I365_PC_IOCARD)
+ 	*value |= (status & I365_CS_STSCHG) ? 0 : SS_STSCHG;
+     else {
+@@ -1005,7 +1016,7 @@
+ 	    *value |= (status & VG469_VSENSE_A_VS2) ? 0 : SS_XVCARD;
+ 	}
+     }
+-    
++
+     DEBUG(1, "i82365: GetStatus(%d) = %#4.4x\n", sock, *value);
+     return 0;
+ } /* i365_get_status */
+@@ -1016,7 +1027,7 @@
+ {
+     socket_info_t *t = &socket[sock];
+     u_char reg, vcc, vpp;
+-    
++
+     reg = i365_get(sock, I365_POWER);
+     state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0;
+     state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0;
+@@ -1057,14 +1068,14 @@
+     reg = i365_get(sock, I365_INTCTL);
+     state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET;
+     if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD;
+-    state->io_irq = reg & I365_IRQ_MASK;
+-    
++    state->io_irq = REG2SOCKIRQ(sock, reg & I365_IRQ_MASK);
++
+     /* speaker control */
+     if (t->flags & IS_CIRRUS) {
+ 	if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA)
+ 	    state->flags |= SS_SPKR_ENA;
+     }
+-    
++
+     /* Card status change mask */
+     reg = i365_get(sock, I365_CSCINT);
+     state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0;
+@@ -1075,7 +1086,7 @@
+ 	state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0;
+ 	state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0;
+     }
+-    
++
+     DEBUG(1, "i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+ 	  "io_irq %d, csc_mask %#2.2x\n", sock, state->flags,
+ 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+@@ -1088,21 +1099,21 @@
+ {
+     socket_info_t *t = &socket[sock];
+     u_char reg;
+-    
++
+     DEBUG(1, "i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+ 	  "io_irq %d, csc_mask %#2.2x)\n", sock, state->flags,
+ 	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+-    
++
+     /* First set global controller options */
+     set_bridge_state(sock);
+-    
++
+     /* IO card, RESET flag, IO interrupt */
+     reg = t->intr;
+-    reg |= state->io_irq;
++    reg |= SOCKIRQ2REG(sock, state->io_irq);
+     reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+     reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+     i365_set(sock, I365_INTCTL, reg);
+-    
++
+     reg = I365_PWR_NORESET;
+     if (state->flags & SS_PWR_AUTO) reg |= I365_PWR_AUTO;
+     if (state->flags & SS_OUTPUT_ENA) reg |= I365_PWR_OUT;
+@@ -1165,7 +1176,7 @@
+ 	default:	return -EINVAL;
+ 	}
+     }
+-    
++
+     if (reg != i365_get(sock, I365_POWER))
+ 	i365_set(sock, I365_POWER, reg);
+ 
+@@ -1175,9 +1186,9 @@
+ 	i365_bflip(sock, PD67_MISC_CTL_1, PD67_MC1_SPKR_ENA,
+ 		   state->flags & SS_SPKR_ENA);
+     }
+-    
++
+     /* Card status change interrupt mask */
+-    reg = t->cs_irq << 4;
++    reg = SOCKIRQ2REG(sock, t->cs_irq) << 4;
+     if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+     if (state->flags & SS_IOCARD) {
+ 	if (state->csc_mask & SS_STSCHG) reg |= I365_CSC_STSCHG;
+@@ -1188,7 +1199,7 @@
+     }
+     i365_set(sock, I365_CSCINT, reg);
+     i365_get(sock, I365_CSC);
+-    
++
+     return 0;
+ } /* i365_set_socket */
+ 
+@@ -1197,7 +1208,7 @@
+ static int i365_get_io_map(u_short sock, struct pccard_io_map *io)
+ {
+     u_char map, ioctl, addr;
+-    
++
+     map = io->map;
+     if (map > 1) return -EINVAL;
+     io->start = i365_get_pair(sock, I365_IO(map)+I365_W_START);
+@@ -1220,7 +1231,7 @@
+ static int i365_set_io_map(u_short sock, struct pccard_io_map *io)
+ {
+     u_char map, ioctl;
+-    
++
+     DEBUG(1, "i82365: SetIOMap(%d, %d, %#2.2x, %d ns, "
+ 	  "%#4.4x-%#4.4x)\n", sock, io->map, io->flags,
+ 	  io->speed, io->start, io->stop);
+@@ -1250,30 +1261,30 @@
+ {
+     u_short base, i;
+     u_char map, addr;
+-    
++
+     map = mem->map;
+     if (map > 4) return -EINVAL;
+     addr = i365_get(sock, I365_ADDRWIN);
+     mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0;
+     base = I365_MEM(map);
+-    
++
+     i = i365_get_pair(sock, base+I365_W_START);
+     mem->flags |= (i & I365_MEM_16BIT) ? MAP_16BIT : 0;
+     mem->flags |= (i & I365_MEM_0WS) ? MAP_0WS : 0;
+     mem->sys_start = ((u_long)(i & 0x0fff) << 12);
+-    
++
+     i = i365_get_pair(sock, base+I365_W_STOP);
+     mem->speed  = (i & I365_MEM_WS0) ? 1 : 0;
+     mem->speed += (i & I365_MEM_WS1) ? 2 : 0;
+     mem->speed = to_ns(mem->speed);
+     mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff;
+-    
++
+     i = i365_get_pair(sock, base+I365_W_OFF);
+     mem->flags |= (i & I365_MEM_WRPROT) ? MAP_WRPROT : 0;
+     mem->flags |= (i & I365_MEM_REG) ? MAP_ATTRIB : 0;
+     mem->card_start = ((u_int)(i & 0x3fff) << 12) + mem->sys_start;
+     mem->card_start &= 0x3ffffff;
+-    
++
+     DEBUG(1, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
+ 	  "5lx, %#5.5x\n", sock, mem->map, mem->flags, mem->speed,
+ 	  mem->sys_start, mem->sys_stop, mem->card_start);
+@@ -1281,12 +1292,12 @@
+ } /* i365_get_mem_map */
+ 
+ /*====================================================================*/
+-  
++
+ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
+ {
+     u_short base, i;
+     u_char map;
+-    
++
+     DEBUG(1, "i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+ 	  "lx, %#5.5x)\n", sock, mem->map, mem->flags, mem->speed,
+ 	  mem->sys_start, mem->sys_stop, mem->card_start);
+@@ -1297,17 +1308,17 @@
+ 	return -EINVAL;
+     if ((mem->sys_start > 0xffffff) || (mem->sys_stop > 0xffffff))
+ 	return -EINVAL;
+-	
++
+     /* Turn off the window before changing anything */
+     if (i365_get(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
+ 	i365_bclr(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+-    
++
+     base = I365_MEM(map);
+     i = (mem->sys_start >> 12) & 0x0fff;
+     if (mem->flags & MAP_16BIT) i |= I365_MEM_16BIT;
+     if (mem->flags & MAP_0WS) i |= I365_MEM_0WS;
+     i365_set_pair(sock, base+I365_W_START, i);
+-    
++
+     i = (mem->sys_stop >> 12) & 0x0fff;
+     switch (to_cycles(mem->speed)) {
+     case 0:	break;
+@@ -1316,12 +1327,12 @@
+     default:	i |= I365_MEM_WS1 | I365_MEM_WS0; break;
+     }
+     i365_set_pair(sock, base+I365_W_STOP, i);
+-    
++
+     i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+     if (mem->flags & MAP_WRPROT) i |= I365_MEM_WRPROT;
+     if (mem->flags & MAP_ATTRIB) i |= I365_MEM_REG;
+     i365_set_pair(sock, base+I365_W_OFF, i);
+-    
++
+     /* Turn on the window if necessary */
+     if (mem->flags & MAP_ACTIVE)
+ 	i365_bset(sock, I365_ADDRWIN, I365_ENA_MEM(map));
+@@ -1332,7 +1343,7 @@
+ 
+     Routines for accessing socket information and register dumps via
+     /proc/bus/pccard/...
+-    
++
+ ======================================================================*/
+ 
+ #ifdef CONFIG_PROC_FS
+@@ -1353,7 +1364,7 @@
+     u_short sock = (socket_info_t *)data - socket;
+     char *p = buf;
+     int i, top;
+-    
++
+     u_long flags = 0;
+     ISA_LOCK(sock, flags);
+     top = 0x40;
+@@ -1399,7 +1410,7 @@
+ 
+ /*====================================================================*/
+ 
+-/* this is horribly ugly... proper locking needs to be done here at 
++/* this is horribly ugly... proper locking needs to be done here at
+  * some time... */
+ #define LOCKED(x) do { \
+ 	int retval; \
+@@ -1532,7 +1543,7 @@
+     /* Set up interrupt handler(s) */
+     if (grab_irq != 0)
+ 	request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt);
+-    
++
+     if (register_ss_entry(sockets, &pcic_operations) != 0)
+ 	printk(KERN_NOTICE "i82365: register_ss_entry() failed\n");
+ 
+@@ -1544,9 +1555,9 @@
+     	poll_timer.expires = jiffies + poll_interval;
+ 	add_timer(&poll_timer);
+     }
+-    
++
+     return 0;
+-    
++
+ } /* init_i82365 */
+ 
+ static void __exit exit_i82365(void)
+--- linux-2.4.25/drivers/pcmcia/rsrc_mgr.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/rsrc_mgr.c	2004-03-31 17:15:09.000000000 +0200
+@@ -28,7 +28,7 @@
+     and other provisions required by the GPL.  If you do not delete
+     the provisions above, a recipient may use your version of this
+     file under either the MPL or the GPL.
+-    
++
+ ======================================================================*/
+ 
+ #define __NO_VERSION__
+@@ -55,6 +55,10 @@
+ #include <pcmcia/cistpl.h>
+ #include "cs_internal.h"
+ 
++#ifndef ISAMEM_PHYS
++#define ISAMEM_PHYS 0
++#endif
++
+ /*====================================================================*/
+ 
+ /* Parameters that can be set with 'insmod' */
+@@ -62,7 +66,7 @@
+ #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+ 
+ INT_MODULE_PARM(probe_mem,	1);		/* memory probe? */
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+ INT_MODULE_PARM(probe_io,	1);		/* IO port probe? */
+ INT_MODULE_PARM(mem_limit,	0x10000);
+ #endif
+@@ -85,7 +89,7 @@
+ /* IO port resource database */
+ static resource_map_t io_db = { 0, 0, &io_db };
+ 
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+ 
+ typedef struct irq_info_t {
+     u_int			Attributes;
+@@ -133,6 +137,7 @@
+ static inline int check_mem_resource(unsigned long b, unsigned long n,
+ 				     struct pci_dev *dev)
+ {
++	b += ISAMEM_PHYS;
+ 	return check_resource(resource_parent(b, n, IORESOURCE_MEM, dev), b, n);
+ }
+ 
+@@ -169,10 +174,15 @@
+ static int request_mem_resource(unsigned long b, unsigned long n,
+ 				char *name, struct pci_dev *dev)
+ {
+-	struct resource *res = make_resource(b, n, IORESOURCE_MEM, name);
+-	struct resource *pr = resource_parent(b, n, IORESOURCE_MEM, dev);
++	struct resource *res;
++	struct resource *pr;
+ 	int err = -ENOMEM;
+ 
++	b += ISAMEM_PHYS;
++
++	res = make_resource(b, n, IORESOURCE_MEM, name);
++	pr = resource_parent(b, n, IORESOURCE_MEM, dev);
++
+ 	if (res) {
+ 		err = request_resource(pr, res);
+ 		if (err)
+@@ -181,10 +191,16 @@
+ 	return err;
+ }
+ 
++void release_mem_resource(unsigned long b, unsigned long n)
++{
++	b += ISAMEM_PHYS;
++	release_mem_region(b, n);
++}
++
+ /*======================================================================
+ 
+     These manage the internal databases of available resources.
+-    
++
+ ======================================================================*/
+ 
+ static int add_interval(resource_map_t *map, u_long base, u_long num)
+@@ -248,25 +264,25 @@
+ 
+     These routines examine a region of IO or memory addresses to
+     determine what ranges might be genuinely available.
+-    
++
+ ======================================================================*/
+ 
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+ static void do_io_probe(ioaddr_t base, ioaddr_t num)
+ {
+-    
++
+     ioaddr_t i, j, bad, any;
+     u_char *b, hole, most;
+-    
++
+     printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:",
+ 	   base, base+num-1);
+-    
++
+     /* First, what does a floating port look like? */
+     b = kmalloc(256, GFP_KERNEL);
+     if (!b) {
+             printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes");
+             return;
+-    }   
++    }
+     memset(b, 0, 256);
+     for (i = base, most = 0; i < base+num; i += 8) {
+ 	if (check_io_resource(i, 8, NULL))
+@@ -308,7 +324,7 @@
+ 	    printk(" %#04x-%#04x", bad, i-1);
+ 	}
+     }
+-    
++
+     printk(any ? "\n" : " clean.\n");
+ }
+ #endif
+@@ -318,7 +334,7 @@
+     The memory probe.  If the memory list includes a 64K-aligned block
+     below 1MB, we probe in 64K chunks, and as soon as we accumulate at
+     least mem_limit free space, we quit.
+-    
++
+ ======================================================================*/
+ 
+ static int do_mem_probe(u_long base, u_long num,
+@@ -332,7 +348,7 @@
+     bad = fail = 0;
+     step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+     for (i = j = base; i < base+num; i = j + step) {
+-	if (!fail) {	
++	if (!fail) {
+ 	    for (j = i; j < base+num; j += step)
+ 		if ((check_mem_resource(j, step, s->cap.cb_dev) == 0) &&
+ 		    is_valid(j))
+@@ -356,7 +372,7 @@
+     return (num - bad);
+ }
+ 
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+ 
+ static u_long inv_probe(int (*is_valid)(u_long),
+ 			int (*do_cksum)(u_long),
+@@ -383,7 +399,7 @@
+     static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
+     static int hi = 0, lo = 0;
+     u_long b, i, ok = 0;
+-    
++
+     if (!probe_mem) return;
+     /* We do up to four passes through the list */
+     if (!force_low) {
+@@ -414,14 +430,14 @@
+     }
+ }
+ 
+-#else /* CONFIG_ISA */
++#else /* CONFIG_PCMCIA_PROBE */
+ 
+ void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long),
+ 		  int force_low, socket_info_t *s)
+ {
+     resource_map_t *m, *n;
+     static int done = 0;
+-    
++
+     if (!probe_mem || done++)
+ 	return;
+ 
+@@ -432,7 +448,7 @@
+     }
+ }
+ 
+-#endif /* CONFIG_ISA */
++#endif /* CONFIG_PCMCIA_PROBE */
+ 
+ /*======================================================================
+ 
+@@ -444,7 +460,7 @@
+     should be a power of two, greater than or equal to 'num'.  A value
+     of 0 means that all bits of *base are significant.  *base should
+     also be strictly less than 'align'.
+-    
++
+ ======================================================================*/
+ 
+ int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
+@@ -452,7 +468,7 @@
+ {
+     ioaddr_t try;
+     resource_map_t *m;
+-    
++
+     for (m = io_db.next; m != &io_db; m = m->next) {
+ 	try = (m->base & ~(align-1)) + *base;
+ 	for (try = (try >= m->base) ? try : try+align;
+@@ -500,10 +516,10 @@
+     This checks to see if an interrupt is available, with support
+     for interrupt sharing.  We don't support reserving interrupts
+     yet.  If the interrupt is available, we allocate it.
+-    
++
+ ======================================================================*/
+ 
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+ 
+ static void fake_irq(int i, void *d, struct pt_regs *r) { }
+ static inline int check_irq(int irq)
+@@ -570,7 +586,7 @@
+ 
+ /*====================================================================*/
+ 
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+ 
+ void undo_irq(u_int Attributes, int irq)
+ {
+@@ -600,7 +616,7 @@
+ 
+     The various adjust_* calls form the external interface to the
+     resource database.
+-    
++
+ ======================================================================*/
+ 
+ static int adjust_memory(adjust_t *adj)
+@@ -632,7 +648,7 @@
+     default:
+ 	ret = CS_UNSUPPORTED_FUNCTION;
+     }
+-    
++
+     return ret;
+ }
+ 
+@@ -641,7 +657,7 @@
+ static int adjust_io(adjust_t *adj)
+ {
+     int base, num;
+-    
++
+     base = adj->resource.io.BasePort;
+     num = adj->resource.io.NumPorts;
+     if ((base < 0) || (base > 0xffff))
+@@ -653,7 +669,7 @@
+     case ADD_MANAGED_RESOURCE:
+ 	if (add_interval(&io_db, base, num) != 0)
+ 	    return CS_IN_USE;
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+ 	if (probe_io)
+ 	    do_io_probe(base, num);
+ #endif
+@@ -673,15 +689,15 @@
+ 
+ static int adjust_irq(adjust_t *adj)
+ {
+-#ifdef CONFIG_ISA
++#ifdef CONFIG_PCMCIA_PROBE
+     int irq;
+     irq_info_t *info;
+-    
++
+     irq = adj->resource.irq.IRQ;
+     if ((irq < 0) || (irq > 15))
+ 	return CS_BAD_IRQ;
+     info = &irq_table[irq];
+-    
++
+     switch (adj->Action) {
+     case ADD_MANAGED_RESOURCE:
+ 	if (info->Attributes & RES_REMOVED)
+@@ -716,7 +732,7 @@
+ {
+     if (CHECK_HANDLE(handle))
+ 	return CS_BAD_HANDLE;
+-    
++
+     switch (adj->Resource) {
+     case RES_MEMORY_RANGE:
+ 	return adjust_memory(adj);
+@@ -736,7 +752,7 @@
+ void release_resource_db(void)
+ {
+     resource_map_t *p, *q;
+-    
++
+     for (p = mem_db.next; p != &mem_db; p = q) {
+ 	q = p->next;
+ 	kfree(p);
+--- linux-2.4.25/drivers/pcmcia/sa1100.h~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100.h	2004-03-31 17:15:09.000000000 +0200
+@@ -204,7 +204,9 @@
+ extern struct pcmcia_low_level flexanet_pcmcia_ops;
+ extern struct pcmcia_low_level simpad_pcmcia_ops;
+ extern struct pcmcia_low_level graphicsmaster_pcmcia_ops;
++extern struct pcmcia_low_level adsagc_pcmcia_ops;
+ extern struct pcmcia_low_level adsbitsy_pcmcia_ops;
++extern struct pcmcia_low_level adsbitsyplus_pcmcia_ops;
+ extern struct pcmcia_low_level stork_pcmcia_ops;
+ extern struct pcmcia_low_level badge4_pcmcia_ops;
+ 
+--- linux-2.4.25/drivers/pcmcia/sa1100_adsbitsy.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_adsbitsy.c	2004-03-31 17:15:09.000000000 +0200
+@@ -11,28 +11,156 @@
+  */
+ #include <linux/kernel.h>
+ #include <linux/sched.h>
++#include <linux/ioport.h>
+ 
+ #include <asm/hardware.h>
++#include <asm/hardware/sa1111.h>
++#include <asm/irq.h>
+ 
+ #include "sa1100_generic.h"
+ #include "sa1111_generic.h"
+ 
++int adsbitsy_smc91111_present(void);
++
++#ifndef	CONFIG_SMC91111
++#define adsbitsy_smc91111_present() 0
++#endif
++
++static struct irqs {
++	int irq;
++	const char *str;
++} irqs[] = {
++	{ S0_CD_VALID,    "SA1111 PCMCIA card detect" },
++	{ S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
++	{ S1_CD_VALID,    "SA1111 CF card detect"     },
++	{ S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
++};
++
+ static int adsbitsy_pcmcia_init(struct pcmcia_init *init)
+ {
+-  /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+-  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
++  int ret=0;
++  int nirq = 0;
++  int slots = 0;
++  int i;
+ 
+-  /* Disable Power 3.3V/5V for PCMCIA/CF */
+-  PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
++  /* Set GPIO_A<1:0> to be outputs for PCMCIA power controller: */
++  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1);
+ 
+-  /* Why? */			 
+-  MECR = 0x09430943;
++  /* Disable Power 3.3V/5V for PCMCIA */
++  PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1;
+ 
+-  return sa1111_pcmcia_init(init);
++  if (!request_mem_region(_PCCR, 512, "PCMCIA"))
++	  return -1;
++
++
++  INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) |
++             SA1111_IRQMASK_HI(S0_CD_VALID)   |
++             SA1111_IRQMASK_HI(S0_BVD1_STSCHG);
++
++  nirq = 2;
++  slots = 1;
++
++  if (!adsbitsy_smc91111_present()) {
++    /* If the SMC91111 is used CF cannot be used */
++    /* Set GPIO_A<3:2> to be outputs for CF power controller: */
++    PA_DDR &= ~(GPIO_GPIO2 | GPIO_GPIO3);
++
++    /* Disable Power 3.3V/5V for CF */
++    PA_DWR |= GPIO_GPIO2 | GPIO_GPIO3;
++
++    INTPOL1 |= SA1111_IRQMASK_HI(S1_READY_NINT) |
++               SA1111_IRQMASK_HI(S1_CD_VALID)   |
++               SA1111_IRQMASK_HI(S1_BVD1_STSCHG);
++
++    nirq = 4;
++    slots = 2;
++  }
++
++  for (i = ret = 0; i < nirq; i++) {
++	  ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
++			    irqs[i].str, NULL);
++	  if (ret)
++		  break;
++  }
++
++  if (i < nirq) {
++	  printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n",
++		 irqs[i].irq, ret);
++	  while (i--)
++		  free_irq(irqs[i].irq, NULL);
++
++	  release_mem_region(_PCCR, 16);
++  }
++
++  return ret ? -1 : slots;
+ }
+ 
+-static int
+-adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf)
++static int adsbitsy_pcmcia_shutdown(void)
++{
++
++  free_irq(S0_CD_VALID, NULL);
++  free_irq(S0_BVD1_STSCHG, NULL);
++  INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) | SA1111_IRQMASK_HI(S0_BVD1_STSCHG));
++
++  if (!adsbitsy_smc91111_present()) {
++    free_irq(S1_CD_VALID, NULL);
++    free_irq(S1_BVD1_STSCHG, NULL);
++    INTPOL1 &= ~(SA1111_IRQMASK_HI(S1_CD_VALID) | SA1111_IRQMASK_HI(S1_BVD1_STSCHG));
++  }
++
++  return 0;
++}
++
++
++static int adsbitsy_pcmcia_socket_state(struct pcmcia_state_array *state)
++{
++	unsigned long status;
++
++	if (adsbitsy_smc91111_present()) {
++		if(state->size<1) return -1;
++	}
++	else
++		if(state->size<2) return -1;
++
++	memset(state->state, 0,
++	       (state->size)*sizeof(struct pcmcia_state));
++
++	status = PCSR;
++
++	state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
++	state->state[0].ready  = status & PCSR_S0_READY  ? 1 : 0;
++	state->state[0].bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
++	state->state[0].bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
++	state->state[0].wrprot = status & PCSR_S0_WP     ? 1 : 0;
++	state->state[0].vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
++	state->state[0].vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
++
++	if (state->size > 1) {
++		if (adsbitsy_smc91111_present()) {
++			// If there is SMC91111 on ADS Bitsy connector board
++			// it returns not detect/ready/...
++			state->state[1].detect = 0;
++			state->state[1].ready = 0;
++			state->state[1].bvd1 = 0;
++			state->state[1].bvd2 = 0;
++			state->state[1].wrprot = 0;
++			state->state[1].vs_3v = 0;
++			state->state[1].vs_Xv = 0;
++		}
++		else {
++			state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1;
++			state->state[1].ready  = status & PCSR_S1_READY  ? 1 : 0;
++			state->state[1].bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
++			state->state[1].bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
++			state->state[1].wrprot = status & PCSR_S1_WP     ? 1 : 0;
++			state->state[1].vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
++			state->state[1].vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
++		}
++	}
++	return 1;
++}
++
++static int adsbitsy_pcmcia_configure_socket(const struct pcmcia_configure *conf)
+ {
+   unsigned int pa_dwr_mask, pa_dwr_set;
+   int ret;
+@@ -54,10 +182,11 @@
+ 
+     switch (conf->vcc) {
+     default:
+-    case 0:	pa_dwr_set = 0;				break;
++    case 0:	pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3;   break;
+     case 33:	pa_dwr_set = GPIO_GPIO2;		break;
+     case 50:	pa_dwr_set = GPIO_GPIO3;		break;
+     }
++    break;
+ 
+   default:
+     return -1;
+@@ -83,8 +212,8 @@
+ 
+ struct pcmcia_low_level adsbitsy_pcmcia_ops = {
+   init:			adsbitsy_pcmcia_init,
+-  shutdown:		sa1111_pcmcia_shutdown,
+-  socket_state:		sa1111_pcmcia_socket_state,
++  shutdown:		adsbitsy_pcmcia_shutdown,
++  socket_state:		adsbitsy_pcmcia_socket_state,
+   get_irq_info:		sa1111_pcmcia_get_irq_info,
+   configure_socket:	adsbitsy_pcmcia_configure_socket,
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_adsbitsyplus.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,236 @@
++/*
++ * drivers/pcmcia/sa1100_adsbitsyplus.c
++ *
++ * PCMCIA implementation routines for ADS Bitsy Plus
++ *
++ * Created Feb 7, 2003 by Robert Whaley <rwhaley@applieddata.net>
++ *
++ * This file comes from sa1100_adsbitsy.c of Woojung Huh <whuh@applieddata.net>
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++
++#include <asm/hardware.h>
++#include <asm/hardware/sa1111.h>
++#include <asm/irq.h>
++
++#include "sa1100_generic.h"
++#include "sa1111_generic.h"
++
++int adsbitsy_smc91111_present(void);
++
++#ifndef	CONFIG_SMC91111
++#define adsbitsy_smc91111_present() 0
++#endif
++
++static struct irqs {
++	int irq;
++	const char *str;
++} irqs[] = {
++	{ S0_CD_VALID,    "SA1111 PCMCIA card detect" },
++	{ S0_BVD1_STSCHG, "SA1111 PCMCIA BVD1"        },
++	{ S1_CD_VALID,    "SA1111 CF card detect"     },
++	{ S1_BVD1_STSCHG, "SA1111 CF BVD1"            },
++};
++
++#define sock0_3_3_reverse_logic() ((ADS_CPLD_IO2 & ADS_IO2_CPLD_REV_MASK) >= ADS_IO2_CPLD_REV_5_MAGIC)
++
++static int adsbitsyplus_pcmcia_init(struct pcmcia_init *init)
++{
++  int ret=0;
++  int nirq = 0;
++  int slots = 0;
++  int i;
++
++  /* Set GPIO_A<1:0> to be outputs for PCMCIA power controller: */
++  PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1);
++
++  /* Disable Power 3.3V/5V for PCMCIA */
++  if (sock0_3_3_reverse_logic())
++	  PA_DWR = (PA_DWR & ~GPIO_GPIO0) | GPIO_GPIO1;
++  else
++	  PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1;
++
++  if (!request_mem_region(_PCCR, 512, "PCMCIA"))
++	  return -1;
++
++
++  INTPOL1 |= SA1111_IRQMASK_HI(S0_READY_NINT) |
++             SA1111_IRQMASK_HI(S0_CD_VALID)   |
++             SA1111_IRQMASK_HI(S0_BVD1_STSCHG);
++
++  nirq = 2;
++  slots = 1;
++
++  if (!adsbitsy_smc91111_present()) {
++    /* If the SMC91111 is used CF cannot be used */
++    /* Set GPIO_A<3:2> to be outputs for CF power controller: */
++    PA_DDR &= ~(GPIO_GPIO2 | GPIO_GPIO3);
++
++    /* Disable Power 3.3V/5V for CF */
++    PA_DWR |= GPIO_GPIO2 | GPIO_GPIO3;
++
++    INTPOL1 |= SA1111_IRQMASK_HI(S1_READY_NINT) |
++               SA1111_IRQMASK_HI(S1_CD_VALID)   |
++               SA1111_IRQMASK_HI(S1_BVD1_STSCHG);
++
++    nirq = 4;
++    slots = 2;
++  }
++
++  for (i = ret = 0; i < nirq; i++) {
++	  ret = request_irq(irqs[i].irq, init->handler, SA_INTERRUPT,
++			    irqs[i].str, NULL);
++	  if (ret)
++		  break;
++  }
++
++  if (i < nirq) {
++	  printk(KERN_ERR "sa1111_pcmcia: unable to grab IRQ%d (%d)\n",
++		 irqs[i].irq, ret);
++	  while (i--)
++		  free_irq(irqs[i].irq, NULL);
++
++	  release_mem_region(_PCCR, 16);
++  }
++
++  return ret ? -1 : slots;
++}
++
++static int adsbitsyplus_pcmcia_shutdown(void)
++{
++
++  free_irq(S0_CD_VALID, NULL);
++  free_irq(S0_BVD1_STSCHG, NULL);
++  INTPOL1 &= ~(SA1111_IRQMASK_HI(S0_CD_VALID) | SA1111_IRQMASK_HI(S0_BVD1_STSCHG));
++
++  if (!adsbitsy_smc91111_present()) {
++    free_irq(S1_CD_VALID, NULL);
++    free_irq(S1_BVD1_STSCHG, NULL);
++    INTPOL1 &= ~(SA1111_IRQMASK_HI(S1_CD_VALID) | SA1111_IRQMASK_HI(S1_BVD1_STSCHG));
++  }
++
++  return 0;
++}
++
++
++static int adsbitsyplus_pcmcia_socket_state(struct pcmcia_state_array *state)
++{
++	unsigned long status;
++
++	if (adsbitsy_smc91111_present()) {
++		if(state->size<1) return -1;
++	}
++	else
++		if(state->size<2) return -1;
++
++	memset(state->state, 0,
++	       (state->size)*sizeof(struct pcmcia_state));
++
++	status = PCSR;
++
++	state->state[0].detect = status & PCSR_S0_DETECT ? 0 : 1;
++	state->state[0].ready  = status & PCSR_S0_READY  ? 1 : 0;
++	state->state[0].bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
++	state->state[0].bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
++	state->state[0].wrprot = status & PCSR_S0_WP     ? 1 : 0;
++	state->state[0].vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
++	state->state[0].vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
++
++	if (state->size > 1) {
++		if (adsbitsy_smc91111_present()) {
++			// If there is SMC91111 on ADS Bitsy connector board
++			// it returns not detect/ready/...
++			state->state[1].detect = 0;
++			state->state[1].ready = 0;
++			state->state[1].bvd1 = 0;
++			state->state[1].bvd2 = 0;
++			state->state[1].wrprot = 0;
++			state->state[1].vs_3v = 0;
++			state->state[1].vs_Xv = 0;
++		}
++		else {
++			state->state[1].detect = status & PCSR_S1_DETECT ? 0 : 1;
++			state->state[1].ready  = status & PCSR_S1_READY  ? 1 : 0;
++			state->state[1].bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
++			state->state[1].bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
++			state->state[1].wrprot = status & PCSR_S1_WP     ? 1 : 0;
++			state->state[1].vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
++			state->state[1].vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
++		}
++	}
++	return 1;
++}
++
++static int adsbitsyplus_pcmcia_configure_socket(const struct pcmcia_configure *conf)
++{
++  unsigned int pa_dwr_mask, pa_dwr_set;
++  int ret;
++
++  switch (conf->sock) {
++  case 0:
++    pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
++
++    if (sock0_3_3_reverse_logic()) {
++	    switch (conf->vcc) {
++	    default:
++	    case 0:	pa_dwr_set = GPIO_GPIO1;		break;
++	    case 33:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
++	    case 50:	pa_dwr_set = 0;				break;
++	    }
++    } else {
++	    switch (conf->vcc) {
++	    default:
++	    case 0:	pa_dwr_set = GPIO_GPIO0 | GPIO_GPIO1;	break;
++	    case 33:	pa_dwr_set = GPIO_GPIO1;		break;
++	    case 50:	pa_dwr_set = GPIO_GPIO0;		break;
++	    }
++    }
++    break;
++
++  case 1:
++    pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
++
++    switch (conf->vcc) {
++    default:
++    case 0:	pa_dwr_set = GPIO_GPIO2 | GPIO_GPIO3;   break;
++    case 33:	pa_dwr_set = GPIO_GPIO2;		break;
++    case 50:	pa_dwr_set = GPIO_GPIO3;		break;
++    }
++    break;
++
++  default:
++    return -1;
++  }
++
++  if (conf->vpp != conf->vcc && conf->vpp != 0) {
++    printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
++		__FUNCTION__, conf->vpp);
++    return -1;
++  }
++
++  ret = sa1111_pcmcia_configure_socket(conf);
++  if (ret == 0) {
++    unsigned long flags;
++
++    local_irq_save(flags);
++    PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
++    local_irq_restore(flags);
++  }
++
++  return ret;
++}
++
++struct pcmcia_low_level adsbitsyplus_pcmcia_ops = {
++  init:			adsbitsyplus_pcmcia_init,
++  shutdown:		adsbitsyplus_pcmcia_shutdown,
++  socket_state:		adsbitsyplus_pcmcia_socket_state,
++  get_irq_info:		sa1111_pcmcia_get_irq_info,
++  configure_socket:	adsbitsyplus_pcmcia_configure_socket,
++
++  socket_init:		sa1111_pcmcia_socket_init,
++  socket_suspend:	sa1111_pcmcia_socket_suspend,
++};
++
+--- linux-2.4.25/drivers/pcmcia/sa1100_freebird.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_freebird.c	2004-03-31 17:15:09.000000000 +0200
+@@ -67,9 +67,6 @@
+ 
+   if(state_array->size<2) return -1;
+ 
+-  memset(state_array->state, 0,
+-	 (state_array->size)*sizeof(struct pcmcia_state));
+-
+   levels = LINKUP_PRS;
+ //printk("LINKUP_PRS=%x \n",levels);
+ 
+--- linux-2.4.25/drivers/pcmcia/sa1100_generic.c~2.4.25-vrs2.patch	2003-06-13 16:51:35.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_generic.c	2004-03-31 17:15:09.000000000 +0200
+@@ -992,10 +992,18 @@
+   if(machine_is_graphicsmaster())
+     pcmcia_low_level = &graphicsmaster_pcmcia_ops;
+ #endif
++#ifdef CONFIG_SA1100_ADSAGC
++  if(machine_is_adsagc())
++    pcmcia_low_level = &graphicsmaster_pcmcia_ops;
++#endif
+ #ifdef CONFIG_SA1100_ADSBITSY
+   if(machine_is_adsbitsy())
+     pcmcia_low_level = &adsbitsy_pcmcia_ops;
+ #endif
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++  if(machine_is_adsbitsyplus())
++    pcmcia_low_level = &adsbitsyplus_pcmcia_ops;
++#endif
+ #ifdef CONFIG_SA1100_STORK
+   if(machine_is_stork())
+     pcmcia_low_level = &stork_pcmcia_ops;
+@@ -1067,7 +1075,7 @@
+    * We initialize the MECR to default values here, because we are
+    * not guaranteed to see a SetIOMap operation at runtime.
+    */
+-  mecr = 0;
++  mecr = MECR;
+ 
+   clock = cpufreq_get(0);
+ 
+--- linux-2.4.25/drivers/pcmcia/sa1100_graphicsclient.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_graphicsclient.c	2004-03-31 17:15:09.000000000 +0200
+@@ -3,6 +3,8 @@
+  *
+  * PCMCIA implementation routines for Graphics Client Plus
+  *
++ * Nov/14/01 Woojung
++ *    Set MECR at initializing time
+  * 9/12/01   Woojung
+  *    Turn power OFF at startup
+  * 1/31/2001 Woojung Huh
+@@ -19,11 +21,6 @@
+ #include <asm/irq.h>
+ #include "sa1100_generic.h"
+ 
+-#error This is broken!
+-
+-#define	S0_CD_IRQ		60				// Socket 0 Card Detect IRQ
+-#define	S0_STS_IRQ		55				// Socket 0 PCMCIA IRQ
+-
+ static volatile unsigned long *PCMCIA_Status = 
+ 		((volatile unsigned long *) ADS_p2v(_ADS_CS_STATUS));
+ 
+@@ -46,20 +43,23 @@
+   *PCMCIA_Power &= ~0x03;
+ 
+   /* Register interrupts */
+-  irq = S0_CD_IRQ;
++  irq = IRQ_GRAPHICSCLIENT_S0_CD;
+   res = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL);
+   if (res < 0) {
+-	  printk(KERN_ERR "%s: Request for IRQ %lu failed\n", __FUNCTION__, irq);
++	  printk(KERN_ERR "%s: Request for IRQ %u failed\n", __FUNCTION__, irq);
+ 	  return	-1;
+   }
+ 
++  // Nov/14/01 WH
++  MECR = 0x00000943;
++
+   return 1;			// 1 PCMCIA Slot
+ }
+ 
+ static int gcplus_pcmcia_shutdown(void)
+ {
+   /* disable IRQs */
+-  free_irq( S0_CD_IRQ, NULL);
++  free_irq( IRQ_GRAPHICSCLIENT_S0_CD, NULL);
+   
+   /* Shutdown PCMCIA power */
+   mdelay(2);						// 2msec
+@@ -74,9 +74,6 @@
+ 
+   if(state_array->size<1) return -1;
+ 
+-  memset(state_array->state, 0, 
+-	 (state_array->size)*sizeof(struct pcmcia_state));
+-
+   levels=*PCMCIA_Status;
+ 
+   state_array->state[0].detect=(levels & ADS_CS_ST_A_CD)?1:0;
+@@ -96,7 +93,7 @@
+ 		return -1;
+ 
+ 	if (info->sock == 0)
+-		info->irq = S0_STS_IRQ;
++		info->irq = IRQ_GRAPHICSCLIENT_S0_STS;
+ 
+   	return 0;
+ }
+@@ -143,6 +140,11 @@
+ 
+   restore_flags(flags);
+ 
++  if (configure->irq)
++	  enable_irq(IRQ_GRAPHICSCLIENT_S0_STS);
++  else
++	  disable_irq(IRQ_GRAPHICSCLIENT_S0_STS);
++
+   return 0;
+ }
+ 
+--- linux-2.4.25/drivers/pcmcia/sa1100_graphicsmaster.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_graphicsmaster.c	2004-03-31 17:15:09.000000000 +0200
+@@ -12,13 +12,13 @@
+ #include <linux/sched.h>
+ 
+ #include <asm/hardware.h>
++#include <asm/hardware/sa1111.h>
+ 
+ #include "sa1100_generic.h"
+ #include "sa1111_generic.h"
+ 
+ static int graphicsmaster_pcmcia_init(struct pcmcia_init *init)
+ {
+-  int return_val=0;
+ 
+   /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
+   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
+@@ -26,9 +26,6 @@
+   /* Disable Power 3.3V/5V for PCMCIA/CF */
+   PA_DWR |= GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3;
+ 
+-  /* why? */
+-  MECR = 0x09430943;
+-
+   return sa1111_pcmcia_init(init);
+ }
+ 
+@@ -59,6 +56,10 @@
+     case 33:	pa_dwr_set = GPIO_GPIO3;		break;
+     case 50:	pa_dwr_set = GPIO_GPIO2;		break;
+     }
++    break;
++
++  default:
++    return -1;
+   }
+ 
+   if (conf->vpp != conf->vcc && conf->vpp != 0) {
+--- linux-2.4.25/drivers/pcmcia/sa1100_h3600.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_h3600.c	2004-03-31 17:15:09.000000000 +0200
+@@ -29,6 +29,9 @@
+ 	set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_IRQ0 | GPIO_H3600_PCMCIA_IRQ1,
+ 			  GPIO_FALLING_EDGE);
+ 
++	set_GPIO_IRQ_edge(GPIO_H3600_PCMCIA_CD0 | GPIO_H3600_PCMCIA_CD1,
++			  GPIO_NO_EDGES);
++
+ 	/*
+ 	 * Register interrupts
+ 	 */
+--- linux-2.4.25/drivers/pcmcia/sa1100_jornada720.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_jornada720.c	2004-03-31 17:15:09.000000000 +0200
+@@ -8,6 +8,7 @@
+ #include <linux/sched.h>
+ 
+ #include <asm/hardware.h>
++#include <asm/hardware/sa1111.h>
+ 
+ #include "sa1100_generic.h"
+ #include "sa1111_generic.h"
+@@ -88,7 +89,7 @@
+ 
+     local_irq_save(flags);
+     PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
+-    locla_irq_restore(flags);
++    local_irq_restore(flags);
+   }
+ 
+   return ret;
+--- linux-2.4.25/drivers/pcmcia/sa1100_pangolin.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_pangolin.c	2004-03-31 17:15:09.000000000 +0200
+@@ -53,9 +53,6 @@
+ 
+   if(state_array->size<2) return -1;
+ 
+-  memset(state_array->state, 0, 
+-	 (state_array->size)*sizeof(struct pcmcia_state));
+-
+   levels=GPLR;
+ #ifndef CONFIG_SA1100_PANGOLIN_PCMCIA_IDE
+   state_array->state[1].detect=((levels & GPIO_PCMCIA_CD)==0)?1:0;
+--- linux-2.4.25/drivers/pcmcia/sa1100_shannon.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_shannon.c	2004-03-31 17:15:09.000000000 +0200
+@@ -53,9 +53,6 @@
+ {
+ 	unsigned long levels;
+ 
+-	memset(state_array->state, 0,
+-	       state_array->size * sizeof(struct pcmcia_state));
+-
+ 	levels = GPLR;
+ 
+ 	state_array->state[0].detect = (levels & SHANNON_GPIO_EJECT_0) ? 0 : 1;
+--- linux-2.4.25/drivers/pcmcia/sa1100_simpad.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_simpad.c	2004-03-31 17:15:09.000000000 +0200
+@@ -63,9 +63,6 @@
+ 
+   if(state_array->size<2) return -1;
+ 
+-  memset(state_array->state, 0, 
+-	 (state_array->size)*sizeof(struct pcmcia_state));
+-
+   levels=GPLR;
+ 
+   state_array->state[1].detect=((levels & GPIO_CF_CD)==0)?1:0;
+--- linux-2.4.25/drivers/pcmcia/sa1100_stork.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/pcmcia/sa1100_stork.c	2004-03-31 17:15:09.000000000 +0200
+@@ -79,9 +79,6 @@
+ 
+         if(state_array->size<2) return -1;
+ 
+-        memset(state_array->state, 0, 
+-               (state_array->size)*sizeof(struct pcmcia_state));
+-
+         levels=GPLR;
+ 
+ 	if (debug > 1)
+--- linux-2.4.25/drivers/pcmcia/sa1100_yopy.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/pcmcia/sa1100_yopy.c	2004-03-31 17:15:09.000000000 +0200
+@@ -73,9 +73,6 @@
+ 	if (state_array->size != 1)
+ 		return -1;
+ 
+-	memset(state_array->state, 0,
+-	       state_array->size * sizeof(struct pcmcia_state));
+-
+ 	levels = GPLR;
+ 
+ 	state_array->state[0].detect = (levels & GPIO_CF_CD)    ? 0 : 1;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pld/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,28 @@
++#
++# Makefile for the kernel pld device drivers.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definitions are now inherited from the
++# parent makes..
++#
++#  $Id$
++#
++
++O_TARGET := pld.o
++
++export-objs	:= pld_hotswap.o
++obj-y		:=
++obj-m		:=
++obj-n		:=
++obj-		:=
++
++obj-$(CONFIG_PLD)              += pld_epxa.o
++obj-$(CONFIG_PLD_HOTSWAP)      += pld_hotswap.o
++
++include $(TOPDIR)/Rules.make
++
++fastdep:
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pld/pld_epxa.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,375 @@
++
++/*
++ *  drivers/char/epxapld.c
++ *
++ *  Copyright (C) 2001 Altera 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
++ */
++
++#include <linux/config.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <asm/io.h>
++#include <asm/uaccess.h>
++#include <asm/arch/excalibur.h>
++#include <asm/arch/hardware.h>
++#define PLD_CONF00_TYPE (volatile unsigned int *)
++#define MODE_CTRL00_TYPE (volatile unsigned int *)
++//#define DEBUG(x) x
++#define DEBUG(x)
++
++#include <asm/arch/mode_ctrl00.h>
++#include <asm/arch/pld_conf00.h>
++#ifdef CONFIG_PLD_HOTSWAP
++#include <linux/pld/pld_hotswap.h>
++#endif
++#include <linux/pld/pld_epxa.h>
++
++/*
++ *	Macros
++ */
++
++
++#define PLD_BASE (IO_ADDRESS(EXC_PLD_CONFIG00_BASE))
++#define CLOCK_DIV_RATIO ((1 + EXC_AHB2_CLK_FREQUENCY/32000000) & CONFIG_CONTROL_CLOCK_RATIO_MSK)
++/*
++ *	STRUCTURES
++ */
++
++
++struct  pld_sbihdr{
++	unsigned int fpos;
++	unsigned int temp;
++};
++
++static DECLARE_MUTEX(pld_sem);
++
++
++static void lock_pld (void)
++{
++	/* Lock the pld i/f  */
++	unsigned int tmp;
++
++	tmp = readl(CONFIG_CONTROL(PLD_BASE));
++	tmp |= CONFIG_CONTROL_LK_MSK;
++
++	writel(tmp,CONFIG_CONTROL(PLD_BASE));
++}
++
++static void unlock_excalibur_pld (void)
++{
++	/* Unlock the pld i/f */
++
++	if (readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_LK_MSK ){
++		writel(CONFIG_UNLOCK_MAGIC, CONFIG_UNLOCK(PLD_BASE));
++		while (readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_LK_MSK);
++        }
++}
++
++
++static int place_pld_into_configure_mode (void)
++{
++	unsigned int tmp;
++
++
++	if( readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_CO_MSK ){
++		/*
++		 *	Already being configured!!!
++		 */
++		printk(KERN_WARNING "pld0: Device already being configured!\n");
++		return -EBUSY;
++	}
++
++	/* Set up the config clock */
++
++	writel(CLOCK_DIV_RATIO,CONFIG_CONTROL_CLOCK(PLD_BASE));
++	while(readl(CONFIG_CONTROL_CLOCK(PLD_BASE))
++	      !=CLOCK_DIV_RATIO);
++	/* Tell the device we wish to configure it */
++	tmp = readl(CONFIG_CONTROL(PLD_BASE));
++	tmp |= CONFIG_CONTROL_CO_MSK;
++	writel(tmp,CONFIG_CONTROL(PLD_BASE));
++
++
++	/*
++	 *	Wait for the busy bit to clear then check for errors.
++	 */
++
++	while((tmp=readl(CONFIG_CONTROL(PLD_BASE))&CONFIG_CONTROL_B_MSK ));
++
++	if ( tmp & CONFIG_CONTROL_E_MSK ){
++		if ( tmp & CONFIG_CONTROL_ES_0_MSK ){
++		        /* Already being programmed via JTAG */
++			printk(KERN_WARNING "pld0:JTAG configuration alreay in progress\n");
++			return -EBUSY;
++
++		}
++		if ( tmp & CONFIG_CONTROL_ES_1_MSK ){
++			/* No config clock configured */
++			printk(KERN_ERR "pld0:No config clock!\n");
++			BUG();
++			return -EBUSY;
++		}
++		if ( tmp & CONFIG_CONTROL_ES_2_MSK ){
++			/* Already being programmed via External device */
++			printk(KERN_WARNING "pld0:JTAG configuration alreay in progress\n");
++			return -EBUSY;
++		}
++	}
++
++	return 0;
++}
++
++
++static int write_pld_data_word(unsigned int config_data)
++{
++	unsigned int tmp;
++
++	do{
++		tmp = readl(CONFIG_CONTROL(PLD_BASE));
++	}
++        while ( ( tmp & CONFIG_CONTROL_B_MSK ) &&
++		!( tmp & CONFIG_CONTROL_E_MSK ));
++
++        if ( tmp & CONFIG_CONTROL_E_MSK ){
++		printk("pld0: Error writing pld data, CONFIG_CONTROL=%#x\n",tmp);
++
++		return -EILSEQ;
++	}
++
++        writel(config_data,CONFIG_CONTROL_DATA(PLD_BASE));
++	return 0;
++
++}
++
++
++static int wait_for_device_to_configure (void)
++{
++	int i=0x10000;
++
++	while(readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_B_MSK);
++
++	/*
++	 * Wait for the config bit (CO) to go low, indicating that everything
++	 * is Ok. If it doesn't, assume that is screwed up somehow and
++	 * clear the CO bit to abort the configuration.
++	 */
++
++	while(readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_B_MSK);
++
++	while (i&&(readl(CONFIG_CONTROL(PLD_BASE)) & CONFIG_CONTROL_CO_MSK)){
++		i--;
++	}
++
++	if (!i){
++		writel(0,CONFIG_CONTROL(PLD_BASE));
++		printk(KERN_WARNING "pld0: Invalid PLD config data\n");
++		return -EILSEQ;
++	}
++
++	return 0;
++}
++
++
++
++static int pld_open(struct inode* inode, struct file *filep)
++{
++
++	struct pld_sbihdr* sbihdr;
++
++	/* Check the device minor number */
++	if(minor(inode->i_rdev)){
++		DEBUG(printk("pld0: minor=%d",minor(inode->i_rdev));)
++			return -ENODEV;
++	}
++
++	/* Create our private data and link it to the file structure */
++	sbihdr=kmalloc(sizeof(struct pld_sbihdr),GFP_KERNEL);
++
++	if(!sbihdr)
++		return -ENOMEM;
++
++	filep->private_data=sbihdr;
++
++	sbihdr->fpos=0;
++	sbihdr->temp=0;
++	return 0;
++}
++
++static int pld_release(struct inode* inode, struct file *filep){
++	int ret_code;
++
++	kfree(filep->private_data);
++      	ret_code=wait_for_device_to_configure();
++	lock_pld();
++	return ret_code;
++}
++
++static ssize_t pld_write(struct file* filep, const char* data, size_t count, loff_t* ppos){
++
++	struct pld_sbihdr* sbihdr=filep->private_data;
++	int bytes_left=count;
++	int result;
++	DEBUG(int i=0);
++
++
++	/* Can't seek (pwrite) on pld.  */
++	if (ppos != &filep->f_pos)
++		return -ESPIPE;
++
++
++	/* Check access to the whole are in one go */
++	if(!access_ok(VERIFY_READ,(const void*)data, count)){
++		return -EFAULT;
++	}
++
++	/*
++	 * We now lock against writes.
++	 */
++	if (down_interruptible(&pld_sem))
++		return -ERESTARTSYS;
++
++	if(!sbihdr->fpos){
++		/*
++		 * unlock the pld and place in configure mode
++		 */
++		unlock_excalibur_pld();
++		result=place_pld_into_configure_mode();
++		if(result)
++			return result;
++	}
++	DEBUG(printk("data= %#x count=%#x 0ffset=%#x\n",*data, count, *ppos));
++
++	while(bytes_left){
++		char tmp;
++		__get_user(tmp,data);
++		/* read our header ! */
++		sbihdr->temp|=tmp << (8*(sbihdr->fpos&3));
++		if((sbihdr->fpos&3)==3){
++			if(write_pld_data_word(sbihdr->temp))
++			{
++				DEBUG(printk("pos=%d\n",sbihdr->fpos);)
++					return -EILSEQ;
++			}
++			DEBUG(if(i<10){)
++			      DEBUG(printk("fpos2 :%#x data=%#x\n",sbihdr->fpos,sbihdr->temp));
++			      DEBUG(i++);
++			      DEBUG(});
++			sbihdr->temp=0;
++			DEBUG(words_written++);
++		}
++		sbihdr->fpos++;
++		data++;
++		bytes_left--;
++	}
++
++	up(&pld_sem);
++	return (count);
++}
++
++int pld_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg)
++{
++
++	switch(cmd){
++
++#ifdef CONFIG_PLD_HOTSWAP
++	case PLD_IOC_ADD_PLD_DEV:
++	{
++		struct pldhs_dev_desc desc;
++		struct pldhs_dev_info info;
++		char *name;
++		void *data;
++		int result=0;
++
++		result=copy_from_user(&desc,(const void*)arg,sizeof(struct pldhs_dev_desc));
++		if(result)
++			return -EFAULT;
++		result=copy_from_user(&info,(const void*)desc.info,sizeof(struct pldhs_dev_info));
++		if(result)
++			return -EFAULT;
++		name=kmalloc(info.nsize,GFP_KERNEL);
++		if(!name)
++			return -ENOMEM;
++
++		result=copy_from_user(name,(const void*)desc.name,info.nsize);
++		if(result){
++			result=-EFAULT;
++			goto ioctl_out;
++		}
++
++		data=kmalloc(info.pssize,GFP_KERNEL);
++		if(!data){
++			result=-ENOMEM;
++			goto ioctl_out;
++		}
++
++		result=copy_from_user(data,(const void*)desc.data,info.pssize);
++		if(result){
++			result=-EFAULT;
++			goto ioctl_out1;
++		}
++		result=pldhs_add_device(&info,name,data);
++
++	ioctl_out1:
++		kfree(data);
++	ioctl_out:
++		kfree(name);
++		return result;
++
++	}
++
++	case PLD_IOC_REMOVE_PLD_DEVS:
++		pldhs_remove_devices();
++		return 0;
++
++	case PLD_IOC_SET_INT_MODE:
++		if(cmd==3){
++			printk(KERN_INFO "Interrupt mode set to 3 (Six individual interrupts)\n");
++			return 0;
++		}else{
++			printk(KERN_INFO "There is no interrupt handler available for this mode (%d). You will need to add one\n to implement whatever scheme you require\n");
++			return -EACCES;
++		}
++#endif
++	default:
++		return -ENOTTY;
++	}
++}
++
++
++static struct file_operations pld_fops={
++	write:      pld_write,
++	ioctl:      pld_ioctl,
++	open:       pld_open,
++	release:    pld_release
++};
++
++static int __init pld_init(void){
++	int major;
++	major=register_chrdev(0,"pld",&pld_fops);
++	printk(KERN_INFO "Using PLD major num=%d\n",major);
++	if (major<0){
++	        return major;
++	}
++	return 0;
++}
++
++__initcall(pld_init);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/pld/pld_hotswap.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,188 @@
++/*
++ *  linux/drivers/pld/pld_hotswap.c
++ *
++ *  Pld driver for Altera EPXA Excalibur devices
++ *
++ *
++ *  Copyright 2001 Altera Corporation (cdavies@altera.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
++ *
++ *  $Id$
++ *
++ */
++
++/*
++ * pld_hotswap ops contains the basic operation required for adding
++ * and removing devices from the system.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/types.h>
++#include <linux/pagemap.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/init.h>
++#include <linux/kmod.h>
++#include <linux/proc_fs.h>
++#include <linux/list.h>
++#include <asm/uaccess.h>
++#include <linux/pld/pld_hotswap.h>
++
++
++static struct pld_hotswap_ops pldhs_driver_list={
++       list: LIST_HEAD_INIT(pldhs_driver_list.list),
++       name: "",
++};
++
++static spinlock_t list_lock=SPIN_LOCK_UNLOCKED;
++
++
++
++static struct pld_hotswap_ops *  pldhs_find_driver(char* name)
++{
++       struct pld_hotswap_ops * ptr;
++       struct list_head *list_pos;
++
++       spin_lock(&list_lock);
++       list_for_each(list_pos,&pldhs_driver_list.list){
++               ptr=(struct pld_hotswap_ops *)list_pos;
++               if(!strcmp(name, ptr->name)){
++                       spin_unlock(&list_lock);
++                       return ptr;
++
++               }
++       }
++       spin_unlock(&list_lock);
++       return 0;
++}
++
++
++
++int pldhs_register_driver(struct pld_hotswap_ops *drv)
++{
++
++       /* Check that the device is not already on the list
++        * if so, do nothing */
++       if(pldhs_find_driver(drv->name)){
++               return 0;
++       }
++
++       printk(KERN_INFO "PLD: Registering hotswap driver %s\n",drv->name);
++       /* Add this at the start of the list */
++       spin_lock(&list_lock);
++       list_add((struct list_head*)drv,&pldhs_driver_list.list);
++       spin_unlock(&list_lock);
++
++       return 0;
++}
++
++int pldhs_unregister_driver(char *name)
++{
++       struct pld_hotswap_ops *ptr;
++
++       ptr=pldhs_find_driver(name);
++       if(!ptr){
++               return -ENODEV;
++       }
++
++       printk(KERN_INFO "PLD: Unregistering hotswap driver%s\n",name);
++       spin_lock(&list_lock);
++       list_del((struct list_head*)ptr);
++       spin_unlock(&list_lock);
++
++       return 0;
++}
++
++int pldhs_add_device(struct pldhs_dev_info* dev_info,char *drv_name, void* dev_ps_data)
++{
++       struct pld_hotswap_ops * ptr;
++
++       ptr=pldhs_find_driver(drv_name);
++
++       if(!ptr){
++               /* try requesting this module*/
++               request_module(drv_name);
++               /* is the driver there now? */
++               ptr=pldhs_find_driver(drv_name);
++               if(!ptr){
++                       printk("pld hotswap: Failed to load a driver for %s\n",drv_name);
++                       return -ENODEV;
++               }
++       }
++
++       if(!ptr->add_device){
++               printk(KERN_WARNING "pldhs: no add_device() function for driver %s\n",drv_name);
++               return 0;
++       }
++
++       return ptr->add_device(dev_info,dev_ps_data);
++}
++
++int pldhs_remove_devices(void)
++{
++       struct list_head *list_pos;
++       struct pld_hotswap_ops * ptr;
++
++
++       spin_lock(&list_lock);
++       list_for_each(list_pos,&pldhs_driver_list.list){
++               ptr=(struct pld_hotswap_ops *)list_pos;
++               if(ptr->remove_devices)
++                       ptr->remove_devices();
++
++       }
++       spin_unlock(&list_lock);
++
++       return 0;
++}
++
++#ifdef CONFIG_PROC_FS
++int pldhs_read_proc(char* buf,char** start,off_t offset,int count,int *eof,void *data){
++
++
++       struct list_head *list_pos;
++       struct pld_hotswap_ops * ptr;
++       int i,len=0;
++
++       *start=buf;
++       spin_lock(&list_lock);
++       list_for_each(list_pos,&pldhs_driver_list.list){
++               ptr=(struct pld_hotswap_ops *)list_pos;
++               if(ptr->proc_read){
++                       i=ptr->proc_read(buf,start,offset,count,eof,data);
++                       count-=i;
++                       len+=i;
++                       *start+=i;
++               }
++       }
++       spin_unlock(&list_lock);
++
++       *start=NULL;
++       *eof=1;
++       return len;
++}
++
++void __init pldhs_init(void){
++       create_proc_read_entry("pld",0,NULL,pldhs_read_proc,NULL);
++}
++
++__initcall(pldhs_init);
++#endif
++
++EXPORT_SYMBOL(pldhs_register_driver);
++EXPORT_SYMBOL(pldhs_unregister_driver);
+--- linux-2.4.25/drivers/scsi/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/scsi/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -21,7 +21,7 @@
+ 
+ O_TARGET := scsidrv.o
+ 
+-export-objs	:= scsi_syms.o 53c700.o
++export-objs	:= scsi_syms.o 53c700.o scsi_error.o
+ mod-subdirs	:= pcmcia ../acorn/scsi
+ 
+ 
+--- linux-2.4.25/drivers/scsi/scsi.c~2.4.25-vrs2.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/scsi/scsi.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1334,14 +1334,10 @@
+  */
+ int scsi_retry_command(Scsi_Cmnd * SCpnt)
+ {
+-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+-	       sizeof(SCpnt->data_cmnd));
+-	SCpnt->request_buffer = SCpnt->buffer;
+-	SCpnt->request_bufflen = SCpnt->bufflen;
+-	SCpnt->use_sg = SCpnt->old_use_sg;
+-	SCpnt->cmd_len = SCpnt->old_cmd_len;
+-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+-	SCpnt->underflow = SCpnt->old_underflow;
++	/*
++	 * Restore the SCSI command state.
++	 */
++	scsi_setup_cmd_retry(SCpnt);
+ 
+         /*
+          * Zero the sense information from the last time we tried
+--- linux-2.4.25/drivers/scsi/scsi.h~2.4.25-vrs2.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/scsi/scsi.h	2004-03-31 17:15:09.000000000 +0200
+@@ -465,6 +465,7 @@
+ 				   int sectors);
+ extern struct Scsi_Device_Template *scsi_get_request_dev(struct request *);
+ extern int scsi_init_cmd_errh(Scsi_Cmnd * SCpnt);
++extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt);
+ extern int scsi_insert_special_cmd(Scsi_Cmnd * SCpnt, int);
+ extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
+ 			       int block_sectors);
+@@ -588,6 +589,7 @@
+ 	unsigned changed:1;	/* Data invalid due to media change */
+ 	unsigned busy:1;	/* Used to prevent races */
+ 	unsigned lockable:1;	/* Able to prevent media removal */
++	unsigned locked:1;	/* Media removal disabled */
+ 	unsigned borken:1;	/* Tell the Seagate driver to be 
+ 				 * painfully slow on this device */
+ 	unsigned tagged_supported:1;	/* Supports SCSI-II tagged queuing */
+--- linux-2.4.25/drivers/scsi/scsi_dma.c~2.4.25-vrs2.patch	2002-02-25 20:38:04.000000000 +0100
++++ linux-2.4.25/drivers/scsi/scsi_dma.c	2004-03-31 17:15:09.000000000 +0200
+@@ -30,6 +30,15 @@
+ typedef unsigned char FreeSectorBitmap;
+ #elif SECTORS_PER_PAGE <= 32
+ typedef unsigned int FreeSectorBitmap;
++#elif SECTORS_PER_PAGE <= 64
++#if 0
++typedef unsigned long long FreeSectorBitmap;
++#else
++typedef struct {
++	unsigned long l,h;
++} FreeSectorBitmap;
++#define LARGE_MALLOC
++#endif
+ #else
+ #error You lose.
+ #endif
+@@ -69,6 +78,7 @@
+  *              to allocate more memory in order to be able to write the
+  *              data to disk, you would wedge the system.
+  */
++#ifndef LARGE_MALLOC
+ void *scsi_malloc(unsigned int len)
+ {
+ 	unsigned int nbits, mask;
+@@ -167,6 +177,97 @@
+ 	panic("scsi_free:Bad offset");
+ }
+ 
++#else
++
++void *scsi_malloc(unsigned int len)
++{
++	unsigned int nbits;
++	unsigned long maskl, maskh, flags;
++	FreeSectorBitmap *fsb;
++	int i;
++
++	if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
++		return NULL;
++
++	save_flags_cli (flags);
++	nbits = len >> 9;
++	if (nbits < 32) {
++		maskl = (1 << nbits) - 1;
++		maskh = 0;
++	} else {
++		maskl = (unsigned long)-1;
++		maskh = (1 << (nbits - 32)) - 1;
++	}
++
++	fsb = dma_malloc_freelist;
++
++	for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++) {
++		unsigned long mml, mmh;
++		int j;
++		mml = maskl;
++		mmh = maskh;
++		j = 0;
++		do {
++			if ((fsb->l & mml) == 0 && (fsb->h & mmh) == 0) {
++				fsb->h |= mmh;
++				fsb->l |= mml;
++				restore_flags (flags);
++				scsi_dma_free_sectors -= nbits;
++#ifdef DEBUG
++				printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9));
++#endif
++				return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
++			}
++			mmh = (mmh << 1) | (mml >> 31);
++			mml <<= 1;
++			j++;
++		} while (!(mmh & (1 << 31)));
++		fsb ++;
++	}
++	return NULL;  /* Nope.  No more */
++}
++
++int scsi_free(void *obj, unsigned int len)
++{
++	unsigned int page, sector, nbits;
++	unsigned long maskl, maskh, flags;
++
++#ifdef DEBUG
++	printk("scsi_free %p %d\n",obj, len);
++#endif
++
++	for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
++		unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
++		if ((unsigned long) obj >= page_addr &&
++		    (unsigned long) obj < page_addr + PAGE_SIZE) {
++			sector = (((unsigned long) obj) - page_addr) >> 9;
++			nbits = len >> 9;
++			if (nbits < 32) {
++				maskl = (1 << nbits) - 1;
++				maskh = 0;
++			} else {
++				maskl = (unsigned long)-1;
++				maskh = (1 << (nbits - 32)) - 1;
++			}
++			if ((sector + nbits) > SECTORS_PER_PAGE)
++				panic ("scsi_free:Bad memory alignment");
++			maskh = (maskh << sector) | (maskl >> (32 - sector));
++			maskl = maskl << sector;
++			save_flags_cli(flags);
++			if (((dma_malloc_freelist[page].l & maskl) != maskl) ||
++			    ((dma_malloc_freelist[page].h & maskh) != maskh))
++				panic("scsi_free:Trying to free unused memory");
++			scsi_dma_free_sectors += nbits;
++			dma_malloc_freelist[page].l &= ~maskl;
++			dma_malloc_freelist[page].h &= ~maskh;
++			restore_flags(flags);
++			return 0;
++		}
++	}
++	panic("scsi_free:Bad offset");
++}
++#endif
++
+ 
+ /*
+  * Function:    scsi_resize_dma_pool
+--- linux-2.4.25/drivers/scsi/scsi_error.c~2.4.25-vrs2.patch	2002-11-29 00:53:14.000000000 +0100
++++ linux-2.4.25/drivers/scsi/scsi_error.c	2004-03-31 17:15:09.000000000 +0200
+@@ -35,6 +35,8 @@
+ #include "hosts.h"
+ #include "constants.h"
+ 
++#include <scsi/scsi_ioctl.h> /* grr */
++
+ /*
+  * We must always allow SHUTDOWN_SIGS.  Even if we are not a module,
+  * the host drivers that we are using may be loaded as modules, and
+@@ -49,6 +51,13 @@
+  */
+ #define SHUTDOWN_SIGS	(sigmask(SIGHUP))
+ 
++/*
++ * The number of times we retry a REQUEST SENSE and TEST UNIT READY
++ * respectively.  This is arbitary.
++ */
++#define SENSE_RETRIES	5
++#define TUR_RETRIES	5
++
+ #ifdef DEBUG
+ #define SENSE_TIMEOUT SCSI_TIMEOUT
+ #define ABORT_TIMEOUT SCSI_TIMEOUT
+@@ -385,16 +394,12 @@
+  */
+ STATIC int scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
+ {
+-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+-	       sizeof(SCpnt->data_cmnd));
+-	SCpnt->request_buffer = SCpnt->buffer;
+-	SCpnt->request_bufflen = SCpnt->bufflen;
+-	SCpnt->use_sg = SCpnt->old_use_sg;
+-	SCpnt->cmd_len = SCpnt->old_cmd_len;
+-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+-	SCpnt->underflow = SCpnt->old_underflow;
++	int tries = 0;
+ 
+-	scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
++	do {
++		scsi_setup_cmd_retry(SCpnt);
++		scsi_send_eh_cmnd(SCpnt, SCpnt->timeout_per_command);
++	} while (SCpnt->eh_state == NEEDS_RETRY && tries++ < SCpnt->allowed);
+ 
+ 	/*
+ 	 * Hey, we are done.  Let's look to see what happened.
+@@ -421,16 +426,10 @@
+ 	static unsigned char generic_sense[6] =
+ 	{REQUEST_SENSE, 0, 0, 0, 255, 0};
+ 	unsigned char scsi_result0[256], *scsi_result = NULL;
+-	int saved_result;
++	int saved_result, tries;
+ 
+ 	ASSERT_LOCK(&io_request_lock, 0);
+ 
+-	memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
+-	       sizeof(generic_sense));
+-
+-	if (SCpnt->device->scsi_level <= SCSI_2)
+-		SCpnt->cmnd[1] = SCpnt->lun << 5;
+-
+ 	scsi_result = (!SCpnt->host->hostt->unchecked_isa_dma)
+ 	    ? &scsi_result0[0] : kmalloc(512, GFP_ATOMIC | GFP_DMA);
+ 
+@@ -438,24 +437,41 @@
+ 		printk("cannot allocate scsi_result in scsi_request_sense.\n");
+ 		return FAILED;
+ 	}
+-	/*
+-	 * Zero the sense buffer.  Some host adapters automatically always request
+-	 * sense, so it is not a good idea that SCpnt->request_buffer and
+-	 * SCpnt->sense_buffer point to the same address (DB).
+-	 * 0 is not a valid sense code. 
+-	 */
+-	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+-	memset((void *) scsi_result, 0, 256);
+ 
+ 	saved_result = SCpnt->result;
+-	SCpnt->request_buffer = scsi_result;
+-	SCpnt->request_bufflen = 256;
+-	SCpnt->use_sg = 0;
+-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+-	SCpnt->sc_data_direction = SCSI_DATA_READ;
+-	SCpnt->underflow = 0;
+ 
+-	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
++	tries = 0;
++	do {
++		memcpy((void *) SCpnt->cmnd, (void *) generic_sense,
++		       sizeof(generic_sense));
++
++		if (SCpnt->device->scsi_level <= SCSI_2)
++			SCpnt->cmnd[1] = SCpnt->lun << 5;
++
++		/*
++		 * Zero the sense buffer.  Some host adapters automatically
++		 * always request sense, so it is not a good idea that
++		 * SCpnt->request_buffer and SCpnt->sense_buffer point to
++		 * the same address (DB).  0 is not a valid sense code. 
++		 */
++		memset((void *) SCpnt->sense_buffer, 0,
++		       sizeof(SCpnt->sense_buffer));
++		memset((void *) scsi_result, 0, 256);
++
++		SCpnt->request_buffer = scsi_result;
++		SCpnt->request_bufflen = 256;
++		SCpnt->use_sg = 0;
++		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
++		SCpnt->sc_data_direction = SCSI_DATA_READ;
++		SCpnt->underflow = 0;
++
++		scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
++		/*
++		 * If the SCSI device responded with "logical unit
++		 * is in process of becoming ready", we need to
++		 * retry this command.
++		 */
++	} while (SCpnt->eh_state == NEEDS_RETRY && tries++ < SENSE_RETRIES);
+ 
+ 	/* Last chance to have valid sense data */
+ 	if (!scsi_sense_valid(SCpnt))
+@@ -470,15 +486,8 @@
+ 	 * When we eventually call scsi_finish, we really wish to complete
+ 	 * the original request, so let's restore the original data. (DB)
+ 	 */
+-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+-	       sizeof(SCpnt->data_cmnd));
+ 	SCpnt->result = saved_result;
+-	SCpnt->request_buffer = SCpnt->buffer;
+-	SCpnt->request_bufflen = SCpnt->bufflen;
+-	SCpnt->use_sg = SCpnt->old_use_sg;
+-	SCpnt->cmd_len = SCpnt->old_cmd_len;
+-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+-	SCpnt->underflow = SCpnt->old_underflow;
++	scsi_setup_cmd_retry(SCpnt);
+ 
+ 	/*
+ 	 * Hey, we are done.  Let's look to see what happened.
+@@ -496,40 +505,42 @@
+ {
+ 	static unsigned char tur_command[6] =
+ 	{TEST_UNIT_READY, 0, 0, 0, 0, 0};
++	int tries = 0;
+ 
+-	memcpy((void *) SCpnt->cmnd, (void *) tur_command,
+-	       sizeof(tur_command));
++	do {
++		memcpy((void *) SCpnt->cmnd, (void *) tur_command,
++		       sizeof(tur_command));
+ 
+-	if (SCpnt->device->scsi_level <= SCSI_2)
+-		SCpnt->cmnd[1] = SCpnt->lun << 5;
++		if (SCpnt->device->scsi_level <= SCSI_2)
++			SCpnt->cmnd[1] = SCpnt->lun << 5;
+ 
+-	/*
+-	 * Zero the sense buffer.  The SCSI spec mandates that any
+-	 * untransferred sense data should be interpreted as being zero.
+-	 */
+-	memset((void *) SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
++		/*
++		 * Zero the sense buffer.  The SCSI spec mandates that any
++		 * untransferred sense data should be interpreted as being zero.
++		 */
++		memset((void *) SCpnt->sense_buffer, 0,
++		       sizeof(SCpnt->sense_buffer));
+ 
+-	SCpnt->request_buffer = NULL;
+-	SCpnt->request_bufflen = 0;
+-	SCpnt->use_sg = 0;
+-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+-	SCpnt->underflow = 0;
+-	SCpnt->sc_data_direction = SCSI_DATA_NONE;
++		SCpnt->request_buffer = NULL;
++		SCpnt->request_bufflen = 0;
++		SCpnt->use_sg = 0;
++		SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
++		SCpnt->underflow = 0;
++		SCpnt->sc_data_direction = SCSI_DATA_NONE;
+ 
+-	scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
++		scsi_send_eh_cmnd(SCpnt, SENSE_TIMEOUT);
++		/*
++		 * If the SCSI device responded with "logical unit
++		 * is in process of becoming ready", we need to
++		 * retry this command.
++		 */
++	} while (SCpnt->eh_state == NEEDS_RETRY && tries++ < TUR_RETRIES);
+ 
+ 	/*
+ 	 * When we eventually call scsi_finish, we really wish to complete
+ 	 * the original request, so let's restore the original data. (DB)
+ 	 */
+-	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
+-	       sizeof(SCpnt->data_cmnd));
+-	SCpnt->request_buffer = SCpnt->buffer;
+-	SCpnt->request_bufflen = SCpnt->bufflen;
+-	SCpnt->use_sg = SCpnt->old_use_sg;
+-	SCpnt->cmd_len = SCpnt->old_cmd_len;
+-	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
+-	SCpnt->underflow = SCpnt->old_underflow;
++	scsi_setup_cmd_retry(SCpnt);
+ 
+ 	/*
+ 	 * Hey, we are done.  Let's look to see what happened.
+@@ -589,7 +600,6 @@
+ 
+ 	host = SCpnt->host;
+ 
+-      retry:
+ 	/*
+ 	 * We will use a queued command if possible, otherwise we will emulate the
+ 	 * queuing and calling of completion function ourselves.
+@@ -672,14 +682,13 @@
+ 		SCSI_LOG_ERROR_RECOVERY(3,
+ 			printk("scsi_send_eh_cmnd: scsi_eh_completed_normally %x\n", ret));
+ 		switch (ret) {
+-		case SUCCESS:
+-			SCpnt->eh_state = SUCCESS;
+-			break;
+-		case NEEDS_RETRY:
+-			goto retry;
+-		case FAILED:
+ 		default:
+-			SCpnt->eh_state = FAILED;
++			ret = FAILED;
++			/*FALLTHROUGH*/
++		case FAILED:
++		case NEEDS_RETRY:
++		case SUCCESS:
++			SCpnt->eh_state = ret;
+ 			break;
+ 		}
+ 	} else {
+@@ -1220,6 +1229,82 @@
+ 
+ 
+ /*
++ * Function:	scsi_eh_lock_done
++ *
++ * Purpose:	free the command and request structures associated
++ *		with the error handlers door lock request
++ *
++ * Arguments:	SCpnt - the SCSI command block for the door lock request.
++ *
++ * Returns:	Nothing
++ *
++ * Notes:	We completed the asynchronous door lock request, and
++ *		it has either locked the door or failed.  We must free
++ *		the command structures associated with this request.
++ */
++static void scsi_eh_lock_done(struct scsi_cmnd *SCpnt)
++{
++	struct scsi_request *SRpnt = SCpnt->sc_request;
++
++	SCpnt->sc_request = NULL;
++	SRpnt->sr_command = NULL;
++
++	scsi_release_command(SCpnt);
++	scsi_release_request(SRpnt);
++}
++
++
++/*
++ * Function:	scsi_eh_lock_door
++ *
++ * Purpose:	Prevent medium removal for the specified device
++ *
++ * Arguments:	dev - SCSI device to prevent medium removal
++ *
++ * Locking:	We must be called from process context;
++ *		scsi_allocate_request() may sleep.
++ *
++ * Returns:	Nothing
++ *
++ * Notes:	We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request
++ *		on the head of the devices request queue, and continue.
++ *
++ * Bugs:	scsi_allocate_request() may sleep waiting for existing
++ *		requests to be processed.  However, since we haven't
++ *		kicked off any request processing for this host, this
++ *		may deadlock.
++ *
++ *		If scsi_allocate_request() fails for what ever reason,
++ *		we completely forget to lock the door.
++ */
++STATIC void scsi_eh_lock_door(struct scsi_device *dev)
++{
++	struct scsi_request *SRpnt = scsi_allocate_request(dev);
++
++	if (SRpnt == NULL) {
++		/* what now? */
++		return;
++	}
++
++	SRpnt->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL;
++	SRpnt->sr_cmnd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
++	SRpnt->sr_cmnd[2] = 0;
++	SRpnt->sr_cmnd[3] = 0;
++	SRpnt->sr_cmnd[4] = SCSI_REMOVAL_PREVENT;
++	SRpnt->sr_cmnd[5] = 0;
++	SRpnt->sr_data_direction = SCSI_DATA_NONE;
++	SRpnt->sr_bufflen = 0;
++	SRpnt->sr_buffer = NULL;
++	SRpnt->sr_allowed = 5;
++	SRpnt->sr_done = scsi_eh_lock_done;
++	SRpnt->sr_timeout_per_command = 10 * HZ;
++	SRpnt->sr_cmd_len = COMMAND_SIZE(SRpnt->sr_cmnd[0]);
++
++	scsi_insert_special_req(SRpnt, 1);
++}
++
++
++/*
+  * Function:  scsi_restart_operations
+  *
+  * Purpose:     Restart IO operations to the specified host.
+@@ -1241,6 +1326,15 @@
+ 	ASSERT_LOCK(&io_request_lock, 0);
+ 
+ 	/*
++	 * If the door was locked, we need to insert a door lock request
++	 * onto the head of the SCSI request queue for the device.  There
++	 * is no point trying to lock the door of an off-line device.
++	 */
++	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
++		if (SDpnt->online && SDpnt->locked)
++			scsi_eh_lock_door(SDpnt);
++
++	/*
+ 	 * Next free up anything directly waiting upon the host.  This will be
+ 	 * requests for character device operations, and also for ioctls to queued
+ 	 * block devices.
+@@ -1260,8 +1354,7 @@
+ 		request_queue_t *q;
+ 		if ((host->can_queue > 0 && (host->host_busy >= host->can_queue))
+ 		    || (host->host_blocked)
+-		    || (host->host_self_blocked)
+-		    || (SDpnt->device_blocked)) {
++		    || (host->host_self_blocked)) {
+ 			break;
+ 		}
+ 		q = &SDpnt->request_queue;
+@@ -1271,136 +1364,202 @@
+ }
+ 
+ /*
+- * Function:  scsi_unjam_host
++ * Function:	scsi_eh_find_failed_command
+  *
+- * Purpose:     Attempt to fix a host which has a command that failed for
+- *              some reason.
++ * Purpose:	Find a failed Scsi_Cmnd structure on a device.
+  *
+- * Arguments:   host    - host that needs unjamming.
+- * 
+- * Returns:     Nothing
++ * Arguments:	SDpnt	- Scsi_Device structure
+  *
+- * Notes:       When we come in here, we *know* that all commands on the
+- *              bus have either completed, failed or timed out.  We also
+- *              know that no further commands are being sent to the host,
+- *              so things are relatively quiet and we have freedom to
+- *              fiddle with things as we wish.
++ * Returns:	Pointer to Scsi_Cmnd structure, or NULL on failure
++ */
++STATIC Scsi_Cmnd *scsi_eh_find_failed_command(Scsi_Device *SDpnt)
++{
++	Scsi_Cmnd *SCpnt;
++
++	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
++		if (SCpnt->state == SCSI_STATE_FAILED ||
++		    SCpnt->state == SCSI_STATE_TIMEOUT)
++			return SCpnt;
++
++	return NULL;
++}
++
++
++/*
++ * Function:	scsi_eh_test_and_retry
+  *
+- * Additional note:  This is only the *default* implementation.  It is possible
+- *              for individual drivers to supply their own version of this
+- *              function, and if the maintainer wishes to do this, it is
+- *              strongly suggested that this function be taken as a template
+- *              and modified.  This function was designed to correctly handle
+- *              problems for about 95% of the different cases out there, and
+- *              it should always provide at least a reasonable amount of error
+- *              recovery.
++ * Purpose:	Try to retry a failed command.
+  *
+- * Note3:       Any command marked 'FAILED' or 'TIMEOUT' must eventually
+- *              have scsi_finish_command() called for it.  We do all of
+- *              the retry stuff here, so when we restart the host after we
+- *              return it should have an empty queue.
++ * Arguments:	SCpnt	- scsi command structure
++ *		done	- list of commands that have been successfully
++ *			  completed.
++ *
++ * Returns:	SUCCESS or FAILED
++ *
++ * Note:	If the TEST UNIT READY command successfully executes,
++ *		but returns some form of "device not ready", we wait
++ *		a while, and retry 3 times.  The device could be still
++ *		re-initialising.
+  */
+-STATIC int scsi_unjam_host(struct Scsi_Host *host)
++STATIC int scsi_eh_test_and_retry(Scsi_Cmnd *SCpnt, Scsi_Cmnd **done)
+ {
+-	int devices_failed;
+-	int numfailed;
+-	int ourrtn;
+-	int rtn = FALSE;
+-	int result;
+-	Scsi_Cmnd *SCloop;
+-	Scsi_Cmnd *SCpnt;
+-	Scsi_Device *SDpnt;
+-	Scsi_Device *SDloop;
+-	Scsi_Cmnd *SCdone;
+-	int timed_out;
++	int rtn, tries = 3;
+ 
+-	ASSERT_LOCK(&io_request_lock, 0);
++	do {
++		rtn = scsi_test_unit_ready(SCpnt);
++		if (rtn != SUCCESS)
++			return rtn;
+ 
+-	SCdone = NULL;
++		if (scsi_unit_is_ready(SCpnt))
++			break;
++
++		if (tries-- == 0)
++			return FAILED;
++
++		scsi_sleep(5 * HZ);
++	} while (1);
++
++	rtn = scsi_eh_retry_command(SCpnt);
++	if (rtn == SUCCESS) {
++		SCpnt->host->host_failed--;
++		scsi_eh_finish_command(done, SCpnt);
++	}
++
++	return rtn;
++}
+ 
+-	/*
+-	 * First, protect against any sort of race condition.  If any of the outstanding
+-	 * commands are in states that indicate that we are not yet blocked (i.e. we are
+-	 * not in a quiet state) then we got woken up in error.  If we ever end up here,
+-	 * we need to re-examine some of the assumptions.
+-	 */
+-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+-			if (SCpnt->state == SCSI_STATE_FAILED
+-			    || SCpnt->state == SCSI_STATE_TIMEOUT
+-			    || SCpnt->state == SCSI_STATE_INITIALIZING
+-			    || SCpnt->state == SCSI_STATE_UNUSED) {
+-				continue;
+-			}
+-			/*
+-			 * Rats.  Something is still floating around out there.  This could
+-			 * be the result of the fact that the upper level drivers are still frobbing
+-			 * commands that might have succeeded.  There are two outcomes.  One is that
+-			 * the command block will eventually be freed, and the other one is that
+-			 * the command will be queued and will be finished along the way.
+-			 */
+-			SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
+ 
+ /*
+- *        panic("SCSI Error handler woken too early\n");
++ * Function:	scsi_eh_restart_device
+  *
+- * This is no longer a problem, since now the code cares only about
+- * SCSI_STATE_TIMEOUT and SCSI_STATE_FAILED.
+- * Other states are useful only to release active commands when devices are
+- * set offline. If (host->host_active == host->host_busy) we can safely assume
+- * that there are no commands in state other then TIMEOUT od FAILED. (DB)
++ * Purpose:	Retry all failed or timed out commands for a device
+  *
+- * FIXME:
+- * It is not easy to release correctly commands according to their state when 
+- * devices are set offline, when the state is neither TIMEOUT nor FAILED.
+- * When a device is set offline, we can have some command with
+- * rq_status=RQ_SCSY_BUSY, owner=SCSI_STATE_HIGHLEVEL, 
+- * state=SCSI_STATE_INITIALIZING and the driver module cannot be released.
+- * (DB, 17 May 1998)
++ * Arguments:	SDpnt	- SCSI device to retry
++ *		done	- list of commands that have been successfully
++ *			  completed.
++ *
++ * Returns:	SUCCESS or failure code
+  */
++STATIC int scsi_eh_restart_device(Scsi_Device *SDpnt, Scsi_Cmnd **done)
++{
++	Scsi_Cmnd *SCpnt, *SCnext;
++	int rtn = SUCCESS;
++
++	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {
++		SCnext = SCpnt->next;
++
++		if (SCpnt->state == SCSI_STATE_FAILED ||
++		    SCpnt->state == SCSI_STATE_TIMEOUT) {
++			rtn = scsi_eh_test_and_retry(SCpnt, done);
++			if (rtn != SUCCESS)
++				break;
++		}
++	}
++
++	return rtn;
++}
++
++/*
++ * Function:	scsi_eh_set_device_offline
++ *
++ * Purpose:	set a device off line
++ *
++ * Arguments:	SDpnt	- SCSI device to take off line
++ *		done	- list of commands that have been successfully
++ *			  completed.
++ *		reason	- text string describing why the device is off-line
++ *
++ * Returns:	Nothing
++ *
++ * Notes:	In addition, we complete each failed or timed out command
++ *		attached to this device.
++ */
++STATIC void scsi_eh_set_device_offline(Scsi_Device *SDpnt, Scsi_Cmnd **done,
++				       const char *reason)
++{
++	Scsi_Cmnd *SCpnt, *SCnext;
++
++	printk(KERN_ERR "scsi: device set offline - %s: "
++		"host %d channel %d id %d lun %d\n",
++		reason, SDpnt->host->host_no, SDpnt->channel,
++		SDpnt->id, SDpnt->lun);
++
++	SDpnt->online = FALSE;
++
++	for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCnext) {
++		SCnext = SCpnt->next;
++
++		switch (SCpnt->state) {
++		case SCSI_STATE_TIMEOUT:
++			SCpnt->result |= DRIVER_TIMEOUT;
++			/*FALLTHROUGH*/
++
++		case SCSI_STATE_FAILED:
++			SCSI_LOG_ERROR_RECOVERY(3,
++				printk("Finishing command for device %d %x\n",
++					SDpnt->id, SCpnt->result));
++
++			SDpnt->host->host_failed--;
++			scsi_eh_finish_command(done, SCpnt);
++			break;
++
++		default:
++			break;
+ 		}
+ 	}
++}
++
++static void scsi_unjam_request_sense(struct Scsi_Host *host, Scsi_Cmnd **done)
++{
++	int rtn;
++	int result;
++	Scsi_Cmnd *SCpnt;
++	Scsi_Device *SDpnt;
+ 
+ 	/*
+ 	 * Next, see if we need to request sense information.  if so,
+ 	 * then get it now, so we have a better idea of what to do.
+-	 * FIXME(eric) this has the unfortunate side effect that if a host
+-	 * adapter does not automatically request sense information, that we end
+-	 * up shutting it down before we request it.  All hosts should be doing this
+-	 * anyways, so for now all I have to say is tough noogies if you end up in here.
+-	 * On second thought, this is probably a good idea.  We *really* want to give
+-	 * authors an incentive to automatically request this.
++	 * FIXME(eric) this has the unfortunate side effect that if a
++	 * host adapter does not automatically request sense information,
++	 * that we end up shutting it down before we request it.  All
++	 * hosts should be doing this anyways, so for now all I have
++	 * to say is tough noogies if you end up in here.  On second
++	 * thought, this is probably a good idea.  We *really* want
++	 * to give authors an incentive to automatically request this.
+ 	 */
+-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
++	SCSI_LOG_ERROR_RECOVERY(3,
++		printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
+ 
+ 	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+ 		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+-			if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt)) {
++			if (SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt))
+ 				continue;
+-			}
+-			SCSI_LOG_ERROR_RECOVERY(2, printk("scsi_unjam_host: Requesting sense for %d\n",
+-							  SCpnt->target));
++
++			SCSI_LOG_ERROR_RECOVERY(2,
++				printk("scsi_unjam_host: Requesting sense for %d\n",
++					  SCpnt->target));
+ 			rtn = scsi_request_sense(SCpnt);
+-			if (rtn != SUCCESS) {
++			if (rtn != SUCCESS)
+ 				continue;
+-			}
+-			SCSI_LOG_ERROR_RECOVERY(3, printk("Sense requested for %p - result %x\n",
+-						  SCpnt, SCpnt->result));
++
++			SCSI_LOG_ERROR_RECOVERY(3,
++				printk("Sense requested for %p - result %x\n",
++					  SCpnt, SCpnt->result));
+ 			SCSI_LOG_ERROR_RECOVERY(3, print_sense("bh", SCpnt));
+ 
+ 			result = scsi_decide_disposition(SCpnt);
+ 
+ 			/*
+-			 * If the result was normal, then just pass it along to the
+-			 * upper level.
++			 * If the result was normal, then just pass
++			 * it along to the upper level.
+ 			 */
+ 			if (result == SUCCESS) {
+ 				SCpnt->host->host_failed--;
+-				scsi_eh_finish_command(&SCdone, SCpnt);
++				scsi_eh_finish_command(done, SCpnt);
+ 			}
+-			if (result != NEEDS_RETRY) {
++			if (result != NEEDS_RETRY)
+ 				continue;
+-			}
++
+ 			/* 
+ 			 * We only come in here if we want to retry a
+ 			 * command.  The test to see whether the command
+@@ -1410,20 +1569,29 @@
+ 			 */
+ 			SCpnt->state = NEEDS_RETRY;
+ 			rtn = scsi_eh_retry_command(SCpnt);
+-			if (rtn != SUCCESS) {
++			if (rtn != SUCCESS)
+ 				continue;
+-			}
++
+ 			/*
+ 			 * We eventually hand this one back to the top level.
+ 			 */
+ 			SCpnt->host->host_failed--;
+-			scsi_eh_finish_command(&SCdone, SCpnt);
++			scsi_eh_finish_command(done, SCpnt);
+ 		}
+ 	}
++}
++
++static void scsi_unjam_count(struct Scsi_Host *host, Scsi_Cmnd **done)
++{
++	Scsi_Device *SDpnt;
++	Scsi_Cmnd *SCpnt;
++	int devices_failed;
++	int numfailed;
++	int timed_out;
+ 
+ 	/*
+-	 * Go through the list of commands and figure out where we stand and how bad things
+-	 * really are.
++	 * Go through the list of commands and figure out where we
++	 * stand and how bad things really are.
+ 	 */
+ 	numfailed = 0;
+ 	timed_out = 0;
+@@ -1433,359 +1601,478 @@
+ 
+ 		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+ 			if (SCpnt->state == SCSI_STATE_FAILED) {
+-				SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d failed\n",
+-							 SCpnt->target));
++				SCSI_LOG_ERROR_RECOVERY(5,
++					printk("Command to ID %d failed\n",
++						 SCpnt->target));
+ 				numfailed++;
+ 				device_error++;
+ 			}
+ 			if (SCpnt->state == SCSI_STATE_TIMEOUT) {
+-				SCSI_LOG_ERROR_RECOVERY(5, printk("Command to ID %d timedout\n",
+-							 SCpnt->target));
++				SCSI_LOG_ERROR_RECOVERY(5,
++					printk("Command to ID %d timedout\n",
++						 SCpnt->target));
+ 				timed_out++;
+ 				device_error++;
+ 			}
+ 		}
+-		if (device_error > 0) {
++		if (device_error > 0)
+ 			devices_failed++;
+-		}
+ 	}
+ 
+-	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d+%d commands on %d devices require eh work\n",
+-				  numfailed, timed_out, devices_failed));
++	SCSI_LOG_ERROR_RECOVERY(2,
++		printk("Total of %d+%d commands on %d devices require eh work\n",
++			  numfailed, timed_out, devices_failed));
++}
++
++static void scsi_unjam_abort(struct Scsi_Host *host, Scsi_Cmnd **done)
++{
++	Scsi_Device *SDpnt;
++	Scsi_Cmnd *SCpnt;
++	int rtn;
+ 
+-	if (host->host_failed == 0) {
+-		ourrtn = TRUE;
+-		goto leave;
+-	}
+ 	/*
+-	 * Next, try and see whether or not it makes sense to try and abort
+-	 * the running command.  This only works out to be the case if we have
+-	 * one command that has timed out.  If the command simply failed, it
+-	 * makes no sense to try and abort the command, since as far as the
+-	 * host adapter is concerned, it isn't running.
++	 * Next, try and see whether or not it makes sense to try and
++	 * abort the running command.  This only works out to be the
++	 * case if we have one command that has timed out.  If the
++	 * command simply failed, it makes no sense to try and abort
++	 * the command, since as far as the host adapter is concerned,
++	 * it isn't running.
+ 	 */
+ 
+-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
++	SCSI_LOG_ERROR_RECOVERY(3,
++		printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
+ 
+ 	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+-		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
+-			if (SCloop->state != SCSI_STATE_TIMEOUT) {
++		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
++			if (SCpnt->state != SCSI_STATE_TIMEOUT)
+ 				continue;
+-			}
+-			rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
+-			if (rtn == SUCCESS) {
+-				rtn = scsi_test_unit_ready(SCloop);
+ 
+-				if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+-					rtn = scsi_eh_retry_command(SCloop);
+-
+-					if (rtn == SUCCESS) {
+-						SCloop->host->host_failed--;
+-						scsi_eh_finish_command(&SCdone, SCloop);
+-					}
+-				}
+-			}
++			rtn = scsi_try_to_abort_command(SCpnt, ABORT_TIMEOUT);
++			if (rtn == SUCCESS)
++				scsi_eh_test_and_retry(SCpnt, done);
+ 		}
+ 	}
++}
++
++static void scsi_unjam_device_reset(struct Scsi_Host *host, Scsi_Cmnd **done)
++{
++	Scsi_Device *SDpnt;
++	Scsi_Cmnd *SCpnt;
++	int rtn;
+ 
+-	/*
+-	 * If we have corrected all of the problems, then we are done.
+-	 */
+-	if (host->host_failed == 0) {
+-		ourrtn = TRUE;
+-		goto leave;
+-	}
+ 	/*
+ 	 * Either the abort wasn't appropriate, or it didn't succeed.
+-	 * Now try a bus device reset.  Still, look to see whether we have
+-	 * multiple devices that are jammed or not - if we have multiple devices,
+-	 * it makes no sense to try BUS_DEVICE_RESET - we really would need
+-	 * to try a BUS_RESET instead.
++	 * Now try a bus device reset.  Still, look to see whether we
++	 * have multiple devices that are jammed or not - if we have
++	 * multiple devices, it makes no sense to try BUS_DEVICE_RESET
++	 * - we really would need to try a BUS_RESET instead.
+ 	 *
+-	 * Does this make sense - should we try BDR on each device individually?
+-	 * Yes, definitely.
++	 * Does this make sense - should we try BDR on each device
++	 * individually?  Yes, definitely.
+ 	 */
+-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
++	SCSI_LOG_ERROR_RECOVERY(3,
++		printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
+ 
+ 	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+-		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
+-			if (SCloop->state == SCSI_STATE_FAILED
+-			    || SCloop->state == SCSI_STATE_TIMEOUT) {
+-				break;
+-			}
+-		}
+-
+-		if (SCloop == NULL) {
++		SCpnt = scsi_eh_find_failed_command(SDpnt);
++		if (SCpnt == NULL)
+ 			continue;
+-		}
++
+ 		/*
+-		 * OK, we have a device that is having problems.  Try and send
+-		 * a bus device reset to it.
+-		 *
+-		 * FIXME(eric) - make sure we handle the case where multiple
+-		 * commands to the same device have failed. They all must
+-		 * get properly restarted.
++		 * OK, we have a device that is having problems.
++		 * Try and send a bus device reset to it.
+ 		 */
+-		rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT);
++		rtn = scsi_try_bus_device_reset(SCpnt, RESET_TIMEOUT);
+ 
+-		if (rtn == SUCCESS) {
+-			rtn = scsi_test_unit_ready(SCloop);
++		/*
++		 * A successful bus device reset causes all commands
++		 * currently executing on the device to terminate.
++		 * We expect the HBA driver to "forget" all commands
++		 * associated with this device.
++		 *
++		 * Retry each failed or timed out command currently
++		 * outstanding for this device.
++		 *
++		 * If any command fails, bail out.  We will try a
++		 * bus reset instead.
++		 */
++		if (rtn == SUCCESS)
++			scsi_eh_restart_device(SDpnt, done);
++	}
++}
+ 
+-			if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+-				rtn = scsi_eh_retry_command(SCloop);
++static void scsi_unjam_bus_reset(struct Scsi_Host *host, Scsi_Cmnd **done)
++{
++	Scsi_Device *SDpnt;
++	Scsi_Cmnd *SCpnt;
++	int rtn, channel, max_channel = 0;
+ 
+-				if (rtn == SUCCESS) {
+-					SCloop->host->host_failed--;
+-					scsi_eh_finish_command(&SCdone, SCloop);
+-				}
+-			}
+-		}
+-	}
++	/*
++	 * If we ended up here, we have serious problems.  The only thing
++	 * left to try is a full bus reset.  If someone has grabbed the
++	 * bus and isn't letting go, then perhaps this will help.
++	 */
++	SCSI_LOG_ERROR_RECOVERY(3,
++		printk("scsi_unjam_host: Try hard bus reset\n"));
+ 
+-	if (host->host_failed == 0) {
+-		ourrtn = TRUE;
+-		goto leave;
+-	}
+ 	/*
+-	 * If we ended up here, we have serious problems.  The only thing left
+-	 * to try is a full bus reset.  If someone has grabbed the bus and isn't
+-	 * letting go, then perhaps this will help.
++	 * Find the maximum channel number for this host.
+ 	 */
+-	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard bus reset\n"));
++	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
++		if (SDpnt->channel > max_channel)
++			max_channel = SDpnt->channel;
+ 
+-	/* 
+-	 * We really want to loop over the various channels, and do this on
+-	 * a channel by channel basis.  We should also check to see if any
+-	 * of the failed commands are on soft_reset devices, and if so, skip
+-	 * the reset.  
++	/*
++	 * Loop over each channel, and see if it any device on
++	 * each channel has failed.
+ 	 */
+-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+-	      next_device:
+-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+-			if (SCpnt->state != SCSI_STATE_FAILED
+-			    && SCpnt->state != SCSI_STATE_TIMEOUT) {
++	for (channel = 0; channel <= max_channel; channel++) {
++		Scsi_Cmnd *failed_command;
++		int soft_reset;
++
++ try_again:
++ 		failed_command = NULL;
++ 		soft_reset = 0;
++
++		/*
++		 * Loop over each device on this channel locating any
++		 * failed command.  We need a Scsi_Cmnd structure to
++		 * call the bus reset function.
++		 *
++		 * We also need to check if any of the failed commands
++		 * are on soft_reset devices, and if so, skip the reset.  
++		 */
++		for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
++			if (SDpnt->channel != channel)
+ 				continue;
+-			}
+-			/*
+-			 * We have a failed command.  Make sure there are no other failed
+-			 * commands on the same channel that are timed out and implement a
+-			 * soft reset.
+-			 */
+-			for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
+-				for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
+-					if (SCloop->channel != SCpnt->channel) {
+-						continue;
+-					}
+-					if (SCloop->state != SCSI_STATE_FAILED
+-					    && SCloop->state != SCSI_STATE_TIMEOUT) {
+-						continue;
+-					}
+-					if (SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT) {
+-						/* 
+-						 * If this device uses the soft reset option, and this
+-						 * is one of the devices acting up, then our only
+-						 * option is to wait a bit, since the command is
+-						 * supposedly still running.  
+-						 *
+-						 * FIXME(eric) - right now we will just end up falling
+-						 * through to the 'take device offline' case.
+-						 *
+-						 * FIXME(eric) - It is possible that the command completed
+-						 * *after* the error recovery procedure started, and if this
+-						 * is the case, we are worrying about nothing here.
+-						 */
+ 
+-						scsi_sleep(1 * HZ);
+-						goto next_device;
+-					}
+-				}
+-			}
++			SCpnt = scsi_eh_find_failed_command(SDpnt);
++			if (SCpnt)
++				failed_command = SCpnt;
+ 
+ 			/*
+-			 * We now know that we are able to perform a reset for the
+-			 * bus that SCpnt points to.  There are no soft-reset devices
+-			 * with outstanding timed out commands.
++			 * If this device has timed out or failed commands,
++			 * and uses the soft_reset option.
+ 			 */
+-			rtn = scsi_try_bus_reset(SCpnt);
+-			if (rtn == SUCCESS) {
+-				for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
+-					for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
+-						if (SCloop->channel != SCpnt->channel) {
+-							continue;
+-						}
+-						if (SCloop->state != SCSI_STATE_FAILED
+-						    && SCloop->state != SCSI_STATE_TIMEOUT) {
+-							continue;
+-						}
+-						rtn = scsi_test_unit_ready(SCloop);
++			if (SCpnt && SDpnt->soft_reset)
++				soft_reset = 1;
++		}
+ 
+-						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+-							rtn = scsi_eh_retry_command(SCloop);
++		/*
++		 * If this channel hasn't failed, we
++		 * don't need to reset it.
++		 */
++		if (!failed_command)
++			continue;
+ 
+-							if (rtn == SUCCESS) {
+-								SCpnt->host->host_failed--;
+-								scsi_eh_finish_command(&SCdone, SCloop);
+-							}
+-						}
+-						/*
+-						 * If the bus reset worked, but we are still unable to
+-						 * talk to the device, take it offline.
+-						 * FIXME(eric) - is this really the correct thing to do?
+-						 */
+-						if (rtn != SUCCESS) {
+-							printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after bus reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
++		/* 
++		 * If this device uses the soft reset option, and this
++		 * is one of the devices acting up, then our only
++		 * option is to wait a bit, since the command is
++		 * supposedly still running.  
++		 *
++		 * FIXME(eric) - right now we will just end up falling
++		 * through to the 'take device offline' case.
++		 *
++		 * FIXME(eric) - It is possible that the command completed
++		 * *after* the error recovery procedure started, and if
++		 * this is the case, we are worrying about nothing here.
++		 *
++		 * FIXME(rmk) - This should be bounded; we shouldn't wait
++		 * for an infinite amount of time for any device.
++		 */
++		if (soft_reset) {
++			SCSI_LOG_ERROR_RECOVERY(3,
++				printk("scsi_unjam_host: unable to try bus "
++					"reset for host %d channel %d\n",
++					host->host_no, channel));
++			scsi_sleep(1 * HZ);
++			goto try_again;
++		}
+ 
+-							SDloop->online = FALSE;
+-							SDloop->host->host_failed--;
+-							scsi_eh_finish_command(&SCdone, SCloop);
+-						}
+-					}
+-				}
++		/*
++		 * We now know that we are able to perform a reset for the
++		 * bus that SCpnt points to.  There are no soft-reset devices
++		 * with outstanding timed out commands.
++		 */
++		rtn = scsi_try_bus_reset(failed_command);
++
++		/*
++		 * If we failed to reset the bus, move on to the next bus.
++		 */
++		if (rtn != SUCCESS)
++			continue;
++
++		/*
++		 * We succeeded.  Retry each failed command.
++		 */
++		for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
++			if (SDpnt->channel != channel)
++				continue;
++
++			rtn = scsi_eh_restart_device(SDpnt, done);
++
++			if (rtn != SUCCESS) {
++				SCpnt = scsi_eh_find_failed_command(SDpnt);
++
++				/*
++				 * This device failed again.  Since a bus
++				 * reset freed it up, chances are we've
++				 * hit the same problem, so try the same
++				 * solution.  We also need to ensure that
++				 * the SCSI bus is in the BUS FREE state
++				 * so we can try to talk to other devices.
++				 */
++				scsi_try_bus_reset(SCpnt);
++				scsi_eh_set_device_offline(SDpnt, done,
++					"not ready or command retry "
++					"failed after bus reset");
+ 			}
+ 		}
+ 	}
++}
++
++static void scsi_unjam_host_reset(struct Scsi_Host *host, Scsi_Cmnd **done)
++{
++	Scsi_Device *SDpnt;
++	Scsi_Cmnd *SCpnt;
++	Scsi_Cmnd *failed_command = NULL;
++	int rtn, soft_reset;
+ 
+-	if (host->host_failed == 0) {
+-		ourrtn = TRUE;
+-		goto leave;
+-	}
+ 	/*
+-	 * If we ended up here, we have serious problems.  The only thing left
+-	 * to try is a full host reset - perhaps the firmware on the device
+-	 * crashed, or something like that.
++	 * If we ended up here, we have serious problems.  The only thing
++	 * left to try is a full host reset - perhaps the firmware on the
++	 * device crashed, or something like that.
+ 	 *
+-	 * It is assumed that a succesful host reset will cause *all* information
+-	 * about the command to be flushed from both the host adapter *and* the
+-	 * device.
++	 * It is assumed that a succesful host reset will cause *all*
++	 * information about the command to be flushed from both the host
++	 * adapter *and* the device.
+ 	 *
+-	 * FIXME(eric) - it isn't clear that devices that implement the soft reset
+-	 * option can ever be cleared except via cycling the power.  The problem is
+-	 * that sending the host reset command will cause the host to forget
+-	 * about the pending command, but the device won't forget.  For now, we
+-	 * skip the host reset option if any of the failed devices are configured
+-	 * to use the soft reset option.
++	 * FIXME(eric) - it isn't clear that devices that implement the
++	 * soft reset option can ever be cleared except via cycling the
++	 * power.  The problem is that sending the host reset command will
++	 * cause the host to forget about the pending command, but the
++	 * device won't forget.  For now, we skip the host reset option
++	 * if any of the failed devices are configured to use the soft
++	 * reset option.
+ 	 */
++	SCSI_LOG_ERROR_RECOVERY(3,
++		printk("scsi_unjam_host: Try host reset\n"));
++
++ try_again:
++	failed_command = NULL;
++	soft_reset = 0;
++
+ 	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+-	      next_device2:
+-		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
+-			if (SCpnt->state != SCSI_STATE_FAILED
+-			    && SCpnt->state != SCSI_STATE_TIMEOUT) {
+-				continue;
+-			}
+-			if (SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT) {
+-				/* 
+-				 * If this device uses the soft reset option, and this
+-				 * is one of the devices acting up, then our only
+-				 * option is to wait a bit, since the command is
+-				 * supposedly still running.  
+-				 *
+-				 * FIXME(eric) - right now we will just end up falling
+-				 * through to the 'take device offline' case.
+-				 */
+-				SCSI_LOG_ERROR_RECOVERY(3,
+-							printk("scsi_unjam_host: Unable to try hard host reset\n"));
++		/*
++		 * Locate any failed commands for this device.
++		 */
++		SCpnt = scsi_eh_find_failed_command(SDpnt);
++		if (SCpnt)
++			failed_command = SCpnt;
+ 
+-				/*
+-				 * Due to the spinlock, we will never get out of this
+-				 * loop without a proper wait. (DB)
+-				 */
+-				scsi_sleep(1 * HZ);
++		/*
++		 * If this device has timed out or failed commands,
++		 * and uses the soft_reset option.
++		 */
++		if (SCpnt && SDpnt->soft_reset)
++			soft_reset = 1;
++	}
+ 
+-				goto next_device2;
+-			}
+-			SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Try hard host reset\n"));
++	/* 
++	 * If this device uses the soft reset option, and this
++	 * is one of the devices acting up, then our only
++	 * option is to wait a bit, since the command is
++	 * supposedly still running.  
++	 *
++	 * FIXME(eric) - right now we will just end up falling
++	 * through to the 'take device offline' case.
++	 *
++	 * FIXME(rmk) - This should be bounded; we shouldn't wait
++	 * for an infinite amount of time for any device.
++	 */
++	if (soft_reset) {
++		SCSI_LOG_ERROR_RECOVERY(3,
++			printk("scsi_unjam_host: unable to try "
++				"hard host reset\n"));
+ 
+ 			/*
+-			 * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
++			 * Due to the spinlock, we will never get out of this
++			 * loop without a proper wait. (DB)
+ 			 */
+-			rtn = scsi_try_host_reset(SCpnt);
+-			if (rtn == SUCCESS) {
+-				/*
+-				 * FIXME(eric) we assume that all commands are flushed from the
+-				 * controller.  We should get a DID_RESET for all of the commands
+-				 * that were pending.  We should ignore these so that we can
+-				 * guarantee that we are in a consistent state.
+-				 *
+-				 * I believe this to be the case right now, but this needs to be
+-				 * tested.
+-				 */
+-				for (SDloop = host->host_queue; SDloop; SDloop = SDloop->next) {
+-					for (SCloop = SDloop->device_queue; SCloop; SCloop = SCloop->next) {
+-						if (SCloop->state != SCSI_STATE_FAILED
+-						    && SCloop->state != SCSI_STATE_TIMEOUT) {
+-							continue;
+-						}
+-						rtn = scsi_test_unit_ready(SCloop);
+-
+-						if (rtn == SUCCESS && scsi_unit_is_ready(SCloop)) {
+-							rtn = scsi_eh_retry_command(SCloop);
++			scsi_sleep(1 * HZ);
+ 
+-							if (rtn == SUCCESS) {
+-								SCpnt->host->host_failed--;
+-								scsi_eh_finish_command(&SCdone, SCloop);
+-							}
+-						}
+-						if (rtn != SUCCESS) {
+-							printk(KERN_INFO "scsi: device set offline - not ready or command retry failed after host reset: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+-							SDloop->online = FALSE;
+-							SDloop->host->host_failed--;
+-							scsi_eh_finish_command(&SCdone, SCloop);
+-						}
+-					}
+-				}
+-			}
+-		}
++			goto try_again;
+ 	}
+ 
++	SCSI_LOG_ERROR_RECOVERY(3,
++		printk("scsi_unjam_host: Try hard host reset\n"));
++
+ 	/*
+-	 * If we solved all of the problems, then let's rev up the engines again.
+-	 */
+-	if (host->host_failed == 0) {
+-		ourrtn = TRUE;
+-		goto leave;
+-	}
+-	/*
+-	 * If the HOST RESET failed, then for now we assume that the entire host
+-	 * adapter is too hosed to be of any use.  For our purposes, however, it is
+-	 * easier to simply take the devices offline that correspond to commands
+-	 * that failed.
++	 * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
+ 	 */
+-	SCSI_LOG_ERROR_RECOVERY(1, printk("scsi_unjam_host: Take device offline\n"));
++	rtn = scsi_try_host_reset(failed_command);
++	if (rtn == SUCCESS) {
++		/*
++		 * FIXME(eric) we assume that all commands are flushed from
++		 * the controller.  We should get a DID_RESET for all of the
++		 * commands that were pending.  We should ignore these so
++		 * that we can guarantee that we are in a consistent state.
++		 *
++		 * I believe this to be the case right now, but this needs
++		 * to be tested.
++		 */
++		for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
++			rtn = scsi_eh_restart_device(SDpnt, done);
+ 
+-	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
+-		for (SCloop = SDpnt->device_queue; SCloop; SCloop = SCloop->next) {
+-			if (SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT) {
+-				SDloop = SCloop->device;
+-				if (SDloop->online == TRUE) {
+-					printk(KERN_INFO "scsi: device set offline - command error recover failed: host %d channel %d id %d lun %d\n", SDloop->host->host_no, SDloop->channel, SDloop->id, SDloop->lun);
+-					SDloop->online = FALSE;
+-				}
++			if (rtn != SUCCESS) {
++				SCpnt = scsi_eh_find_failed_command(SDpnt);
+ 
+ 				/*
+-				 * This should pass the failure up to the top level driver, and
+-				 * it will have to try and do something intelligent with it.
++				 * This device failed again.  Since a host
++				 * reset freed it up, chances are we've
++				 * hit the same problem, so try the same
++				 * solution.  We also need to ensure that
++				 * the SCSI bus is in the BUS FREE state
++				 * so we can try to talk to other devices.
+ 				 */
+-				SCloop->host->host_failed--;
+-
+-				if (SCloop->state == SCSI_STATE_TIMEOUT) {
+-					SCloop->result |= (DRIVER_TIMEOUT << 24);
+-				}
+-				SCSI_LOG_ERROR_RECOVERY(3, printk("Finishing command for device %d %x\n",
+-				    SDloop->id, SCloop->result));
+-
+-				scsi_eh_finish_command(&SCdone, SCloop);
++				scsi_try_host_reset(SCpnt);
++				scsi_eh_set_device_offline(SDpnt, done,
++					"not ready or command retry "
++					"failed after host reset");
+ 			}
+ 		}
+ 	}
++}
+ 
+-	if (host->host_failed != 0) {
++static void scsi_unjam_failure(struct Scsi_Host *host, Scsi_Cmnd **done)
++{
++	Scsi_Device *SDpnt;
++
++	/*
++	 * If the HOST RESET failed, then for now we assume that the
++	 * entire host adapter is too hosed to be of any use.  For our
++	 * purposes, however, it is easier to simply take the devices
++	 * offline that correspond to commands that failed.
++	 */
++	SCSI_LOG_ERROR_RECOVERY(1,
++		printk("scsi_unjam_host: Take device offline\n"));
++
++	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
++		scsi_eh_set_device_offline(SDpnt, done,
++			"command error recover failed");
++
++	if (host->host_failed != 0)
+ 		panic("scsi_unjam_host: Miscount of number of failed commands.\n");
+-	}
++
+ 	SCSI_LOG_ERROR_RECOVERY(3, printk("scsi_unjam_host: Returning\n"));
++}
+ 
+-	ourrtn = FALSE;
++static void (*unjam_method[])(struct Scsi_Host *, Scsi_Cmnd **) = {
++	scsi_unjam_request_sense,
++	scsi_unjam_count,
++	scsi_unjam_abort,
++	scsi_unjam_device_reset,
++	scsi_unjam_bus_reset,
++	scsi_unjam_host_reset,
++	scsi_unjam_failure,
++};
+ 
+-      leave:
++/*
++ * Function:  scsi_unjam_host
++ *
++ * Purpose:     Attempt to fix a host which has a command that failed for
++ *              some reason.
++ *
++ * Arguments:   host    - host that needs unjamming.
++ * 
++ * Returns:     Nothing
++ *
++ * Notes:       When we come in here, we *know* that all commands on the
++ *              bus have either completed, failed or timed out.  We also
++ *              know that no further commands are being sent to the host,
++ *              so things are relatively quiet and we have freedom to
++ *              fiddle with things as we wish.
++ *
++ * Additional note:  This is only the *default* implementation.  It is possible
++ *              for individual drivers to supply their own version of this
++ *              function, and if the maintainer wishes to do this, it is
++ *              strongly suggested that this function be taken as a template
++ *              and modified.  This function was designed to correctly handle
++ *              problems for about 95% of the different cases out there, and
++ *              it should always provide at least a reasonable amount of error
++ *              recovery.
++ *
++ * Note3:       Any command marked 'FAILED' or 'TIMEOUT' must eventually
++ *              have scsi_finish_command() called for it.  We do all of
++ *              the retry stuff here, so when we restart the host after we
++ *              return it should have an empty queue.
++ */
++STATIC int scsi_unjam_host(struct Scsi_Host *host)
++{
++	Scsi_Cmnd *SCdone = NULL;
++	Scsi_Cmnd *SCpnt;
++	Scsi_Device *SDpnt;
++	int ourrtn = FALSE;
++	int i;
++
++	ASSERT_LOCK(&io_request_lock, 0);
++
++	/*
++	 * First, protect against any sort of race condition.  If any of the outstanding
++	 * commands are in states that indicate that we are not yet blocked (i.e. we are
++	 * not in a quiet state) then we got woken up in error.  If we ever end up here,
++	 * we need to re-examine some of the assumptions.
++	 */
++	for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
++		for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next) {
++			if (SCpnt->state == SCSI_STATE_FAILED
++			    || SCpnt->state == SCSI_STATE_TIMEOUT
++			    || SCpnt->state == SCSI_STATE_INITIALIZING
++			    || SCpnt->state == SCSI_STATE_UNUSED) {
++				continue;
++			}
++			/*
++			 * Rats.  Something is still floating around out there.  This could
++			 * be the result of the fact that the upper level drivers are still frobbing
++			 * commands that might have succeeded.  There are two outcomes.  One is that
++			 * the command block will eventually be freed, and the other one is that
++			 * the command will be queued and will be finished along the way.
++			 */
++			SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
++
++/*
++ *        panic("SCSI Error handler woken too early\n");
++ *
++ * This is no longer a problem, since now the code cares only about
++ * SCSI_STATE_TIMEOUT and SCSI_STATE_FAILED.
++ * Other states are useful only to release active commands when devices are
++ * set offline. If (host->host_active == host->host_busy) we can safely assume
++ * that there are no commands in state other then TIMEOUT od FAILED. (DB)
++ *
++ * FIXME:
++ * It is not easy to release correctly commands according to their state when 
++ * devices are set offline, when the state is neither TIMEOUT nor FAILED.
++ * When a device is set offline, we can have some command with
++ * rq_status=RQ_SCSY_BUSY, owner=SCSI_STATE_HIGHLEVEL, 
++ * state=SCSI_STATE_INITIALIZING and the driver module cannot be released.
++ * (DB, 17 May 1998)
++ */
++		}
++	}
++
++	for (i = 0; i < ARRAY_SIZE(unjam_method); i++) {
++		unjam_method[i](host, &SCdone);
++
++		/*
++		 * If we solved all of the problems, then
++		 * let's rev up the engines again.
++		 */
++		if (host->host_failed == 0) {
++			ourrtn = TRUE;
++			break;
++		}
++	}
+ 
+ 	/*
+ 	 * We should have a list of commands that we 'finished' during the course of
+@@ -2025,3 +2312,17 @@
+  * tab-width: 8
+  * End:
+  */
++
++EXPORT_SYMBOL(scsi_eh_times_out);
++EXPORT_SYMBOL(scsi_eh_retry_command);
++EXPORT_SYMBOL(scsi_request_sense);
++EXPORT_SYMBOL(scsi_test_unit_ready);
++EXPORT_SYMBOL(scsi_unit_is_ready);
++EXPORT_SYMBOL(scsi_eh_finish_command);
++EXPORT_SYMBOL(scsi_try_to_abort_command);
++EXPORT_SYMBOL(scsi_try_bus_device_reset);
++EXPORT_SYMBOL(scsi_try_bus_reset);
++EXPORT_SYMBOL(scsi_try_host_reset);
++EXPORT_SYMBOL(scsi_sense_valid);
++EXPORT_SYMBOL(scsi_done);
++EXPORT_SYMBOL(scsi_decide_disposition);
+--- linux-2.4.25/drivers/scsi/scsi_ioctl.c~2.4.25-vrs2.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/scsi/scsi_ioctl.c	2004-03-31 17:15:09.000000000 +0200
+@@ -153,6 +153,29 @@
+ 	return result;
+ }
+ 
++int scsi_set_medium_removal(Scsi_Device *dev, char state)
++{
++	char scsi_cmd[MAX_COMMAND_SIZE];
++	int ret;
++
++	if (!dev->removable || !dev->lockable)
++		return 0;
++
++	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
++	scsi_cmd[1] = (dev->scsi_level <= SCSI_2) ? (dev->lun << 5) : 0;
++	scsi_cmd[2] = 0;
++	scsi_cmd[3] = 0;
++	scsi_cmd[4] = state;
++	scsi_cmd[5] = 0;
++
++	ret = ioctl_internal_command(dev, scsi_cmd, IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
++
++	if (ret == 0)
++		dev->locked = state == SCSI_REMOVAL_PREVENT;
++
++	return ret;
++}
++
+ /*
+  * This interface is depreciated - users should use the scsi generic (sg)
+  * interface instead, as this is a more flexible approach to performing
+@@ -450,24 +473,9 @@
+ 		return scsi_ioctl_send_command((Scsi_Device *) dev,
+ 					     (Scsi_Ioctl_Command *) arg);
+ 	case SCSI_IOCTL_DOORLOCK:
+-		if (!dev->removable || !dev->lockable)
+-			return 0;
+-		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+-		scsi_cmd[1] = cmd_byte1;
+-		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+-		scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
+-		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+-				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
+-		break;
++		return scsi_set_medium_removal(dev, SCSI_REMOVAL_PREVENT);
+ 	case SCSI_IOCTL_DOORUNLOCK:
+-		if (!dev->removable || !dev->lockable)
+-			return 0;
+-		scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+-		scsi_cmd[1] = cmd_byte1;
+-		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+-		scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
+-		return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
+-				   IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
++		return scsi_set_medium_removal(dev, SCSI_REMOVAL_ALLOW);
+ 	case SCSI_IOCTL_TEST_UNIT_READY:
+ 		scsi_cmd[0] = TEST_UNIT_READY;
+ 		scsi_cmd[1] = cmd_byte1;
+--- linux-2.4.25/drivers/scsi/scsi_lib.c~2.4.25-vrs2.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/scsi/scsi_lib.c	2004-03-31 17:15:09.000000000 +0200
+@@ -208,6 +208,30 @@
+ }
+ 
+ /*
++ * Function:	scsi_setup_cmd_retry()
++ *
++ * Purpose:	Restore the command state for a retry
++ *
++ * Arguments:	SCpnt	- command to be restored
++ *
++ * Returns:	Nothing
++ *
++ * Notes:	Immediately prior to retrying a command, we need
++ *		to restore certain fields that we saved above.
++ */
++void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt)
++{
++	memcpy((void *) SCpnt->cmnd, (void *) SCpnt->data_cmnd,
++	       sizeof(SCpnt->data_cmnd));
++	SCpnt->request_buffer = SCpnt->buffer;
++	SCpnt->request_bufflen = SCpnt->bufflen;
++	SCpnt->use_sg = SCpnt->old_use_sg;
++	SCpnt->cmd_len = SCpnt->old_cmd_len;
++	SCpnt->sc_data_direction = SCpnt->sc_old_data_direction;
++	SCpnt->underflow = SCpnt->old_underflow;
++}
++
++/*
+  * Function:    scsi_queue_next_request()
+  *
+  * Purpose:     Handle post-processing of completed commands.
+@@ -723,7 +747,7 @@
+ 			printk("scsi%d: ERROR on channel %d, id %d, lun %d, CDB: ",
+ 			       SCpnt->host->host_no, (int) SCpnt->channel,
+ 			       (int) SCpnt->target, (int) SCpnt->lun);
+-			print_command(SCpnt->cmnd);
++			print_command(SCpnt->data_cmnd);
+ 			print_sense("sd", SCpnt);
+ 			SCpnt = scsi_end_request(SCpnt, 0, block_sectors);
+ 			return;
+@@ -898,8 +922,17 @@
+ 		 * space.   Technically the error handling thread should be
+ 		 * doing this crap, but the error handler isn't used by
+ 		 * most hosts.
++		 *
++		 * (rmk)
++		 * Trying to lock the door can cause deadlocks.  We therefore
++		 * only use this for old hosts; our door locking is now done
++		 * by the error handler in scsi_restart_operations for new
++		 * eh hosts.
++		 *
++		 * Note that we don't clear was_reset here; this is used by
++		 * st.c, and either one or other has to die.
+ 		 */
+-		if (SDpnt->was_reset) {
++		if (SHpnt->hostt->use_new_eh_code == 0 && SDpnt->was_reset) {
+ 			/*
+ 			 * We need to relock the door, but we might
+ 			 * be in an interrupt handler.  Only do this
+@@ -910,7 +943,7 @@
+ 			 * this work.
+ 			 */
+ 			SDpnt->was_reset = 0;
+-			if (SDpnt->removable && !in_interrupt()) {
++			if (SDpnt->removable && SDpnt->locked && !in_interrupt()) {
+ 				spin_unlock_irq(&io_request_lock);
+ 				scsi_ioctl(SDpnt, SCSI_IOCTL_DOORLOCK, 0);
+ 				spin_lock_irq(&io_request_lock);
+--- linux-2.4.25/drivers/scsi/scsi_syms.c~2.4.25-vrs2.patch	2002-08-03 02:39:44.000000000 +0200
++++ linux-2.4.25/drivers/scsi/scsi_syms.c	2004-03-31 17:15:09.000000000 +0200
+@@ -103,3 +103,6 @@
+ extern int scsi_delete_timer(Scsi_Cmnd *);
+ EXPORT_SYMBOL(scsi_add_timer);
+ EXPORT_SYMBOL(scsi_delete_timer);
++
++extern int scsi_set_medium_removal(Scsi_Device *dev, char state);
++EXPORT_SYMBOL(scsi_set_medium_removal);
+--- linux-2.4.25/drivers/scsi/sd.c~2.4.25-vrs2.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/scsi/sd.c	2004-03-31 17:15:09.000000000 +0200
+@@ -399,6 +399,7 @@
+ 			this_count = 0xffff;
+ 
+ 		SCpnt->cmnd[0] += READ_10 - READ_6;
++		SCpnt->cmnd[1] |= 1 << 3; /* Set FUA --rmk */
+ 		SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+ 		SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+ 		SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+@@ -524,7 +525,7 @@
+ 	if (SDev->removable)
+ 		if (SDev->access_count==1)
+ 			if (scsi_block_when_processing_errors(SDev))
+-				scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL);
++				scsi_set_medium_removal(SDev, SCSI_REMOVAL_PREVENT);
+ 
+ 	
+ 	return 0;
+@@ -553,7 +554,7 @@
+ 	if (SDev->removable) {
+ 		if (!SDev->access_count)
+ 			if (scsi_block_when_processing_errors(SDev))
+-				scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL);
++				scsi_set_medium_removal(SDev, SCSI_REMOVAL_ALLOW);
+ 	}
+ 	if (SDev->host->hostt->module)
+ 		__MOD_DEC_USE_COUNT(SDev->host->hostt->module);
+--- linux-2.4.25/drivers/scsi/sr_ioctl.c~2.4.25-vrs2.patch	2002-11-29 00:53:14.000000000 +0100
++++ linux-2.4.25/drivers/scsi/sr_ioctl.c	2004-03-31 17:15:09.000000000 +0200
+@@ -214,9 +214,8 @@
+ 
+ int sr_lock_door(struct cdrom_device_info *cdi, int lock)
+ {
+-	return scsi_ioctl(scsi_CDs[MINOR(cdi->dev)].device,
+-		      lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK,
+-			  0);
++	return scsi_set_medium_removal(scsi_CDs[MINOR(cdi->dev)].device,
++		      lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
+ }
+ 
+ int sr_drive_status(struct cdrom_device_info *cdi, int slot)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/21285.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,600 @@
++/*
++ * linux/drivers/char/serial_21285.c
++ *
++ * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
++ *
++ * Based on drivers/char/serial.c
++ *
++ *  $Id$
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/major.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/console.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/hardware/dec21285.h>
++#include <asm/hardware.h>
++
++#define BAUD_BASE		(mem_fclk_21285/64)
++
++#define SERIAL_21285_NAME	"ttyFB"
++#define SERIAL_21285_MAJOR	204
++#define SERIAL_21285_MINOR	4
++
++#define SERIAL_21285_AUXNAME	"cuafb"
++#define SERIAL_21285_AUXMAJOR	205
++#define SERIAL_21285_AUXMINOR	4
++
++#ifdef CONFIG_SERIAL_21285_OLD
++#include <asm/mach-types.h>
++/*
++ * Compatability with a mistake made a long time ago.
++ * Note - the use of "ttyI", "/dev/ttyS0" and major/minor 5,64
++ * is HIGHLY DEPRECIATED, and will be removed in the 2.5
++ * kernel series.
++ *					-- rmk 15/04/2000 
++ */
++#define SERIAL_21285_OLD_NAME	"ttyI"
++#define SERIAL_21285_OLD_MAJOR	TTY_MAJOR
++#define SERIAL_21285_OLD_MINOR	64
++
++static struct tty_driver rs285_old_driver;
++#endif
++
++static struct tty_driver rs285_driver, callout_driver;
++static int rs285_refcount;
++static struct tty_struct *rs285_table[1];
++
++static struct termios *rs285_termios[1];
++static struct termios *rs285_termios_locked[1];
++
++static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char;
++static struct tty_struct *rs285_tty;
++static DECLARE_MUTEX(rs285_sem);
++static int rs285_use_count;
++static unsigned long rs285_irq_enabled;
++
++#define TX_IRQ_BIT	(0)
++#define RX_IRQ_BIT	(1)
++
++static void rs285_stop_tx(void)
++{
++	if (test_and_clear_bit(TX_IRQ_BIT, &rs285_irq_enabled))
++		disable_irq(IRQ_CONTX);
++}
++
++static void rs285_start_tx(void)
++{
++	if (!test_and_set_bit(TX_IRQ_BIT, &rs285_irq_enabled))
++		enable_irq(IRQ_CONTX);
++}
++
++static void rs285_stop_rx(void)
++{
++	if (test_and_clear_bit(RX_IRQ_BIT, &rs285_irq_enabled))
++		disable_irq(IRQ_CONRX);
++}
++
++static void rs285_start_rx(void)
++{
++	if (!test_and_set_bit(RX_IRQ_BIT, &rs285_irq_enabled))
++		enable_irq(IRQ_CONRX);
++}
++
++static int rs285_write_room(struct tty_struct *tty)
++{
++	return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1);
++}
++
++static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	if (!rs285_tty) {
++		rs285_stop_rx();
++		return;
++	}
++	while (!(*CSR_UARTFLG & 0x10)) {
++		int ch, flag;
++		ch = *CSR_UARTDR;
++		flag = *CSR_RXSTAT;
++		if (flag & 4)
++			tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN);
++		if (flag & 2)
++			flag = TTY_PARITY;
++		else if (flag & 1)
++			flag = TTY_FRAME;
++		tty_insert_flip_char(rs285_tty, ch, flag);
++	}
++	tty_flip_buffer_push(rs285_tty);
++}
++
++static void rs285_send_xchar(struct tty_struct *tty, char ch)
++{
++	x_char = ch;
++	rs285_start_tx();
++}
++
++static void rs285_throttle(struct tty_struct *tty)
++{
++	if (I_IXOFF(tty))
++		rs285_send_xchar(tty, STOP_CHAR(tty));
++}
++
++static void rs285_unthrottle(struct tty_struct *tty)
++{
++	if (I_IXOFF(tty)) {
++		if (x_char)
++			x_char = 0;
++		else
++			rs285_send_xchar(tty, START_CHAR(tty));
++	}
++}
++
++static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	while (!(*CSR_UARTFLG & 0x20)) {
++		if (x_char) {
++			*CSR_UARTDR = x_char;
++			x_char = 0;
++			continue;
++		}
++		if (putp == getp) {
++			rs285_stop_tx();
++			break;
++		}
++		*CSR_UARTDR = *getp;
++		if (++getp >= wbuf + sizeof(wbuf))
++			getp = wbuf;
++	}
++	if (rs285_tty)
++		wake_up_interruptible(&rs285_tty->write_wait);
++}
++
++static inline int rs285_xmit(int ch)
++{
++	if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf))
++		return 0;
++	*putp = ch;
++	if (++putp >= wbuf + sizeof(wbuf))
++		putp = wbuf;
++	rs285_start_tx();
++	return 1;
++}
++
++static int rs285_write(struct tty_struct *tty, int from_user,
++		       const u_char * buf, int count)
++{
++	int i;
++
++	if (from_user && verify_area(VERIFY_READ, buf, count))
++		return -EINVAL;
++
++	for (i = 0; i < count; i++) {
++		char ch;
++		if (from_user)
++			__get_user(ch, buf + i);
++		else
++			ch = buf[i];
++		if (!rs285_xmit(ch))
++			break;
++	}
++	return i;
++}
++
++static void rs285_put_char(struct tty_struct *tty, u_char ch)
++{
++	rs285_xmit(ch);
++}
++
++static int rs285_chars_in_buffer(struct tty_struct *tty)
++{
++	return sizeof(wbuf) - rs285_write_room(tty);
++}
++
++static void rs285_flush_buffer(struct tty_struct *tty)
++{
++	rs285_stop_tx();
++	putp = getp = wbuf;
++	if (x_char)
++		rs285_start_tx();
++}
++
++static inline void rs285_set_cflag(int cflag)
++{
++	int h_lcr, baud, quot;
++
++	switch (cflag & CSIZE) {
++	case CS5:
++		h_lcr = 0x10;
++		break;
++	case CS6:
++		h_lcr = 0x30;
++		break;
++	case CS7:
++		h_lcr = 0x50;
++		break;
++	default: /* CS8 */
++		h_lcr = 0x70;
++		break;
++
++	}
++	if (cflag & CSTOPB)
++		h_lcr |= 0x08;
++	if (cflag & PARENB)
++		h_lcr |= 0x02;
++	if (!(cflag & PARODD))
++		h_lcr |= 0x04;
++
++	switch (cflag & CBAUD) {
++	case B200:	baud = 200;		break;
++	case B300:	baud = 300;		break;
++	case B1200:	baud = 1200;		break;
++	case B1800:	baud = 1800;		break;
++	case B2400:	baud = 2400;		break;
++	case B4800:	baud = 4800;		break;
++	default:
++	case B9600:	baud = 9600;		break;
++	case B19200:	baud = 19200;		break;
++	case B38400:	baud = 38400;		break;
++	case B57600:	baud = 57600;		break;
++	case B115200:	baud = 115200;		break;
++	}
++
++	/*
++	 * The documented expression for selecting the divisor is:
++	 *  BAUD_BASE / baud - 1
++	 * However, typically BAUD_BASE is not divisible by baud, so
++	 * we want to select the divisor that gives us the minimum
++	 * error.  Therefore, we want:
++	 *  int(BAUD_BASE / baud - 0.5) ->
++	 *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
++	 *  int((BAUD_BASE - (baud >> 1)) / baud)
++	 */
++	quot = (BAUD_BASE - (baud >> 1)) / baud;
++
++	*CSR_UARTCON = 0;
++	*CSR_L_UBRLCR = quot & 0xff;
++	*CSR_M_UBRLCR = (quot >> 8) & 0x0f;
++	*CSR_H_UBRLCR = h_lcr;
++	*CSR_UARTCON = 1;
++}
++
++static void rs285_set_termios(struct tty_struct *tty, struct termios *old)
++{
++	if (old && tty->termios->c_cflag == old->c_cflag)
++		return;
++	rs285_set_cflag(tty->termios->c_cflag);
++}
++
++
++static void rs285_stop(struct tty_struct *tty)
++{
++	rs285_stop_tx();
++}
++
++static void rs285_start(struct tty_struct *tty)
++{
++	rs285_start_tx();
++}
++
++static void rs285_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++	int orig_jiffies = jiffies;
++	while (*CSR_UARTFLG & 8) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(1);
++		if (signal_pending(current))
++			break;
++		if (timeout && time_after(jiffies, orig_jiffies + timeout))
++			break;
++	}
++	set_current_state(TASK_RUNNING);
++}
++
++static int rs285_open(struct tty_struct *tty, struct file *filp)
++{
++	int line, ret;
++
++	MOD_INC_USE_COUNT;
++
++	line = MINOR(tty->device) - tty->driver.minor_start;
++	if (line)
++		return -ENODEV;
++
++	ret = down_interruptible(&rs285_sem);
++	if (ret)
++		return ret;
++
++	tty->driver_data = NULL;
++	rs285_tty = tty;
++
++	if (rs285_use_count == 0) {
++		rs285_irq_enabled = 3;
++		ret = request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL);
++		if (ret == 0) {
++			ret = request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285",
++					  NULL);
++			if (ret)
++				free_irq(IRQ_CONRX, NULL);
++		}
++	}
++
++	if (ret == 0)
++		rs285_use_count++;
++
++	up(&rs285_sem);
++
++	return ret;
++}
++
++static void rs285_close(struct tty_struct *tty, struct file *filp)
++{
++	down(&rs285_sem);
++	if (!--rs285_use_count) {
++		rs285_wait_until_sent(tty, 0);
++		rs285_stop_rx();
++		rs285_stop_tx();
++		rs285_tty = NULL;
++		free_irq(IRQ_CONTX, NULL);
++		free_irq(IRQ_CONRX, NULL);
++	}
++	up(&rs285_sem);
++	MOD_DEC_USE_COUNT;
++}
++
++static int __init rs285_init(void)
++{
++	int baud = B9600;
++
++	if (machine_is_personal_server())
++		baud = B57600;
++
++	rs285_driver.magic = TTY_DRIVER_MAGIC;
++	rs285_driver.driver_name = "serial_21285";
++	rs285_driver.name = SERIAL_21285_NAME;
++	rs285_driver.major = SERIAL_21285_MAJOR;
++	rs285_driver.minor_start = SERIAL_21285_MINOR;
++	rs285_driver.num = 1;
++	rs285_driver.type = TTY_DRIVER_TYPE_SERIAL;
++	rs285_driver.subtype = SERIAL_TYPE_NORMAL;
++	rs285_driver.init_termios = tty_std_termios;
++	rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL;
++	rs285_driver.flags = TTY_DRIVER_REAL_RAW;
++	rs285_driver.refcount = &rs285_refcount;
++	rs285_driver.table = rs285_table;
++	rs285_driver.termios = rs285_termios;
++	rs285_driver.termios_locked = rs285_termios_locked;
++
++	rs285_driver.open = rs285_open;
++	rs285_driver.close = rs285_close;
++	rs285_driver.write = rs285_write;
++	rs285_driver.put_char = rs285_put_char;
++	rs285_driver.write_room = rs285_write_room;
++	rs285_driver.chars_in_buffer = rs285_chars_in_buffer;
++	rs285_driver.flush_buffer = rs285_flush_buffer;
++	rs285_driver.throttle = rs285_throttle;
++	rs285_driver.unthrottle = rs285_unthrottle;
++	rs285_driver.send_xchar = rs285_send_xchar;
++	rs285_driver.set_termios = rs285_set_termios;
++	rs285_driver.stop = rs285_stop;
++	rs285_driver.start = rs285_start;
++	rs285_driver.wait_until_sent = rs285_wait_until_sent;
++
++	callout_driver = rs285_driver;
++	callout_driver.name = SERIAL_21285_AUXNAME;
++	callout_driver.major = SERIAL_21285_AUXMAJOR;
++	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
++
++#ifdef CONFIG_SERIAL_21285_OLD
++	if (!machine_is_ebsa285() && !machine_is_netwinder()) {
++		rs285_old_driver = rs285_driver;
++		rs285_old_driver.name = SERIAL_21285_OLD_NAME;
++		rs285_old_driver.major = SERIAL_21285_OLD_MAJOR;
++		rs285_old_driver.minor_start = SERIAL_21285_OLD_MINOR;
++
++		if (tty_register_driver(&rs285_old_driver))
++			printk(KERN_ERR "Couldn't register old 21285 serial driver\n");
++	}
++#endif
++
++	if (tty_register_driver(&rs285_driver))
++		printk(KERN_ERR "Couldn't register 21285 serial driver\n");
++	if (tty_register_driver(&callout_driver))
++		printk(KERN_ERR "Couldn't register 21285 callout driver\n");
++
++	return 0;
++}
++
++static void __exit rs285_fini(void)
++{
++	unsigned long flags;
++	int ret;
++
++	save_flags(flags);
++	cli();
++	ret = tty_unregister_driver(&callout_driver);
++	if (ret)
++		printk(KERN_ERR "Unable to unregister 21285 callout driver "
++			"(%d)\n", ret);
++	ret = tty_unregister_driver(&rs285_driver);
++	if (ret)
++		printk(KERN_ERR "Unable to unregister 21285 driver (%d)\n",
++			ret);
++#ifdef CONFIG_SERIAL_21285_OLD
++	if (!machine_is_ebsa285() && !machine_is_netwinder()) {
++		ret = tty_unregister_driver(&rs285_old_driver);
++		if (ret)
++			printk(KERN_ERR "Unable to unregister old 21285 "
++				"driver (%d)\n", ret);
++	}
++#endif
++	free_irq(IRQ_CONTX, NULL);
++	free_irq(IRQ_CONRX, NULL);
++	restore_flags(flags);
++}
++
++module_init(rs285_init);
++module_exit(rs285_fini);
++
++#ifdef CONFIG_SERIAL_21285_CONSOLE
++/************** console driver *****************/
++
++static void rs285_console_write(struct console *co, const char *s, u_int count)
++{
++	int i;
++
++	rs285_stop_tx();
++	for (i = 0; i < count; i++) {
++		while (*CSR_UARTFLG & 0x20);
++		*CSR_UARTDR = s[i];
++		if (s[i] == '\n') {
++			while (*CSR_UARTFLG & 0x20);
++			*CSR_UARTDR = '\r';
++		}
++	}
++	rs285_start_tx();
++}
++
++static kdev_t rs285_console_device(struct console *c)
++{
++	return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
++}
++
++static int __init rs285_console_setup(struct console *co, char *options)
++{
++	int baud = 9600;
++	int bits = 8;
++	int parity = 'n';
++	int cflag = CREAD | HUPCL | CLOCAL;
++
++	if (machine_is_personal_server())
++		baud = 57600;
++
++	if (options) {
++		char *s = options;
++		baud = simple_strtoul(options, NULL, 10);
++		while (*s >= '0' && *s <= '9')
++			s++;
++		if (*s)
++			parity = *s++;
++		if (*s)
++			bits = *s - '0';
++	}
++
++	/*
++	 *    Now construct a cflag setting.
++	 */
++	switch (baud) {
++	case 1200:
++		cflag |= B1200;
++		break;
++	case 2400:
++		cflag |= B2400;
++		break;
++	case 4800:
++		cflag |= B4800;
++		break;
++	case 9600:
++		cflag |= B9600;
++		break;
++	case 19200:
++		cflag |= B19200;
++		break;
++	case 38400:
++		cflag |= B38400;
++		break;
++	case 57600:
++		cflag |= B57600;
++		break;
++	case 115200:
++		cflag |= B115200;
++		break;
++	default:
++		cflag |= B9600;
++		break;
++	}
++	switch (bits) {
++	case 7:
++		cflag |= CS7;
++		break;
++	default:
++		cflag |= CS8;
++		break;
++	}
++	switch (parity) {
++	case 'o':
++	case 'O':
++		cflag |= PARODD;
++		break;
++	case 'e':
++	case 'E':
++		cflag |= PARENB;
++		break;
++	}
++	co->cflag = cflag;
++	rs285_set_cflag(cflag);
++	rs285_console_write(NULL, "\e[2J\e[Hboot ", 12);
++	if (options)
++		rs285_console_write(NULL, options, strlen(options));
++	else
++		rs285_console_write(NULL, "no options", 10);
++	rs285_console_write(NULL, "\n", 1);
++
++	return 0;
++}
++
++#ifdef CONFIG_SERIAL_21285_OLD
++static struct console rs285_old_cons =
++{
++	SERIAL_21285_OLD_NAME,
++	rs285_console_write,
++	NULL,
++	rs285_console_device,
++	NULL,
++	rs285_console_setup,
++	CON_PRINTBUFFER,
++	-1,
++	0,
++	NULL
++};
++#endif
++
++static struct console rs285_cons =
++{
++	name:		SERIAL_21285_NAME,
++	write:		rs285_console_write,
++	device:		rs285_console_device,
++	setup:		rs285_console_setup,
++	flags:		CON_PRINTBUFFER,
++	index:		-1,
++};
++
++void __init rs285_console_init(void)
++{
++#ifdef CONFIG_SERIAL_21285_OLD
++	if (!machine_is_ebsa285() && !machine_is_netwinder())
++		register_console(&rs285_old_cons);
++#endif
++	register_console(&rs285_cons);
++}
++
++#endif /* CONFIG_SERIAL_21285_CONSOLE */
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/8250.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,2170 @@
++/*
++ *  linux/drivers/serial/8250.c
++ *
++ *  Driver for 8250/16550-type serial ports
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright (C) 2001 Russell King.
++ *
++ * 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.
++ *
++ *  $Id$
++ *
++ * A note about mapbase / membase
++ *
++ *  mapbase is the physical address of the IO port.  Currently, we don't
++ *  support this very well, and it may well be dropped from this driver
++ *  in future.  As such, mapbase should be NULL.
++ *
++ *  membase is an 'ioremapped' cookie.  This is compatible with the old
++ *  serial.c driver, and is currently the preferred form.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/major.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/serial_reg.h>
++#include <linux/serialP.h>
++#include <linux/delay.h>
++#include <linux/serial_core.h>
++#include <linux/kmod.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++
++#include "8250.h"
++
++/*
++ * Configuration:
++ *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option
++ *                is unsafe when used on edge-triggered interrupts.
++ */
++unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
++
++/*
++ * Debugging.
++ */
++#if 0
++#define DEBUG_AUTOCONF(fmt...)	printk(fmt)
++#else
++#define DEBUG_AUTOCONF(fmt...)	do { } while (0)
++#endif
++
++#if 0
++#define DEBUG_INTR(fmt...)	printk(fmt)
++#else
++#define DEBUG_INTR(fmt...)	do { } while (0)
++#endif
++
++#define PASS_LIMIT	256
++
++/*
++ * We default to IRQ0 for the "no irq" hack.   Some
++ * machine types want others as well - they're free
++ * to redefine this in their header file.
++ */
++#define is_real_interrupt(irq)	((irq) != 0)
++
++/*
++ * This converts from our new CONFIG_ symbols to the symbols
++ * that asm/serial.h expects.  You _NEED_ to comment out the
++ * linux/config.h include contained inside asm/serial.h for
++ * this to work.
++ */
++#undef CONFIG_SERIAL_MANY_PORTS
++#undef CONFIG_SERIAL_DETECT_IRQ
++#undef CONFIG_SERIAL_MULTIPORT
++#undef CONFIG_HUB6
++
++#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
++#define CONFIG_SERIAL_DETECT_IRQ 1
++#endif
++#ifdef CONFIG_SERIAL_8250_MULTIPORT
++#define CONFIG_SERIAL_MULTIPORT 1
++#endif
++#ifdef CONFIG_SERIAL_8250_HUB6
++#define CONFIG_HUB6 1
++#endif
++#ifdef CONFIG_SERIAL_8250_MANY_PORTS
++#define CONFIG_SERIAL_MANY_PORTS 1
++#endif
++
++#include <asm/serial.h>
++
++static struct old_serial_port old_serial_port[] = {
++	SERIAL_PORT_DFNS /* defined in asm/serial.h */
++};
++
++#define UART_NR	ARRAY_SIZE(old_serial_port)
++
++static struct tty_driver normal, callout;
++static struct tty_struct *serial8250_table[UART_NR];
++static struct termios *serial8250_termios[UART_NR], *serial8250_termios_locked[UART_NR];
++
++#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
++
++#define PORT_RSA_MAX 4
++static int probe_rsa[PORT_RSA_MAX];
++static int force_rsa[PORT_RSA_MAX];
++#endif /* CONFIG_SERIAL_8250_RSA  */
++
++struct uart_8250_port {
++	struct uart_port	port;
++	struct timer_list	timer;		/* "no irq" timer */
++	struct list_head	list;		/* ports on this IRQ */
++	unsigned int		capabilities;	/* port capabilities */
++	unsigned char		acr;
++	unsigned char		ier;
++	unsigned short		rev;
++	unsigned char		lcr;
++	unsigned char		mcr;
++	unsigned char		mcr_mask;	/* mask of user bits */
++	unsigned char		mcr_force;	/* mask of forced bits */
++	unsigned char		efr;
++	unsigned int		lsr_break_flag;
++
++	/*
++	 * We provide a per-port pm hook.
++	 */
++	void			(*pm)(struct uart_port *port,
++				      unsigned int state, unsigned int old);
++};
++
++struct irq_info {
++	spinlock_t		lock;
++	struct list_head	*head;
++};
++
++static struct irq_info irq_lists[NR_IRQS];
++
++/*
++ * Here we define the default xmit fifo size used for each type of UART.
++ */
++static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = {
++	{ "unknown",	1,	0 },
++	{ "8250",	1,	0 },
++	{ "16450",	1,	0 },
++	{ "16550",	1,	0 },
++	{ "16550A",	16,	UART_CLEAR_FIFO | UART_USE_FIFO },
++	{ "Cirrus",	1, 	0 },
++	{ "ST16650",	1,	UART_CLEAR_FIFO | UART_STARTECH },
++	{ "ST16650V2",	32,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
++	{ "TI16750",	64,	UART_CLEAR_FIFO | UART_USE_FIFO },
++	{ "Startech",	1,	0 },
++	{ "16C950/954",	128,	UART_CLEAR_FIFO | UART_USE_FIFO },
++	{ "ST16654",	64,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
++	{ "XR16850",	128,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
++	{ "RSA",	2048,	UART_CLEAR_FIFO | UART_USE_FIFO }
++};
++
++static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
++{
++	offset <<= up->port.regshift;
++
++	switch (up->port.iotype) {
++#ifdef CONFIG_SERIAL_8250_HUB6
++	case SERIAL_IO_HUB6:
++		outb(up->port.hub6 - 1 + offset, up->port.iobase);
++		return inb(up->port.iobase + 1);
++#endif
++
++	case SERIAL_IO_MEM:
++		return readb(up->port.membase + offset);
++
++	default:
++		return inb(up->port.iobase + offset);
++	}
++}
++
++static _INLINE_ void
++serial_out(struct uart_8250_port *up, int offset, int value)
++{
++	offset <<= up->port.regshift;
++
++	switch (up->port.iotype) {
++#ifdef CONFIG_SERIAL_8250_HUB6
++	case SERIAL_IO_HUB6:
++		outb(up->port.hub6 - 1 + offset, up->port.iobase);
++		outb(value, up->port.iobase + 1);
++		break;
++#endif
++
++	case SERIAL_IO_MEM:
++		writeb(value, up->port.membase + offset);
++		break;
++
++	default:
++		outb(value, up->port.iobase + offset);
++	}
++}
++
++/*
++ * We used to support using pause I/O for certain machines.  We
++ * haven't supported this for a while, but just in case it's badly
++ * needed for certain old 386 machines, I've left these #define's
++ * in....
++ */
++#define serial_inp(up, offset)		serial_in(up, offset)
++#define serial_outp(up, offset, value)	serial_out(up, offset, value)
++
++
++/*
++ * For the 16C950
++ */
++static void serial_icr_write(struct uart_8250_port *up, int offset, int value)
++{
++	serial_out(up, UART_SCR, offset);
++	serial_out(up, UART_ICR, value);
++}
++
++static unsigned int serial_icr_read(struct uart_8250_port *up, int offset)
++{
++	unsigned int value;
++
++	serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD);
++	serial_out(up, UART_SCR, offset);
++	value = serial_in(up, UART_ICR);
++	serial_icr_write(up, UART_ACR, up->acr);
++
++	return value;
++}
++
++#ifdef CONFIG_SERIAL_8250_RSA
++/*
++ * Attempts to turn on the RSA FIFO.  Returns zero on failure.
++ * We set the port uart clock rate if we succeed.
++ */
++static int __enable_rsa(struct uart_8250_port *up)
++{
++	unsigned char mode;
++	int result;
++
++	mode = serial_inp(up, UART_RSA_MSR);
++	result = mode & UART_RSA_MSR_FIFO;
++
++	if (!result) {
++		serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
++		mode = serial_inp(up, UART_RSA_MSR);
++		result = mode & UART_RSA_MSR_FIFO;
++	}
++
++	if (result)
++		up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16;
++
++	return result;
++}
++
++static void enable_rsa(struct uart_8250_port *up)
++{
++	if (up->port.type == PORT_RSA) {
++		if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) {
++			spin_lock_irq(&up->port.lock);
++			__enable_rsa(up);
++			spin_unlock_irq(&up->port.lock);
++		}
++		if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16)
++			serial_outp(up, UART_RSA_FRR, 0);
++	}
++}
++
++/*
++ * Attempts to turn off the RSA FIFO.  Returns zero on failure.
++ * It is unknown why interrupts were disabled in here.  However,
++ * the caller is expected to preserve this behaviour by grabbing
++ * the spinlock before calling this function.
++ */
++static void disable_rsa(struct uart_8250_port *up)
++{
++	unsigned char mode;
++	int result;
++
++	if (up->port.type == PORT_RSA &&
++	    up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) {
++		spin_lock_irq(&up->port.lock);
++
++		mode = serial_inp(up, UART_RSA_MSR);
++		result = !(mode & UART_RSA_MSR_FIFO);
++
++		if (!result) {
++			serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
++			mode = serial_inp(up, UART_RSA_MSR);
++			result = !(mode & UART_RSA_MSR_FIFO);
++		}
++
++		if (result)
++			up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16;
++		spin_unlock_irq(&up->port.lock);
++	}
++}
++#endif /* CONFIG_SERIAL_8250_RSA */
++
++/*
++ * This is a quickie test to see how big the FIFO is.
++ * It doesn't work at all the time, more's the pity.
++ */
++static int size_fifo(struct uart_8250_port *up)
++{
++	unsigned char old_fcr, old_mcr, old_dll, old_dlm;
++	int count;
++
++	old_fcr = serial_inp(up, UART_FCR);
++	old_mcr = serial_inp(up, UART_MCR);
++	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
++		    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
++	serial_outp(up, UART_MCR, UART_MCR_LOOP);
++	serial_outp(up, UART_LCR, UART_LCR_DLAB);
++	old_dll = serial_inp(up, UART_DLL);
++	old_dlm = serial_inp(up, UART_DLM);
++	serial_outp(up, UART_DLL, 0x01);
++	serial_outp(up, UART_DLM, 0x00);
++	serial_outp(up, UART_LCR, 0x03);
++	for (count = 0; count < 256; count++)
++		serial_outp(up, UART_TX, count);
++	mdelay(20);/* FIXME - schedule_timeout */
++	for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) &&
++	     (count < 256); count++)
++		serial_inp(up, UART_RX);
++	serial_outp(up, UART_FCR, old_fcr);
++	serial_outp(up, UART_MCR, old_mcr);
++	serial_outp(up, UART_LCR, UART_LCR_DLAB);
++	serial_outp(up, UART_DLL, old_dll);
++	serial_outp(up, UART_DLM, old_dlm);
++
++	return count;
++}
++
++/*
++ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
++ * When this function is called we know it is at least a StarTech
++ * 16650 V2, but it might be one of several StarTech UARTs, or one of
++ * its clones.  (We treat the broken original StarTech 16650 V1 as a
++ * 16550, and why not?  Startech doesn't seem to even acknowledge its
++ * existence.)
++ * 
++ * What evil have men's minds wrought...
++ */
++static void autoconfig_has_efr(struct uart_8250_port *up)
++{
++	unsigned char id1, id2, id3, rev, saved_dll, saved_dlm;
++
++	/*
++	 * First we check to see if it's an Oxford Semiconductor UART.
++	 *
++	 * If we have to do this here because some non-National
++	 * Semiconductor clone chips lock up if you try writing to the
++	 * LSR register (which serial_icr_read does)
++	 */
++
++	/*
++	 * Check for Oxford Semiconductor 16C950.
++	 *
++	 * EFR [4] must be set else this test fails.
++	 *
++	 * This shouldn't be necessary, but Mike Hudson (Exoray@isys.ca)
++	 * claims that it's needed for 952 dual UART's (which are not
++	 * recommended for new designs).
++	 */
++	up->acr = 0;
++	serial_out(up, UART_LCR, 0xBF);
++	serial_out(up, UART_EFR, 0x10);
++	serial_out(up, UART_LCR, 0x00);
++	id1 = serial_icr_read(up, UART_ID1);
++	id2 = serial_icr_read(up, UART_ID2);
++	id3 = serial_icr_read(up, UART_ID3);
++	rev = serial_icr_read(up, UART_REV);
++
++	DEBUG_AUTOCONF("950id=%02x:%02x:%02x:%02x ", id1, id2, id3, rev);
++
++	if (id1 == 0x16 && id2 == 0xC9 &&
++	    (id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
++		up->port.type = PORT_16C950;
++		up->rev = rev | (id3 << 8);
++		return;
++	}
++	
++	/*
++	 * We check for a XR16C850 by setting DLL and DLM to 0, and then
++	 * reading back DLL and DLM.  The chip type depends on the DLM
++	 * value read back:
++	 *  0x10 - XR16C850 and the DLL contains the chip revision.
++	 *  0x12 - XR16C2850.
++	 *  0x14 - XR16C854.
++	 */
++	serial_outp(up, UART_LCR, UART_LCR_DLAB);
++	saved_dll = serial_inp(up, UART_DLL);
++	saved_dlm = serial_inp(up, UART_DLM);
++	serial_outp(up, UART_DLL, 0);
++	serial_outp(up, UART_DLM, 0);
++	id2 = serial_inp(up, UART_DLL);
++	id1 = serial_inp(up, UART_DLM);
++	serial_outp(up, UART_DLL, saved_dll);
++	serial_outp(up, UART_DLM, saved_dlm);
++
++	DEBUG_AUTOCONF("850id=%02x:%02x ", id1, id2);
++
++	if (id1 == 0x10 || id1 == 0x12 || id1 == 0x14) {
++		if (id1 == 0x10)
++			up->rev = id2;
++		up->port.type = PORT_16850;
++		return;
++	}
++
++	/*
++	 * It wasn't an XR16C850.
++	 *
++	 * We distinguish between the '654 and the '650 by counting
++	 * how many bytes are in the FIFO.  I'm using this for now,
++	 * since that's the technique that was sent to me in the
++	 * serial driver update, but I'm not convinced this works.
++	 * I've had problems doing this in the past.  -TYT
++	 */
++	if (size_fifo(up) == 64)
++		up->port.type = PORT_16654;
++	else
++		up->port.type = PORT_16650V2;
++}
++
++/*
++ * We detected a chip without a FIFO.  Only two fall into
++ * this category - the original 8250 and the 16450.  The
++ * 16450 has a scratch register (accessible with LCR=0)
++ */
++static void autoconfig_8250(struct uart_8250_port *up)
++{
++	unsigned char scratch, status1, status2;
++
++	up->port.type = PORT_8250;
++
++	scratch = serial_in(up, UART_SCR);
++	serial_outp(up, UART_SCR, 0xa5);
++	status1 = serial_in(up, UART_SCR);
++	serial_outp(up, UART_SCR, 0x5a);
++	status2 = serial_in(up, UART_SCR);
++	serial_outp(up, UART_SCR, scratch);
++
++	if (status1 == 0xa5 && status2 == 0x5a)
++		up->port.type = PORT_16450;
++}
++
++/*
++ * We know that the chip has FIFOs.  Does it have an EFR?  The
++ * EFR is located in the same register position as the IIR and
++ * we know the top two bits of the IIR are currently set.  The
++ * EFR should contain zero.  Try to read the EFR.
++ */
++static void autoconfig_16550a(struct uart_8250_port *up)
++{
++	unsigned char status1, status2;
++
++	up->port.type = PORT_16550A;
++
++	/*
++	 * Check for presence of the EFR when DLAB is set.
++	 * Only ST16C650V1 UARTs pass this test.
++	 */
++	serial_outp(up, UART_LCR, UART_LCR_DLAB);
++	if (serial_in(up, UART_EFR) == 0) {
++		DEBUG_AUTOCONF("EFRv1 ");
++		up->port.type = PORT_16650;
++		return;
++	}
++
++	/*
++	 * Maybe it requires 0xbf to be written to the LCR.
++	 * (other ST16C650V2 UARTs, TI16C752A, etc)
++	 */
++	serial_outp(up, UART_LCR, 0xBF);
++	if (serial_in(up, UART_EFR) == 0) {
++		DEBUG_AUTOCONF("EFRv2 ");
++		autoconfig_has_efr(up);
++		return;
++	}
++
++	/*
++	 * Check for a National Semiconductor SuperIO chip.
++	 * Attempt to switch to bank 2, read the value of the LOOP bit
++	 * from EXCR1. Switch back to bank 0, change it in MCR. Then
++	 * switch back to bank 2, read it from EXCR1 again and check
++	 * it's changed. If so, set baud_base in EXCR2 to 921600.
++	 */
++	serial_outp(up, UART_LCR, 0);
++	status1 = serial_in(up, UART_MCR);
++	serial_outp(up, UART_LCR, 0xE0);
++	status2 = serial_in(up, 0x02); /* EXCR1 */
++
++	if (!((status2 ^ status1) & UART_MCR_LOOP)) {
++		serial_outp(up, UART_LCR, 0);
++		serial_outp(up, UART_MCR, status1 ^ UART_MCR_LOOP);
++		serial_outp(up, UART_LCR, 0xE0);
++		status2 = serial_in(up, 0x02); /* EXCR1 */
++		serial_outp(up, UART_LCR, 0);
++		serial_outp(up, UART_MCR, status1);
++
++		if ((status2 ^ status1) & UART_MCR_LOOP) {
++			serial_outp(up, UART_LCR, 0xE0);
++			status1 = serial_in(up, 0x04); /* EXCR1 */
++			status1 &= ~0xB0; /* Disable LOCK, mask out PRESL[01] */
++			status1 |= 0x10;  /* 1.625 divisor for baud_base --> 921600 */
++			serial_outp(up, 0x04, status1);
++			serial_outp(up, UART_LCR, 0);
++
++			up->port.type = PORT_NS16550A;
++			up->port.uartclk = 921600*16;
++			return;
++		}
++	}
++
++	/*
++	 * No EFR.  Try to detect a TI16750, which only sets bit 5 of
++	 * the IIR when 64 byte FIFO mode is enabled when DLAB is set.
++	 * Try setting it with and without DLAB set.  Cheap clones
++	 * set bit 5 without DLAB set.
++	 */
++	serial_outp(up, UART_LCR, 0);
++	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
++	status1 = serial_in(up, UART_IIR) >> 5;
++	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
++	serial_outp(up, UART_LCR, UART_LCR_DLAB);
++	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
++	status2 = serial_in(up, UART_IIR) >> 5;
++	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
++
++	DEBUG_AUTOCONF("iir1=%d iir2=%d ", status1, status2);
++
++	if (status1 == 6 && status2 == 7) {
++		up->port.type = PORT_16750;
++		return;
++	}
++}
++
++/*
++ * This routine is called by rs_init() to initialize a specific serial
++ * port.  It determines what type of UART chip this serial port is
++ * using: 8250, 16450, 16550, 16550A.  The important question is
++ * whether or not this UART is a 16550A or not, since this will
++ * determine whether or not we can use its FIFO features or not.
++ */
++static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
++{
++	unsigned char status1, scratch, scratch2, scratch3;
++	unsigned char save_lcr, save_mcr;
++	unsigned long flags;
++
++	if (!up->port.iobase && !up->port.mapbase && !up->port.membase)
++		return;
++
++	DEBUG_AUTOCONF("ttyS%d: autoconf (0x%04x, 0x%p): ",
++			up->port.line, up->port.iobase, up->port.membase);
++
++	/*
++	 * We really do need global IRQs disabled here - we're going to
++	 * be frobbing the chips IRQ enable register to see if it exists.
++	 */
++	spin_lock_irqsave(&up->port.lock, flags);
++
++	if (!(up->port.flags & UPF_BUGGY_UART)) {
++		/*
++		 * Do a simple existence test first; if we fail this,
++		 * there's no point trying anything else.
++		 * 
++		 * 0x80 is used as a nonsense port to prevent against
++		 * false positives due to ISA bus float.  The
++		 * assumption is that 0x80 is a non-existent port;
++		 * which should be safe since include/asm/io.h also
++		 * makes this assumption.
++		 *
++		 * Note: this is safe as long as MCR bit 4 is clear
++		 * and the device is in "PC" mode.
++		 */
++		scratch = serial_inp(up, UART_IER);
++		serial_outp(up, UART_IER, 0);
++#ifdef __i386__
++		outb(0xff, 0x080);
++#endif
++		scratch2 = serial_inp(up, UART_IER);
++		serial_outp(up, UART_IER, 0x0F);
++#ifdef __i386__
++		outb(0, 0x080);
++#endif
++		scratch3 = serial_inp(up, UART_IER);
++		serial_outp(up, UART_IER, scratch);
++		if (scratch2 != 0 || scratch3 != 0x0F) {
++			/*
++			 * We failed; there's nothing here
++			 */
++			DEBUG_AUTOCONF("IER test failed (%02x, %02x) ",
++				       scratch2, scratch3);
++			goto out;
++		}
++	}
++
++	save_mcr = serial_in(up, UART_MCR);
++	save_lcr = serial_in(up, UART_LCR);
++
++	/* 
++	 * Check to see if a UART is really there.  Certain broken
++	 * internal modems based on the Rockwell chipset fail this
++	 * test, because they apparently don't implement the loopback
++	 * test mode.  So this test is skipped on the COM 1 through
++	 * COM 4 ports.  This *should* be safe, since no board
++	 * manufacturer would be stupid enough to design a board
++	 * that conflicts with COM 1-4 --- we hope!
++	 */
++	if (!(up->port.flags & UPF_SKIP_TEST)) {
++		serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A);
++		status1 = serial_inp(up, UART_MSR) & 0xF0;
++		serial_outp(up, UART_MCR, save_mcr);
++		if (status1 != 0x90) {
++			DEBUG_AUTOCONF("LOOP test failed (%02x) ",
++				       status1);
++			goto out;
++		}
++	}
++
++	/*
++	 * We're pretty sure there's a port here.  Lets find out what
++	 * type of port it is.  The IIR top two bits allows us to find
++	 * out if its 8250 or 16450, 16550, 16550A or later.  This
++	 * determines what we test for next.
++	 *
++	 * We also initialise the EFR (if any) to zero for later.  The
++	 * EFR occupies the same register location as the FCR and IIR.
++	 */
++	serial_outp(up, UART_LCR, 0xBF);
++	serial_outp(up, UART_EFR, 0);
++	serial_outp(up, UART_LCR, 0);
++
++	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
++	scratch = serial_in(up, UART_IIR) >> 6;
++
++	DEBUG_AUTOCONF("iir=%d ", scratch);
++
++	switch (scratch) {
++	case 0:
++		autoconfig_8250(up);
++		break;
++	case 1:
++		up->port.type = PORT_UNKNOWN;
++		break;
++	case 2:
++		up->port.type = PORT_16550;
++		break;
++	case 3:
++		autoconfig_16550a(up);
++		break;
++	}
++
++#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
++	/*
++	 * Only probe for RSA ports if we got the region.
++	 */
++	if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) {
++		int i;
++
++		for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
++			if (!probe_rsa[i] && !force_rsa[i])
++				break;
++			if (((probe_rsa[i] != up->port.iobase) ||
++			     check_region(up->port.iobase + UART_RSA_BASE, 16)) &&
++			    (force_rsa[i] != up->port.iobase))
++				continue;
++			if (__enable_rsa(up)) {
++				up->port.type = PORT_RSA;
++				break;
++			}
++		}
++	}
++#endif
++	serial_outp(up, UART_LCR, save_lcr);
++
++	up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size;
++	up->capabilities = uart_config[up->port.type].flags;
++
++	if (up->port.type == PORT_UNKNOWN)
++		goto out;
++
++	/*
++	 * Reset the UART.
++	 */
++#ifdef CONFIG_SERIAL_8250_RSA
++	if (up->port.type == PORT_RSA)
++		serial_outp(up, UART_RSA_FRR, 0);
++#endif
++	serial_outp(up, UART_MCR, save_mcr);
++	serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO |
++				     UART_FCR_CLEAR_RCVR |
++				     UART_FCR_CLEAR_XMIT));
++	serial_outp(up, UART_FCR, 0);
++	(void)serial_in(up, UART_RX);
++	serial_outp(up, UART_IER, 0);
++
++ out:
++	spin_unlock_irqrestore(&up->port.lock, flags);
++
++#ifdef CONFIG_SERIAL_8250_RSA
++	if (up->port.iobase && up->port.type == PORT_RSA) {
++		release_region(up->port.iobase, 8);
++		request_region(up->port.iobase + UART_RSA_BASE, 16,
++			       "serial_rsa");
++	}
++#endif
++	DEBUG_AUTOCONF("type=%s\n", uart_config[up->port.type].name);
++}
++
++static void autoconfig_irq(struct uart_8250_port *up)
++{
++	unsigned char save_mcr, save_ier;
++	unsigned char save_ICP = 0;
++	unsigned int ICP = 0;
++	unsigned long irqs;
++	int irq;
++
++	if (up->port.flags & UPF_FOURPORT) {
++		ICP = (up->port.iobase & 0xfe0) | 0x1f;
++		save_ICP = inb_p(ICP);
++		outb_p(0x80, ICP);
++		(void) inb_p(ICP);
++	}
++
++	/* forget possible initially masked and pending IRQ */
++	probe_irq_off(probe_irq_on());
++	save_mcr = serial_inp(up, UART_MCR);
++	save_ier = serial_inp(up, UART_IER);
++	serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
++	
++	irqs = probe_irq_on();
++	serial_outp(up, UART_MCR, 0);
++	udelay (10);
++	if (up->port.flags & UPF_FOURPORT)  {
++		serial_outp(up, UART_MCR,
++			    UART_MCR_DTR | UART_MCR_RTS);
++	} else {
++		serial_outp(up, UART_MCR,
++			    UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2);
++	}
++	serial_outp(up, UART_IER, 0x0f);	/* enable all intrs */
++	(void)serial_inp(up, UART_LSR);
++	(void)serial_inp(up, UART_RX);
++	(void)serial_inp(up, UART_IIR);
++	(void)serial_inp(up, UART_MSR);
++	serial_outp(up, UART_TX, 0xFF);
++	udelay (20);
++	irq = probe_irq_off(irqs);
++
++	serial_outp(up, UART_MCR, save_mcr);
++	serial_outp(up, UART_IER, save_ier);
++
++	if (up->port.flags & UPF_FOURPORT)
++		outb_p(save_ICP, ICP);
++
++	up->port.irq = (irq > 0) ? irq : 0;
++}
++
++static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++
++	if (up->ier & UART_IER_THRI) {
++		up->ier &= ~UART_IER_THRI;
++		serial_out(up, UART_IER, up->ier);
++	}
++	if (up->port.type == PORT_16C950 && tty_stop) {
++		up->acr |= UART_ACR_TXDIS;
++		serial_icr_write(up, UART_ACR, up->acr);
++	}
++}
++
++static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++
++	if (!(up->ier & UART_IER_THRI)) {
++		up->ier |= UART_IER_THRI;
++		serial_out(up, UART_IER, up->ier);
++	}
++	/*
++	 * We only do this from uart_start
++	 */
++	if (tty_start && up->port.type == PORT_16C950) {
++		up->acr &= ~UART_ACR_TXDIS;
++		serial_icr_write(up, UART_ACR, up->acr);
++	}
++}
++
++static void serial8250_stop_rx(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++
++	up->ier &= ~UART_IER_RLSI;
++	up->port.read_status_mask &= ~UART_LSR_DR;
++	serial_out(up, UART_IER, up->ier);
++}
++
++static void serial8250_enable_ms(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++
++	up->ier |= UART_IER_MSI;
++	serial_out(up, UART_IER, up->ier);
++}
++
++static _INLINE_ void
++receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
++{
++	struct tty_struct *tty = up->port.info->tty;
++	unsigned char ch;
++	int max_count = 256;
++
++	do {
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
++			/*
++			 * FIXME: Deadlock can happen here if we're a
++			 * low-latency port.  We're holding the per-port
++			 * spinlock, and we call flush_to_ldisc->
++			 * n_tty_receive_buf->n_tty_receive_char->
++			 * opost->uart_put_char.
++			 */
++			tty->flip.tqueue.routine((void *)tty);
++			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++				return; // if TTY_DONT_FLIP is set
++		}
++		ch = serial_inp(up, UART_RX);
++		*tty->flip.char_buf_ptr = ch;
++		*tty->flip.flag_buf_ptr = TTY_NORMAL;
++		up->port.icount.rx++;
++
++		if (*status & (UART_LSR_BI | UART_LSR_PE |
++			       UART_LSR_FE | UART_LSR_OE)) {
++			/*
++			 * For statistics only
++			 */
++			if (*status & UART_LSR_BI) {
++				*status &= ~(UART_LSR_FE | UART_LSR_PE);
++				up->port.icount.brk++;
++				/*
++				 * We do the SysRQ and SAK checking
++				 * here because otherwise the break
++				 * may get masked by ignore_status_mask
++				 * or read_status_mask.
++				 */
++				if (uart_handle_break(&up->port))
++					goto ignore_char;
++			} else if (*status & UART_LSR_PE)
++				up->port.icount.parity++;
++			else if (*status & UART_LSR_FE)
++				up->port.icount.frame++;
++			if (*status & UART_LSR_OE)
++				up->port.icount.overrun++;
++
++			/*
++			 * Mask off conditions which should be ingored.
++			 */
++			*status &= up->port.read_status_mask;
++
++#ifdef CONFIG_SERIAL_8250_CONSOLE
++			if (up->port.line == up->port.cons->index) {
++				/* Recover the break flag from console xmit */
++				*status |= up->lsr_break_flag;
++				up->lsr_break_flag = 0;
++			}
++#endif
++			if (*status & UART_LSR_BI) {
++				DEBUG_INTR("handling break....");
++				*tty->flip.flag_buf_ptr = TTY_BREAK;
++			} else if (*status & UART_LSR_PE)
++				*tty->flip.flag_buf_ptr = TTY_PARITY;
++			else if (*status & UART_LSR_FE)
++				*tty->flip.flag_buf_ptr = TTY_FRAME;
++		}
++		if (uart_handle_sysrq_char(&up->port, ch, regs))
++			goto ignore_char;
++		if ((*status & up->port.ignore_status_mask) == 0) {
++			tty->flip.flag_buf_ptr++;
++			tty->flip.char_buf_ptr++;
++			tty->flip.count++;
++		}
++		if ((*status & UART_LSR_OE) &&
++		    tty->flip.count < TTY_FLIPBUF_SIZE) {
++			/*
++			 * Overrun is special, since it's reported
++			 * immediately, and doesn't affect the current
++			 * character.
++			 */
++			*tty->flip.flag_buf_ptr = TTY_OVERRUN;
++			tty->flip.flag_buf_ptr++;
++			tty->flip.char_buf_ptr++;
++			tty->flip.count++;
++		}
++	ignore_char:
++		*status = serial_inp(up, UART_LSR);
++	} while ((*status & UART_LSR_DR) && (max_count-- > 0));
++	tty_flip_buffer_push(tty);
++}
++
++static _INLINE_ void transmit_chars(struct uart_8250_port *up)
++{
++	struct circ_buf *xmit = &up->port.info->xmit;
++	int count;
++
++	if (up->port.x_char) {
++		serial_outp(up, UART_TX, up->port.x_char);
++		up->port.icount.tx++;
++		up->port.x_char = 0;
++		return;
++	}
++	if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
++		serial8250_stop_tx(&up->port, 0);
++		return;
++	}
++
++	count = up->port.fifosize;
++	do {
++		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
++		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++		up->port.icount.tx++;
++		if (uart_circ_empty(xmit))
++			break;
++	} while (--count > 0);
++
++	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++		uart_write_wakeup(&up->port);
++
++	DEBUG_INTR("THRE...");
++
++	if (uart_circ_empty(xmit))
++		serial8250_stop_tx(&up->port, 0);
++}
++
++static _INLINE_ void check_modem_status(struct uart_8250_port *up)
++{
++	int status;
++
++	status = serial_in(up, UART_MSR);
++
++	if ((status & UART_MSR_ANY_DELTA) == 0)
++		return;
++
++	if (status & UART_MSR_TERI)
++		up->port.icount.rng++;
++	if (status & UART_MSR_DDSR)
++		up->port.icount.dsr++;
++	if (status & UART_MSR_DDCD)
++		uart_handle_dcd_change(&up->port, status & UART_MSR_DCD);
++	if (status & UART_MSR_DCTS)
++		uart_handle_cts_change(&up->port, status & UART_MSR_CTS);
++
++	wake_up_interruptible(&up->port.info->delta_msr_wait);
++}
++
++/*
++ * This handles the interrupt from one port.
++ */
++static inline void
++serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
++{
++	unsigned int status = serial_inp(up, UART_LSR);
++
++	DEBUG_INTR("status = %x...", status);
++
++	if (status & UART_LSR_DR)
++		receive_chars(up, &status, regs);
++	check_modem_status(up);
++	if (status & UART_LSR_THRE)
++		transmit_chars(up);
++}
++
++/*
++ * This is the serial driver's interrupt routine.
++ *
++ * Arjan thinks the old way was overly complex, so it got simplified.
++ * Alan disagrees, saying that need the complexity to handle the weird
++ * nature of ISA shared interrupts.  (This is a special exception.)
++ *
++ * In order to handle ISA shared interrupts properly, we need to check
++ * that all ports have been serviced, and therefore the ISA interrupt
++ * line has been de-asserted.
++ *
++ * This means we need to loop through all ports. checking that they
++ * don't have an interrupt pending.
++ */
++static void serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct irq_info *i = dev_id;
++	struct list_head *l, *end = NULL;
++	int pass_counter = 0;
++
++	DEBUG_INTR("serial8250_interrupt(%d)...", irq);
++
++	spin_lock(&i->lock);
++
++	l = i->head;
++	do {
++		struct uart_8250_port *up;
++		unsigned int iir;
++
++		up = list_entry(l, struct uart_8250_port, list);
++
++		iir = serial_in(up, UART_IIR);
++		if (!(iir & UART_IIR_NO_INT)) {
++			spin_lock(&up->port.lock);
++			serial8250_handle_port(up, regs);
++			spin_unlock(&up->port.lock);
++
++			end = NULL;
++		} else if (end == NULL)
++			end = l;
++
++		l = l->next;
++
++		if (l == i->head && pass_counter++ > PASS_LIMIT) {
++			/* If we hit this, we're dead. */
++			printk(KERN_ERR "serial8250: too much work for "
++				"irq%d\n", irq);
++			break;
++		}
++	} while (l != end);
++
++	spin_unlock(&i->lock);
++
++	DEBUG_INTR("end.\n");
++}
++
++/*
++ * To support ISA shared interrupts, we need to have one interrupt
++ * handler that ensures that the IRQ line has been deasserted
++ * before returning.  Failing to do this will result in the IRQ
++ * line being stuck active, and, since ISA irqs are edge triggered,
++ * no more IRQs will be seen.
++ */
++static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
++{
++	spin_lock_irq(&i->lock);
++
++	if (!list_empty(i->head)) {
++		if (i->head == &up->list)
++			i->head = i->head->next;
++		list_del(&up->list);
++	} else {
++		BUG_ON(i->head != &up->list);
++		i->head = NULL;
++	}
++
++	spin_unlock_irq(&i->lock);
++}
++
++static int serial_link_irq_chain(struct uart_8250_port *up)
++{
++	struct irq_info *i = irq_lists + up->port.irq;
++	int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
++
++	spin_lock_irq(&i->lock);
++
++	if (i->head) {
++		list_add(&up->list, i->head);
++		spin_unlock_irq(&i->lock);
++
++		ret = 0;
++	} else {
++		INIT_LIST_HEAD(&up->list);
++		i->head = &up->list;
++		spin_unlock_irq(&i->lock);
++
++		ret = request_irq(up->port.irq, serial8250_interrupt,
++				  irq_flags, "serial", i);
++		if (ret < 0)
++			serial_do_unlink(i, up);
++	}
++
++	return ret;
++}
++
++static void serial_unlink_irq_chain(struct uart_8250_port *up)
++{
++	struct irq_info *i = irq_lists + up->port.irq;
++
++	BUG_ON(i->head == NULL);
++
++	if (list_empty(i->head))
++		free_irq(up->port.irq, i);
++
++	serial_do_unlink(i, up);
++}
++
++/*
++ * This function is used to handle ports that do not have an
++ * interrupt.  This doesn't work very well for 16450's, but gives
++ * barely passable results for a 16550A.  (Although at the expense
++ * of much CPU overhead).
++ */
++static void serial8250_timeout(unsigned long data)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)data;
++	unsigned int timeout;
++	unsigned int iir;
++
++	iir = serial_in(up, UART_IIR);
++	if (!(iir & UART_IIR_NO_INT)) {
++		spin_lock(&up->port.lock);
++		serial8250_handle_port(up, NULL);
++		spin_unlock(&up->port.lock);
++	}
++
++	timeout = up->port.timeout;
++	timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
++	mod_timer(&up->timer, jiffies + timeout);
++}
++
++static unsigned int serial8250_tx_empty(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned long flags;
++	unsigned int ret;
++
++	spin_lock_irqsave(&up->port.lock, flags);
++	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
++	spin_unlock_irqrestore(&up->port.lock, flags);
++
++	return ret;
++}
++
++static unsigned int serial8250_get_mctrl(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned long flags;
++	unsigned char status;
++	unsigned int ret;
++
++	spin_lock_irqsave(&up->port.lock, flags);
++	status = serial_in(up, UART_MSR);
++	spin_unlock_irqrestore(&up->port.lock, flags);
++
++	ret = 0;
++	if (status & UART_MSR_DCD)
++		ret |= TIOCM_CAR;
++	if (status & UART_MSR_RI)
++		ret |= TIOCM_RNG;
++	if (status & UART_MSR_DSR)
++		ret |= TIOCM_DSR;
++	if (status & UART_MSR_CTS)
++		ret |= TIOCM_CTS;
++	return ret;
++}
++
++static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned char mcr = 0;
++
++	if (mctrl & TIOCM_RTS)
++		mcr |= UART_MCR_RTS;
++	if (mctrl & TIOCM_DTR)
++		mcr |= UART_MCR_DTR;
++	if (mctrl & TIOCM_OUT1)
++		mcr |= UART_MCR_OUT1;
++	if (mctrl & TIOCM_OUT2)
++		mcr |= UART_MCR_OUT2;
++	if (mctrl & TIOCM_LOOP)
++		mcr |= UART_MCR_LOOP;
++
++	mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr;
++
++	serial_out(up, UART_MCR, mcr);
++}
++
++static void serial8250_break_ctl(struct uart_port *port, int break_state)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned long flags;
++
++	spin_lock_irqsave(&up->port.lock, flags);
++	if (break_state == -1)
++		up->lcr |= UART_LCR_SBC;
++	else
++		up->lcr &= ~UART_LCR_SBC;
++	serial_out(up, UART_LCR, up->lcr);
++	spin_unlock_irqrestore(&up->port.lock, flags);
++}
++
++static int serial8250_startup(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned long flags;
++	unsigned char lsr, iir;
++	int retval;
++
++	up->capabilities = uart_config[up->port.type].flags;
++	up->mcr = 0;
++	up->efr = 0;
++	up->ier = 0;
++
++	if (up->port.type == PORT_16C950) {
++		/* Wake up and initialize UART */
++		up->acr = 0;
++		serial_outp(up, UART_LCR, 0xBF);
++		serial_outp(up, UART_EFR, UART_EFR_ECB);
++		serial_outp(up, UART_IER, 0);
++		serial_outp(up, UART_LCR, 0);
++		serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
++		serial_outp(up, UART_LCR, 0xBF);
++		serial_outp(up, UART_EFR, UART_EFR_ECB);
++		serial_outp(up, UART_LCR, 0);
++	}
++
++#ifdef CONFIG_SERIAL_8250_RSA
++	/*
++	 * If this is an RSA port, see if we can kick it up to the
++	 * higher speed clock.
++	 */
++	enable_rsa(up);
++#endif
++
++	/*
++	 * Clear the FIFO buffers and disable them.
++	 * (they will be reeanbled in change_speed())
++	 */
++	if (up->capabilities & UART_CLEAR_FIFO) {
++		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
++		serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
++				UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
++		serial_outp(up, UART_FCR, 0);
++	}
++
++	/*
++	 * Clear the interrupt registers.
++	 */
++	(void) serial_inp(up, UART_LSR);
++	(void) serial_inp(up, UART_RX);
++	(void) serial_inp(up, UART_IIR);
++	(void) serial_inp(up, UART_MSR);
++
++	/*
++	 * At this point, there's no way the LSR could still be 0xff;
++	 * if it is, then bail out, because there's likely no UART
++	 * here.
++	 */
++	if (!(up->port.flags & UPF_BUGGY_UART) &&
++	    (serial_inp(up, UART_LSR) == 0xff)) {
++		printk("ttyS%d: LSR safety check engaged!\n", up->port.line);
++		return -ENODEV;
++	}
++
++	/*
++	 * If the "interrupt" for this port doesn't correspond with any
++	 * hardware interrupt, we use a timer-based system.  The original
++	 * driver used to do this with IRQ0.
++	 */
++	if (!is_real_interrupt(up->port.irq)) {
++		unsigned int timeout = up->port.timeout;
++
++		timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
++
++		up->timer.data = (unsigned long)up;
++		mod_timer(&up->timer, jiffies + timeout);
++	} else {
++		retval = serial_link_irq_chain(up);
++		if (retval)
++			return retval;
++	}
++
++	/*
++	 * Now, initialize the UART
++	 */
++	serial_outp(up, UART_LCR, UART_LCR_WLEN8);
++
++	spin_lock_irqsave(&up->port.lock, flags);
++	if (up->port.flags & UPF_FOURPORT) {
++		if (!is_real_interrupt(up->port.irq))
++			up->port.mctrl |= TIOCM_OUT1;
++	} else
++		/*
++		 * Most PC uarts need OUT2 raised to enable interrupts.
++		 */
++		if (is_real_interrupt(up->port.irq))
++			up->port.mctrl |= TIOCM_OUT2;
++
++	serial8250_set_mctrl(&up->port, up->port.mctrl);
++
++	/*
++	 * Do a quick test to see if we receive an
++	 * interrupt when we enable the TX irq.
++	 */
++	serial_outp(up, UART_IER, UART_IER_THRI);
++	lsr = serial_in(up, UART_LSR);
++	iir = serial_in(up, UART_IIR);
++	serial_outp(up, UART_IER, 0);
++
++	if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
++		up->capabilities |= UART_BAD_TX_ENABLE;
++		printk("ttyS%d - enabling bad tx status workarounds\n",
++			port->line);
++	}
++
++	spin_unlock_irqrestore(&up->port.lock, flags);
++
++	/*
++	 * Finally, enable interrupts.  Note: Modem status interrupts
++	 * are set via change_speed(), which will be occuring imminently
++	 * anyway, so we don't enable them here.
++	 */
++	up->ier = UART_IER_RLSI | UART_IER_RDI;
++	serial_outp(up, UART_IER, up->ier);
++
++	if (up->port.flags & UPF_FOURPORT) {
++		unsigned int icp;
++		/*
++		 * Enable interrupts on the AST Fourport board
++		 */
++		icp = (up->port.iobase & 0xfe0) | 0x01f;
++		outb_p(0x80, icp);
++		(void) inb_p(icp);
++	}
++
++	/*
++	 * And clear the interrupt registers again for luck.
++	 */
++	(void) serial_inp(up, UART_LSR);
++	(void) serial_inp(up, UART_RX);
++	(void) serial_inp(up, UART_IIR);
++	(void) serial_inp(up, UART_MSR);
++
++	return 0;
++}
++
++static void serial8250_shutdown(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned long flags;
++
++	/*
++	 * Disable interrupts from this port
++	 */
++	up->ier = 0;
++	serial_outp(up, UART_IER, 0);
++
++	spin_lock_irqsave(&up->port.lock, flags);
++	if (up->port.flags & UPF_FOURPORT) {
++		/* reset interrupts on the AST Fourport board */
++		inb((up->port.iobase & 0xfe0) | 0x1f);
++		up->port.mctrl |= TIOCM_OUT1;
++	} else
++		up->port.mctrl &= ~TIOCM_OUT2;
++
++	serial8250_set_mctrl(&up->port, up->port.mctrl);
++	spin_unlock_irqrestore(&up->port.lock, flags);
++
++	/*
++	 * Disable break condition and FIFOs
++	 */
++	serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC);
++	serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO |
++				  UART_FCR_CLEAR_RCVR |
++				  UART_FCR_CLEAR_XMIT);
++	serial_outp(up, UART_FCR, 0);
++
++#ifdef CONFIG_SERIAL_8250_RSA
++	/*
++	 * Reset the RSA board back to 115kbps compat mode.
++	 */
++	disable_rsa(up);
++#endif
++
++	/*
++	 * Read data port to reset things, and then unlink from
++	 * the IRQ chain.
++	 */
++	(void) serial_in(up, UART_RX);
++
++	if (!is_real_interrupt(up->port.irq))
++		del_timer_sync(&up->timer);
++	else
++		serial_unlink_irq_chain(up);
++}
++
++static void serial8250_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned char cval, fcr = 0;
++	unsigned long flags;
++
++	switch (cflag & CSIZE) {
++	case CS5:
++		cval = 0x00;
++		break;
++	case CS6:
++		cval = 0x01;
++		break;
++	case CS7:
++		cval = 0x02;
++		break;
++	default:
++	case CS8:
++		cval = 0x03;
++		break;
++	}
++
++	if (cflag & CSTOPB)
++		cval |= 0x04;
++	if (cflag & PARENB)
++		cval |= UART_LCR_PARITY;
++	if (!(cflag & PARODD))
++		cval |= UART_LCR_EPAR;
++#ifdef CMSPAR
++	if (cflag & CMSPAR)
++		cval |= UART_LCR_SPAR;
++#endif
++
++	/*
++	 * Work around a bug in the Oxford Semiconductor 952 rev B
++	 * chip which causes it to seriously miscalculate baud rates
++	 * when DLL is 0.
++	 */
++	if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
++	    up->rev == 0x5201)
++		quot ++;
++
++	if (up->capabilities & UART_USE_FIFO) {
++		if ((up->port.uartclk / quot) < (2400 * 16))
++			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
++#ifdef CONFIG_SERIAL_8250_RSA
++		else if (up->port.type == PORT_RSA)
++			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
++#endif
++		else
++			fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
++	}
++	if (up->port.type == PORT_16750)
++		fcr |= UART_FCR7_64BYTE;
++
++	/*
++	 * Ok, we're now changing the port state.  Do it with
++	 * interrupts disabled.
++	 */
++	spin_lock_irqsave(&up->port.lock, flags);
++
++	up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
++	if (iflag & IGNPAR)
++		up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
++	if (iflag & (BRKINT | PARMRK))
++		up->port.read_status_mask |= UART_LSR_BI;
++
++	/*
++	 * Characteres to ignore
++	 */
++	up->port.ignore_status_mask = 0;
++	if (iflag & IGNPAR)
++		up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
++	if (iflag & IGNBRK) {
++		up->port.ignore_status_mask |= UART_LSR_BI;
++		/*
++		 * If we're ignoring parity and break indicators,
++		 * ignore overruns too (for real raw support).
++		 */
++		if (iflag & IGNPAR)
++			up->port.ignore_status_mask |= UART_LSR_OE;
++	}
++
++	/*
++	 * ignore all characters if CREAD is not set
++	 */
++	if ((cflag & CREAD) == 0)
++		up->port.ignore_status_mask |= UART_LSR_DR;
++
++	/*
++	 * CTS flow control flag and modem status interrupts
++	 */
++	up->ier &= ~UART_IER_MSI;
++	if (UART_ENABLE_MS(&up->port, cflag))
++		up->ier |= UART_IER_MSI;
++
++	serial_out(up, UART_IER, up->ier);
++
++	if (up->capabilities & UART_MCRAFE) {
++		/*
++		 * TI16C750 hardware flow control
++		 */
++		up->mcr &= ~UART_MCR_AFE;
++		if (cflag & CRTSCTS)
++			up->mcr |= UART_MCR_AFE;
++	}
++	if (up->capabilities & UART_EFRAFE) {
++		/*
++		 * TI16C752/Startech hardware flow control
++		 * FIXME:
++		 * - TI16C752 requires control thresholds
++		 *   to be set for auto-RTS.
++		 * - We only enable auto-CTS here.
++		 * Note: ST16C654 does not allow MCR bit 1
++		 * to override RTS when UART_EFR_RTS is set.
++		 */
++		up->efr &= ~UART_EFR_CTS;
++		if (cflag & CRTSCTS)
++			up->efr |= UART_EFR_CTS;
++		serial_outp(up, UART_LCR, 0xBF);
++		serial_outp(up, UART_EFR, up->efr);
++	}
++
++	if (up->capabilities & UART_NATSEMI) {
++		/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
++		serial_outp(up, UART_LCR, 0xe0);
++	} else {
++		serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
++	}
++	serial_outp(up, UART_DLL, quot & 0xff);		/* LS of divisor */
++	serial_outp(up, UART_DLM, quot >> 8);		/* MS of divisor */
++	if (up->port.type == PORT_16750)
++		serial_outp(up, UART_FCR, fcr);		/* set fcr */
++	serial_outp(up, UART_LCR, cval);		/* reset DLAB */
++	up->lcr = cval;					/* Save LCR */
++	if (up->port.type != PORT_16750) {
++		if (fcr & UART_FCR_ENABLE_FIFO) {
++			/* emulated UARTs (Lucent Venus 167x) need two steps */
++			serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO);
++		}
++		serial_outp(up, UART_FCR, fcr);		/* set fcr */
++	}
++	serial8250_set_mctrl(&up->port, up->port.mctrl);
++	spin_unlock_irqrestore(&up->port.lock, flags);
++}
++
++static void
++serial8250_pm(struct uart_port *port, unsigned int state,
++	      unsigned int oldstate)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	if (state) {
++		/* sleep */
++		if (up->capabilities & UART_STARTECH) {
++			/* Arrange to enter sleep mode */
++			serial_outp(up, UART_LCR, 0xBF);
++			serial_outp(up, UART_EFR, UART_EFR_ECB);
++			serial_outp(up, UART_LCR, 0);
++			serial_outp(up, UART_IER, UART_IERX_SLEEP);
++			serial_outp(up, UART_LCR, 0xBF);
++			serial_outp(up, UART_EFR, 0);
++			serial_outp(up, UART_LCR, 0);
++		}
++		if (up->port.type == PORT_16750) {
++			/* Arrange to enter sleep mode */
++			serial_outp(up, UART_IER, UART_IERX_SLEEP);
++		}
++	} else {
++		/* wake */
++		if (up->capabilities & UART_STARTECH) {
++			/* Wake up UART */
++			serial_outp(up, UART_LCR, 0xBF);
++			serial_outp(up, UART_EFR, UART_EFR_ECB);
++			/*
++			 * Turn off LCR == 0xBF so we actually set the IER
++			 * register on the XR16C850
++			 */
++			serial_outp(up, UART_LCR, 0);
++			serial_outp(up, UART_IER, 0);
++			/*
++			 * Now reset LCR so we can turn off the ECB bit
++			 */
++			serial_outp(up, UART_LCR, 0xBF);
++			serial_outp(up, UART_EFR, 0);
++			/*
++			 * For a XR16C850, we need to set the trigger levels
++			 */
++			if (up->port.type == PORT_16850) {
++				unsigned char fctr;
++
++				fctr = serial_inp(up, UART_FCTR) &
++					 ~(UART_FCTR_RX | UART_FCTR_TX);
++				serial_outp(up, UART_FCTR, fctr |
++						UART_FCTR_TRGD |
++						UART_FCTR_RX);
++				serial_outp(up, UART_TRG, UART_TRG_96);
++				serial_outp(up, UART_FCTR, fctr |
++						UART_FCTR_TRGD |
++						UART_FCTR_TX);
++				serial_outp(up, UART_TRG, UART_TRG_96);
++			}
++			serial_outp(up, UART_LCR, 0);
++		}
++
++		if (up->port.type == PORT_16750) {
++			/* Wake up UART */
++			serial_outp(up, UART_IER, 0);
++		}
++	}
++}
++
++/*
++ * Resource handling.  This is complicated by the fact that resources
++ * depend on the port type.  Maybe we should be claiming the standard
++ * 8250 ports, and then trying to get other resources as necessary?
++ */
++static int
++serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res)
++{
++	unsigned int size = 8 << up->port.regshift;
++	int ret = 0;
++
++	switch (up->port.iotype) {
++	case SERIAL_IO_MEM:
++		if (up->port.mapbase) {
++			*res = request_mem_region(up->port.mapbase, size, "serial");
++			if (!*res)
++				ret = -EBUSY;
++		}
++		break;
++
++	case SERIAL_IO_HUB6:
++	case SERIAL_IO_PORT:
++		*res = request_region(up->port.iobase, size, "serial");
++		if (!*res)
++			ret = -EBUSY;
++		break;
++	}
++	return ret;
++}
++
++static int
++serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res)
++{
++	unsigned int size = 8 << up->port.regshift;
++	unsigned long start;
++	int ret = 0;
++
++	switch (up->port.iotype) {
++	case SERIAL_IO_MEM:
++		if (up->port.mapbase) {
++			start = up->port.mapbase;
++			start += UART_RSA_BASE << up->port.regshift;
++			*res = request_mem_region(start, size, "serial-rsa");
++			if (!*res)
++				ret = -EBUSY;
++		}
++		break;
++
++	case SERIAL_IO_HUB6:
++	case SERIAL_IO_PORT:
++		start = up->port.iobase;
++		start += UART_RSA_BASE << up->port.regshift;
++		*res = request_region(start, size, "serial-rsa");
++		if (!*res)
++			ret = -EBUSY;
++		break;
++	}
++
++	return ret;
++}
++
++static void serial8250_release_port(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	unsigned long start, offset = 0, size = 0;
++
++	if (up->port.type == PORT_RSA) {
++		offset = UART_RSA_BASE << up->port.regshift;
++		size = 8;
++	}
++
++	size <<= up->port.regshift;
++
++	switch (up->port.iotype) {
++	case SERIAL_IO_MEM:
++		if (up->port.mapbase) {
++			/*
++			 * Unmap the area.
++			 */
++			if (up->port.flags & UPF_IOREMAP) {
++				iounmap(up->port.membase);
++				up->port.membase = NULL;
++			}
++
++			start = up->port.mapbase;
++
++			if (size)
++				release_mem_region(start + offset, size);
++			release_mem_region(start, 8 << up->port.regshift);
++		}
++		break;
++
++	case SERIAL_IO_HUB6:
++	case SERIAL_IO_PORT:
++		start = up->port.iobase;
++
++		if (size)
++			release_region(start + offset, size);
++		release_region(start + offset, 8 << up->port.regshift);
++		break;
++
++	default:
++		break;
++	}
++}
++
++static int serial8250_request_port(struct uart_port *port)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	struct resource *res = NULL, *res_rsa = NULL;
++	int ret = 0;
++
++	if (up->port.flags & UPF_RESOURCES) {
++		if (up->port.type == PORT_RSA) {
++			ret = serial8250_request_rsa_resource(up, &res_rsa);
++			if (ret < 0)
++				return ret;
++		}
++
++		ret = serial8250_request_std_resource(up, &res);
++	}
++
++	/*
++	 * If we have a mapbase, then request that as well.
++	 */
++	if (ret == 0 && up->port.flags & UPF_IOREMAP) {
++		int size = res->end - res->start + 1;
++
++		up->port.membase = ioremap(up->port.mapbase, size);
++		if (!up->port.membase)
++			ret = -ENOMEM;
++	}
++
++	if (ret < 0) {
++		if (res_rsa)
++			release_resource(res_rsa);
++		if (res)
++			release_resource(res);
++	}
++	return ret;
++}
++
++static void serial8250_config_port(struct uart_port *port, int flags)
++{
++	struct uart_8250_port *up = (struct uart_8250_port *)port;
++	struct resource *res_std = NULL, *res_rsa = NULL;
++	int probeflags = PROBE_ANY;
++	int ret;
++
++#ifdef CONFIG_MCA
++	/*
++	 * Don't probe for MCA ports on non-MCA machines.
++	 */
++	if (up->port.flags & UPF_BOOT_ONLYMCA && !MCA_bus)
++		return;
++#endif
++
++	/*
++	 * Find the region that we can probe for.  This in turn
++	 * tells us whether we can probe for the type of port.
++	 */
++	if (up->port.flags & UPF_RESOURCES) {
++		ret = serial8250_request_std_resource(up, &res_std);
++		if (ret < 0)
++			return;
++
++		ret = serial8250_request_rsa_resource(up, &res_rsa);
++		if (ret < 0)
++			probeflags &= ~PROBE_RSA;
++	} else {
++		probeflags &= ~PROBE_RSA;
++	}
++
++	if (flags & UART_CONFIG_TYPE)
++		autoconfig(up, probeflags);
++	if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ)
++		autoconfig_irq(up);
++
++	/*
++	 * If the port wasn't an RSA port, release the resource.
++	 */
++	if (up->port.type != PORT_RSA && res_rsa)
++		release_resource(res_rsa);
++
++	if (up->port.type == PORT_UNKNOWN && res_std)
++		release_resource(res_std);
++}
++
++static int
++serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++	if (ser->irq >= NR_IRQS || ser->irq < 0 ||
++	    ser->baud_base < 9600 || ser->type < PORT_UNKNOWN ||
++	    ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS ||
++	    ser->type == PORT_STARTECH)
++		return -EINVAL;
++	return 0;
++}
++
++static const char *
++serial8250_type(struct uart_port *port)
++{
++	int type = port->type;
++
++	if (type >= ARRAY_SIZE(uart_config))
++		type = 0;
++	return uart_config[type].name;
++}
++
++static struct uart_ops serial8250_pops = {
++	.tx_empty	= serial8250_tx_empty,
++	.set_mctrl	= serial8250_set_mctrl,
++	.get_mctrl	= serial8250_get_mctrl,
++	.stop_tx	= serial8250_stop_tx,
++	.start_tx	= serial8250_start_tx,
++	.stop_rx	= serial8250_stop_rx,
++	.enable_ms	= serial8250_enable_ms,
++	.break_ctl	= serial8250_break_ctl,
++	.startup	= serial8250_startup,
++	.shutdown	= serial8250_shutdown,
++	.change_speed	= serial8250_change_speed,
++	.pm		= serial8250_pm,
++	.type		= serial8250_type,
++	.release_port	= serial8250_release_port,
++	.request_port	= serial8250_request_port,
++	.config_port	= serial8250_config_port,
++	.verify_port	= serial8250_verify_port,
++};
++
++static struct uart_8250_port serial8250_ports[UART_NR];
++
++static void __init serial8250_isa_init_ports(void)
++{
++	struct uart_8250_port *up;
++	static int first = 1;
++	int i;
++
++	if (!first)
++		return;
++	first = 0;
++
++	for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
++	     i++, up++) {
++		up->port.iobase   = old_serial_port[i].port;
++		up->port.irq      = irq_cannonicalize(old_serial_port[i].irq);
++		up->port.uartclk  = old_serial_port[i].baud_base * 16;
++		up->port.flags    = old_serial_port[i].flags |
++				    UPF_RESOURCES;
++		up->port.hub6     = old_serial_port[i].hub6;
++		up->port.membase  = old_serial_port[i].iomem_base;
++		up->port.iotype   = old_serial_port[i].io_type;
++		up->port.regshift = old_serial_port[i].iomem_reg_shift;
++		up->port.ops      = &serial8250_pops;
++
++		if (up->port.iotype == UPIO_MEM && up->port.mapbase)
++			up->port.flags |= UPF_IOREMAP;
++
++		if (share_irqs)
++			up->port.flags |= UPF_SHARE_IRQ;
++	}
++}
++
++static void __init serial8250_register_ports(struct uart_driver *drv)
++{
++	int i;
++
++	serial8250_isa_init_ports();
++
++	for (i = 0; i < UART_NR; i++) {
++		struct uart_8250_port *up = &serial8250_ports[i];
++
++		up->port.line = i;
++		up->port.ops = &serial8250_pops;
++		init_timer(&up->timer);
++		up->timer.function = serial8250_timeout;
++
++		/*
++		 * ALPHA_KLUDGE_MCR needs to be killed.
++		 */
++		up->mcr_mask = ~ALPHA_KLUDGE_MCR;
++		up->mcr_force = ALPHA_KLUDGE_MCR;
++
++		uart_add_one_port(drv, &up->port);
++	}
++}
++
++#ifdef CONFIG_SERIAL_8250_CONSOLE
++
++#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
++
++/*
++ *	Wait for transmitter & holding register to empty
++ */
++static inline void wait_for_xmitr(struct uart_8250_port *up)
++{
++	unsigned int status, tmout = 10000;
++
++	/* Wait up to 10ms for the character(s) to be sent. */
++	do {
++		status = serial_in(up, UART_LSR);
++
++		if (status & UART_LSR_BI)
++			up->lsr_break_flag = UART_LSR_BI;
++
++		if (--tmout == 0)
++			break;
++		udelay(1);
++	} while ((status & BOTH_EMPTY) != BOTH_EMPTY);
++
++	/* Wait up to 1s for flow control if necessary */
++	if (up->port.flags & UPF_CONS_FLOW) {
++		tmout = 1000000;
++		while (--tmout &&
++		       ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
++			udelay(1);
++	}
++}
++
++/*
++ *	Print a string to the serial port trying not to disturb
++ *	any possible real use of the port...
++ *
++ *	The console_lock must be held when we get here.
++ */
++static void
++serial8250_console_write(struct console *co, const char *s, unsigned int count)
++{
++	struct uart_8250_port *up = &serial8250_ports[co->index];
++	unsigned int ier;
++	int i;
++
++	/*
++	 *	First save the UER then disable the interrupts
++	 */
++	ier = serial_in(up, UART_IER);
++	serial_out(up, UART_IER, 0);
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++, s++) {
++		wait_for_xmitr(up);
++
++		/*
++		 *	Send the character out.
++		 *	If a LF, also do CR...
++		 */
++		serial_out(up, UART_TX, *s);
++		if (*s == 10) {
++			wait_for_xmitr(up);
++			serial_out(up, UART_TX, 13);
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore the IER
++	 */
++	wait_for_xmitr(up);
++	serial_out(up, UART_IER, ier);
++}
++
++static kdev_t serial8250_console_device(struct console *co)
++{
++	return MKDEV(TTY_MAJOR, 64 + co->index);
++}
++
++static int __init serial8250_console_setup(struct console *co, char *options)
++{
++	struct uart_port *port;
++	int baud = 9600;
++	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 >= UART_NR)
++		co->index = 0;
++	port = &serial8250_ports[co->index].port;
++
++	/*
++	 * Temporary fix.
++	 */
++	spin_lock_init(&port->lock);
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++
++	return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct console serial8250_console = {
++	.name		= "ttyS",
++	.write		= serial8250_console_write,
++	.device		= serial8250_console_device,
++	.setup		= serial8250_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++void __init serial8250_console_init(void)
++{
++	serial8250_isa_init_ports();
++	register_console(&serial8250_console);
++}
++
++#define SERIAL8250_CONSOLE	&serial8250_console
++#else
++#define SERIAL8250_CONSOLE	NULL
++#endif
++
++static struct uart_driver serial8250_reg = {
++	.owner			= THIS_MODULE,
++#ifdef CONFIG_DEVFS_FS
++	.normal_name		= "tts/%d",
++	.callout_name		= "cua/%d",
++#else
++	.normal_name		= "ttyS",
++	.callout_name		= "cua",
++#endif
++	.normal_major		= TTY_MAJOR,
++	.callout_major		= TTYAUX_MAJOR,
++	.normal_driver		= &normal,
++	.callout_driver		= &callout,
++	.table			= serial8250_table,
++	.termios		= serial8250_termios,
++	.termios_locked		= serial8250_termios_locked,
++	.minor			= 64,
++	.nr			= UART_NR,
++	.cons			= SERIAL8250_CONSOLE,
++};
++
++/*
++ * register_serial and unregister_serial allows for 16x50 serial ports to be
++ * configured at run-time, to support PCMCIA modems.
++ */
++
++static int __register_serial(struct serial_struct *req, int line)
++{
++	struct uart_port port;
++
++	port.iobase   = req->port;
++	port.membase  = req->iomem_base;
++	port.irq      = req->irq;
++	port.uartclk  = req->baud_base * 16;
++	port.fifosize = req->xmit_fifo_size;
++	port.regshift = req->iomem_reg_shift;
++	port.iotype   = req->io_type;
++	port.flags    = req->flags | UPF_BOOT_AUTOCONF;
++	port.mapbase  = req->iomap_base;
++	port.line     = line;
++
++	if (share_irqs)
++		port.flags |= UPF_SHARE_IRQ;
++
++	if (HIGH_BITS_OFFSET)
++		port.iobase |= (long) req->port_high << HIGH_BITS_OFFSET;
++
++	/*
++	 * If a clock rate wasn't specified by the low level
++	 * driver, then default to the standard clock rate.
++	 */
++	if (port.uartclk == 0)
++		port.uartclk = BASE_BAUD * 16;
++
++	return uart_register_port(&serial8250_reg, &port);
++}
++
++/**
++ *	register_serial - configure a 16x50 serial port at runtime
++ *	@req: request structure
++ *
++ *	Configure the serial port specified by the request. If the
++ *	port exists and is in use an error is returned. If the port
++ *	is not currently in the table it is added.
++ *
++ *	The port is then probed and if necessary the IRQ is autodetected
++ *	If this fails an error is returned.
++ *
++ *	On success the port is ready to use and the line number is returned.
++ */
++int register_serial(struct serial_struct *req)
++{
++	return __register_serial(req, -1);
++}
++
++/**
++ *	unregister_serial - remove a 16x50 serial port at runtime
++ *	@line: serial line number
++ *
++ *	Remove one serial port.  This may be called from interrupt
++ *	context.
++ */
++void unregister_serial(int line)
++{
++	uart_unregister_port(&serial8250_reg, line);
++}
++
++/*
++ * This is for ISAPNP only.
++ */
++void serial8250_get_irq_map(unsigned int *map)
++{
++	int i;
++
++	for (i = 0; i < UART_NR; i++) {
++		if (serial8250_ports[i].port.type != PORT_UNKNOWN &&
++		    serial8250_ports[i].port.irq < 16)
++			*map |= 1 << serial8250_ports[i].port.irq;
++	}
++}
++
++static int __init serial8250_init(void)
++{
++	int ret, i;
++
++	for (i = 0; i < NR_IRQS; i++)
++		spin_lock_init(&irq_lists[i].lock);
++
++	ret = uart_register_driver(&serial8250_reg);
++	if (ret >= 0)
++		serial8250_register_ports(&serial8250_reg);
++
++	return ret;
++}
++
++static void __exit serial8250_exit(void)
++{
++	int i;
++
++	for (i = 0; i < UART_NR; i++)
++		uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port);
++
++	uart_unregister_driver(&serial8250_reg);
++}
++
++module_init(serial8250_init);
++module_exit(serial8250_exit);
++
++EXPORT_SYMBOL(register_serial);
++EXPORT_SYMBOL(unregister_serial);
++EXPORT_SYMBOL(serial8250_get_irq_map);
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Generic 8250/16x50 serial driver");
++
++MODULE_PARM(share_irqs, "i");
++MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices"
++	" (unsafe)");
++
++#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE)
++MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
++MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA");
++MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
++MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA");
++#endif /* CONFIG_SERIAL_8250_RSA  */
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/8250.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,88 @@
++/*
++ *  linux/drivers/serial/8250.h
++ *
++ *  Driver for 8250/16550-type serial ports
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright (C) 2001 Russell King.
++ *
++ * 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.
++ *
++ *  $Id$
++ */
++
++#include <linux/config.h>
++
++struct serial8250_probe {
++	struct module	*owner;
++	int		(*pci_init_one)(struct pci_dev *dev);
++	void		(*pci_remove_one)(struct pci_dev *dev);
++	void		(*pnp_init)(void);
++};
++
++int serial8250_register_probe(struct serial8250_probe *probe);
++void serial8250_unregister_probe(struct serial8250_probe *probe);
++void serial8250_get_irq_map(unsigned int *map);
++
++struct old_serial_port {
++	unsigned int uart;
++	unsigned int baud_base;
++	unsigned int port;
++	unsigned int irq;
++	unsigned int flags;
++	unsigned char hub6;
++	unsigned char io_type;
++	unsigned char *iomem_base;
++	unsigned short iomem_reg_shift;
++};
++
++struct serial8250_config {
++	const char	*name;
++	unsigned int	dfl_xmit_fifo_size;
++	unsigned int	flags;
++};
++
++#define UART_CLEAR_FIFO		0x01
++#define UART_USE_FIFO		0x02
++#define UART_STARTECH		0x04
++#define UART_NATSEMI		0x08
++#define UART_MCRAFE		0x10	/* TI16C750-style auto-flow */
++#define UART_EFRAFE		0x20	/* TI16C752/startech auto-flow */
++
++#define UART_BAD_TX_ENABLE	0x80000000
++
++#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
++#define SERIAL_INLINE
++#endif
++  
++#ifdef SERIAL_INLINE
++#define _INLINE_ inline
++#else
++#define _INLINE_
++#endif
++
++#define PROBE_RSA	(1 << 0)
++#define PROBE_ANY	(~0)
++
++#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
++
++#ifdef CONFIG_SERIAL_8250_SHARE_IRQ
++#define SERIAL8250_SHARE_IRQS 1
++#else
++#define SERIAL8250_SHARE_IRQS 0
++#endif
++
++#if defined(__alpha__) && !defined(CONFIG_PCI)
++/*
++ * Digital did something really horribly wrong with the OUT1 and OUT2
++ * lines on at least some ALPHA's.  The failure mode is that if either
++ * is cleared, the machine locks up with endless interrupts.
++ */
++#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
++#else
++#define ALPHA_KLUDGE_MCR 0
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/8250_pci.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,1080 @@
++/*
++ *  linux/drivers/char/serial_8250_pci.c
++ *
++ *  Probe module for 8250/16550-type PCI serial ports.
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  $Id$
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/serial.h>
++
++/* 2.4.6 compatibility cruft ;( */
++#define pci_board __pci_board
++#include <linux/serialP.h>
++#undef pci_board
++
++#include <asm/bitops.h>
++#include <asm/byteorder.h>
++#include <asm/serial.h>
++
++#include "8250.h"
++
++#ifndef IS_PCI_REGION_IOPORT
++#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
++				      IORESOURCE_IO)
++#endif
++#ifndef IS_PCI_REGION_IOMEM
++#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
++				      IORESOURCE_MEM)
++#endif
++#ifndef PCI_IRQ_RESOURCE
++#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
++#endif
++
++#ifndef pci_get_subvendor
++#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
++#define pci_get_subdevice(dev)  ((dev)->subsystem_device)
++#endif
++
++struct serial_private {
++	unsigned int nr;
++	struct pci_board *board;
++	int line[0];
++};
++
++struct pci_board {
++	int flags;
++	int num_ports;
++	int base_baud;
++	int uart_offset;
++	int reg_shift;
++	int (*init_fn)(struct pci_dev *dev, struct pci_board *board,
++			int enable);
++	int first_uart_offset;
++};
++
++static int
++get_pci_port(struct pci_dev *dev, struct pci_board *board,
++	     struct serial_struct *req, int idx)
++{
++	unsigned long port;
++	int base_idx;
++	int max_port;
++	int offset;
++
++	base_idx = SPCI_FL_GET_BASE(board->flags);
++	if (board->flags & SPCI_FL_BASE_TABLE)
++		base_idx += idx;
++
++	if (board->flags & SPCI_FL_REGION_SZ_CAP) {
++		max_port = pci_resource_len(dev, base_idx) / 8;
++		if (idx >= max_port)
++			return 1;
++	}
++			
++	offset = board->first_uart_offset;
++
++	/* Timedia/SUNIX uses a mixture of BARs and offsets */
++	/* Ugh, this is ugly as all hell --- TYT */
++	if(dev->vendor == PCI_VENDOR_ID_TIMEDIA )  /* 0x1409 */
++		switch(idx) {
++			case 0: base_idx=0;
++				break;
++			case 1: base_idx=0; offset=8;
++				break;
++			case 2: base_idx=1; 
++				break;
++			case 3: base_idx=1; offset=8;
++				break;
++			case 4: /* BAR 2*/
++			case 5: /* BAR 3 */
++			case 6: /* BAR 4*/
++			case 7: base_idx=idx-2; /* BAR 5*/
++		}
++
++	/* Some Titan cards are also a little weird */
++	if (dev->vendor == PCI_VENDOR_ID_TITAN &&
++	    (dev->device == PCI_DEVICE_ID_TITAN_400L ||
++	     dev->device == PCI_DEVICE_ID_TITAN_800L)) {
++		switch (idx) {
++		case 0: base_idx = 1;
++			break;
++		case 1: base_idx = 2;
++			break;
++		default:
++			base_idx = 4;
++			offset = 8 * (idx - 2);
++		}
++	}
++  
++	port =  pci_resource_start(dev, base_idx) + offset;
++
++	if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
++		port += idx * (board->uart_offset ? board->uart_offset : 8);
++
++	if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
++		req->port = port;
++		if (HIGH_BITS_OFFSET)
++			req->port_high = port >> HIGH_BITS_OFFSET;
++		else
++			req->port_high = 0;
++		return 0;
++	}
++	req->io_type = SERIAL_IO_MEM;
++	req->iomem_base = ioremap(port, board->uart_offset);
++	req->iomem_reg_shift = board->reg_shift;
++	req->port = 0;
++	return 0;
++}
++
++static _INLINE_ int get_pci_irq(struct pci_dev *dev,
++				struct pci_board *board,
++				int idx)
++{
++	int base_idx;
++
++	if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
++		return dev->irq;
++
++	base_idx = SPCI_FL_GET_IRQBASE(board->flags);
++	if (board->flags & SPCI_FL_IRQ_TABLE)
++		base_idx += idx;
++	
++	return PCI_IRQ_RESOURCE(dev, base_idx);
++}
++
++/*
++ * Some PCI serial cards using the PLX 9050 PCI interface chip require
++ * that the card interrupt be explicitly enabled or disabled.  This
++ * seems to be mainly needed on card using the PLX which also use I/O
++ * mapped memory.
++ */
++static int __devinit
++pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
++{
++	u8 data, *p, irq_config;
++	int pci_config;
++
++	irq_config = 0x41;
++	pci_config = PCI_COMMAND_MEMORY;
++	if (dev->vendor == PCI_VENDOR_ID_PANACOM)
++		irq_config = 0x43;
++	if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
++	    (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) {
++		/*
++		 * As the megawolf cards have the int pins active
++		 * high, and have 2 UART chips, both ints must be
++		 * enabled on the 9050. Also, the UARTS are set in
++		 * 16450 mode by default, so we have to enable the
++		 * 16C950 'enhanced' mode so that we can use the deep
++		 * FIFOs
++		 */
++		irq_config = 0x5b;
++		pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
++	}
++	
++	pci_read_config_byte(dev, PCI_COMMAND, &data);
++
++	if (enable)
++		pci_write_config_byte(dev, PCI_COMMAND,
++				      data | pci_config);
++	
++	/* enable/disable interrupts */
++	p = ioremap(pci_resource_start(dev, 0), 0x80);
++	writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
++	iounmap(p);
++
++	if (!enable)
++		pci_write_config_byte(dev, PCI_COMMAND,
++				      data & ~pci_config);
++	return 0;
++}
++
++
++/*
++ * SIIG serial cards have an PCI interface chip which also controls
++ * the UART clocking frequency. Each UART can be clocked independently
++ * (except cards equiped with 4 UARTs) and initial clocking settings
++ * are stored in the EEPROM chip. It can cause problems because this
++ * version of serial driver doesn't support differently clocked UART's
++ * on single PCI card. To prevent this, initialization functions set
++ * high frequency clocking for all UART's on given card. It is safe (I
++ * hope) because it doesn't touch EEPROM settings to prevent conflicts
++ * with other OSes (like M$ DOS).
++ *
++ *  SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999
++ * 
++ * There is two family of SIIG serial cards with different PCI
++ * interface chip and different configuration methods:
++ *     - 10x cards have control registers in IO and/or memory space;
++ *     - 20x cards have control registers in standard PCI configuration space.
++ */
++
++#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
++#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
++
++static int __devinit
++pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
++{
++       u16 data, *p;
++
++       if (!enable) return 0;
++
++       p = ioremap(pci_resource_start(dev, 0), 0x80);
++
++       switch (dev->device & 0xfff8) {
++               case PCI_DEVICE_ID_SIIG_1S_10x:         /* 1S */
++                       data = 0xffdf;
++                       break;
++               case PCI_DEVICE_ID_SIIG_2S_10x:         /* 2S, 2S1P */
++                       data = 0xf7ff;
++                       break;
++               default:                                /* 1S1P, 4S */
++                       data = 0xfffb;
++                       break;
++       }
++
++       writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
++       iounmap(p);
++       return 0;
++}
++
++#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
++#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
++
++static int __devinit
++pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
++{
++       u8 data;
++
++       if (!enable) return 0;
++
++       /* Change clock frequency for the first UART. */
++       pci_read_config_byte(dev, 0x6f, &data);
++       pci_write_config_byte(dev, 0x6f, data & 0xef);
++
++       /* If this card has 2 UART, we have to do the same with second UART. */
++       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
++           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
++               pci_read_config_byte(dev, 0x73, &data);
++               pci_write_config_byte(dev, 0x73, data & 0xef);
++       }
++       return 0;
++}
++
++/* Added for EKF Intel i960 serial boards */
++static int __devinit
++pci_inteli960ni_fn(struct pci_dev *dev,
++		   struct pci_board *board,
++		   int enable)
++{
++	unsigned long oldval;
++	
++	if (!(pci_get_subdevice(dev) & 0x1000))
++		return(-1);
++
++	if (!enable) /* is there something to deinit? */
++		return(0);
++   
++	/* is firmware started? */
++	pci_read_config_dword(dev, 0x44, (void*) &oldval); 
++	if (oldval == 0x00001000L) { /* RESET value */ 
++		printk(KERN_DEBUG "Local i960 firmware missing");
++		return(-1); 
++	}
++	return(0);
++}
++
++/*
++ * Timedia has an explosion of boards, and to avoid the PCI table from
++ * growing *huge*, we use this function to collapse some 70 entries
++ * in the PCI table into one, for sanity's and compactness's sake.
++ */
++static unsigned short timedia_single_port[] = {
++	0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 };
++static unsigned short timedia_dual_port[] = {
++	0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
++	0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, 
++	0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, 
++	0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079,
++	0xD079, 0 };
++static unsigned short timedia_quad_port[] = {
++	0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, 
++	0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, 
++	0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
++	0xB157, 0 };
++static unsigned short timedia_eight_port[] = {
++	0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, 
++	0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 };
++static struct timedia_struct {
++	int num;
++	unsigned short *ids;
++} timedia_data[] = {
++	{ 1, timedia_single_port },
++	{ 2, timedia_dual_port },
++	{ 4, timedia_quad_port },
++	{ 8, timedia_eight_port },
++	{ 0, 0 }
++};
++
++static int __devinit
++pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
++{
++	int	i, j;
++	unsigned short *ids;
++
++	if (!enable)
++		return 0;
++
++	for (i=0; timedia_data[i].num; i++) {
++		ids = timedia_data[i].ids;
++		for (j=0; ids[j]; j++) {
++			if (pci_get_subdevice(dev) == ids[j]) {
++				board->num_ports = timedia_data[i].num;
++				return 0;
++			}
++		}
++	}
++	return 0;
++}
++
++static int __devinit
++pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable)
++{
++	__set_current_state(TASK_UNINTERRUPTIBLE);
++	schedule_timeout(HZ/10);
++	return 0;
++}
++
++/*
++ * This is the configuration table for all of the PCI serial boards
++ * which we support.  It is directly indexed by the pci_board_num_t enum
++ * value, which is encoded in the pci_device_id PCI probe table's
++ * driver_data member.
++ */
++enum pci_board_num_t {
++	pbn_b0_1_115200,
++	pbn_default = 0,
++
++	pbn_b0_2_115200,
++	pbn_b0_4_115200,
++
++	pbn_b0_1_921600,
++	pbn_b0_2_921600,
++	pbn_b0_4_921600,
++
++	pbn_b0_bt_1_115200,
++	pbn_b0_bt_2_115200,
++	pbn_b0_bt_1_460800,
++	pbn_b0_bt_2_460800,
++
++	pbn_b1_1_115200,
++	pbn_b1_2_115200,
++	pbn_b1_4_115200,
++	pbn_b1_8_115200,
++
++	pbn_b1_2_921600,
++	pbn_b1_4_921600,
++	pbn_b1_8_921600,
++
++	pbn_b1_2_1382400,
++	pbn_b1_4_1382400,
++	pbn_b1_8_1382400,
++
++	pbn_b2_8_115200,
++	pbn_b2_4_460800,
++	pbn_b2_8_460800,
++	pbn_b2_16_460800,
++	pbn_b2_4_921600,
++	pbn_b2_8_921600,
++
++	pbn_b2_bt_1_115200,
++	pbn_b2_bt_2_115200,
++	pbn_b2_bt_4_115200,
++	pbn_b2_bt_2_921600,
++
++	pbn_panacom,
++	pbn_panacom2,
++	pbn_panacom4,
++	pbn_plx_romulus,
++	pbn_oxsemi,
++	pbn_timedia,
++	pbn_intel_i960,
++	pbn_sgi_ioc3,
++#ifdef CONFIG_DDB5074
++	pbn_nec_nile4,
++#endif
++#if 0
++	pbn_dci_pccom8,
++#endif
++	pbn_xircom_combo,
++
++	pbn_siig10x_0,
++	pbn_siig10x_1,
++	pbn_siig10x_2,
++	pbn_siig10x_4,
++	pbn_siig20x_0,
++	pbn_siig20x_2,
++	pbn_siig20x_4,
++	
++	pbn_computone_4,
++	pbn_computone_6,
++	pbn_computone_8,
++};
++
++static struct pci_board pci_boards[] __devinitdata = {
++	/*
++	 * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
++	 * Offset to get to next UART's registers,
++	 * Register shift to use for memory-mapped I/O,
++	 * Initialization function, first UART offset
++	 */
++
++	/* Generic serial board, pbn_b0_1_115200, pbn_default */
++	{ SPCI_FL_BASE0, 1, 115200 },		/* pbn_b0_1_115200,
++						   pbn_default */
++
++	{ SPCI_FL_BASE0, 2, 115200 },		/* pbn_b0_2_115200 */
++	{ SPCI_FL_BASE0, 4, 115200 },		/* pbn_b0_4_115200 */
++
++	{ SPCI_FL_BASE0, 1, 921600 },		/* pbn_b0_1_921600 */
++	{ SPCI_FL_BASE0, 2, 921600 },		/* pbn_b0_2_921600 */
++	{ SPCI_FL_BASE0, 4, 921600 },		/* pbn_b0_4_921600 */
++
++	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */
++	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */
++	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */
++	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */
++
++	{ SPCI_FL_BASE1, 1, 115200 },		/* pbn_b1_1_115200 */
++	{ SPCI_FL_BASE1, 2, 115200 },		/* pbn_b1_2_115200 */
++	{ SPCI_FL_BASE1, 4, 115200 },		/* pbn_b1_4_115200 */
++	{ SPCI_FL_BASE1, 8, 115200 },		/* pbn_b1_8_115200 */
++
++	{ SPCI_FL_BASE1, 2, 921600 },		/* pbn_b1_2_921600 */
++	{ SPCI_FL_BASE1, 4, 921600 },		/* pbn_b1_4_921600 */
++	{ SPCI_FL_BASE1, 8, 921600 },		/* pbn_b1_8_921600 */
++
++	{ SPCI_FL_BASE1, 2, 1382400 },		/* pbn_b1_2_1382400 */
++	{ SPCI_FL_BASE1, 4, 1382400 },		/* pbn_b1_4_1382400 */
++	{ SPCI_FL_BASE1, 8, 1382400 },		/* pbn_b1_8_1382400 */
++
++	{ SPCI_FL_BASE2, 8, 115200 },		/* pbn_b2_8_115200 */
++	{ SPCI_FL_BASE2, 4, 460800 },		/* pbn_b2_4_460800 */
++	{ SPCI_FL_BASE2, 8, 460800 },		/* pbn_b2_8_460800 */
++	{ SPCI_FL_BASE2, 16, 460800 },		/* pbn_b2_16_460800 */
++	{ SPCI_FL_BASE2, 4, 921600 },		/* pbn_b2_4_921600 */
++	{ SPCI_FL_BASE2, 8, 921600 },		/* pbn_b2_8_921600 */
++
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */
++
++	{ SPCI_FL_BASE2, 2, 921600, /* IOMEM */		   /* pbn_panacom */
++		0x400, 7, pci_plx9050_fn },
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_panacom2 */
++		0x400, 7, pci_plx9050_fn },
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_panacom4 */
++		0x400, 7, pci_plx9050_fn },
++	{ SPCI_FL_BASE2, 4, 921600,			   /* pbn_plx_romulus */
++		0x20, 2, pci_plx9050_fn, 0x03 },
++		/* This board uses the size of PCI Base region 0 to
++		 * signal now many ports are available */
++	{ SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */
++	{ SPCI_FL_BASE_TABLE, 1, 921600,		   /* pbn_timedia */
++		0, 0, pci_timedia_fn },
++	/* EKF addition for i960 Boards form EKF with serial port */
++	{ SPCI_FL_BASE0, 32, 921600, /* max 256 ports */   /* pbn_intel_i960 */
++		8<<2, 2, pci_inteli960ni_fn, 0x10000},
++	{ SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE,		   /* pbn_sgi_ioc3 */
++		1, 458333, 0, 0, 0, 0x20178 },
++#ifdef CONFIG_DDB5074
++	/*
++	 * NEC Vrc-5074 (Nile 4) builtin UART.
++	 * Conditionally compiled in since this is a motherboard device.
++	 */
++	{ SPCI_FL_BASE0, 1, 520833,			   /* pbn_nec_nile4 */
++		64, 3, NULL, 0x300 },
++#endif
++#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */		   /* pbn_dci_pccom8 */
++	{ SPCI_FL_BASE3, 8, 115200, 8 },
++#endif
++	{ SPCI_FL_BASE0, 1, 115200,			  /* pbn_xircom_combo */
++		0, 0, pci_xircom_fn },
++
++	{ SPCI_FL_BASE2, 1, 460800,			   /* pbn_siig10x_0 */
++		0, 0, pci_siig10x_fn },
++	{ SPCI_FL_BASE2, 1, 921600,			   /* pbn_siig10x_1 */
++		0, 0, pci_siig10x_fn },
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siig10x_2 */
++		0, 0, pci_siig10x_fn },
++	{ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siig10x_4 */
++		0, 0, pci_siig10x_fn },
++	{ SPCI_FL_BASE0, 1, 921600,			   /* pbn_siix20x_0 */
++		0, 0, pci_siig20x_fn },
++	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,   /* pbn_siix20x_2 */
++		0, 0, pci_siig20x_fn },
++	{ SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,   /* pbn_siix20x_4 */
++		0, 0, pci_siig20x_fn },
++
++	{ SPCI_FL_BASE0, 4, 921600, /* IOMEM */		   /* pbn_computone_4 */
++		0x40, 2, NULL, 0x200 },
++	{ SPCI_FL_BASE0, 6, 921600, /* IOMEM */		   /* pbn_computone_6 */
++		0x40, 2, NULL, 0x200 },
++	{ SPCI_FL_BASE0, 8, 921600, /* IOMEM */		   /* pbn_computone_8 */
++		0x40, 2, NULL, 0x200 },
++};
++
++/*
++ * Given a complete unknown PCI device, try to use some heuristics to
++ * guess what the configuration might be, based on the pitiful PCI
++ * serial specs.  Returns 0 on success, 1 on failure.
++ */
++static int __devinit serial_pci_guess_board(struct pci_dev *dev,
++					   struct pci_board *board)
++{
++	int	num_iomem = 0, num_port = 0, first_port = -1;
++	int	i;
++	
++	/*
++	 * If it is not a communications device or the programming
++	 * interface is greater than 6, give up.
++	 *
++	 * (Should we try to make guesses for multiport serial devices
++	 * later?) 
++	 */
++	if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
++	    ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
++	    (dev->class & 0xff) > 6)
++		return 1;
++
++	for (i=0; i < 6; i++) {
++		if (IS_PCI_REGION_IOPORT(dev, i)) {
++			num_port++;
++			if (first_port == -1)
++				first_port = i;
++		}
++		if (IS_PCI_REGION_IOMEM(dev, i))
++			num_iomem++;
++	}
++
++	/*
++	 * If there is 1 or 0 iomem regions, and exactly one port, use
++	 * it.
++	 */
++	if (num_iomem <= 1 && num_port == 1) {
++		board->flags = first_port;
++		return 0;
++	}
++	return 1;
++}
++
++/*
++ * return -1 to refuse
++ */
++static int pci_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
++{
++	struct serial_private *priv;
++	struct pci_board *board, tmp;
++	struct serial_struct serial_req;
++	int base_baud, rc, k;
++
++	board = &pci_boards[ent->driver_data];
++
++	rc = pci_enable_device(dev);
++	if (rc)
++		return rc;
++
++	if (ent->driver_data == pbn_default &&
++	    serial_pci_guess_board(dev, board))
++		return -ENODEV;
++	else if (serial_pci_guess_board(dev, &tmp) == 0) {
++		printk(KERN_INFO "Redundant entry in serial pci_table.  "
++		       "Please send the output of\n"
++		       "lspci -vv, this message (%d,%d,%d,%d)\n"
++		       "and the manufacturer and name of "
++		       "serial board or modem board\n"
++		       "to serial-pci-info@lists.sourceforge.net.\n",
++		       dev->vendor, dev->device,
++		       pci_get_subvendor(dev), pci_get_subdevice(dev));
++	}
++
++
++	priv = kmalloc(sizeof(struct serial_private) +
++			      sizeof(unsigned int) * board->num_ports,
++			      GFP_KERNEL);
++	if (!priv)
++		return -ENOMEM;
++
++	/*
++	 * Run the initialization function, if any
++	 */
++	if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0)) {
++		kfree(priv);
++		return -ENODEV;
++	}
++
++	base_baud = board->base_baud;
++	if (!base_baud)
++		base_baud = BASE_BAUD;
++	memset(&serial_req, 0, sizeof(serial_req));
++	for (k=0; k < board->num_ports; k++) {
++		serial_req.irq = get_pci_irq(dev, board, k);
++		if (get_pci_port(dev, board, &serial_req, k))
++			break;
++#ifdef SERIAL_DEBUG_PCI
++		printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
++		       serial_req.port, serial_req.irq, serial_req.io_type);
++#endif
++		serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
++		serial_req.baud_base = base_baud;
++		priv->line[k] = register_serial(&serial_req);
++		if (priv->line[k] < 0)
++			break;
++	}
++
++	priv->board = board;
++	priv->nr = k;
++
++	pci_set_drvdata(dev, priv);
++
++	return 0;
++}
++
++static void pci_remove_one(struct pci_dev *dev)
++{
++	struct serial_private *priv = pci_get_drvdata(dev);
++	int i;
++
++	pci_set_drvdata(dev, NULL);
++
++	for (i = 0; i < priv->nr; i++)
++		unregister_serial(priv->line[i]);
++
++	priv->board->init_fn(dev, priv->board, 0);
++
++	kfree(priv);
++}
++
++static struct pci_device_id serial_pci_tbl[] __devinitdata = {
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
++		pbn_b1_8_1382400 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
++		pbn_b1_4_1382400 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
++		pbn_b1_2_1382400 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0,
++		pbn_b1_8_1382400 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0,
++		pbn_b1_4_1382400 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0,
++		pbn_b1_2_1382400 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0,
++		pbn_b1_8_921600 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0,
++		pbn_b1_8_921600 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0,
++		pbn_b1_4_921600 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0,
++		pbn_b1_4_921600 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0,
++		pbn_b1_2_921600 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0,
++		pbn_b1_8_921600 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0,
++		pbn_b1_8_921600 },
++	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351,
++		PCI_SUBVENDOR_ID_CONNECT_TECH,
++		PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0,
++		pbn_b1_4_921600 },
++
++	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_bt_1_115200 },
++	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_bt_2_115200 },
++	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_bt_4_115200 },
++	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_bt_2_115200 },
++	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_bt_4_115200 },
++	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_8_115200 },
++
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b2_bt_2_115200 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b2_bt_2_921600 },
++	/* VScom SPCOM800, from sl@s.pl */
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, 
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_8_921600 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b2_4_921600 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
++		PCI_SUBVENDOR_ID_KEYSPAN,
++		PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0,
++		pbn_panacom },
++	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_panacom4 },
++	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_panacom2 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
++		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
++		PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, 
++		pbn_b2_4_460800 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
++		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
++		PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, 
++		pbn_b2_8_460800 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
++		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
++		PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, 
++		pbn_b2_16_460800 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
++		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
++		PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, 
++		pbn_b2_16_460800 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
++		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
++		PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, 
++		pbn_b2_4_460800 },
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
++		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
++		PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, 
++		pbn_b2_8_460800 },
++	/* Megawolf Romulus PCI Serial Card, from Mike Hudson */
++	/* (Exoray@isys.ca) */
++	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS,
++		0x10b5, 0x106a, 0, 0,
++		pbn_plx_romulus },
++	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b1_4_115200 },
++	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b1_2_115200 },
++	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b1_8_115200 },
++	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b1_8_115200 },
++	{	PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
++		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, 
++		pbn_b0_4_921600 },
++	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b0_4_115200 },
++	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b0_2_115200 },
++
++	/* Digitan DS560-558, from jimd@esoft.com */
++	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b1_1_115200 },
++
++	/* 3Com US Robotics 56k Voice Internal PCI model 5610 */
++	{	PCI_VENDOR_ID_USR, 0x1008,
++		PCI_ANY_ID, PCI_ANY_ID, },
++
++	/* Titan Electronic cards */
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b0_1_921600 },
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b0_2_921600 },
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b0_4_921600 },
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 
++		pbn_b0_4_921600 },
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L,
++		PCI_ANY_ID, PCI_ANY_ID,
++		SPCI_FL_BASE1, 1, 921600 },
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L,
++		PCI_ANY_ID, PCI_ANY_ID,
++		SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 },
++	/* The 400L and 800L have a custom hack in get_pci_port */
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L,
++		PCI_ANY_ID, PCI_ANY_ID,
++		SPCI_FL_BASE_TABLE, 4, 921600 },
++	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
++		PCI_ANY_ID, PCI_ANY_ID,
++		SPCI_FL_BASE_TABLE, 8, 921600 },
++
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_1 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_1 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_1 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_4 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_4 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig10x_4 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_0 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_2 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_4 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_4 },
++	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_siig20x_4 },
++
++	/* Computone devices submitted by Doug McNash dmcnash@computone.com */
++	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
++		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
++		0, 0, pbn_computone_4 },
++	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
++		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
++		0, 0, pbn_computone_8 },
++	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
++		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
++		0, 0, pbn_computone_6 },
++
++	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi },
++	{	PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
++		PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia },
++
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_2_115200 },
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_2_115200 },
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_2_115200 },
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_2_460800 },
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_2_460800 },
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_2_460800 },
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_1_115200 },
++	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b0_bt_1_460800 },
++
++	/* RAStel 2 port modem, gerg@moreton.com.au */
++	{	PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_b2_bt_2_115200 },
++
++	/* EKF addition for i960 Boards form EKF with serial port */
++	{	PCI_VENDOR_ID_INTEL, 0x1960,
++		0xE4BF, PCI_ANY_ID, 0, 0,
++		pbn_intel_i960 },
++
++	/* Xircom Cardbus/Ethernet combos */
++	{	PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_xircom_combo },
++
++	/*
++	 * Untested PCI modems, sent in from various folks...
++	 */
++
++	/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
++	{	PCI_VENDOR_ID_ROCKWELL, 0x1004,
++		0x1048, 0x1500, 0, 0,
++		pbn_b1_1_115200 },
++
++	{	PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3,
++		0xFF00, 0, 0, 0,
++		pbn_sgi_ioc3 },
++
++#ifdef CONFIG_DDB5074
++	/*
++	 * NEC Vrc-5074 (Nile 4) builtin UART.
++	 * Conditionally compiled in since this is a motherboard device.
++	 */
++	{	PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_nec_nile4 },
++#endif
++
++#if 0	/* PCI_DEVICE_ID_DCI_PCCOM8 ? */
++	{	PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8,
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++		pbn_dci_pccom8 },
++#endif
++
++	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
++	  PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, },
++	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
++	  PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, },
++	{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
++	  PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, },
++	{ 0, }
++};
++
++static struct pci_driver serial_pci_driver = {
++	name:		"serial",
++	probe:		pci_init_one,
++	remove:		pci_remove_one,
++	id_table:	serial_pci_tbl,
++};
++
++static int __init serial8250_pci_init(void)
++{
++	return pci_module_init(&serial_pci_driver);
++}
++
++static void __exit serial8250_pci_exit(void)
++{
++	pci_unregister_driver(&serial_pci_driver);
++}
++
++module_init(serial8250_pci_init);
++module_exit(serial8250_pci_exit);
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module");
++MODULE_GENERIC_TABLE(pci, serial_pci_tbl);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/8250_pnp.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,553 @@
++/*
++ *  linux/drivers/char/serial_8250_pnp.c
++ *
++ *  Probe module for 8250/16550-type ISAPNP serial ports.
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ *  $Id$
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/isapnp.h>
++#include <linux/string.h>
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/serialP.h>
++
++#include <asm/bitops.h>
++#include <asm/byteorder.h>
++#include <asm/serial.h>
++
++#include "8250.h"
++
++static struct serial_state rs_table[] = { };
++#define NR_PORTS 0
++
++struct pnpbios_device_id
++{
++	char id[8];
++	unsigned long driver_data;
++};
++
++static const struct pnpbios_device_id pnp_dev_table[] = {
++	/* Archtek America Corp. */
++	/* Archtek SmartLink Modem 3334BT Plug & Play */
++	{	"AAC000F",		0	},
++	/* Anchor Datacomm BV */
++	/* SXPro 144 External Data Fax Modem Plug & Play */
++	{	"ADC0001",		0	},
++	/* SXPro 288 External Data Fax Modem Plug & Play */
++	{	"ADC0002",		0	},
++	/* Rockwell 56K ACF II Fax+Data+Voice Modem */
++	{	"AKY1021",		SPCI_FL_NO_SHIRQ	},
++	/* AZT3005 PnP SOUND DEVICE */
++	{	"AZT4001",		0	},
++	/* Best Data Products Inc. Smart One 336F PnP Modem */
++	{	"BDP3336",		0	},
++	/*  Boca Research */
++	/* Boca Complete Ofc Communicator 14.4 Data-FAX */
++	{	"BRI0A49",		0	},
++	/* Boca Research 33,600 ACF Modem */
++	{	"BRI1400",		0	},
++	/* Boca 33.6 Kbps Internal FD34FSVD */
++	{	"BRI3400",		0	},
++	/* Boca 33.6 Kbps Internal FD34FSVD */
++	{	"BRI0A49",		0	},
++	/* Best Data Products Inc. Smart One 336F PnP Modem */
++	{	"BDP3336",		0	},
++	/* Computer Peripherals Inc */
++	/* EuroViVa CommCenter-33.6 SP PnP */
++	{	"CPI4050",		0	},
++	/* Creative Labs */
++	/* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
++	{	"CTL3001",		0	},
++	/* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
++	{	"CTL3011",		0	},
++	/* Creative */
++	/* Creative Modem Blaster Flash56 DI5601-1 */
++	{	"DMB1032",		0	},
++	/* Creative Modem Blaster V.90 DI5660 */
++	{	"DMB2001",		0	},
++	/* FUJITSU */
++	/* Fujitsu 33600 PnP-I2 R Plug & Play */
++	{	"FUJ0202",		0	},
++	/* Fujitsu FMV-FX431 Plug & Play */
++	{	"FUJ0205",		0	},
++	/* Fujitsu 33600 PnP-I4 R Plug & Play */
++	{	"FUJ0206",		0	},
++	/* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
++	{	"FUJ0209",		0	},
++	/* Archtek America Corp. */
++	/* Archtek SmartLink Modem 3334BT Plug & Play */
++	{	"GVC000F",		0	},
++	/* Hayes */
++	/* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
++	{	"HAY0001",		0	},
++	/* Hayes Optima 336 V.34 + FAX + Voice PnP */
++	{	"HAY000C",		0	},
++	/* Hayes Optima 336B V.34 + FAX + Voice PnP */
++	{	"HAY000D",		0	},
++	/* Hayes Accura 56K Ext Fax Modem PnP */
++	{	"HAY5670",		0	},
++	/* Hayes Accura 56K Ext Fax Modem PnP */
++	{	"HAY5674",		0	},
++	/* Hayes Accura 56K Fax Modem PnP */
++	{	"HAY5675",		0	},
++	/* Hayes 288, V.34 + FAX */
++	{	"HAYF000",		0	},
++	/* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
++	{	"HAYF001",		0	},
++	/* IBM */
++	/* IBM Thinkpad 701 Internal Modem Voice */
++	{	"IBM0033",		0	},
++	/* Intertex */
++	/* Intertex 28k8 33k6 Voice EXT PnP */
++	{	"IXDC801",		0	},
++	/* Intertex 33k6 56k Voice EXT PnP */
++	{	"IXDC901",		0	},
++	/* Intertex 28k8 33k6 Voice SP EXT PnP */
++	{	"IXDD801",		0	},
++	/* Intertex 33k6 56k Voice SP EXT PnP */
++	{	"IXDD901",		0	},
++	/* Intertex 28k8 33k6 Voice SP INT PnP */
++	{	"IXDF401",		0	},
++	/* Intertex 28k8 33k6 Voice SP EXT PnP */
++	{	"IXDF801",		0	},
++	/* Intertex 33k6 56k Voice SP EXT PnP */
++	{	"IXDF901",		0	},
++	/* Kortex International */
++	/* KORTEX 28800 Externe PnP */
++	{	"KOR4522",		0	},
++	/* KXPro 33.6 Vocal ASVD PnP */
++	{	"KORF661",		0	},
++	/* Lasat */
++	/* LASAT Internet 33600 PnP */
++	{	"LAS4040",		0	},
++	/* Lasat Safire 560 PnP */
++	{	"LAS4540",		0	},
++	/* Lasat Safire 336  PnP */
++	{	"LAS5440",		0	},
++	/* Microcom, Inc. */
++	/* Microcom TravelPorte FAST V.34 Plug & Play */
++	{	"MNP0281",		0	},
++	/* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
++	{	"MNP0336",		0	},
++	/* Microcom DeskPorte FAST EP 28.8 Plug & Play */
++	{	"MNP0339",		0	},
++	/* Microcom DeskPorte 28.8P Plug & Play */
++	{	"MNP0342",		0	},
++	/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
++	{	"MNP0500",		0	},
++	/* Microcom DeskPorte FAST ES 28.8 Plug & Play */
++	{	"MNP0501",		0	},
++	/* Microcom DeskPorte 28.8S Internal Plug & Play */
++	{	"MNP0502",		0	},
++	/* Motorola */
++	/* Motorola BitSURFR Plug & Play */
++	{	"MOT1105",		0	},
++	/* Motorola TA210 Plug & Play */
++	{	"MOT1111",		0	},
++	/* Motorola HMTA 200 (ISDN) Plug & Play */
++	{	"MOT1114",		0	},
++	/* Motorola BitSURFR Plug & Play */
++	{	"MOT1115",		0	},
++	/* Motorola Lifestyle 28.8 Internal */
++	{	"MOT1190",		0	},
++	/* Motorola V.3400 Plug & Play */
++	{	"MOT1501",		0	},
++	/* Motorola Lifestyle 28.8 V.34 Plug & Play */
++	{	"MOT1502",		0	},
++	/* Motorola Power 28.8 V.34 Plug & Play */
++	{	"MOT1505",		0	},
++	/* Motorola ModemSURFR External 28.8 Plug & Play */
++	{	"MOT1509",		0	},
++	/* Motorola Premier 33.6 Desktop Plug & Play */
++	{	"MOT150A",		0	},
++	/* Motorola VoiceSURFR 56K External PnP */
++	{	"MOT150F",		0	},
++	/* Motorola ModemSURFR 56K External PnP */
++	{	"MOT1510",		0	},
++	/* Motorola ModemSURFR 56K Internal PnP */
++	{	"MOT1550",		0	},
++	/* Motorola ModemSURFR Internal 28.8 Plug & Play */
++	{	"MOT1560",		0	},
++	/* Motorola Premier 33.6 Internal Plug & Play */
++	{	"MOT1580",		0	},
++	/* Motorola OnlineSURFR 28.8 Internal Plug & Play */
++	{	"MOT15B0",		0	},
++	/* Motorola VoiceSURFR 56K Internal PnP */
++	{	"MOT15F0",		0	},
++	/* Com 1 */
++	/*  Deskline K56 Phone System PnP */
++	{	"MVX00A1",		0	},
++	/* PC Rider K56 Phone System PnP */
++	{	"MVX00F2",		0	},
++	/* Pace 56 Voice Internal Plug & Play Modem */
++	{	"PMC2430",		0	},
++	/* Generic */
++	/* Generic standard PC COM port	 */
++	{	"PNP0500",		0	},
++	/* Generic 16550A-compatible COM port */
++	{	"PNP0501",		0	},
++	/* Compaq 14400 Modem */
++	{	"PNPC000",		0	},
++	/* Compaq 2400/9600 Modem */
++	{	"PNPC001",		0	},
++	/* Dial-Up Networking Serial Cable between 2 PCs */
++	{	"PNPC031",		0	},
++	/* Dial-Up Networking Parallel Cable between 2 PCs */
++	{	"PNPC032",		0	},
++	/* Standard 9600 bps Modem */
++	{	"PNPC100",		0	},
++	/* Standard 14400 bps Modem */
++	{	"PNPC101",		0	},
++	/*  Standard 28800 bps Modem*/
++	{	"PNPC102",		0	},
++	/*  Standard Modem*/
++	{	"PNPC103",		0	},
++	/*  Standard 9600 bps Modem*/
++	{	"PNPC104",		0	},
++	/*  Standard 14400 bps Modem*/
++	{	"PNPC105",		0	},
++	/*  Standard 28800 bps Modem*/
++	{	"PNPC106",		0	},
++	/*  Standard Modem */
++	{	"PNPC107",		0	},
++	/* Standard 9600 bps Modem */
++	{	"PNPC108",		0	},
++	/* Standard 14400 bps Modem */
++	{	"PNPC109",		0	},
++	/* Standard 28800 bps Modem */
++	{	"PNPC10A",		0	},
++	/* Standard Modem */
++	{	"PNPC10B",		0	},
++	/* Standard 9600 bps Modem */
++	{	"PNPC10C",		0	},
++	/* Standard 14400 bps Modem */
++	{	"PNPC10D",		0	},
++	/* Standard 28800 bps Modem */
++	{	"PNPC10E",		0	},
++	/* Standard Modem */
++	{	"PNPC10F",		0	},
++	/* Standard PCMCIA Card Modem */
++	{	"PNP2000",		0	},
++	/* Rockwell */
++	/* Modular Technology */
++	/* Rockwell 33.6 DPF Internal PnP */
++	/* Modular Technology 33.6 Internal PnP */
++	{	"ROK0030",		0	},
++	/* Kortex International */
++	/* KORTEX 14400 Externe PnP */
++	{	"ROK0100",		0	},
++	/* Viking Components, Inc */
++	/* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
++	{	"ROK4920",		0	},
++	/* Rockwell */
++	/* British Telecom */
++	/* Modular Technology */
++	/* Rockwell 33.6 DPF External PnP */
++	/* BT Prologue 33.6 External PnP */
++	/* Modular Technology 33.6 External PnP */
++	{	"RSS00A0",		0	},
++	/* Viking 56K FAX INT */
++	{	"RSS0262",		0	},
++	/* SupraExpress 28.8 Data/Fax PnP modem */
++	{	"SUP1310",		0	},
++	/* SupraExpress 33.6 Data/Fax PnP modem */
++	{	"SUP1421",		0	},
++	/* SupraExpress 33.6 Data/Fax PnP modem */
++	{	"SUP1590",		0	},
++	/* SupraExpress 33.6 Data/Fax PnP modem */
++	{	"SUP1760",		0	},
++	/* Phoebe Micro */
++	/* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
++	{	"TEX0011",		0	},
++	/* Archtek America Corp. */
++	/* Archtek SmartLink Modem 3334BT Plug & Play */
++	{	"UAC000F",		0	},
++	/* 3Com Corp. */
++	/* Gateway Telepath IIvi 33.6 */
++	{	"USR0000",		0	},
++	/*  Sportster Vi 14.4 PnP FAX Voicemail */
++	{	"USR0004",		0	},
++	/* U.S. Robotics 33.6K Voice INT PnP */
++	{	"USR0006",		0	},
++	/* U.S. Robotics 33.6K Voice EXT PnP */
++	{	"USR0007",		0	},
++	/* U.S. Robotics 33.6K Voice INT PnP */
++	{	"USR2002",		0	},
++	/* U.S. Robotics 56K Voice INT PnP */
++	{	"USR2070",		0	},
++	/* U.S. Robotics 56K Voice EXT PnP */
++	{	"USR2080",		0	},
++	/* U.S. Robotics 56K FAX INT */
++	{	"USR3031",		0	},
++	/* U.S. Robotics 56K Voice INT PnP */
++	{	"USR3070",		0	},
++	/* U.S. Robotics 56K Voice EXT PnP */
++	{	"USR3080",		0	},
++	/* U.S. Robotics 56K Voice INT PnP */
++	{	"USR3090",		0	},
++	/* U.S. Robotics 56K Message  */
++	{	"USR9100",		0	},
++	/* U.S. Robotics 56K FAX EXT PnP*/
++	{	"USR9160",		0	},
++	/* U.S. Robotics 56K FAX INT PnP*/
++	{	"USR9170",		0	},
++	/* U.S. Robotics 56K Voice EXT PnP*/
++	{	"USR9180",		0	},
++	/* U.S. Robotics 56K Voice INT PnP*/
++	{	"USR9190",		0	},
++	{	"",			0	}
++};
++
++static void inline avoid_irq_share(struct pci_dev *dev)
++{
++	int i, map = 0x1FF8;
++	struct serial_state *state = rs_table;
++	struct isapnp_irq *irq;
++	struct isapnp_resources *res = dev->sysdata;
++
++	for (i = 0; i < NR_PORTS; i++) {
++		if (state->type != PORT_UNKNOWN)
++			clear_bit(state->irq, &map);
++		state++;
++	}
++
++	for ( ; res; res = res->alt)
++		for(irq = res->irq; irq; irq = irq->next)
++			irq->map = map;
++}
++
++static char *modem_names[] __devinitdata = {
++	"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
++	"56K", "56k", "K56", "33.6", "28.8", "14.4",
++	"33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
++	"33600", "28800", "14400", "V.90", "V.34", "V.32", 0
++};
++
++static int __devinit check_name(char *name)
++{
++	char **tmp;
++
++	for (tmp = modem_names; *tmp; tmp++)
++		if (strstr(name, *tmp))
++			return 1;
++
++	return 0;
++}
++
++static int inline check_compatible_id(struct pci_dev *dev)
++{
++	int i;
++	for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
++		if ((dev->vendor_compatible[i] ==
++		     ISAPNP_VENDOR('P', 'N', 'P')) &&
++		    (swab16(dev->device_compatible[i]) >= 0xc000) &&
++		    (swab16(dev->device_compatible[i]) <= 0xdfff))
++			return 0;
++	return 1;
++}
++
++/*
++ * Given a complete unknown ISA PnP device, try to use some heuristics to
++ * detect modems. Currently use such heuristic set:
++ *     - dev->name or dev->bus->name must contain "modem" substring;
++ *     - device must have only one IO region (8 byte long) with base adress
++ *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
++ *
++ * Such detection looks very ugly, but can detect at least some of numerous
++ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
++ * table.
++ */
++static int serial_pnp_guess_board(struct pci_dev *dev, int *flags)
++{
++	struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
++	struct isapnp_resources *resa;
++
++	if (!(check_name(dev->name) || check_name(dev->bus->name)) &&
++	    !(check_compatible_id(dev)))
++		return -ENODEV;
++
++	if (!res || res->next)
++		return -ENODEV;
++
++	for (resa = res->alt; resa; resa = resa->alt) {
++		struct isapnp_port *port;
++		for (port = res->port; port; port = port->next)
++			if ((port->size == 8) &&
++			    ((port->min == 0x2f8) ||
++			     (port->min == 0x3f8) ||
++			     (port->min == 0x2e8) ||
++			     (port->min == 0x3e8)))
++				return 0;
++	}
++
++	return -ENODEV;
++}
++
++static int
++pnp_init_one(struct pci_dev *dev, const struct pnpbios_device_id *ent,
++	     char *slot_name)
++{
++	struct serial_struct serial_req;
++	int ret, line, flags = ent ? ent->driver_data : 0;
++
++	if (!ent) {
++		ret = serial_pnp_guess_board(dev, &flags);
++		if (ret)
++			return ret;
++	}
++
++	if (dev->prepare(dev) < 0) {
++		printk("serial: PNP device '%s' prepare failed\n",
++			slot_name);
++		return -ENODEV;
++	}
++
++	if (dev->active)
++		return -ENODEV;
++
++	if (flags & SPCI_FL_NO_SHIRQ)
++		avoid_irq_share(dev);
++
++	if (dev->activate(dev) < 0) {
++		printk("serial: PNP device '%s' activate failed\n",
++			slot_name);
++		return -ENODEV;
++	}
++
++	memset(&serial_req, 0, sizeof(serial_req));
++	serial_req.irq = dev->irq_resource[0].start;
++	serial_req.port = pci_resource_start(dev, 0);
++	if (HIGH_BITS_OFFSET)
++		serial_req.port = pci_resource_start(dev, 0) >> HIGH_BITS_OFFSET;
++
++#ifdef SERIAL_DEBUG_PCI
++	printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
++	       serial_req.port, serial_req.irq, serial_req.io_type);
++#endif
++
++	serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
++	serial_req.baud_base = 115200;
++	line = register_serial(&serial_req);
++
++	if (line >= 0) {
++		pci_set_drvdata(dev, (void *)(line + 1));
++
++		/*
++		 * Public health warning: remove this once the 2.5
++		 * pnpbios_module_init() stuff is incorporated.
++		 */
++		dev->driver = (void *)pnp_dev_table;
++	} else
++		dev->deactivate(dev);
++
++	return line >= 0 ? 0 : -ENODEV;
++}
++
++static void pnp_remove_one(struct pci_dev *dev)
++{
++	int line = (int)pci_get_drvdata(dev);
++
++	if (line) {
++		pci_set_drvdata(dev, NULL);
++
++		unregister_serial(line - 1);
++
++		dev->deactivate(dev);
++	}
++}
++
++static char hex[] = "0123456789ABCDEF";
++
++/*
++ * This function should vanish when 2.5 comes around and
++ * we have pnpbios_module_init()
++ */
++static void pnp_init(void)
++{
++	const struct pnpbios_device_id *id;
++	struct pci_dev *dev = NULL;
++
++#ifdef SERIAL_DEBUG_PNP
++	printk("Entered probe_serial_pnp()\n");
++#endif
++
++	isapnp_for_each_dev(dev) {
++		char slot_name[8];
++		u32 pnpid;
++
++		if (dev->active)
++			continue;
++
++		pnpid = dev->vendor << 16 | dev->device;
++		pnpid = cpu_to_le32(pnpid);
++
++#define HEX(id,a) hex[((id)>>a) & 15]
++#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
++		slot_name[0] = CHAR(pnpid, 26);
++		slot_name[1] = CHAR(pnpid, 21);
++		slot_name[2] = CHAR(pnpid, 16);
++		slot_name[3] = HEX(pnpid, 12);
++		slot_name[4] = HEX(pnpid, 8);
++		slot_name[5] = HEX(pnpid, 4);
++		slot_name[6] = HEX(pnpid, 0);
++		slot_name[7] = '\0';
++		
++		for (id = pnp_dev_table; id->id[0]; id++)
++			if (memcmp(id->id, slot_name, 7) == 0)
++				break;
++
++		if (id->id[0])
++			pnp_init_one(dev, id, slot_name);
++		else
++			pnp_init_one(dev, NULL, slot_name);
++	}
++
++#ifdef SERIAL_DEBUG_PNP
++	printk("Leaving probe_serial_pnp() (probe finished)\n");
++#endif
++}
++
++static int __init serial8250_pnp_init(void)
++{
++	if (!isapnp_present()) {
++#ifdef SERIAL_DEBUG_PNP
++		printk("Leaving probe_serial_pnp() (no isapnp)\n");
++#endif
++		return -ENODEV;
++	}
++	pnp_init();
++	return 0;
++}
++
++static void __exit serial8250_pnp_exit(void)
++{
++	struct pci_dev *dev = NULL;
++
++	isapnp_for_each_dev(dev) {
++		if (dev->driver != (void *)pnp_dev_table)
++			continue;
++		pnp_remove_one(dev);
++	}
++}
++
++module_init(serial8250_pnp_init);
++module_exit(serial8250_pnp_exit);
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("Generic 8250/16x50 PNPBIOS serial probe module");
++MODULE_GENERIC_TABLE(pnp, pnp_dev_table);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,91 @@
++#
++# Serial device configuration
++#
++# $Id$
++#
++mainmenu_option next_comment
++comment 'Serial drivers'
++
++if [ "$CONFIG_ARM" = "y" ]; then
++  # I don't have this in my tree yet.
++  dep_bool 'Anakin serial port support' CONFIG_SERIAL_ANAKIN $CONFIG_ARCH_ANAKIN
++  dep_bool '  Console on Anakin serial port' CONFIG_SERIAL_ANAKIN_CONSOLE $CONFIG_SERIAL_ANAKIN
++  if [ "$CONFIG_SERIAL_ANAKIN" = "y" ]; then
++     int  '  Default Anakin serial baudrate' CONFIG_ANAKIN_DEFAULT_BAUDRATE 9600
++  fi
++
++  dep_tristate 'ARM AMBA serial port support' CONFIG_SERIAL_AMBA $CONFIG_ARCH_INTEGRATOR
++  dep_bool '  Support for console on AMBA serial port' CONFIG_SERIAL_AMBA_CONSOLE $CONFIG_SERIAL_AMBA
++  if [ "$CONFIG_SERIAL_AMBA" = "y" ]; then
++     define_bool CONFIG_SERIAL_INTEGRATOR y
++  fi
++
++  dep_tristate 'CLPS711X serial port support' CONFIG_SERIAL_CLPS711X $CONFIG_ARCH_CLPS711X
++  dep_bool '  Support for console on CLPS711X serial port' CONFIG_SERIAL_CLPS711X_CONSOLE $CONFIG_SERIAL_CLPS711X
++
++  dep_bool 'DC21285 serial port support' CONFIG_SERIAL_21285 $CONFIG_FOOTBRIDGE
++  dep_bool '  Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD $CONFIG_SERIAL_21285 $CONFIG_OBSOLETE
++  dep_bool '  Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE $CONFIG_SERIAL_21285
++
++  dep_bool 'Excalibur serial port (uart00) support' CONFIG_SERIAL_UART00 $CONFIG_ARCH_CAMELOT
++  dep_bool '  Support for console on Excalibur serial port' CONFIG_SERIAL_UART00_CONSOLE $CONFIG_SERIAL_UART00
++
++
++  dep_bool 'SA1100 serial port support' CONFIG_SERIAL_SA1100 $CONFIG_ARCH_SA1100
++  dep_bool '  Console on SA1100 serial port' CONFIG_SERIAL_SA1100_CONSOLE $CONFIG_SERIAL_SA1100
++  if [ "$CONFIG_SERIAL_SA1100" = "y" ]; then
++     int  '  Default SA1100 serial baudrate' CONFIG_SA1100_DEFAULT_BAUDRATE 9600
++  fi
++
++  dep_tristate 'ARM Omaha serial port support' CONFIG_SERIAL_OMAHA $CONFIG_ARCH_OMAHA
++  dep_bool '  Support for console on Omaha serial port' CONFIG_SERIAL_OMAHA_CONSOLE $CONFIG_SERIAL_OMAHA
++
++  dep_tristate 'AT91RM9200 serial port support' CONFIG_SERIAL_AT91 $CONFIG_ARCH_AT91RM9200
++  dep_bool '  Console on AT91RM9200 serial port' CONFIG_SERIAL_AT91_CONSOLE $CONFIG_SERIAL_AT91
++
++fi
++#
++# The new 8250/16550 serial drivers
++dep_tristate '8250/16550 and compatible serial support (EXPERIMENTAL)' CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL
++dep_bool '  Console on 8250/16550 and compatible serial port (EXPERIMENTAL)' CONFIG_SERIAL_8250_CONSOLE $CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL
++
++dep_mbool 'Extended 8250/16550 serial driver options' CONFIG_SERIAL_8250_EXTENDED $CONFIG_SERIAL_8250
++dep_bool '  Support more than 4 serial ports' CONFIG_SERIAL_8250_MANY_PORTS $CONFIG_SERIAL_8250_EXTENDED
++dep_bool '  Support for sharing serial interrupts' CONFIG_SERIAL_8250_SHARE_IRQ $CONFIG_SERIAL_8250_EXTENDED
++dep_bool '  Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_8250_DETECT_IRQ $CONFIG_SERIAL_8250_EXTENDED
++dep_bool '  Support special multiport boards' CONFIG_SERIAL_8250_MULTIPORT $CONFIG_SERIAL_8250_EXTENDED
++dep_bool '  Support Bell Technologies HUB6 card' CONFIG_SERIAL_8250_HUB6 $CONFIG_SERIAL_8250_EXTENDED
++
++if [ "$CONFIG_SERIAL_AMBA" = "y" -o \
++     "$CONFIG_SERIAL_CLPS711X" = "y" -o \
++     "$CONFIG_SERIAL_SA1100" = "y" -o \
++     "$CONFIG_SERIAL_ANAKIN" = "y" -o \
++     "$CONFIG_SERIAL_UART00" = "y" -o \
++     "$CONFIG_SERIAL_8250" = "y"  -o \
++     "$CONFIG_SERIAL_OMAHA" = "y" -o \
++     "$CONFIG_SERIAL_AT91" = "y" ]; then
++   define_bool CONFIG_SERIAL_CORE y
++else
++   if [ "$CONFIG_SERIAL_AMBA" = "m" -o \
++        "$CONFIG_SERIAL_CLPS711X" = "m" -o \
++        "$CONFIG_SERIAL_SA1100" = "m" -o \
++        "$CONFIG_SERIAL_ANAKIN" = "m" -o \
++        "$CONFIG_SERIAL_UART00" = "m" -o \
++        "$CONFIG_SERIAL_8250" = "m"  -o \
++        "$CONFIG_SERIAL_OMAHA" = "m" -o \
++        "$CONFIG_SERIAL_AT91" = "m" ]; then
++      define_bool CONFIG_SERIAL_CORE m
++   fi
++fi
++if [ "$CONFIG_SERIAL_AMBA_CONSOLE" = "y" -o \
++     "$CONFIG_SERIAL_CLPS711X_CONSOLE" = "y" -o \
++     "$CONFIG_SERIAL_SA1100_CONSOLE" = "y" -o \
++     "$CONFIG_SERIAL_ANAKIN_CONSOLE" = "y" -o \
++     "$CONFIG_SERIAL_UART00_CONSOLE" = "y" -o \
++     "$CONFIG_SERIAL_8250_CONSOLE" = "y" -o \
++     "$CONFIG_SERIAL_OMAHA" = "y" -o \
++     "$CONFIG_SERIAL_AT91_CONSOLE" = "y" ]; then
++   define_bool CONFIG_SERIAL_CORE_CONSOLE y
++fi
++
++endmenu
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,39 @@
++#
++# Makefile for the kernel serial device drivers.
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definitions are now inherited from the
++# parent makes..
++#
++#  $Id$
++#
++
++O_TARGET := serial.o
++
++export-objs	:= core.o 8250.o
++obj-y		:=
++obj-m		:=
++obj-n		:=
++obj-		:=
++
++serial-8250-y :=
++serial-8250-$(CONFIG_PCI) += 8250_pci.o
++serial-8250-$(CONFIG_ISAPNP) += 8250_pnp.o
++obj-$(CONFIG_SERIAL_CORE) += core.o
++obj-$(CONFIG_SERIAL_21285) += 21285.o
++obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
++obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o
++obj-$(CONFIG_SERIAL_AMBA) += amba.o
++obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
++obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
++obj-$(CONFIG_SERIAL_UART00) += uart00.o
++obj-$(CONFIG_SERIAL_OMAHA) += omaha.o
++obj-$(CONFIG_SERIAL_AT91US3) += at91us3.o
++
++include $(TOPDIR)/Rules.make
++
++fastdep:
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/amba.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,770 @@
++/*
++ *  linux/drivers/char/serial_amba.c
++ *
++ *  Driver for AMBA serial ports
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright 1999 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id$
++ *
++ * This is a generic driver for ARM AMBA-type serial ports.  They
++ * have a lot of 16550-like features, but are not register compatable.
++ * Note that although they do have CTS, DCD and DSR inputs, they do
++ * not have an RI input, nor do they have DTR or RTS outputs.  If
++ * required, these have to be supplied via some other means (eg, GPIO)
++ * and hooked into this driver.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++
++#include <asm/hardware/serial_amba.h>
++
++#define UART_NR		2
++
++#define SERIAL_AMBA_MAJOR	204
++#define SERIAL_AMBA_MINOR	16
++#define SERIAL_AMBA_NR		UART_NR
++
++#define CALLOUT_AMBA_NAME	"cuaam"
++#define CALLOUT_AMBA_MAJOR	205
++#define CALLOUT_AMBA_MINOR	16
++#define CALLOUT_AMBA_NR		UART_NR
++
++static struct tty_driver normal, callout;
++static struct tty_struct *amba_table[UART_NR];
++static struct termios *amba_termios[UART_NR], *amba_termios_locked[UART_NR];
++#ifdef SUPPORT_SYSRQ
++static struct console amba_console;
++#endif
++
++#define AMBA_ISR_PASS_LIMIT	256
++
++/*
++ * Access macros for the AMBA UARTs
++ */
++#define UART_GET_INT_STATUS(p)	readb((p)->membase + AMBA_UARTIIR)
++#define UART_PUT_ICR(p, c)	writel((c), (p)->membase + AMBA_UARTICR)
++#define UART_GET_FR(p)		readb((p)->membase + AMBA_UARTFR)
++#define UART_GET_CHAR(p)	readb((p)->membase + AMBA_UARTDR)
++#define UART_PUT_CHAR(p, c)	writel((c), (p)->membase + AMBA_UARTDR)
++#define UART_GET_RSR(p)		readb((p)->membase + AMBA_UARTRSR)
++#define UART_GET_CR(p)		readb((p)->membase + AMBA_UARTCR)
++#define UART_PUT_CR(p,c)	writel((c), (p)->membase + AMBA_UARTCR)
++#define UART_GET_LCRL(p)	readb((p)->membase + AMBA_UARTLCR_L)
++#define UART_PUT_LCRL(p,c)	writel((c), (p)->membase + AMBA_UARTLCR_L)
++#define UART_GET_LCRM(p)	readb((p)->membase + AMBA_UARTLCR_M)
++#define UART_PUT_LCRM(p,c)	writel((c), (p)->membase + AMBA_UARTLCR_M)
++#define UART_GET_LCRH(p)	readb((p)->membase + AMBA_UARTLCR_H)
++#define UART_PUT_LCRH(p,c)	writel((c), (p)->membase + AMBA_UARTLCR_H)
++#define UART_RX_DATA(s)		(((s) & AMBA_UARTFR_RXFE) == 0)
++#define UART_TX_READY(s)	(((s) & AMBA_UARTFR_TXFF) == 0)
++#define UART_TX_EMPTY(p)	((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0)
++
++#define UART_DUMMY_RSR_RX	256
++#define UART_PORT_SIZE		64
++
++/*
++ * On the Integrator platform, the port RTS and DTR are provided by
++ * bits in the following SC_CTRLS register bits:
++ *        RTS  DTR
++ *  UART0  7    6
++ *  UART1  5    4
++ */
++#define SC_CTRLC	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
++#define SC_CTRLS	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)
++
++/*
++ * We wrap our port structure around the generic uart_port.
++ */
++struct uart_amba_port {
++	struct uart_port	port;
++	unsigned int		dtr_mask;
++	unsigned int		rts_mask;
++	unsigned int		old_status;
++};
++
++static void ambauart_stop_tx(struct uart_port *port, unsigned int tty_stop)
++{
++	unsigned int cr;
++
++	cr = UART_GET_CR(port);
++	cr &= ~AMBA_UARTCR_TIE;
++	UART_PUT_CR(port, cr);
++}
++
++static void ambauart_start_tx(struct uart_port *port, unsigned int tty_start)
++{
++	unsigned int cr;
++
++	cr = UART_GET_CR(port);
++	cr |= AMBA_UARTCR_TIE;
++	UART_PUT_CR(port, cr);
++}
++
++static void ambauart_stop_rx(struct uart_port *port)
++{
++	unsigned int cr;
++
++	cr = UART_GET_CR(port);
++	cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE);
++	UART_PUT_CR(port, cr);
++}
++
++static void ambauart_enable_ms(struct uart_port *port)
++{
++	unsigned int cr;
++
++	cr = UART_GET_CR(port);
++	cr |= AMBA_UARTCR_MSIE;
++	UART_PUT_CR(port, cr);
++}
++
++static void
++#ifdef SUPPORT_SYSRQ
++ambauart_rx_chars(struct uart_port *port, struct pt_regs *regs)
++#else
++ambauart_rx_chars(struct uart_port *port)
++#endif
++{
++	struct tty_struct *tty = port->info->tty;
++	unsigned int status, ch, rsr, max_count = 256;
++
++	status = UART_GET_FR(port);
++	while (UART_RX_DATA(status) && max_count--) {
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
++			tty->flip.tqueue.routine((void *)tty);
++			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
++				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
++				return;
++			}
++		}
++
++		ch = UART_GET_CHAR(port);
++
++		*tty->flip.char_buf_ptr = ch;
++		*tty->flip.flag_buf_ptr = TTY_NORMAL;
++		port->icount.rx++;
++
++		/*
++		 * Note that the error handling code is
++		 * out of the main execution path
++		 */
++		rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
++		if (rsr & AMBA_UARTRSR_ANY) {
++			if (rsr & AMBA_UARTRSR_BE) {
++				rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE);
++				port->icount.brk++;
++				if (uart_handle_break(port))
++					goto ignore_char;
++			} else if (rsr & AMBA_UARTRSR_PE)
++				port->icount.parity++;
++			else if (rsr & AMBA_UARTRSR_FE)
++				port->icount.frame++;
++			if (rsr & AMBA_UARTRSR_OE)
++				port->icount.overrun++;
++
++			rsr &= port->read_status_mask;
++
++			if (rsr & AMBA_UARTRSR_BE)
++				*tty->flip.flag_buf_ptr = TTY_BREAK;
++			else if (rsr & AMBA_UARTRSR_PE)
++				*tty->flip.flag_buf_ptr = TTY_PARITY;
++			else if (rsr & AMBA_UARTRSR_FE)
++				*tty->flip.flag_buf_ptr = TTY_FRAME;
++		}
++
++		if (uart_handle_sysrq_char(port, ch, regs))
++			goto ignore_char;
++
++		if ((rsr & port->ignore_status_mask) == 0) {
++			tty->flip.flag_buf_ptr++;
++			tty->flip.char_buf_ptr++;
++			tty->flip.count++;
++		}
++		if ((rsr & AMBA_UARTRSR_OE) &&
++		    tty->flip.count < TTY_FLIPBUF_SIZE) {
++			/*
++			 * Overrun is special, since it's reported
++			 * immediately, and doesn't affect the current
++			 * character
++			 */
++			*tty->flip.char_buf_ptr++ = 0;
++			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
++			tty->flip.count++;
++		}
++	ignore_char:
++		status = UART_GET_FR(port);
++	}
++	tty_flip_buffer_push(tty);
++	return;
++}
++
++static void ambauart_tx_chars(struct uart_port *port)
++{
++	struct circ_buf *xmit = &port->info->xmit;
++	int count;
++
++	if (port->x_char) {
++		UART_PUT_CHAR(port, port->x_char);
++		port->icount.tx++;
++		port->x_char = 0;
++		return;
++	}
++	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
++		ambauart_stop_tx(port, 0);
++		return;
++	}
++
++	count = port->fifosize >> 1;
++	do {
++		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
++		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++		port->icount.tx++;
++		if (uart_circ_empty(xmit))
++			break;
++	} while (--count > 0);
++
++	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++		uart_write_wakeup(port);
++
++	if (uart_circ_empty(xmit))
++		ambauart_stop_tx(port, 0);
++}
++
++static void ambauart_modem_status(struct uart_port *port)
++{
++	struct uart_amba_port *uap = (struct uart_amba_port *)port;
++	unsigned int status, delta;
++
++	UART_PUT_ICR(&uap->port, 0);
++
++	status = UART_GET_FR(&uap->port) & AMBA_UARTFR_MODEM_ANY;
++
++	delta = status ^ uap->old_status;
++	uap->old_status = status;
++
++	if (!delta)
++		return;
++
++	if (delta & AMBA_UARTFR_DCD)
++		uart_handle_dcd_change(&uap->port, status & AMBA_UARTFR_DCD);
++
++	if (delta & AMBA_UARTFR_DSR)
++		uap->port.icount.dsr++;
++
++	if (delta & AMBA_UARTFR_CTS)
++		uart_handle_cts_change(&uap->port, status & AMBA_UARTFR_CTS);
++
++	wake_up_interruptible(&uap->port.info->delta_msr_wait);
++}
++
++static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct uart_port *port = dev_id;
++	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
++
++	status = UART_GET_INT_STATUS(port);
++	do {
++		if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS))
++#ifdef SUPPORT_SYSRQ
++			ambauart_rx_chars(port, regs);
++#else
++			ambauart_rx_chars(port);
++#endif
++		if (status & AMBA_UARTIIR_TIS)
++			ambauart_tx_chars(port);
++		if (status & AMBA_UARTIIR_MIS)
++			ambauart_modem_status(port);
++
++		if (pass_counter-- == 0)
++			break;
++
++		status = UART_GET_INT_STATUS(port);
++	} while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS |
++			   AMBA_UARTIIR_TIS));
++}
++
++static unsigned int ambauart_tx_empty(struct uart_port *port)
++{
++	return UART_GET_FR(port) & AMBA_UARTFR_BUSY ? 0 : TIOCSER_TEMT;
++}
++
++static unsigned int ambauart_get_mctrl(struct uart_port *port)
++{
++	unsigned int result = 0;
++	unsigned int status;
++
++	status = UART_GET_FR(port);
++	if (status & AMBA_UARTFR_DCD)
++		result |= TIOCM_CAR;
++	if (status & AMBA_UARTFR_DSR)
++		result |= TIOCM_DSR;
++	if (status & AMBA_UARTFR_CTS)
++		result |= TIOCM_CTS;
++
++	return result;
++}
++
++static void ambauart_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++	struct uart_amba_port *uap = (struct uart_amba_port *)port;
++	unsigned int ctrls = 0, ctrlc = 0;
++
++	if (mctrl & TIOCM_RTS)
++		ctrlc |= uap->rts_mask;
++	else
++		ctrls |= uap->rts_mask;
++
++	if (mctrl & TIOCM_DTR)
++		ctrlc |= uap->dtr_mask;
++	else
++		ctrls |= uap->dtr_mask;
++
++	__raw_writel(ctrls, SC_CTRLS);
++	__raw_writel(ctrlc, SC_CTRLC);
++}
++
++static void ambauart_break_ctl(struct uart_port *port, int break_state)
++{
++	unsigned long flags;
++	unsigned int lcr_h;
++
++	spin_lock_irqsave(&port->lock, flags);
++	lcr_h = UART_GET_LCRH(port);
++	if (break_state == -1)
++		lcr_h |= AMBA_UARTLCR_H_BRK;
++	else
++		lcr_h &= ~AMBA_UARTLCR_H_BRK;
++	UART_PUT_LCRH(port, lcr_h);
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static int ambauart_startup(struct uart_port *port)
++{
++	struct uart_amba_port *uap = (struct uart_amba_port *)port;
++	int retval;
++
++	/*
++	 * Allocate the IRQ
++	 */
++	retval = request_irq(port->irq, ambauart_int, 0, "amba", port);
++	if (retval)
++		return retval;
++
++	/*
++	 * initialise the old status of the modem signals
++	 */
++	uap->old_status = UART_GET_FR(port) & AMBA_UARTFR_MODEM_ANY;
++
++	/*
++	 * Finally, enable interrupts
++	 */
++	UART_PUT_CR(port, AMBA_UARTCR_UARTEN | AMBA_UARTCR_RIE |
++			  AMBA_UARTCR_RTIE);
++
++	return 0;
++}
++
++static void ambauart_shutdown(struct uart_port *port)
++{
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(port->irq, port);
++
++	/*
++	 * disable all interrupts, disable the port
++	 */
++	UART_PUT_CR(port, 0);
++
++	/* disable break condition and fifos */
++	UART_PUT_LCRH(port, UART_GET_LCRH(port) &
++		~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN));
++}
++
++static void ambauart_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot)
++{
++	unsigned int lcr_h, old_cr;
++	unsigned long flags;
++
++#if DEBUG
++	printk("ambauart_set_cflag(0x%x) called\n", cflag);
++#endif
++	/* byte size and parity */
++	switch (cflag & CSIZE) {
++	case CS5:
++		lcr_h = AMBA_UARTLCR_H_WLEN_5;
++		break;
++	case CS6:
++		lcr_h = AMBA_UARTLCR_H_WLEN_6;
++		break;
++	case CS7:
++		lcr_h = AMBA_UARTLCR_H_WLEN_7;
++		break;
++	default: // CS8
++		lcr_h = AMBA_UARTLCR_H_WLEN_8;
++		break;
++	}
++	if (cflag & CSTOPB)
++		lcr_h |= AMBA_UARTLCR_H_STP2;
++	if (cflag & PARENB) {
++		lcr_h |= AMBA_UARTLCR_H_PEN;
++		if (!(cflag & PARODD))
++			lcr_h |= AMBA_UARTLCR_H_EPS;
++	}
++	if (port->fifosize > 1)
++		lcr_h |= AMBA_UARTLCR_H_FEN;
++
++	spin_lock_irqsave(&port->lock, flags);
++
++	port->read_status_mask = AMBA_UARTRSR_OE;
++	if (iflag & INPCK)
++		port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
++	if (iflag & (BRKINT | PARMRK))
++		port->read_status_mask |= AMBA_UARTRSR_BE;
++
++	/*
++	 * Characters to ignore
++	 */
++	port->ignore_status_mask = 0;
++	if (iflag & IGNPAR)
++		port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
++	if (iflag & IGNBRK) {
++		port->ignore_status_mask |= AMBA_UARTRSR_BE;
++		/*
++		 * If we're ignoring parity and break indicators,
++		 * ignore overruns too (for real raw support).
++		 */
++		if (iflag & IGNPAR)
++			port->ignore_status_mask |= AMBA_UARTRSR_OE;
++	}
++
++	/*
++	 * Ignore all characters if CREAD is not set.
++	 */
++	if ((cflag & CREAD) == 0)
++		port->ignore_status_mask |= UART_DUMMY_RSR_RX;
++
++	old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE;
++
++	if (UART_ENABLE_MS(port, cflag))
++		old_cr |= AMBA_UARTCR_MSIE;
++
++	UART_PUT_CR(port, 0);
++
++	/* Set baud rate */
++	quot -= 1;
++	UART_PUT_LCRM(port, ((quot & 0xf00) >> 8));
++	UART_PUT_LCRL(port, (quot & 0xff));
++
++	/*
++	 * ----------v----------v----------v----------v-----
++	 * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
++	 * ----------^----------^----------^----------^-----
++	 */
++	UART_PUT_LCRH(port, lcr_h);
++	UART_PUT_CR(port, old_cr);
++
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static const char *ambauart_type(struct uart_port *port)
++{
++	return port->type == PORT_AMBA ? "AMBA" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'
++ */
++static void ambauart_release_port(struct uart_port *port)
++{
++	release_mem_region(port->mapbase, UART_PORT_SIZE);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'
++ */
++static int ambauart_request_port(struct uart_port *port)
++{
++	return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_amba")
++			!= NULL ? 0 : -EBUSY;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void ambauart_config_port(struct uart_port *port, int flags)
++{
++	if (flags & UART_CONFIG_TYPE) {
++		port->type = PORT_AMBA;
++		ambauart_request_port(port);
++	}
++}
++
++/*
++ * verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int ambauart_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++	int ret = 0;
++	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
++		ret = -EINVAL;
++	if (ser->irq < 0 || ser->irq >= NR_IRQS)
++		ret = -EINVAL;
++	if (ser->baud_base < 9600)
++		ret = -EINVAL;
++	return ret;
++}
++
++static struct uart_ops amba_pops = {
++	.tx_empty	= ambauart_tx_empty,
++	.set_mctrl	= ambauart_set_mctrl,
++	.get_mctrl	= ambauart_get_mctrl,
++	.stop_tx	= ambauart_stop_tx,
++	.start_tx	= ambauart_start_tx,
++	.stop_rx	= ambauart_stop_rx,
++	.enable_ms	= ambauart_enable_ms,
++	.break_ctl	= ambauart_break_ctl,
++	.startup	= ambauart_startup,
++	.shutdown	= ambauart_shutdown,
++	.change_speed	= ambauart_change_speed,
++	.type		= ambauart_type,
++	.release_port	= ambauart_release_port,
++	.request_port	= ambauart_request_port,
++	.config_port	= ambauart_config_port,
++	.verify_port	= ambauart_verify_port,
++};
++
++static struct uart_amba_port amba_ports[UART_NR] = {
++	{
++		.port	= {
++			.membase	= (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
++			.mapbase	= INTEGRATOR_UART0_BASE,
++			.iotype		= SERIAL_IO_MEM,
++			.irq		= IRQ_UARTINT0,
++			.uartclk	= 14745600,
++			.fifosize	= 16,
++			.ops		= &amba_pops,
++			.flags		= ASYNC_BOOT_AUTOCONF,
++			.line		= 0,
++		},
++		.dtr_mask	= 1 << 5,
++		.rts_mask	= 1 << 4,
++	},
++	{
++		.port	= {
++			.membase	= (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
++			.mapbase	= INTEGRATOR_UART1_BASE,
++			.iotype		= SERIAL_IO_MEM,
++			.irq		= IRQ_UARTINT1,
++			.uartclk	= 14745600,
++			.fifosize	= 16,
++			.ops		= &amba_pops,
++			.flags		= ASYNC_BOOT_AUTOCONF,
++			.line		= 1,
++		},
++		.dtr_mask	= 1 << 7,
++		.rts_mask	= 1 << 6,
++	}
++};
++
++#ifdef CONFIG_SERIAL_AMBA_CONSOLE
++
++static void ambauart_console_write(struct console *co, const char *s, unsigned int count)
++{
++	struct uart_port *port = &amba_ports[co->index].port;
++	unsigned int status, old_cr;
++	int i;
++
++	/*
++	 *	First save the CR then disable the interrupts
++	 */
++	old_cr = UART_GET_CR(port);
++	UART_PUT_CR(port, AMBA_UARTCR_UARTEN);
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++) {
++		do {
++			status = UART_GET_FR(port);
++		} while (!UART_TX_READY(status));
++		UART_PUT_CHAR(port, s[i]);
++		if (s[i] == '\n') {
++			do {
++				status = UART_GET_FR(port);
++			} while (!UART_TX_READY(status));
++			UART_PUT_CHAR(port, '\r');
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore the TCR
++	 */
++	do {
++		status = UART_GET_FR(port);
++	} while (status & AMBA_UARTFR_BUSY);
++	UART_PUT_CR(port, old_cr);
++}
++
++static kdev_t ambauart_console_device(struct console *co)
++{
++	return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + co->index);
++}
++
++static void __init
++ambauart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++	if (UART_GET_CR(port) & AMBA_UARTCR_UARTEN) {
++		unsigned int lcr_h, quot;
++		lcr_h = UART_GET_LCRH(port);
++
++		*parity = 'n';
++		if (lcr_h & AMBA_UARTLCR_H_PEN) {
++			if (lcr_h & AMBA_UARTLCR_H_EPS)
++				*parity = 'e';
++			else
++				*parity = 'o';
++		}
++
++		if ((lcr_h & 0x60) == AMBA_UARTLCR_H_WLEN_7)
++			*bits = 7;
++		else
++			*bits = 8;
++
++		quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8;
++		*baud = port->uartclk / (16 * (quot + 1));
++	}
++}
++
++static int __init ambauart_console_setup(struct console *co, char *options)
++{
++	struct uart_port *port;
++	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 >= UART_NR)
++		co->index = 0;
++	port = &amba_ports[co->index].port;
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++	else
++		ambauart_console_get_options(port, &baud, &parity, &bits);
++
++	return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct console amba_console = {
++	.name		= "ttyAM",
++	.write		= ambauart_console_write,
++	.device		= ambauart_console_device,
++	.setup		= ambauart_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++void __init ambauart_console_init(void)
++{
++	register_console(&amba_console);
++}
++
++#define AMBA_CONSOLE	&amba_console
++#else
++#define AMBA_CONSOLE	NULL
++#endif
++
++static struct uart_driver amba_reg = {
++	.owner			= THIS_MODULE,
++	.normal_major		= SERIAL_AMBA_MAJOR,
++#ifdef CONFIG_DEVFS_FS
++	.normal_name		= "ttyAM%d",
++	.callout_name		= "cuaam%d",
++#else
++	.normal_name		= "ttyAM",
++	.callout_name		= "cuaam",
++#endif
++	.normal_driver		= &normal,
++	.callout_major		= CALLOUT_AMBA_MAJOR,
++	.callout_driver		= &callout,
++	.table			= amba_table,
++	.termios		= amba_termios,
++	.termios_locked		= amba_termios_locked,
++	.minor			= SERIAL_AMBA_MINOR,
++	.nr			= UART_NR,
++	.cons			= AMBA_CONSOLE,
++};
++
++static int __init ambauart_init(void)
++{
++	int ret;
++
++	ret = uart_register_driver(&amba_reg);
++	if (ret == 0) {
++		int i;
++
++		for (i = 0; i < UART_NR; i++)
++			uart_add_one_port(&amba_reg, &amba_ports[i].port);
++	}
++	return ret;
++}
++
++static void __exit ambauart_exit(void)
++{
++	int i;
++
++	for (i = 0; i < UART_NR; i++)
++		uart_remove_one_port(&amba_reg, &amba_ports[i].port);
++
++	uart_unregister_driver(&amba_reg);
++}
++
++module_init(ambauart_init);
++module_exit(ambauart_exit);
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd");
++MODULE_DESCRIPTION("ARM AMBA serial port driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/anakin.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,545 @@
++/*
++ *  linux/drivers/char/serial_anakin.c
++ *
++ *  Based on driver for AMBA serial ports, by ARM Limited,
++ *  Deep Blue Solutions Ltd., Linus Torvalds and Theodore Ts'o.
++ *
++ *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
++ *
++ *  Copyright (C) 2001 Blue Mug, Inc. for Acunia N.V.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Changelog:
++ *   20-Apr-2001 TTC	Created
++ *   05-May-2001 W/TTC	Updated for serial_core.c
++ *   27-Jun-2001 jonm	Minor changes; add mctrl support, switch to 
++ *   			SA_INTERRUPT. Works reliably now. No longer requires
++ *   			changes to the serial_core API.
++ *
++ *  $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/circ_buf.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++
++#include <linux/serial_core.h>
++
++#include <asm/arch/serial_reg.h>
++
++#define UART_NR			5
++
++#define SERIAL_ANAKIN_NAME	"ttyAN"
++#define SERIAL_ANAKIN_MAJOR	204
++#define SERIAL_ANAKIN_MINOR	32
++
++#define CALLOUT_ANAKIN_NAME	"cuaan"
++#define CALLOUT_ANAKIN_MAJOR	205
++#define CALLOUT_ANAKIN_MINOR	32
++
++static struct tty_driver normal, callout;
++static struct tty_struct *anakin_table[UART_NR];
++static struct termios *anakin_termios[UART_NR], *anakin_termios_locked[UART_NR];
++static struct uart_state anakin_state[UART_NR];
++static u_int txenable[NR_IRQS];		/* Software interrupt register */
++
++static inline unsigned int
++anakin_in(struct uart_port *port, u_int offset)
++{
++	return __raw_readl(port->base + offset);
++}
++
++static inline void
++anakin_out(struct uart_port *port, u_int offset, unsigned int value)
++{
++	__raw_writel(value, port->base + offset);
++}
++
++static void
++anakin_stop_tx(struct uart_port *port, u_int from_tty)
++{
++	txenable[port->irq] = 0;
++}
++
++static inline void
++anakin_transmit_buffer(struct uart_info *info)
++{
++	struct uart_port *port = info->port;
++
++	while (!(anakin_in(port, 0x10) & TXEMPTY));
++	anakin_out(port, 0x14, info->xmit.buf[info->xmit.tail]);
++	anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
++	info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE-1);
++        info->state->icount.tx++;
++
++	if (info->xmit.head == info->xmit.tail)
++		anakin_stop_tx(port, 0); 
++}
++
++static inline void
++anakin_transmit_x_char(struct uart_info *info)
++{
++	struct uart_port *port = info->port;
++
++	anakin_out(port, 0x14, info->x_char);
++	anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
++	info->state->icount.tx++;
++	info->x_char = 0;
++}
++
++static void
++anakin_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
++{
++	unsigned int flags;
++
++	save_flags_cli(flags);
++
++	// is it this... or below: if (nonempty
++	if (!txenable[port->irq]) {
++		txenable[port->irq] = TXENABLE;
++
++		if ((anakin_in(port, 0x10) & TXEMPTY) && nonempty) {
++		    anakin_transmit_buffer((struct uart_info*)port->unused);
++		}
++	}
++
++	restore_flags(flags);
++}
++
++static void
++anakin_stop_rx(struct uart_port *port)
++{
++	unsigned long flags;
++
++	save_flags_cli(flags);
++	while (anakin_in(port, 0x10) & RXRELEASE) 
++	    anakin_in(port, 0x14);
++	anakin_out(port, 0x18, anakin_in(port, 0x18) | BLOCKRX);
++	restore_flags(flags);
++}
++
++static void
++anakin_enable_ms(struct uart_port *port)
++{
++}
++
++static inline void
++anakin_rx_chars(struct uart_info *info)
++{
++	unsigned int ch;
++	struct tty_struct *tty = info->tty;
++
++	if (!(anakin_in(info->port, 0x10) & RXRELEASE))
++		return;
++
++	ch = anakin_in(info->port, 0x14) & 0xff;
++
++	if (tty->flip.count < TTY_FLIPBUF_SIZE) {
++		*tty->flip.char_buf_ptr++ = ch;
++		*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
++		info->state->icount.rx++;
++		tty->flip.count++;
++	} 
++	tty_flip_buffer_push(tty);
++}
++
++static inline void
++anakin_overrun_chars(struct uart_info *info)
++{
++	unsigned int ch;
++
++	ch = anakin_in(info->port, 0x14);
++	info->state->icount.overrun++;
++}
++
++static inline void
++anakin_tx_chars(struct uart_info *info)
++{
++	if (info->x_char) {
++		anakin_transmit_x_char(info);
++		return; 
++	}
++
++	if (info->xmit.head == info->xmit.tail
++	    || info->tty->stopped
++	    || info->tty->hw_stopped) {
++		anakin_stop_tx(info->port, 0);
++		return;
++	}
++
++	anakin_transmit_buffer(info);
++
++	if (CIRC_CNT(info->xmit.head,
++		     info->xmit.tail,
++		     UART_XMIT_SIZE) < WAKEUP_CHARS)
++		uart_event(info, EVT_WRITE_WAKEUP);
++}
++
++static void
++anakin_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned int status;
++	struct uart_info *info = dev_id;
++
++	status = anakin_in(info->port, 0x1c);
++
++	if (status & RX) 
++		anakin_rx_chars(info);
++
++	if (status & OVERRUN) 
++		anakin_overrun_chars(info);
++
++	if (txenable[info->port->irq] && (status & TX)) 
++		anakin_tx_chars(info);
++}
++
++static u_int
++anakin_tx_empty(struct uart_port *port)
++{
++	return anakin_in(port, 0x10) & TXEMPTY ? TIOCSER_TEMT : 0;
++}
++
++static u_int
++anakin_get_mctrl(struct uart_port *port)
++{
++	unsigned int status = 0;
++
++	status |= (anakin_in(port, 0x10) & CTS ? TIOCM_CTS : 0);
++	status |= (anakin_in(port, 0x18) & DCD ? TIOCM_CAR : 0);
++	status |= (anakin_in(port, 0x18) & DTR ? TIOCM_DTR : 0);
++	status |= (anakin_in(port, 0x18) & RTS ? TIOCM_RTS : 0);
++	
++	return status;
++}
++
++static void
++anakin_set_mctrl(struct uart_port *port, u_int mctrl)
++{
++	unsigned int status;
++
++	status = anakin_in(port, 0x18);
++
++	if (mctrl & TIOCM_RTS) 
++		status |= RTS;
++	else 
++		status &= ~RTS;
++
++	if (mctrl & TIOCM_CAR)
++		status |= DCD;
++	else 
++		status &= ~DCD;
++
++	anakin_out(port, 0x18, status);
++}
++
++static void
++anakin_break_ctl(struct uart_port *port, int break_state)
++{
++	unsigned int status;
++
++	status = anakin_in(port, 0x20);
++
++	if (break_state == -1)
++		status |= SETBREAK;
++	else
++		status &= ~SETBREAK;
++
++	anakin_out(port, 0x20, status);
++}
++
++static int
++anakin_startup(struct uart_port *port, struct uart_info *info)
++{
++	int retval;
++	unsigned int read,write;
++
++	/*
++	 * Allocate the IRQ
++	 */
++	retval = request_irq(port->irq, anakin_int, SA_INTERRUPT, "serial_anakin", info);
++	if (retval)
++		return retval;
++
++	port->ops->set_mctrl(port, info->mctrl);
++
++	/*
++	 * initialise the old status of the modem signals
++	 */
++	port->old_status = 0;
++
++	/*
++	 * Finally, disable IRQ and softIRQs for first byte)
++	 */
++	txenable[port->irq] = 0;
++	read = anakin_in(port, 0x18);
++	write = (read & ~(RTS | DTR | BLOCKRX)) | IRQENABLE;
++	anakin_out(port, 0x18, write);
++
++	/* Store the uart_info pointer so we can reference it in 
++	 * anakin_start_tx() */
++	port->unused = (u_int)info;
++	
++	return 0;
++}
++
++static void
++anakin_shutdown(struct uart_port *port, struct uart_info *info)
++{
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(port->irq, info);
++
++	/*
++	 * disable all interrupts, disable the port
++	 */
++	anakin_out(port, 0x18, anakin_in(port, 0x18) & ~IRQENABLE);
++}
++
++static void
++anakin_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
++{
++	unsigned int flags;
++
++	save_flags_cli(flags);
++	while (!(anakin_in(port, 0x10) & TXEMPTY));
++	anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER)
++			| (quot << 3));
++
++	//parity always set to none
++	anakin_out(port, 0x18, anakin_in(port, 0x18) & ~PARITY);
++	restore_flags(flags);
++}
++
++static const char *anakin_type(struct port *port)
++{
++	return port->type == PORT_ANAKIN ? "ANAKIN" : NULL;
++}
++
++static struct uart_ops anakin_pops = {
++	tx_empty:	anakin_tx_empty,
++	set_mctrl:	anakin_set_mctrl,
++	get_mctrl:	anakin_get_mctrl,
++	stop_tx:	anakin_stop_tx,
++	start_tx:	anakin_start_tx,
++	stop_rx:	anakin_stop_rx,
++	enable_ms:	anakin_enable_ms,
++	break_ctl:	anakin_break_ctl,
++	startup:	anakin_startup,
++	shutdown:	anakin_shutdown,
++	change_speed:	anakin_change_speed,
++	type:		anakin_type,
++};
++
++static struct uart_port anakin_ports[UART_NR] = {
++	{
++		base:		IO_BASE + UART0,
++		irq:		IRQ_UART0,
++		uartclk:	3686400,
++		fifosize:	0,
++		ops:		&anakin_pops,
++	},
++	{
++		base:		IO_BASE + UART1,
++		irq:		IRQ_UART1,
++		uartclk:	3686400,
++		fifosize:	0,
++		ops:		&anakin_pops,
++	},
++	{
++		base:		IO_BASE + UART2,
++		irq:		IRQ_UART2,
++		uartclk:	3686400,
++		fifosize:	0,
++		ops:		&anakin_pops,
++	},
++	{
++		base:		IO_BASE + UART3,
++		irq:		IRQ_UART3,
++		uartclk:	3686400,
++		fifosize:	0,
++		ops:		&anakin_pops,
++	},
++	{
++		base:		IO_BASE + UART4,
++		irq:		IRQ_UART4,
++		uartclk:	3686400,
++		fifosize:	0,
++		ops:		&anakin_pops,
++	},
++};
++
++
++#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE
++
++static void
++anakin_console_write(struct console *co, const char *s, u_int count)
++{
++	struct uart_port *port = anakin_ports + co->index;
++	unsigned int flags, status, i;
++
++	/*
++	 *	First save the status then disable the interrupts
++	 */
++	save_flags_cli(flags);
++	status = anakin_in(port, 0x18);
++	anakin_out(port, 0x18, status & ~IRQENABLE);
++	restore_flags(flags);
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++, s++) {
++		while (!(anakin_in(port, 0x10) & TXEMPTY));
++
++		/*
++		 *	Send the character out.
++		 *	If a LF, also do CR...
++		 */
++		anakin_out(port, 0x14, *s);
++		anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
++
++		if (*s == 10) {
++			while (!(anakin_in(port, 0x10) & TXEMPTY));
++			anakin_out(port, 0x14, 13);
++			anakin_out(port, 0x18, anakin_in(port, 0x18)
++					| SENDREQUEST);
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore the interrupts
++	 */
++	while (!(anakin_in(port, 0x10) & TXEMPTY));
++
++	if (status & IRQENABLE)
++		save_flags_cli(flags);
++ 		anakin_out(port, 0x18, anakin_in(port, 0x18) | IRQENABLE);
++		restore_flags(flags);
++}
++
++static kdev_t
++anakin_console_device(struct console *co)
++{
++	return MKDEV(SERIAL_ANAKIN_MAJOR, SERIAL_ANAKIN_MINOR + co->index);
++}
++
++/*
++ * Read the current UART setup.
++ */
++static void __init
++anakin_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++	int paritycode;
++
++	*baud = GETBAUD (anakin_in(port, 0x10) & PRESCALER);
++	paritycode = GETPARITY(anakin_in(port, 0x18) & PARITY);
++	switch (paritycode) {
++	  case NONEPARITY: *parity = 'n'; break;
++	  case ODDPARITY: *parity = 'o'; break;
++	  case EVENPARITY: *parity = 'e'; break;
++	}
++	*bits = 8;
++}
++
++static int __init
++anakin_console_setup(struct console *co, char *options)
++{
++	struct uart_port *port;
++	int baud = CONFIG_ANAKIN_DEFAULT_BAUDRATE;
++	int bits = 8;
++	int parity = 'n';
++
++	/*
++	 * Check whether an invalid uart number has been specified, and
++	 * if so, search for the first available port that does have
++	 * console support.
++	 */
++	port = uart_get_console(anakin_ports, UART_NR, co);
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits);
++	else
++		anakin_console_get_options(port, &baud, &parity, &bits);
++
++	return uart_set_options(port, co, baud, parity, bits);
++}
++
++static struct console anakin_console = {
++	name:		SERIAL_ANAKIN_NAME,
++	write:		anakin_console_write,
++	device:		anakin_console_device,
++	setup:		anakin_console_setup,
++	flags:		CON_PRINTBUFFER,
++	index:		-1,
++};
++
++void __init
++anakin_console_init(void)
++{
++	register_console(&anakin_console);
++}
++
++#define ANAKIN_CONSOLE		&anakin_console
++#else
++#define ANAKIN_CONSOLE		NULL
++#endif
++
++static struct uart_register anakin_reg = {
++	normal_major:		SERIAL_ANAKIN_MAJOR,
++	normal_name:		SERIAL_ANAKIN_NAME,
++	normal_driver:		&normal,
++	callout_major:		CALLOUT_ANAKIN_MAJOR,
++	callout_name:		CALLOUT_ANAKIN_NAME,
++	callout_driver:		&callout,
++	table:			anakin_table,
++	termios:		anakin_termios,
++	termios_locked:		anakin_termios_locked,
++	minor:			SERIAL_ANAKIN_MINOR,
++	nr:			UART_NR,
++	state:			anakin_state,
++	port:			anakin_ports,
++	cons:			ANAKIN_CONSOLE,
++};
++
++static int __init
++anakin_init(void)
++{
++	return uart_register_port(&anakin_reg);
++}
++
++__initcall(anakin_init);
++
++MODULE_DESCRIPTION("Anakin serial driver");
++MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");
++MODULE_SUPPORTED_DEVICE("ttyAN");
++MODULE_LICENSE("GPL");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/clps711x.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,635 @@
++/*
++ *  linux/drivers/char/serial_clps711x.c
++ *
++ *  Driver for CLPS711x serial ports
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright 1999 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id$
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/circ_buf.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++
++#include <asm/bitops.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <linux/serial_core.h>
++
++#include <asm/hardware/clps7111.h>
++
++#define UART_NR		2
++
++#define SERIAL_CLPS711X_NAME	"ttyAM"
++#define SERIAL_CLPS711X_MAJOR	204
++#define SERIAL_CLPS711X_MINOR	16
++#define SERIAL_CLPS711X_NR	UART_NR
++
++#define CALLOUT_CLPS711X_NAME	"cuaam"
++#define CALLOUT_CLPS711X_MAJOR	205
++#define CALLOUT_CLPS711X_MINOR	16
++#define CALLOUT_CLPS711X_NR	UART_NR
++
++static struct tty_driver normal, callout;
++static struct tty_struct *clps711x_table[UART_NR];
++static struct termios *clps711x_termios[UART_NR], *clps711x_termios_locked[UART_NR];
++
++/*
++ * We use the relevant SYSCON register as a base address for these ports.
++ */
++#define UBRLCR(port)		((port)->iobase + UBRLCR1 - SYSCON1)
++#define UARTDR(port)		((port)->iobase + UARTDR1 - SYSCON1)
++#define SYSFLG(port)		((port)->iobase + SYSFLG1 - SYSCON1)
++#define SYSCON(port)		((port)->iobase + SYSCON1 - SYSCON1)
++
++#define TX_IRQ(port)		((port)->irq)
++#define RX_IRQ(port)		((port)->irq + 1)
++
++#define UART_ANY_ERR		(UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
++
++#define tx_enabled(port)	((port)->unused[0])
++
++static void
++clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop)
++{
++	if (tx_enabled(port)) {
++		disable_irq(TX_IRQ(port));
++		tx_enabled(port) = 0;
++	}
++}
++
++static void
++clps711xuart_start_tx(struct uart_port *port, unsigned int tty_start)
++{
++	if (!tx_enabled(port)) {
++		enable_irq(TX_IRQ(port));
++		tx_enabled(port) = 1;
++	}
++}
++
++static void clps711xuart_stop_rx(struct uart_port *port)
++{
++	disable_irq(RX_IRQ(port));
++}
++
++static void clps711xuart_enable_ms(struct uart_port *port)
++{
++}
++
++static void clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct uart_port *port = dev_id;
++	struct tty_struct *tty = port->info->tty;
++	unsigned int status, ch, flg, ignored = 0;
++
++	status = clps_readl(SYSFLG(port));
++	while (!(status & SYSFLG_URXFE)) {
++		ch = clps_readl(UARTDR(port));
++
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++		port->icount.rx++;
++
++		flg = TTY_NORMAL;
++
++		/*
++		 * Note that the error handling code is
++		 * out of the main execution path
++		 */
++		if (ch & UART_ANY_ERR)
++			goto handle_error;
++
++		if (uart_handle_sysrq_char(port, ch, regs))
++			goto ignore_char;
++
++	error_return:
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++	ignore_char:
++		status = clps_readl(SYSFLG(port));
++	}
++ out:
++	tty_flip_buffer_push(tty);
++	return;
++
++ handle_error:
++	if (ch & UARTDR_PARERR)
++		port->icount.parity++;
++	else if (ch & UARTDR_FRMERR)
++		port->icount.frame++;
++	if (ch & UARTDR_OVERR)
++		port->icount.overrun++;
++
++	if (ch & port->ignore_status_mask) {
++		if (++ignored > 100)
++			goto out;
++		goto ignore_char;
++	}
++	ch &= port->read_status_mask;
++
++	if (ch & UARTDR_PARERR)
++		flg = TTY_PARITY;
++	else if (ch & UARTDR_FRMERR)
++		flg = TTY_FRAME;
++
++	if (ch & UARTDR_OVERR) {
++		/*
++		 * CHECK: does overrun affect the current character?
++		 * ASSUMPTION: it does not.
++		 */
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++		ch = 0;
++		flg = TTY_OVERRUN;
++	}
++#ifdef SUPPORT_SYSRQ
++	port->sysrq = 0;
++#endif
++	goto error_return;
++}
++
++static void clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct uart_port *port = dev_id;
++	struct circ_buf *xmit = &port->info->xmit;
++	int count;
++
++	if (port->x_char) {
++		clps_writel(port->x_char, UARTDR(port));
++		port->icount.tx++;
++		port->x_char = 0;
++		return;
++	}
++	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
++		clps711xuart_stop_tx(port, 0);
++		return;
++	}
++
++	count = port->fifosize >> 1;
++	do {
++		clps_writel(xmit->buf[xmit->tail], UARTDR(port));
++		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++		port->icount.tx++;
++		if (uart_circ_empty(xmit))
++			break;
++	} while (--count > 0);
++
++	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
++		uart_write_wakeup(port);
++
++	if (uart_circ_empty(xmit))
++		clps711xuart_stop_tx(port, 0);
++}
++
++static unsigned int clps711xuart_tx_empty(struct uart_port *port)
++{
++	unsigned int status = clps_readl(SYSFLG(port));
++	return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
++}
++
++static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
++{
++	unsigned int port_addr;
++	unsigned int result = 0;
++	unsigned int status;
++
++	port_addr = SYSFLG(port);
++	if (port_addr == SYSFLG1) {
++		status = clps_readl(SYSFLG1);
++		if (status & SYSFLG1_DCD)
++			result |= TIOCM_CAR;
++		if (status & SYSFLG1_DSR)
++			result |= TIOCM_DSR;
++		if (status & SYSFLG1_CTS)
++			result |= TIOCM_CTS;
++	}
++
++	return result;
++}
++
++static void
++clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
++{
++}
++
++static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
++{
++	unsigned long flags;
++	unsigned int ubrlcr;
++
++	spin_lock_irqsave(&port->lock, flags);
++	ubrlcr = clps_readl(UBRLCR(port));
++	if (break_state == -1)
++		ubrlcr |= UBRLCR_BREAK;
++	else
++		ubrlcr &= ~UBRLCR_BREAK;
++	clps_writel(ubrlcr, UBRLCR(port));
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static int clps711xuart_startup(struct uart_port *port)
++{
++	unsigned int syscon;
++	int retval;
++
++	tx_enabled(port) = 1;
++
++	/*
++	 * Allocate the IRQs
++	 */
++	retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
++			     "clps711xuart_tx", port);
++	if (retval)
++		return retval;
++
++	retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
++			     "clps711xuart_rx", port);
++	if (retval) {
++		free_irq(TX_IRQ(port), port);
++		return retval;
++	}
++
++	/*
++	 * enable the port
++	 */
++	syscon = clps_readl(SYSCON(port));
++	syscon |= SYSCON_UARTEN;
++	clps_writel(syscon, SYSCON(port));
++
++	return 0;
++}
++
++static void clps711xuart_shutdown(struct uart_port *port)
++{
++	unsigned int ubrlcr, syscon;
++
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(TX_IRQ(port), port);	/* TX interrupt */
++	free_irq(RX_IRQ(port), port);	/* RX interrupt */
++
++	/*
++	 * disable the port
++	 */
++	syscon = clps_readl(SYSCON(port));
++	syscon &= ~SYSCON_UARTEN;
++	clps_writel(syscon, SYSCON(port));
++
++	/*
++	 * disable break condition and fifos
++	 */
++	ubrlcr = clps_readl(UBRLCR(port));
++	ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
++	clps_writel(ubrlcr, UBRLCR(port));
++}
++
++static void clps711xuart_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot)
++{
++	unsigned int ubrlcr;
++	unsigned long flags;
++
++#if DEBUG
++	printk("clps711xuart_change_speed(cflag=0x%x, iflag=0x%x, quot=%d) called\n",
++		cflag, iflag, quot);
++#endif
++	/* byte size and parity */
++	switch (cflag & CSIZE) {
++	case CS5:
++		ubrlcr = UBRLCR_WRDLEN5;
++		break;
++	case CS6:
++		ubrlcr = UBRLCR_WRDLEN6;
++		break;
++	case CS7:
++		ubrlcr = UBRLCR_WRDLEN7;
++		break;
++	default: // CS8
++		ubrlcr = UBRLCR_WRDLEN8;
++		break;
++	}
++	if (cflag & CSTOPB)
++		ubrlcr |= UBRLCR_XSTOP;
++	if (cflag & PARENB) {
++		ubrlcr |= UBRLCR_PRTEN;
++		if (!(cflag & PARODD))
++			ubrlcr |= UBRLCR_EVENPRT;
++	}
++	if (port->fifosize > 1)
++		ubrlcr |= UBRLCR_FIFOEN;
++
++	spin_lock_irqsave(&port->lock, flags);
++
++	port->read_status_mask = UARTDR_OVERR;
++	if (iflag & INPCK)
++		port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
++
++	/*
++	 * Characters to ignore
++	 */
++	port->ignore_status_mask = 0;
++	if (iflag & IGNPAR)
++		port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
++	if (iflag & IGNBRK) {
++		/*
++		 * If we're ignoring parity and break indicators,
++		 * ignore overruns to (for real raw support).
++		 */
++		if (iflag & IGNPAR)
++			port->ignore_status_mask |= UARTDR_OVERR;
++	}
++
++	quot -= 1;
++
++	clps_writel(ubrlcr | quot, UBRLCR(port));
++
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static const char *clps711xuart_type(struct uart_port *port)
++{
++	return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void clps711xuart_config_port(struct uart_port *port, int flags)
++{
++	if (flags & UART_CONFIG_TYPE)
++		port->type = PORT_CLPS711X;
++}
++
++static void clps711xuart_release_port(struct uart_port *port)
++{
++}
++
++static int clps711xuart_request_port(struct uart_port *port)
++{
++	return 0;
++}
++
++static struct uart_ops clps711x_pops = {
++	.tx_empty	= clps711xuart_tx_empty,
++	.set_mctrl	= clps711xuart_set_mctrl_null,
++	.get_mctrl	= clps711xuart_get_mctrl,
++	.stop_tx	= clps711xuart_stop_tx,
++	.start_tx	= clps711xuart_start_tx,
++	.stop_rx	= clps711xuart_stop_rx,
++	.enable_ms	= clps711xuart_enable_ms,
++	.break_ctl	= clps711xuart_break_ctl,
++	.startup	= clps711xuart_startup,
++	.shutdown	= clps711xuart_shutdown,
++	.change_speed	= clps711xuart_change_speed,
++	.type		= clps711xuart_type,
++	.config_port	= clps711xuart_config_port,
++	.release_port	= clps711xuart_release_port,
++	.request_port	= clps711xuart_request_port,
++};
++
++static struct uart_port clps711x_ports[UART_NR] = {
++	{
++		.iobase		= SYSCON1,
++		.irq		= IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
++		.uartclk	= 3686400,
++		.fifosize	= 16,
++		.ops		= &clps711x_pops,
++		.line		= 0,
++		.flags		= ASYNC_BOOT_AUTOCONF,
++	},
++	{
++		.iobase		= SYSCON2,
++		.irq		= IRQ_UTXINT2, /* IRQ_URXINT2 */
++		.uartclk	= 3686400,
++		.fifosize	= 16,
++		.ops		= &clps711x_pops,
++		.line		= 1,
++		.flags		= ASYNC_BOOT_AUTOCONF,
++	}
++};
++
++#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
++/*
++ *	Print a string to the serial port trying not to disturb
++ *	any possible real use of the port...
++ *
++ *	The console_lock must be held when we get here.
++ *
++ *	Note that this is called with interrupts already disabled
++ */
++static void
++clps711xuart_console_write(struct console *co, const char *s,
++			   unsigned int count)
++{
++	struct uart_port *port = clps711x_ports + co->index;
++	unsigned int status, syscon;
++	int i;
++
++	/*
++	 *	Ensure that the port is enabled.
++	 */
++	syscon = clps_readl(SYSCON(port));
++	clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++) {
++		do {
++			status = clps_readl(SYSFLG(port));
++		} while (status & SYSFLG_UTXFF);
++		clps_writel(s[i], UARTDR(port));
++		if (s[i] == '\n') {
++			do {
++				status = clps_readl(SYSFLG(port));
++			} while (status & SYSFLG_UTXFF);
++			clps_writel('\r', UARTDR(port));
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore the uart state.
++	 */
++	do {
++		status = clps_readl(SYSFLG(port));
++	} while (status & SYSFLG_UBUSY);
++
++	clps_writel(syscon, SYSCON(port));
++}
++
++static kdev_t clps711xuart_console_device(struct console *co)
++{
++	return MKDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR + co->index);
++}
++
++static void __init
++clps711xuart_console_get_options(struct uart_port *port, int *baud,
++				 int *parity, int *bits)
++{
++	if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
++		unsigned int ubrlcr, quot;
++
++		ubrlcr = clps_readl(UBRLCR(port));
++
++		*parity = 'n';
++		if (ubrlcr & UBRLCR_PRTEN) {
++			if (ubrlcr & UBRLCR_EVENPRT)
++				*parity = 'e';
++			else
++				*parity = 'o';
++		}
++
++		if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7)
++			*bits = 7;
++		else
++			*bits = 8;
++
++		quot = ubrlcr & UBRLCR_BAUD_MASK;
++		*baud = port->uartclk / (16 * (quot + 1));
++	}
++}
++
++static int __init clps711xuart_console_setup(struct console *co, char *options)
++{
++	struct uart_port *port;
++	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.
++	 */
++	port = uart_get_console(clps711x_ports, UART_NR, co);
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++	else
++		clps711xuart_console_get_options(port, &baud, &parity, &bits);
++
++	return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct console clps711x_console = {
++	.name		= SERIAL_CLPS711X_NAME,
++	.write		= clps711xuart_console_write,
++	.device		= clps711xuart_console_device,
++	.setup		= clps711xuart_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++void __init clps711xuart_console_init(void)
++{
++	register_console(&clps711x_console);
++}
++
++#define CLPS711X_CONSOLE	&clps711x_console
++#else
++#define CLPS711X_CONSOLE	NULL
++#endif
++
++static struct uart_driver clps711x_reg = {
++#ifdef CONFIG_DEVFS_FS
++	.normal_name		= SERIAL_CLPS711X_NAME,
++	.callout_name		= CALLOUT_CLPS711X_NAME,
++#else
++	.normal_name		= SERIAL_CLPS711X_NAME,
++	.callout_name		= CALLOUT_CLPS711X_NAME,
++#endif
++
++	.normal_major		= SERIAL_CLPS711X_MAJOR,
++	.normal_driver		= &normal,
++	.callout_major		= CALLOUT_CLPS711X_MAJOR,
++	.callout_driver		= &callout,
++
++	.table			= clps711x_table,
++	.termios		= clps711x_termios,
++	.termios_locked		= clps711x_termios_locked,
++
++	.minor			= SERIAL_CLPS711X_MINOR,
++	.nr			= UART_NR,
++
++	.cons			= CLPS711X_CONSOLE,
++};
++
++static int __init clps711xuart_init(void)
++{
++	int ret, i;
++
++	printk(KERN_INFO "Serial: CLPS711x driver\n");
++
++	ret = uart_register_driver(&clps711x_reg);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < UART_NR; i++)
++		uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
++
++	return 0;
++}
++
++static void __exit clps711xuart_exit(void)
++{
++	int i;
++
++	for (i = 0; i < UART_NR; i++)
++		uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
++
++	uart_unregister_driver(&clps711x_reg);
++}
++
++module_init(clps711xuart_init);
++module_exit(clps711xuart_exit);
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_AUTHOR("Deep Blue Solutions Ltd");
++MODULE_DESCRIPTION("CLPS-711x generic serial driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/core.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,2584 @@
++/*
++ *  linux/drivers/serial/core.c
++ *
++ *  Driver core for serial ports
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright 1999 ARM Limited
++ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id$
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/tty.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/pm.h>
++#include <linux/serial_core.h>
++#include <linux/smp_lock.h>
++
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++
++#undef	DEBUG
++#ifdef DEBUG
++#define DPRINTK(x...)	printk(x)
++#else
++#define DPRINTK(x...)	do { } while (0)
++#endif
++
++#ifndef CONFIG_PM
++#define pm_access(pm)		do { } while (0)
++#define pm_unregister(pm)	do { } while (0)
++#endif
++
++/*
++ * This is used to lock changes in serial line configuration.
++ */
++static DECLARE_MUTEX(port_sem);
++
++#define HIGH_BITS_OFFSET	((sizeof(long)-sizeof(int))*8)
++
++#define uart_users(state)	((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
++
++#ifdef CONFIG_SERIAL_CORE_CONSOLE
++#define uart_console(port)	((port)->cons && (port)->cons->index == (port)->line)
++#else
++#define uart_console(port)	(0)
++#endif
++
++static void uart_change_speed(struct uart_state *state, struct termios *old_termios);
++static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
++static void uart_change_pm(struct uart_state *state, int pm_state);
++
++/*
++ * This routine is used by the interrupt handler to schedule processing in
++ * the software interrupt portion of the driver.
++ */
++void uart_write_wakeup(struct uart_port *port)
++{
++	struct uart_info *info = port->info;
++	tasklet_schedule(&info->tlet);
++}
++
++static void uart_stop(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++	unsigned long flags;
++
++	spin_lock_irqsave(&port->lock, flags);
++	port->ops->stop_tx(port, 1);
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void __uart_start(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++
++	if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
++	    !tty->stopped && !tty->hw_stopped)
++		port->ops->start_tx(port, 1);
++}
++
++static void uart_start(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++	unsigned long flags;
++
++	pm_access(state->pm);
++
++	spin_lock_irqsave(&port->lock, flags);
++	__uart_start(tty);
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static void uart_tasklet_action(unsigned long data)
++{
++	struct uart_state *state = (struct uart_state *)data;
++	struct tty_struct *tty;
++
++	tty = state->info->tty;
++	if (tty) {
++		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++		    tty->ldisc.write_wakeup)
++			tty->ldisc.write_wakeup(tty);
++		wake_up_interruptible(&tty->write_wait);
++	}
++}
++
++static inline void
++uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
++{
++	unsigned long flags;
++	unsigned int old;
++
++	spin_lock_irqsave(&port->lock, flags);
++	old = port->mctrl;
++	port->mctrl = (old & ~clear) | set;
++	if (old != port->mctrl)
++		port->ops->set_mctrl(port, port->mctrl);
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++#define uart_set_mctrl(port,set)	uart_update_mctrl(port,set,0)
++#define uart_clear_mctrl(port,clear)	uart_update_mctrl(port,0,clear)
++
++static inline unsigned int uart_get_altspeed(struct uart_port *port)
++{
++	unsigned int flags = port->flags & UPF_SPD_MASK;
++	unsigned int altbaud = 0;
++
++	if (flags == ASYNC_SPD_HI)
++		altbaud = 57600;
++	if (flags == ASYNC_SPD_VHI)
++		altbaud = 115200;
++	if (flags == ASYNC_SPD_SHI)
++		altbaud = 230400;
++	if (flags == ASYNC_SPD_WARP)
++		altbaud = 460800;
++
++	return altbaud;
++}
++
++/*
++ * Startup the port.  This will be called once per open.  All calls
++ * will be serialised by the per-port semaphore.
++ */
++static int uart_startup(struct uart_state *state, int init_hw)
++{
++	struct uart_info *info = state->info;
++	struct uart_port *port = state->port;
++	unsigned long page;
++	int retval = 0;
++
++	if (info->flags & UIF_INITIALIZED)
++		return 0;
++
++	/*
++	 * Set the TTY IO error marker - we will only clear this
++	 * once we have successfully opened the port.  Also set
++	 * up the tty->alt_speed kludge
++	 */
++	if (info->tty)
++		set_bit(TTY_IO_ERROR, &info->tty->flags);
++
++	if (port->type == PORT_UNKNOWN)
++		return 0;
++
++	/*
++	 * Initialise and allocate the transmit and temporary
++	 * buffer.
++	 */
++	if (!info->xmit.buf) {
++		page = get_zeroed_page(GFP_KERNEL);
++		if (!page)
++			return -ENOMEM;
++
++		info->xmit.buf = (unsigned char *) page;
++		info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE;
++		init_MUTEX(&info->tmpbuf_sem);
++		uart_circ_clear(&info->xmit);
++	}
++
++	port->mctrl = 0;
++
++	retval = port->ops->startup(port);
++	if (retval == 0) {
++		if (init_hw) {
++			/*
++			 * Initialise the hardware port settings.
++			 */
++			uart_change_speed(state, NULL);
++
++			/*
++			 * Setup the RTS and DTR signals once the
++			 * port is open and ready to respond.
++			 */
++			if (info->tty->termios->c_cflag & CBAUD)
++				uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
++		}
++
++		info->flags |= UIF_INITIALIZED;
++
++		clear_bit(TTY_IO_ERROR, &info->tty->flags);
++	}
++
++	if (retval && capable(CAP_SYS_ADMIN))
++		retval = 0;
++
++	return retval;
++}
++
++/*
++ * This routine will shutdown a serial port; interrupts are disabled, and
++ * DTR is dropped if the hangup on close termio flag is on.  Calls to
++ * uart_shutdown are serialised by the per-port semaphore.
++ */
++static void uart_shutdown(struct uart_state *state)
++{
++	struct uart_info *info = state->info;
++	struct uart_port *port = state->port;
++
++	if (!(info->flags & UIF_INITIALIZED))
++		return;
++
++	/*
++	 * Turn off DTR and RTS early.
++	 */
++	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
++		uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
++
++	/*
++	 * clear delta_msr_wait queue to avoid mem leaks: we may free
++	 * the irq here so the queue might never be woken up.  Note
++	 * that we won't end up waiting on delta_msr_wait again since
++	 * any outstanding file descriptors should be pointing at
++	 * hung_up_tty_fops now.
++	 */
++	wake_up_interruptible(&info->delta_msr_wait);
++
++	/*
++	 * Free the IRQ and disable the port.
++	 */
++	port->ops->shutdown(port);
++
++	/*
++	 * Free the transmit buffer page.
++	 */
++	if (info->xmit.buf) {
++		free_page((unsigned long)info->xmit.buf);
++		info->xmit.buf = NULL;
++		info->tmpbuf = NULL;
++	}
++
++	/*
++	 * kill off our tasklet
++	 */
++	tasklet_kill(&info->tlet);
++	if (info->tty)
++		set_bit(TTY_IO_ERROR, &info->tty->flags);
++
++	info->flags &= ~UIF_INITIALIZED;
++}
++
++/**
++ *	uart_update_timeout - update per-port FIFO timeout.
++ *	@port: uart_port structure describing the port.
++ *	@cflag: termios cflag value
++ *	@quot: uart clock divisor quotient
++ *
++ *	Set the port FIFO timeout value.  The @cflag value should
++ *	reflect the actual hardware settings.
++ */
++void
++uart_update_timeout(struct uart_port *port, unsigned int cflag,
++		    unsigned int baud)
++{
++	unsigned int bits;
++
++	/* byte size and parity */
++	switch (cflag & CSIZE) {
++	case CS5:
++		bits = 7;
++		break;
++	case CS6:
++		bits = 8;
++		break;
++	case CS7:
++		bits = 9;
++		break;
++	default:
++		bits = 10;
++		break; // CS8
++	}
++
++	if (cflag & CSTOPB)
++		bits++;
++	if (cflag & PARENB)
++		bits++;
++
++	/*
++	 * The total number of bits to be transmitted in the fifo.
++	 */
++	bits = bits * port->fifosize;
++
++	/*
++	 * Figure the timeout to send the above number of bits.
++	 * Add .02 seconds of slop
++	 */
++	port->timeout = (HZ * bits) / baud + HZ/50;
++}
++
++EXPORT_SYMBOL(uart_update_timeout);
++
++static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
++{
++	u_int quot;
++
++	/* Special case: B0 rate */
++	if (!baud)
++		baud = 9600;
++
++	/* Old HI/VHI/custom speed handling */
++	if (baud == 38400 &&
++	    ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
++		quot = port->custom_divisor;
++	else
++		quot = port->uartclk / (16 * baud);
++
++	return quot;
++}
++
++static void
++uart_change_speed(struct uart_state *state, struct termios *old_termios)
++{
++	struct tty_struct *tty = state->info->tty;
++	struct uart_port *port = state->port;
++	struct termios *termios;
++	unsigned int quot, baud, cflag, try;
++
++	/*
++	 * If we have no tty, termios, or the port does not exist,
++	 * then we can't set the parameters for this port.
++	 */
++	if (!tty || !tty->termios || port->type == PORT_UNKNOWN)
++		return;
++
++	termios = tty->termios;
++
++	cflag = termios->c_cflag;
++
++	for (try = 0; try < 2; try ++) {
++		/* Determine divisor based on baud rate */
++		baud = tty_get_baud_rate(tty);
++		quot = uart_calculate_quot(port, baud);
++		if (quot)
++			break;
++
++		/*
++		 * Oops, the quotient was zero.  Try again with
++		 * the old baud rate if possible.
++		 */
++		termios->c_cflag &= ~CBAUD;
++		if (old_termios) {
++			termios->c_cflag |=
++				 (old_termios->c_cflag & CBAUD);
++			old_termios = NULL;
++			continue;
++		}
++
++		/*
++		 * As a last resort, if the quotient is zero,
++		 * default to 9600 bps
++		 */
++		termios->c_cflag |= B9600;
++	}
++
++	uart_update_timeout(port, cflag, port->uartclk / (16 * quot));
++
++	if (termios->c_cflag & CRTSCTS)
++		state->info->flags |= UIF_CTS_FLOW;
++	else
++		state->info->flags &= ~UIF_CTS_FLOW;
++	if (termios->c_cflag & CLOCAL)
++		state->info->flags &= ~UIF_CHECK_CD;
++	else
++		state->info->flags |= UIF_CHECK_CD;
++
++	/*
++	 * Set up parity check flag
++	 */
++	pm_access(state->pm);
++
++	port->ops->change_speed(port, cflag, termios->c_iflag, quot);
++}
++
++static inline void
++__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
++{
++	unsigned long flags;
++
++	if (!circ->buf)
++		return;
++
++	spin_lock_irqsave(&port->lock, flags);
++	if (uart_circ_chars_free(circ) != 0) {
++		circ->buf[circ->head] = c;
++		circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
++	}
++	spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static inline int
++__uart_user_write(struct uart_port *port, struct circ_buf *circ,
++		  const unsigned char *buf, int count)
++{
++	unsigned long flags;
++	int c, ret = 0;
++
++	if (down_interruptible(&port->info->tmpbuf_sem))
++		return -EINTR;
++
++	while (1) {
++		int c1;
++		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
++		if (count < c)
++			c = count;
++		if (c <= 0)
++			break;
++
++		c -= copy_from_user(port->info->tmpbuf, buf, c);
++		if (!c) {
++			if (!ret)
++				ret = -EFAULT;
++			break;
++		}
++		spin_lock_irqsave(&port->lock, flags);
++		c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
++		if (c1 < c)
++			c = c1;
++		memcpy(circ->buf + circ->head, port->info->tmpbuf, c);
++		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
++		spin_unlock_irqrestore(&port->lock, flags);
++		buf += c;
++		count -= c;
++		ret += c;
++	}
++	up(&port->info->tmpbuf_sem);
++
++	return ret;
++}
++
++static inline int
++__uart_kern_write(struct uart_port *port, struct circ_buf *circ,
++		  const unsigned char *buf, int count)
++{
++	unsigned long flags;
++	int c, ret = 0;
++
++	spin_lock_irqsave(&port->lock, flags);
++	while (1) {
++		c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);
++		if (count < c)
++			c = count;
++		if (c <= 0)
++			break;
++		memcpy(circ->buf + circ->head, buf, c);
++		circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);
++		buf += c;
++		count -= c;
++		ret += c;
++	}
++	spin_unlock_irqrestore(&port->lock, flags);
++
++	return ret;
++}
++
++static void uart_put_char(struct tty_struct *tty, unsigned char ch)
++{
++	struct uart_state *state = tty->driver_data;
++
++	__uart_put_char(state->port, &state->info->xmit, ch);
++}
++
++static void uart_flush_chars(struct tty_struct *tty)
++{
++	uart_start(tty);
++}
++
++static int
++uart_write(struct tty_struct *tty, int from_user, const unsigned char * buf,
++	   int count)
++{
++	struct uart_state *state = tty->driver_data;
++	int ret;
++
++	if (!state->info->xmit.buf)
++		return 0;
++
++	if (from_user)
++		ret = __uart_user_write(state->port, &state->info->xmit, buf, count);
++	else
++		ret = __uart_kern_write(state->port, &state->info->xmit, buf, count);
++
++	uart_start(tty);
++	return ret;
++}
++
++static int uart_write_room(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++
++	return uart_circ_chars_free(&state->info->xmit);
++}
++
++static int uart_chars_in_buffer(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++
++	return uart_circ_chars_pending(&state->info->xmit);
++}
++
++static void uart_flush_buffer(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++	unsigned long flags;
++
++	DPRINTK("uart_flush_buffer(%d) called\n",
++	        MINOR(tty->device) - tty->driver.minor_start);
++
++	spin_lock_irqsave(&port->lock, flags);
++	uart_circ_clear(&state->info->xmit);
++	spin_unlock_irqrestore(&port->lock, flags);
++	wake_up_interruptible(&tty->write_wait);
++	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++	    tty->ldisc.write_wakeup)
++		(tty->ldisc.write_wakeup)(tty);
++}
++
++/*
++ * This function is used to send a high-priority XON/XOFF character to
++ * the device
++ */
++static void uart_send_xchar(struct tty_struct *tty, char ch)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++	unsigned long flags;
++
++	if (port->ops->send_xchar)
++		port->ops->send_xchar(port, ch);
++	else {
++		port->x_char = ch;
++		if (ch) {
++			spin_lock_irqsave(&port->lock, flags);
++			port->ops->start_tx(port, 0);
++			spin_unlock_irqrestore(&port->lock, flags);
++		}
++	}
++}
++
++static void uart_throttle(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++
++	if (I_IXOFF(tty))
++		uart_send_xchar(tty, STOP_CHAR(tty));
++
++	if (tty->termios->c_cflag & CRTSCTS)
++		uart_clear_mctrl(state->port, TIOCM_RTS);
++}
++
++static void uart_unthrottle(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++
++	if (I_IXOFF(tty)) {
++		if (port->x_char)
++			port->x_char = 0;
++		else
++			uart_send_xchar(tty, START_CHAR(tty));
++	}
++
++	if (tty->termios->c_cflag & CRTSCTS)
++		uart_set_mctrl(port, TIOCM_RTS);
++}
++
++static int uart_get_info(struct uart_state *state, struct serial_struct *retinfo)
++{
++	struct uart_port *port = state->port;
++	struct serial_struct tmp;
++
++	memset(&tmp, 0, sizeof(tmp));
++	tmp.type	    = port->type;
++	tmp.line	    = port->line;
++	tmp.port	    = port->iobase;
++	if (HIGH_BITS_OFFSET)
++		tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET;
++	tmp.irq		    = port->irq;
++	tmp.flags	    = port->flags;
++	tmp.xmit_fifo_size  = port->fifosize;
++	tmp.baud_base	    = port->uartclk / 16;
++	tmp.close_delay	    = state->close_delay;
++	tmp.closing_wait    = state->closing_wait;
++	tmp.custom_divisor  = port->custom_divisor;
++	tmp.hub6	    = port->hub6;
++	tmp.io_type         = port->iotype;
++	tmp.iomem_reg_shift = port->regshift;
++	tmp.iomem_base      = (void *)port->mapbase;
++
++	if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
++		return -EFAULT;
++	return 0;
++}
++
++static int
++uart_set_info(struct uart_state *state, struct serial_struct *newinfo)
++{
++	struct serial_struct new_serial;
++	struct uart_port *port = state->port;
++	unsigned long new_port;
++	unsigned int change_irq, change_port, old_flags;
++	unsigned int old_custom_divisor;
++	int retval = 0;
++
++	if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
++		return -EFAULT;
++
++	new_port = new_serial.port;
++	if (HIGH_BITS_OFFSET)
++		new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
++
++	new_serial.irq = irq_cannonicalize(new_serial.irq);
++
++	/*
++	 * This semaphore protects state->count.  It is also
++	 * very useful to prevent opens.  Also, take the
++	 * port configuration semaphore to make sure that a
++	 * module insertion/removal doesn't change anything
++	 * under us.
++	 */
++	down(&state->sem);
++
++	change_irq  = new_serial.irq != port->irq;
++
++	/*
++	 * Since changing the 'type' of the port changes its resource
++	 * allocations, we should treat type changes the same as
++	 * IO port changes.
++	 */
++	change_port = new_port != port->iobase ||
++		      (unsigned long)new_serial.iomem_base != port->mapbase ||
++		      new_serial.hub6 != port->hub6 ||
++		      new_serial.io_type != port->iotype ||
++		      new_serial.iomem_reg_shift != port->regshift ||
++		      new_serial.type != port->type;
++
++	old_flags = port->flags;
++	old_custom_divisor = port->custom_divisor;
++
++	if (!capable(CAP_SYS_ADMIN)) {
++		retval = -EPERM;
++		if (change_irq || change_port ||
++		    (new_serial.baud_base != port->uartclk / 16) ||
++		    (new_serial.close_delay != state->close_delay) ||
++		    (new_serial.closing_wait != state->closing_wait) ||
++		    (new_serial.xmit_fifo_size != port->fifosize) ||
++		    (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0))
++			goto exit;
++		port->flags = ((port->flags & ~UPF_USR_MASK) |
++			       (new_serial.flags & UPF_USR_MASK));
++		port->custom_divisor = new_serial.custom_divisor;
++		goto check_and_exit;
++	}
++
++	/*
++	 * Ask the low level driver to verify the settings.
++	 */
++	if (port->ops->verify_port)
++		retval = port->ops->verify_port(port, &new_serial);
++
++	if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
++	    (new_serial.baud_base < 9600))
++		retval = -EINVAL;
++
++	if (retval)
++		goto exit;
++
++	if (change_port || change_irq) {
++		retval = -EBUSY;
++
++		/*
++		 * Make sure that we are the sole user of this port.
++		 */
++		if (uart_users(state) > 1)
++			goto exit;
++
++		/*
++		 * We need to shutdown the serial port at the old
++		 * port/type/irq combination.
++		 */
++		uart_shutdown(state);
++	}
++
++	if (change_port) {
++		unsigned long old_iobase, old_mapbase;
++		unsigned int old_type, old_iotype, old_hub6, old_shift;
++
++		old_iobase = port->iobase;
++		old_mapbase = port->mapbase;
++		old_type = port->type;
++		old_hub6 = port->hub6;
++		old_iotype = port->iotype;
++		old_shift = port->regshift;
++
++		/*
++		 * Free and release old regions
++		 */
++		if (old_type != PORT_UNKNOWN)
++			port->ops->release_port(port);
++
++		port->iobase = new_port;
++		port->type = new_serial.type;
++		port->hub6 = new_serial.hub6;
++		port->iotype = new_serial.io_type;
++		port->regshift = new_serial.iomem_reg_shift;
++		port->mapbase = (unsigned long)new_serial.iomem_base;
++
++		/*
++		 * Claim and map the new regions
++		 */
++		if (port->type != PORT_UNKNOWN) {
++			retval = port->ops->request_port(port);
++		} else {
++			/* Always success - Jean II */
++			retval = 0;
++		}
++
++		/*
++		 * If we fail to request resources for the
++		 * new port, try to restore the old settings.
++		 */
++		if (retval && old_type != PORT_UNKNOWN) {
++			port->iobase = old_iobase;
++			port->type = old_type;
++			port->hub6 = old_hub6;
++			port->iotype = old_iotype;
++			port->regshift = old_shift;
++			port->mapbase = old_mapbase;
++			retval = port->ops->request_port(port);
++			/*
++			 * If we failed to restore the old settings,
++			 * we fail like this.
++			 */
++			if (retval)
++				port->type = PORT_UNKNOWN;
++
++			/*
++			 * We failed anyway.
++			 */
++			retval = -EBUSY;
++		}
++	}
++
++	port->irq              = new_serial.irq;
++	port->uartclk          = new_serial.baud_base * 16;
++	port->flags            = (port->flags & ~UPF_CHANGE_MASK) |
++				 (new_serial.flags & UPF_CHANGE_MASK);
++	port->custom_divisor   = new_serial.custom_divisor;
++	state->close_delay     = new_serial.close_delay * HZ / 100;
++	state->closing_wait    = new_serial.closing_wait * HZ / 100;
++	port->fifosize         = new_serial.xmit_fifo_size;
++	if (state->info->tty)
++		state->info->tty->low_latency =
++			(port->flags & UPF_LOW_LATENCY) ? 1 : 0;
++
++ check_and_exit:
++	retval = 0;
++	if (port->type == PORT_UNKNOWN)
++		goto exit;
++	if (state->info->flags & UIF_INITIALIZED) {
++		if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
++		    old_custom_divisor != port->custom_divisor) {
++			state->info->tty->alt_speed = uart_get_altspeed(port);
++			uart_change_speed(state, NULL);
++		}
++	} else
++		retval = uart_startup(state, 1);
++ exit:
++	up(&state->sem);
++	return retval;
++}
++
++
++/*
++ * uart_get_lsr_info - get line status register info.
++ * Note: uart_ioctl protects us against hangups.
++ */
++static int uart_get_lsr_info(struct uart_state *state, unsigned int *value)
++{
++	struct uart_port *port = state->port;
++	unsigned int result;
++
++	result = port->ops->tx_empty(port);
++
++	/*
++	 * If we're about to load something into the transmit
++	 * register, we'll pretend the transmitter isn't empty to
++	 * avoid a race condition (depending on when the transmit
++	 * interrupt happens).
++	 */
++	if (port->x_char ||
++	    ((uart_circ_chars_pending(&state->info->xmit) > 0) &&
++	     !state->info->tty->stopped && !state->info->tty->hw_stopped))
++		result &= ~TIOCSER_TEMT;
++	
++	return put_user(result, value);
++}
++
++static int uart_tiocmget(struct tty_struct *tty, struct file *file)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++	int result = -EIO;
++
++	down(&state->sem);
++	if ((!file || !tty_hung_up_p(file)) &&
++	    !(tty->flags & (1 << TTY_IO_ERROR))) {
++		result = port->mctrl;
++		result |= port->ops->get_mctrl(port);
++	}
++	up(&state->sem);
++
++	return result;
++}
++
++static int
++uart_tiocmset(struct tty_struct *tty, struct file *file,
++	      unsigned int set, unsigned int clear)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++	int ret = -EIO;
++
++	down(&state->sem);
++	if ((!file || !tty_hung_up_p(file)) &&
++	    !(tty->flags & (1 << TTY_IO_ERROR))) {
++		uart_update_mctrl(port, set, clear);
++		ret = 0;
++	}
++	up(&state->sem);
++	return ret;
++}
++
++static void uart_break_ctl(struct tty_struct *tty, int break_state)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++
++	BUG_ON(!kernel_locked());
++
++	down(&state->sem);
++
++	if (port->type != PORT_UNKNOWN)
++		port->ops->break_ctl(port, break_state);
++
++	up(&state->sem);
++}
++
++static int uart_do_autoconfig(struct uart_state *state)
++{
++	struct uart_port *port = state->port;
++	int flags, ret;
++
++	if (!capable(CAP_SYS_ADMIN))
++		return -EPERM;
++
++	/*
++	 * Take the per-port semaphore.  This prevents count from
++	 * changing, and hence any extra opens of the port while
++	 * we're auto-configuring.
++	 */
++	if (down_interruptible(&state->sem))
++		return -ERESTARTSYS;
++
++	ret = -EBUSY;
++	if (uart_users(state) == 1) {
++		uart_shutdown(state);
++
++		/*
++		 * If we already have a port type configured,
++		 * we must release its resources.
++		 */
++		if (port->type != PORT_UNKNOWN)
++			port->ops->release_port(port);
++
++		flags = UART_CONFIG_TYPE;
++		if (port->flags & UPF_AUTO_IRQ)
++			flags |= UART_CONFIG_IRQ;
++
++		/*
++		 * This will claim the ports resources if
++		 * a port is found.
++		 */
++		port->ops->config_port(port, flags);
++
++		ret = uart_startup(state, 1);
++	}
++	up(&state->sem);
++	return ret;
++}
++
++/*
++ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
++ * - mask passed in arg for lines of interest
++ *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
++ * Caller should use TIOCGICOUNT to see which one it was
++ */
++static int
++uart_wait_modem_status(struct uart_state *state, unsigned long arg)
++{
++	struct uart_port *port = state->port;
++	DECLARE_WAITQUEUE(wait, current);
++	struct uart_icount cprev, cnow;
++	int ret;
++
++	/*
++	 * note the counters on entry
++	 */
++	spin_lock_irq(&port->lock);
++	memcpy(&cprev, &port->icount, sizeof(struct uart_icount));
++
++	/*
++	 * Force modem status interrupts on
++	 */
++	port->ops->enable_ms(port);
++	spin_unlock_irq(&port->lock);
++
++	add_wait_queue(&state->info->delta_msr_wait, &wait);
++	for (;;) {
++		spin_lock_irq(&port->lock);
++		memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
++		spin_unlock_irq(&port->lock);
++
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
++		    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
++		    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||
++		    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
++			ret = 0;
++			break;
++		}
++
++		schedule();
++
++		/* see if a signal did it */
++		if (signal_pending(current)) {
++			ret = -ERESTARTSYS;
++			break;
++		}
++
++		cprev = cnow;
++	}
++
++	current->state = TASK_RUNNING;
++	remove_wait_queue(&state->info->delta_msr_wait, &wait);
++
++	return ret;
++}
++
++/*
++ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
++ * Return: write counters to the user passed counter struct
++ * NB: both 1->0 and 0->1 transitions are counted except for
++ *     RI where only 0->1 is counted.
++ */
++static int
++uart_get_count(struct uart_state *state, struct serial_icounter_struct *icnt)
++{
++	struct serial_icounter_struct icount;
++	struct uart_icount cnow;
++	struct uart_port *port = state->port;
++
++	spin_lock_irq(&port->lock);
++	memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
++	spin_unlock_irq(&port->lock);
++
++	icount.cts         = cnow.cts;
++	icount.dsr         = cnow.dsr;
++	icount.rng         = cnow.rng;
++	icount.dcd         = cnow.dcd;
++	icount.rx          = cnow.rx;
++	icount.tx          = cnow.tx;
++	icount.frame       = cnow.frame;
++	icount.overrun     = cnow.overrun;
++	icount.parity      = cnow.parity;
++	icount.brk         = cnow.brk;
++	icount.buf_overrun = cnow.buf_overrun;
++
++	return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0;
++}
++
++/*
++ * Called via sys_ioctl under the BKL.  We can use spin_lock_irq() here.
++ */
++static int
++uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
++	   unsigned long arg)
++{
++	struct uart_state *state = tty->driver_data;
++	int ret = -ENOIOCTLCMD;
++
++	BUG_ON(!kernel_locked());
++
++	/*
++	 * These ioctls don't rely on the hardware to be present.
++	 */
++	switch (cmd) {
++	case TIOCGSERIAL:
++		ret = uart_get_info(state, (struct serial_struct *)arg);
++		break;
++
++	case TIOCSSERIAL:
++		ret = uart_set_info(state, (struct serial_struct *)arg);
++		break;
++
++	case TIOCSERCONFIG:
++		ret = uart_do_autoconfig(state);
++		break;
++
++	case TIOCSERGWILD: /* obsolete */
++	case TIOCSERSWILD: /* obsolete */
++		ret = 0;
++		break;
++	}
++
++	if (ret != -ENOIOCTLCMD)
++		goto out;
++
++	if (tty->flags & (1 << TTY_IO_ERROR)) {
++		ret = -EIO;
++		goto out;
++	}
++
++	/*
++	 * The following should only be used when hardware is present.
++	 */
++	switch (cmd) {
++	case TIOCMIWAIT:
++		ret = uart_wait_modem_status(state, arg);
++		break;
++
++	case TIOCGICOUNT:
++		ret = uart_get_count(state, (struct serial_icounter_struct *)arg);
++		break;
++
++	case TIOCMGET:
++		{
++			int val;
++			val = uart_tiocmget(tty, filp);
++			if (val >= 0) {
++				ret = put_user(val, (int *)arg);
++			} else {
++				ret = val;
++			}
++		}
++		break;
++
++	case TIOCMBIS:
++	case TIOCMBIC:
++	case TIOCMSET:
++		{
++			int val, set = 0, clear = 0;
++			ret = get_user(val, (int *)arg);
++			if (ret)
++				break;
++
++			switch (cmd) {
++			case TIOCMBIS:
++				set = val;
++				break;
++			case TIOCMBIC:
++				clear = val;
++				break;
++			case TIOCMSET:
++				set = val;
++				clear = ~val;
++				break;
++			}
++
++			set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
++			clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
++
++			ret = uart_tiocmset(tty, filp, set, clear);
++		}
++		break;
++	}
++
++	if (ret != -ENOIOCTLCMD)
++		goto out;
++
++	down(&state->sem);
++
++	if (tty_hung_up_p(filp)) {
++		ret = -EIO;
++		goto out_up;
++	}
++
++	/*
++	 * All these rely on hardware being present and need to be
++	 * protected against the tty being hung up.
++	 */
++	switch (cmd) {
++	case TIOCSERGETLSR: /* Get line status register */
++		ret = uart_get_lsr_info(state, (unsigned int *)arg);
++		break;
++
++	default: {
++		struct uart_port *port = state->port;
++		if (port->ops->ioctl)
++			ret = port->ops->ioctl(port, cmd, arg);
++		break;
++	}
++	}
++ out_up:
++	up(&state->sem);
++ out:
++	return ret;
++}
++
++static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios)
++{
++	struct uart_state *state = tty->driver_data;
++	unsigned long flags;
++	unsigned int cflag = tty->termios->c_cflag;
++
++	BUG_ON(!kernel_locked());
++
++	/*
++	 * These are the bits that are used to setup various
++	 * flags in the low level driver.
++	 */
++#define RELEVANT_IFLAG(iflag)	((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
++
++	if ((cflag ^ old_termios->c_cflag) == 0 &&
++	    RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
++		return;
++
++	uart_change_speed(state, old_termios);
++
++	/* Handle transition to B0 status */
++	if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
++		uart_clear_mctrl(state->port, TIOCM_RTS | TIOCM_DTR);
++
++	/* Handle transition away from B0 status */
++	if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
++		unsigned int mask = TIOCM_DTR;
++		if (!(cflag & CRTSCTS) ||
++		    !test_bit(TTY_THROTTLED, &tty->flags))
++			mask |= TIOCM_RTS;
++		uart_set_mctrl(state->port, mask);
++	}
++
++	/* Handle turning off CRTSCTS */
++	if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
++		spin_lock_irqsave(&state->port->lock, flags);
++		tty->hw_stopped = 0;
++		__uart_start(tty);
++		spin_unlock_irqrestore(&state->port->lock, flags);
++	}
++
++#if 0
++	/*
++	 * No need to wake up processes in open wait, since they
++	 * sample the CLOCAL flag once, and don't recheck it.
++	 * XXX  It's not clear whether the current behavior is correct
++	 * or not.  Hence, this may change.....
++	 */
++	if (!(old_termios->c_cflag & CLOCAL) &&
++	    (tty->termios->c_cflag & CLOCAL))
++		wake_up_interruptible(&state->info->open_wait);
++#endif
++}
++
++/*
++ * In 2.4.5, calls to this will be serialized via the BKL in
++ *  linux/drivers/char/tty_io.c:tty_release()
++ *  linux/drivers/char/tty_io.c:do_tty_handup()
++ */
++static void uart_close(struct tty_struct *tty, struct file *filp)
++{
++	struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state;
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port;
++
++	BUG_ON(!kernel_locked());
++
++	if (!state || !state->port)
++		return;
++
++	port = state->port;
++
++	DPRINTK("uart_close(%d) called\n", port->line);
++
++	down(&state->sem);
++
++	if (tty_hung_up_p(filp))
++		goto done;
++
++	if ((tty->count == 1) && (state->count != 1)) {
++		/*
++		 * Uh, oh.  tty->count is 1, which means that the tty
++		 * structure will be freed.  state->count should always
++		 * be one in these conditions.  If it's greater than
++		 * one, we've got real problems, since it means the
++		 * serial port won't be shutdown.
++		 */
++		printk("uart_close: bad serial port count; tty->count is 1, "
++		       "state->count is %d\n", state->count);
++		state->count = 1;
++	}
++	if (--state->count < 0) {
++		printk("rs_close: bad serial port count for %s%d: %d\n",
++		       tty->driver.name, port->line, state->count);
++		state->count = 0;
++	}
++	if (state->count)
++		goto done;
++
++	/*
++	 * Save the termios structure, since this port may have
++	 * separate termios for callout and dialin.
++	 */
++	if (state->info->flags & UIF_NORMAL_ACTIVE)
++		state->normal_termios = *tty->termios;
++	if (state->info->flags & UIF_CALLOUT_ACTIVE)
++		state->callout_termios = *tty->termios;
++
++	/*
++	 * Now we wait for the transmit buffer to clear; and we notify
++	 * the line discipline to only process XON/XOFF characters by
++	 * setting tty->closing.
++	 */
++	tty->closing = 1;
++
++	if (state->closing_wait != USF_CLOSING_WAIT_NONE)
++		tty_wait_until_sent(tty, state->closing_wait);
++
++	/*
++	 * At this point, we stop accepting input.  To do this, we
++	 * disable the receive line status interrupts.
++	 */
++	if (state->info->flags & UIF_INITIALIZED) {
++		unsigned long flags;
++		spin_lock_irqsave(&port->lock, flags);
++		port->ops->stop_rx(port);
++		spin_unlock_irqrestore(&port->lock, flags);
++		/*
++		 * Before we drop DTR, make sure the UART transmitter
++		 * has completely drained; this is especially
++		 * important if there is a transmit FIFO!
++		 */
++		uart_wait_until_sent(tty, port->timeout);
++	}
++
++	uart_shutdown(state);
++	uart_flush_buffer(tty);
++	if (tty->ldisc.flush_buffer)
++		tty->ldisc.flush_buffer(tty);
++	tty->closing = 0;
++	state->info->tty = NULL;
++
++	if (state->info->blocked_open) {
++		if (state->close_delay) {
++			set_current_state(TASK_INTERRUPTIBLE);
++			schedule_timeout(state->close_delay);
++			set_current_state(TASK_RUNNING);
++		}
++	} else if (!uart_console(port)) {
++		uart_change_pm(state, 3);
++	}
++
++	/*
++	 * Wake up anyone trying to open this port.
++	 */
++	state->info->flags &= ~(UIF_NORMAL_ACTIVE|UIF_CALLOUT_ACTIVE);
++	wake_up_interruptible(&state->info->open_wait);
++
++ done:
++	up(&state->sem);
++	if (drv->owner)
++		__MOD_DEC_USE_COUNT(drv->owner);
++}
++
++static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++	struct uart_state *state = tty->driver_data;
++	struct uart_port *port = state->port;
++	unsigned long char_time, expire;
++
++	BUG_ON(!kernel_locked());
++
++	if (port->type == PORT_UNKNOWN || port->fifosize == 0)
++		return;
++
++	/*
++	 * Set the check interval to be 1/5 of the estimated time to
++	 * send a single character, and make it at least 1.  The check
++	 * interval should also be less than the timeout.
++	 *
++	 * Note: we have to use pretty tight timings here to satisfy
++	 * the NIST-PCTS.
++	 */
++	char_time = (port->timeout - HZ/50) / port->fifosize;
++	char_time = char_time / 5;
++	if (char_time == 0)
++		char_time = 1;
++	if (timeout && timeout < char_time)
++		char_time = timeout;
++
++	/*
++	 * If the transmitter hasn't cleared in twice the approximate
++	 * amount of time to send the entire FIFO, it probably won't
++	 * ever clear.  This assumes the UART isn't doing flow
++	 * control, which is currently the case.  Hence, if it ever
++	 * takes longer than port->timeout, this is probably due to a
++	 * UART bug of some kind.  So, we clamp the timeout parameter at
++	 * 2*port->timeout.
++	 */
++	if (timeout == 0 || timeout > 2 * port->timeout)
++		timeout = 2 * port->timeout;
++
++	expire = jiffies + timeout;
++
++	DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n",
++		port->line, jiffies, expire);
++
++	/*
++	 * Check whether the transmitter is empty every 'char_time'.
++	 * 'timeout' / 'expire' give us the maximum amount of time
++	 * we wait.
++	 */
++	while (!port->ops->tx_empty(port)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		schedule_timeout(char_time);
++		if (signal_pending(current))
++			break;
++		if (time_after(jiffies, expire))
++			break;
++	}
++	set_current_state(TASK_RUNNING); /* might not be needed */
++}
++
++/*
++ * This is called with the BKL held in
++ *  linux/drivers/char/tty_io.c:do_tty_hangup()
++ * We're called from the eventd thread, so we can sleep for
++ * a _short_ time only.
++ */
++static void uart_hangup(struct tty_struct *tty)
++{
++	struct uart_state *state = tty->driver_data;
++
++	BUG_ON(!kernel_locked());
++	DPRINTK("uart_hangup(%d)\n", state->port->line);
++
++	down(&state->sem);
++	if (state->info && state->info->flags & (UIF_NORMAL_ACTIVE|UIF_CALLOUT_ACTIVE)) {
++		uart_flush_buffer(tty);
++		uart_shutdown(state);
++		state->count = 0;
++		state->info->flags &= ~(UIF_NORMAL_ACTIVE|UIF_CALLOUT_ACTIVE);
++		state->info->tty = NULL;
++		wake_up_interruptible(&state->info->open_wait);
++		wake_up_interruptible(&state->info->delta_msr_wait);
++	}
++	up(&state->sem);
++}
++
++/*
++ * Copy across the serial console cflag setting into the termios settings
++ * for the initial open of the port.  This allows continuity between the
++ * kernel settings, and the settings init adopts when it opens the port
++ * for the first time.
++ */
++static void uart_update_termios(struct uart_state *state)
++{
++	struct tty_struct *tty = state->info->tty;
++	struct uart_port *port = state->port;
++
++	if (uart_console(port) && port->cons->cflag) {
++		tty->termios->c_cflag = port->cons->cflag;
++		port->cons->cflag = 0;
++	}
++
++	/*
++	 * If the device failed to grab its irq resources,
++	 * or some other error occurred, don't try to talk
++	 * to the port hardware.
++	 */
++	if (!(tty->flags & (1 << TTY_IO_ERROR))) {
++		/*
++		 * Make termios settings take effect.
++		 */
++		uart_change_speed(state, NULL);
++
++		/*
++		 * And finally enable the RTS and DTR signals.
++		 */
++		if (tty->termios->c_cflag & CBAUD)
++			uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
++	}
++}
++
++/*
++ * Block the open until the port is ready.  We must be called with
++ * the per-port semaphore held.
++ */
++static int
++uart_block_til_ready(struct file *filp, struct uart_state *state)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct uart_info *info = state->info;
++	struct uart_port *port = state->port;
++	struct termios *termios;
++
++	/*
++	 * If this is a callout device, then just make sure the normal
++	 * device isn't being used.
++	 */
++	if (info->tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
++		if (info->flags & UIF_NORMAL_ACTIVE)
++			return -EBUSY;
++		if ((info->flags & UIF_CALLOUT_ACTIVE) &&
++		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
++		    (info->session != current->session))
++			return -EBUSY;
++		if ((info->flags & UIF_CALLOUT_ACTIVE) &&
++		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
++		    (info->pgrp != current->pgrp))
++			return -EBUSY;
++		info->flags |= UIF_CALLOUT_ACTIVE;
++		return 0;
++	}
++
++	if (info->flags & UIF_CALLOUT_ACTIVE) {
++		termios = &state->normal_termios;
++	} else {
++		termios = state->info->tty->termios;
++	}
++
++	info->blocked_open++;
++	state->count--;
++
++	add_wait_queue(&info->open_wait, &wait);
++	while (1) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		/*
++		 * If we have been hung up, tell userspace/restart open.
++		 */
++		if (tty_hung_up_p(filp) || info->tty == NULL)
++			break;
++
++		/*
++		 * If the port has been closed, tell userspace/restart open.
++		 */
++		if (!(info->flags & UIF_INITIALIZED))
++			break;
++
++		/*
++		 * If non-blocking mode is set, or CLOCAL mode is set,
++		 * we don't want to wait for the modem status lines to
++		 * indicate that the port is ready.
++		 *
++		 * Also, if the port is not enabled/configured, we want
++		 * to allow the open to succeed here.  Note that we will
++		 * have set TTY_IO_ERROR for a non-existant port.
++		 */
++		if ((filp->f_flags & O_NONBLOCK) ||
++		    (termios->c_cflag & CLOCAL) ||
++		    (info->tty->flags & (1 << TTY_IO_ERROR))) {
++			break;
++		}
++
++		if (!(info->flags & UIF_CALLOUT_ACTIVE)) {
++			/*
++			 * Set DTR to allow modem to know we're waiting.  Do
++			 * not set RTS here - we want to make sure we catch
++			 * the data from the modem.
++			 */
++			if (info->tty->termios->c_cflag & CBAUD)
++				uart_set_mctrl(port, TIOCM_DTR);
++
++			/*
++			 * and wait for the carrier to indicate that the
++			 * modem is ready for us.
++			 */
++			if (port->ops->get_mctrl(port) & TIOCM_CAR)
++	                        break;
++		}
++
++		up(&state->sem);
++		schedule();
++		down(&state->sem);
++
++		if (signal_pending(current))
++			break;
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&info->open_wait, &wait);
++
++	state->count++;
++	info->blocked_open--;
++
++	info->flags |= UIF_NORMAL_ACTIVE;
++
++	if (signal_pending(current))
++		return -ERESTARTSYS;
++
++	if (!info->tty || tty_hung_up_p(filp))
++		return -EAGAIN;
++
++	return 0;
++}
++
++static struct uart_state *uart_get(struct uart_driver *drv, int line)
++{
++	struct uart_state *state;
++
++	down(&port_sem);
++	state = drv->state + line;
++	if (down_interruptible(&state->sem)) {
++		state = ERR_PTR(-ERESTARTSYS);
++		goto out;
++	}
++
++	state->count++;
++	if (!state->port) {
++		state->count--;
++		up(&state->sem);
++		state = ERR_PTR(-ENXIO);
++		goto out;
++	}
++
++	if (!state->info) {
++		state->info = kmalloc(sizeof(struct uart_info), GFP_KERNEL);
++		if (state->info) {
++			memset(state->info, 0, sizeof(struct uart_info));
++			init_waitqueue_head(&state->info->open_wait);
++			init_waitqueue_head(&state->info->delta_msr_wait);
++
++			/*
++			 * Link the info into the other structures.
++			 */
++			state->port->info = state->info;
++
++			tasklet_init(&state->info->tlet, uart_tasklet_action,
++				     (unsigned long)state);
++		} else {
++			state->count--;
++			up(&state->sem);
++			state = ERR_PTR(-ENOMEM);
++		}
++	}
++
++ out:
++	up(&port_sem);
++	return state;
++}
++
++/*
++ * In 2.4.5, calls to uart_open are serialised by the BKL in
++ *   linux/fs/devices.c:chrdev_open()
++ * Note that if this fails, then uart_close() _will_ be called.
++ */
++static int uart_open(struct tty_struct *tty, struct file *filp)
++{
++	struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state;
++	struct uart_state *state;
++	int retval, line = MINOR(tty->device) - tty->driver.minor_start;
++
++	BUG_ON(!kernel_locked());
++	DPRINTK("uart_open(%d) called\n", line);
++
++	/*
++	 * tty->driver->num won't change, so we won't fail here with
++	 * tty->driver_data set to something non-NULL (and therefore
++	 * we won't get caught by uart_close()).
++	 */
++	retval = -ENODEV;
++	if (line >= tty->driver.num)
++		goto fail;
++
++	if (!try_inc_mod_count(drv->owner))
++		goto fail;
++
++	/*
++	 * We take the semaphore inside uart_get to guarantee that we won't
++	 * be re-entered while allocating the info structure, or while we
++	 * request any IRQs that the driver may need.  This also has the nice
++	 * side-effect that it delays the action of uart_hangup, so we can
++	 * guarantee that info->tty will always contain something reasonable.
++	 */
++	state = uart_get(drv, line);
++	if (IS_ERR(state)) {
++		retval = PTR_ERR(state);
++		if (!tty->driver_data)
++			goto out;
++		else
++			goto fail;
++	}
++
++	/*
++	 * Once we set tty->driver_data here, we are guaranteed that
++	 * uart_close() will decrement the driver module use count.
++	 * Any failures from here onwards should not touch the count.
++	 */
++	tty->driver_data = state;
++	tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
++	tty->alt_speed = uart_get_altspeed(state->port);
++	state->info->tty = tty;
++
++	/*
++	 * If the port is in the middle of closing, bail out now.
++	 */
++	if (tty_hung_up_p(filp)) {
++		retval = -EAGAIN;
++		state->count--;
++		up(&state->sem);
++		goto fail;
++	}
++
++	/*
++	 * Make sure the device is in D0 state.
++	 */
++	if (state->count == 1)
++		uart_change_pm(state, 0);
++
++	/*
++	 * Start up the serial port.
++	 */
++	retval = uart_startup(state, 0);
++
++	/*
++	 * If we succeeded, wait until the port is ready.
++	 */
++	if (retval == 0)
++		retval = uart_block_til_ready(filp, state);
++
++	/*
++	 * If this is the first open to succeed, adjust things to suit.
++	 */
++	if (retval == 0 && state->count == 1) {
++		if (state->port->flags & UPF_SPLIT_TERMIOS) {
++			if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
++				*tty->termios = state->normal_termios;
++			else
++				*tty->termios = state->callout_termios;
++		}
++
++		uart_update_termios(state);
++
++		state->info->session = current->session;
++		state->info->pgrp = current->pgrp;
++	}
++	up(&state->sem);
++
++	return 0;
++
++ out:
++	if (drv->owner)
++		__MOD_DEC_USE_COUNT(drv->owner);
++ fail:
++	return retval;
++}
++
++static const char *uart_type(struct uart_port *port)
++{
++	const char *str = NULL;
++
++	if (port->ops->type)
++		str = port->ops->type(port);
++
++	if (!str)
++		str = "unknown";
++
++	return str;
++}
++
++#ifdef CONFIG_PROC_FS
++
++static int uart_line_info(char *buf, struct uart_driver *drv, int i)
++{
++	struct uart_state *state = drv->state + i;
++	struct uart_port *port = state->port;
++	char stat_buf[32];
++	unsigned int status;
++	int ret;
++
++	if (!port)
++		return 0;
++
++	ret = sprintf(buf, "%d: uart:%s port:%08X irq:%d",
++			port->line, uart_type(port),
++			port->iobase, port->irq);
++
++	if (port->type == PORT_UNKNOWN) {
++		strcat(buf, "\n");
++		return ret + 1;
++	}
++
++	status = port->ops->get_mctrl(port);
++
++	ret += sprintf(buf + ret, " tx:%d rx:%d",
++			port->icount.tx, port->icount.rx);
++	if (port->icount.frame)
++		ret += sprintf(buf + ret, " fe:%d",
++			port->icount.frame);
++	if (port->icount.parity)
++		ret += sprintf(buf + ret, " pe:%d",
++			port->icount.parity);
++	if (port->icount.brk)
++		ret += sprintf(buf + ret, " brk:%d",
++			port->icount.brk);
++	if (port->icount.overrun)
++		ret += sprintf(buf + ret, " oe:%d",
++			port->icount.overrun);
++
++#define INFOBIT(bit,str) \
++	if (port->mctrl & (bit)) \
++		strcat(stat_buf, (str))
++#define STATBIT(bit,str) \
++	if (status & (bit)) \
++		strcat(stat_buf, (str))
++
++	stat_buf[0] = '\0';
++	stat_buf[1] = '\0';
++	INFOBIT(TIOCM_RTS, "|RTS");
++	STATBIT(TIOCM_CTS, "|CTS");
++	INFOBIT(TIOCM_DTR, "|DTR");
++	STATBIT(TIOCM_DSR, "|DSR");
++	STATBIT(TIOCM_CAR, "|CD");
++	STATBIT(TIOCM_RNG, "|RI");
++	if (stat_buf[0])
++		stat_buf[0] = ' ';
++	strcat(stat_buf, "\n");
++
++	ret += sprintf(buf + ret, stat_buf);
++	return ret;
++}
++
++static int uart_read_proc(char *page, char **start, off_t off,
++			  int count, int *eof, void *data)
++{
++	struct tty_driver *ttydrv = data;
++	struct uart_driver *drv = ttydrv->driver_state;
++	int i, len = 0, l;
++	off_t begin = 0;
++
++	len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n",
++			"", "", "");
++	for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) {
++		l = uart_line_info(page + len, drv, i);
++		len += l;
++		if (len + begin > off + count)
++			goto done;
++		if (len + begin < off) {
++			begin += len;
++			len = 0;
++		}
++	}
++	*eof = 1;
++ done:
++	if (off >= len + begin)
++		return 0;
++	*start = page + (off - begin);
++	return (count < begin + len - off) ? count : (begin + len - off);
++}
++#endif
++
++#ifdef CONFIG_SERIAL_CORE_CONSOLE
++/*
++ *	Check whether an invalid uart number has been specified, and
++ *	if so, search for the first available port that does have
++ *	console support.
++ */
++struct uart_port * __init
++uart_get_console(struct uart_port *ports, int nr, struct console *co)
++{
++	int idx = co->index;
++
++	if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 &&
++				     ports[idx].membase == NULL))
++		for (idx = 0; idx < nr; idx++)
++			if (ports[idx].iobase != 0 ||
++			    ports[idx].membase != NULL)
++				break;
++
++	co->index = idx;
++
++	return ports + idx;
++}
++
++/**
++ *	uart_parse_options - Parse serial port baud/parity/bits/flow contro.
++ *	@options: pointer to option string
++ *	@baud: pointer to an 'int' variable for the baud rate.
++ *	@parity: pointer to an 'int' variable for the parity.
++ *	@bits: pointer to an 'int' variable for the number of data bits.
++ *	@flow: pointer to an 'int' variable for the flow control character.
++ *
++ *	uart_parse_options decodes a string containing the serial console
++ *	options.  The format of the string is <baud><parity><bits><flow>,
++ *	eg: 115200n8r
++ */
++void __init
++uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow)
++{
++	char *s = options;
++
++	*baud = simple_strtoul(s, NULL, 10);
++	while (*s >= '0' && *s <= '9')
++		s++;
++	if (*s)
++		*parity = *s++;
++	if (*s)
++		*bits = *s++ - '0';
++	if (*s)
++		*flow = *s;
++}
++
++struct baud_rates {
++	unsigned int rate;
++	unsigned int cflag;
++};
++
++static struct baud_rates baud_rates[] = {
++	{ 921600, B921600 },
++	{ 460800, B460800 },
++	{ 230400, B230400 },
++	{ 115200, B115200 },
++	{  57600, B57600  },
++	{  38400, B38400  },
++	{  19200, B19200  },
++	{   9600, B9600   },
++	{   4800, B4800   },
++	{   2400, B2400   },
++	{   1200, B1200   },
++	{      0, B38400  }
++};
++
++/**
++ *	uart_set_options - setup the serial console parameters
++ *	@port: pointer to the serial ports uart_port structure
++ *	@co: console pointer
++ *	@baud: baud rate
++ *	@parity: parity character - 'n' (none), 'o' (odd), 'e' (even)
++ *	@bits: number of data bits
++ *	@flow: flow control character - 'r' (rts)
++ */
++int __init
++uart_set_options(struct uart_port *port, struct console *co,
++		 int baud, int parity, int bits, int flow)
++{
++	struct termios termios;
++	unsigned int quot;
++	int i;
++
++	memset(&termios, 0, sizeof(struct termios));
++
++	termios.c_cflag = CREAD | HUPCL | CLOCAL;
++
++	/*
++	 * Construct a cflag setting.
++	 */
++	for (i = 0; baud_rates[i].rate; i++)
++		if (baud_rates[i].rate <= baud)
++			break;
++
++	termios.c_cflag |= baud_rates[i].cflag;
++	baud = baud_rates[i].rate;
++	if (baud == 0)
++		baud = 38400;
++
++	if (bits == 7)
++		termios.c_cflag |= CS7;
++	else
++		termios.c_cflag |= CS8;
++
++	switch (parity) {
++	case 'o': case 'O':
++		termios.c_cflag |= PARODD;
++		/*fall through*/
++	case 'e': case 'E':
++		termios.c_cflag |= PARENB;
++		break;
++	}
++
++	if (flow == 'r')
++		termios.c_cflag |= CRTSCTS;
++
++	quot = (port->uartclk / (16 * baud));
++	port->ops->change_speed(port, termios.c_cflag, 0, quot);
++	co->cflag = termios.c_cflag;
++
++	return 0;
++}
++
++extern void ambauart_console_init(void);
++extern void anakin_console_init(void);
++extern void clps711xuart_console_init(void);
++extern void sa1100_rs_console_init(void);
++extern void serial8250_console_init(void);
++extern void at91_console_init(void);
++
++/*
++ * Central "initialise all serial consoles" container.  Needs to be killed.
++ */
++void __init uart_console_init(void)
++{
++#ifdef CONFIG_SERIAL_AMBA_CONSOLE
++	ambauart_console_init();
++#endif
++#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE
++	anakin_console_init();
++#endif
++#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
++	clps711xuart_console_init();
++#endif
++#ifdef CONFIG_SERIAL_SA1100_CONSOLE
++	sa1100_rs_console_init();
++#endif
++#ifdef CONFIG_SERIAL_AT91_CONSOLE
++	at91_console_init();
++#endif
++#ifdef CONFIG_SERIAL_8250_CONSOLE
++	serial8250_console_init();
++#endif
++#ifdef CONFIG_SERIAL_UART00_CONSOLE
++	uart00_console_init();
++#endif
++}
++#endif /* CONFIG_SERIAL_CORE_CONSOLE */
++
++static void uart_change_pm(struct uart_state *state, int pm_state)
++{
++	struct uart_port *port = state->port;
++	if (port->ops->pm)
++		port->ops->pm(port, pm_state, 0);
++}
++
++#ifdef CONFIG_PM
++int uart_suspend_port(struct uart_state *state)
++{
++	struct uart_port *port = state->port;
++
++	down(&state->sem);
++	if (port) {
++		/*
++		 * Disable the console device before suspending.
++		 */
++		if (uart_console(port))
++			port->cons->flags &= ~CON_ENABLED;
++
++		if (state->info && state->info->flags & UIF_INITIALIZED) {
++			struct uart_ops *ops = port->ops;
++
++			spin_lock_irq(&port->lock);
++			ops->stop_tx(port, 0);
++			ops->set_mctrl(port, 0);
++			ops->stop_rx(port);
++			spin_unlock_irq(&port->lock);
++
++			/*
++			 * Wait for the transmitter to empty.
++			 */
++			while (!ops->tx_empty(port)) {
++				set_current_state(TASK_UNINTERRUPTIBLE);
++				schedule_timeout(10*HZ/1000);
++			}
++			set_current_state(TASK_RUNNING);
++
++			ops->shutdown(port);
++		}
++
++		uart_change_pm(state, 3);
++	}
++
++	up(&state->sem);
++
++	return 0;
++}
++
++int uart_resume_port(struct uart_state *state)
++{
++	struct uart_port *port = state->port;
++
++	down(&state->sem);
++	if (port) {
++		uart_change_pm(state, 0);
++
++		/*
++		 * Re-enable the console device after suspending.
++		 */
++		if (uart_console(port)) {
++			uart_change_speed(state, NULL);
++			port->cons->flags |= CON_ENABLED;
++		}
++
++		if (state->info && state->info->flags & UIF_INITIALIZED) {
++			struct uart_ops *ops = port->ops;
++
++			ops->set_mctrl(port, 0);
++			ops->startup(port);
++			uart_change_speed(state, NULL);
++			spin_lock_irq(&port->lock);
++			ops->set_mctrl(port, port->mctrl);
++			ops->start_tx(port, 0);
++			spin_unlock_irq(&port->lock);
++		}
++	}
++
++	up(&state->sem);
++
++	return 0;
++}
++
++/*
++ *  Wakeup support.
++ */
++static int uart_pm_set_wakeup(struct uart_state *state, int data)
++{
++	int err = 0;
++
++	if (state->port->ops->set_wake)
++		err = state->port->ops->set_wake(state->port, data);
++
++	return err;
++}
++
++static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++	struct uart_state *state = dev->data;
++	int err = 0;
++
++	if (state->port && state->port->type == PORT_UNKNOWN)
++		return 0;
++
++	switch (rqst) {
++	case PM_SUSPEND:
++		err = uart_suspend_port(state);
++		break;
++
++	case PM_RESUME:
++		err = uart_resume_port(state);
++		break;
++
++	case PM_SET_WAKEUP:
++		err = uart_pm_set_wakeup(state, (int)data);
++		break;
++	}
++	return err;
++}
++#endif
++
++static inline void
++uart_report_port(struct uart_driver *drv, struct uart_port *port)
++{
++	printk("%s%d at ", drv->normal_name, port->line);
++	switch (port->iotype) {
++	case UPIO_PORT:
++		printk("I/O 0x%x", port->iobase);
++		break;
++	case UPIO_HUB6:
++		printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6);
++		break;
++	case UPIO_MEM:
++		printk("MMIO 0x%lx", port->mapbase);
++		break;
++	}
++	printk(" (irq = %d) is a %s\n", port->irq, uart_type(port));
++}
++
++static void
++uart_configure_port(struct uart_driver *drv, struct uart_state *state,
++		    struct uart_port *port)
++{
++	unsigned int flags;
++
++	/*
++	 * If there isn't a port here, don't do anything further.
++	 */
++	if (!port->iobase && !port->mapbase && !port->membase)
++		return;
++
++	/*
++	 * Now do the auto configuration stuff.  Note that config_port
++	 * is expected to claim the resources and map the port for us.
++	 */
++	flags = UART_CONFIG_TYPE;
++	if (port->flags & UPF_AUTO_IRQ)
++		flags |= UART_CONFIG_IRQ;
++	if (port->flags & UPF_BOOT_AUTOCONF) {
++		port->type = PORT_UNKNOWN;
++		port->ops->config_port(port, flags);
++	}
++
++	if (port->type != PORT_UNKNOWN) {
++		unsigned long flags;
++
++		uart_report_port(drv, port);
++
++		/*
++		 * Ensure that the modem control lines are de-activated.
++		 * We probably don't need a spinlock around this, but
++		 */
++		spin_lock_irqsave(&port->lock, flags);
++		port->ops->set_mctrl(port, 0);
++		spin_unlock_irqrestore(&port->lock, flags);
++
++		/*
++		 * Power down all ports by default, except the
++		 * console if we have one.
++		 */
++		if (!uart_console(port))
++			uart_change_pm(state, 3);
++	}
++}
++
++/*
++ * This reverses the effects of uart_configure_port, hanging up the
++ * port before removal.
++ */
++static void
++uart_unconfigure_port(struct uart_driver *drv, struct uart_state *state)
++{
++	struct uart_port *port = state->port;
++	struct uart_info *info = state->info;
++
++	if (info && info->tty)
++		tty_vhangup(info->tty);
++
++	down(&state->sem);
++
++	state->info = NULL;
++
++	/*
++	 * Free the port IO and memory resources, if any.
++	 */
++	if (port->type != PORT_UNKNOWN)
++		port->ops->release_port(port);
++
++	/*
++	 * Indicate that there isn't a port here anymore.
++	 */
++	port->type = PORT_UNKNOWN;
++
++	/*
++	 * Kill the tasklet, and free resources.
++	 */
++	if (info) {
++		tasklet_kill(&info->tlet);
++		kfree(info);
++	}
++
++	up(&state->sem);
++}
++
++/**
++ *	uart_register_driver - register a driver with the uart core layer
++ *	@drv: low level driver structure
++ *
++ *	Register a uart driver with the core driver.  We in turn register
++ *	with the tty layer, and initialise the core driver per-port state.
++ *
++ *	We have a proc file in /proc/tty/driver which is named after the
++ *	normal driver.
++ *
++ *	drv->port should be NULL, and the per-port structures should be
++ *	registered using uart_add_one_port after this call has succeeded.
++ */
++int uart_register_driver(struct uart_driver *drv)
++{
++	struct tty_driver *normal, *callout;
++	int i, retval;
++
++	BUG_ON(drv->state);
++
++	/*
++	 * Maybe we should be using a slab cache for this, especially if
++	 * we have a large number of ports to handle.  Note that we also
++	 * allocate space for an integer for reference counting.
++	 */
++	drv->state = kmalloc(sizeof(struct uart_state) * drv->nr +
++			     sizeof(int), GFP_KERNEL);
++	retval = -ENOMEM;
++	if (!drv->state)
++		goto out;
++
++	memset(drv->state, 0, sizeof(struct uart_state) * drv->nr +
++			sizeof(int));
++
++	normal  = drv->normal_driver;
++	callout = drv->callout_driver;
++
++	normal->magic		= TTY_DRIVER_MAGIC;
++	normal->driver_name	= drv->normal_name;
++	normal->name		= drv->normal_name;
++	normal->major		= drv->normal_major;
++	normal->minor_start	= drv->minor;
++	normal->num		= drv->nr;
++	normal->type		= TTY_DRIVER_TYPE_SERIAL;
++	normal->subtype		= SERIAL_TYPE_NORMAL;
++	normal->init_termios	= tty_std_termios;
++	normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++	normal->flags		= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
++	normal->refcount	= (int *)(drv->state + drv->nr);
++	normal->table		= drv->table;
++	normal->termios		= drv->termios;
++	normal->termios_locked	= drv->termios_locked;
++	normal->driver_state    = drv;
++
++	normal->open		= uart_open;
++	normal->close		= uart_close;
++	normal->write		= uart_write;
++	normal->put_char	= uart_put_char;
++	normal->flush_chars	= uart_flush_chars;
++	normal->write_room	= uart_write_room;
++	normal->chars_in_buffer	= uart_chars_in_buffer;
++	normal->flush_buffer	= uart_flush_buffer;
++	normal->ioctl		= uart_ioctl;
++	normal->throttle	= uart_throttle;
++	normal->unthrottle	= uart_unthrottle;
++	normal->send_xchar	= uart_send_xchar;
++	normal->set_termios	= uart_set_termios;
++	normal->stop		= uart_stop;
++	normal->start		= uart_start;
++	normal->hangup		= uart_hangup;
++	normal->break_ctl	= uart_break_ctl;
++	normal->wait_until_sent	= uart_wait_until_sent;
++#ifdef CONFIG_PROC_FS
++	normal->read_proc	= uart_read_proc;
++#endif
++
++	/*
++	 * The callout device is just like the normal device except for
++	 * the major number and the subtype code.
++	 */
++	*callout		= *normal;
++	callout->name		= drv->callout_name;
++	callout->major		= drv->callout_major;
++	callout->subtype	= SERIAL_TYPE_CALLOUT;
++	callout->read_proc	= NULL;
++	callout->proc_entry	= NULL;
++
++	/*
++	 * Initialise the UART state(s).
++	 */
++	for (i = 0; i < drv->nr; i++) {
++		struct uart_state *state = drv->state + i;
++
++		state->callout_termios = callout->init_termios;
++		state->normal_termios  = normal->init_termios;
++		state->close_delay     = 5 * HZ / 10;
++		state->closing_wait    = 30 * HZ;
++
++		init_MUTEX(&state->sem);
++	}
++
++	retval = tty_register_driver(normal);
++	if (retval)
++		goto out;
++
++	retval = tty_register_driver(callout);
++	if (retval)
++		tty_unregister_driver(normal);
++
++ out:
++	if (retval < 0) {
++		kfree(drv->state);
++	}
++	return retval;
++}
++
++/**
++ *	uart_unregister_driver - remove a driver from the uart core layer
++ *	@drv: low level driver structure
++ *
++ *	Remove all references to a driver from the core driver.  The low
++ *	level driver must have removed all its ports via the
++ *	uart_remove_one_port() if it registered them with uart_add_one_port().
++ *	(ie, drv->port == NULL)
++ */
++void uart_unregister_driver(struct uart_driver *drv)
++{
++	tty_unregister_driver(drv->normal_driver);
++	tty_unregister_driver(drv->callout_driver);
++
++	kfree(drv->state);
++	drv->state = NULL;
++}
++
++/**
++ *	uart_add_one_port - attach a driver-defined port structure
++ *	@drv: pointer to the uart low level driver structure for this port
++ *	@port: uart port structure to use for this port.
++ *
++ *	This allows the driver to register its own uart_port structure
++ *	with the core driver.  The main purpose is to allow the low
++ *	level uart drivers to expand uart_port, rather than having yet
++ *	more levels of structures.
++ */
++int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
++{
++	struct uart_state *state;
++	int ret = 0;
++
++	BUG_ON(in_interrupt());
++
++	if (port->line >= drv->nr)
++		return -EINVAL;
++
++	state = drv->state + port->line;
++
++	down(&port_sem);
++	if (state->port) {
++		ret = -EINVAL;
++		goto out;
++	}
++
++	state->port = port;
++
++	spin_lock_init(&port->lock);
++	port->cons = drv->cons;
++	port->info = state->info;
++
++	uart_configure_port(drv, state, port);
++
++	/*
++	 * Register the port whether it's detected or not.  This allows
++	 * setserial to be used to alter this ports parameters.
++	 */
++	tty_register_devfs(drv->normal_driver, 0, drv->minor + port->line);
++	tty_register_devfs(drv->callout_driver, 0, drv->minor + port->line);
++
++#ifdef CONFIG_PM
++	port->cons = drv->cons;
++	state->pm = pm_register(PM_SYS_DEV, PM_SYS_COM, uart_pm);
++	if (state->pm)
++		state->pm->data = state;
++#endif
++
++ out:
++	up(&port_sem);
++
++	return ret;
++}
++
++/**
++ *	uart_remove_one_port - detach a driver defined port structure
++ *	@drv: pointer to the uart low level driver structure for this port
++ *	@port: uart port structure for this port
++ *
++ *	This unhooks (and hangs up) the specified port structure from the
++ *	core driver.  No further calls will be made to the low-level code
++ *	for this port.
++ */
++int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
++{
++	struct uart_state *state = drv->state + port->line;
++
++	BUG_ON(in_interrupt());
++
++	if (state->port != port)
++		printk(KERN_ALERT "Removing wrong port: %p != %p\n",
++			state->port, port);
++
++	down(&port_sem);
++
++	pm_unregister(state->pm);
++
++	/*
++	 * Remove the devices from devfs
++	 */
++	tty_unregister_devfs(drv->normal_driver, drv->minor + port->line);
++	tty_unregister_devfs(drv->callout_driver, drv->minor + port->line);
++
++	uart_unconfigure_port(drv, state);
++	state->port = NULL;
++	up(&port_sem);
++
++	return 0;
++}
++
++/*
++ *	Are the two ports equivalent?
++ */
++static int uart_match_port(struct uart_port *port1, struct uart_port *port2)
++{
++	if (port1->iotype != port2->iotype)
++		return 0;
++
++	switch (port1->iotype) {
++	case UPIO_PORT:
++		return (port1->iobase == port2->iobase);
++	case UPIO_HUB6:
++		return (port1->iobase == port2->iobase) &&
++		       (port1->hub6   == port2->hub6);
++	case UPIO_MEM:
++		return (port1->membase == port2->membase);
++	}
++	return 0;
++}
++
++/*
++ *	Try to find an unused uart_state slot for a port.
++ */
++static struct uart_state *
++uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port)
++{
++	int i;
++
++	/*
++	 * First, find a port entry which matches.  Note: if we do
++	 * find a matching entry, and it has a non-zero use count,
++	 * then we can't register the port.
++	 */
++	for (i = 0; i < drv->nr; i++)
++		if (uart_match_port(drv->state[i].port, port))
++			return &drv->state[i];
++
++	/*
++	 * We didn't find a matching entry, so look for the first
++	 * free entry.  We look for one which hasn't been previously
++	 * used (indicated by zero iobase).
++	 */
++	for (i = 0; i < drv->nr; i++)
++		if (drv->state[i].port->type == PORT_UNKNOWN &&
++		    drv->state[i].port->iobase == 0 &&
++		    drv->state[i].count == 0)
++			return &drv->state[i];
++
++	/*
++	 * That also failed.  Last resort is to find any currently
++	 * entry which doesn't have a real port associated with it.
++	 */
++	for (i = 0; i < drv->nr; i++)
++		if (drv->state[i].port->type == PORT_UNKNOWN &&
++		    drv->state[i].count == 0)
++			return &drv->state[i];
++
++	return NULL;
++}
++
++/**
++ *	uart_register_port: register uart settings with a port
++ *	@drv: pointer to the uart low level driver structure for this port
++ *	@port: uart port structure describing the port
++ *
++ *	Register UART settings with the specified low level driver.  Detect
++ *	the type of the port if UPF_BOOT_AUTOCONF is set, and detect the
++ *	IRQ if UPF_AUTO_IRQ is set.
++ *
++ *	We try to pick the same port for the same IO base address, so that
++ *	when a modem is plugged in, unplugged and plugged back in, it gets
++ *	allocated the same port.
++ *
++ *	Returns negative error, or positive line number.
++ */
++int uart_register_port(struct uart_driver *drv, struct uart_port *port)
++{
++	struct uart_state *state;
++	int ret;
++
++	down(&port_sem);
++
++	state = uart_find_match_or_unused(drv, port);
++
++	if (state) {
++		/*
++		 * Ok, we've found a line that we can use.
++		 *
++		 * If we find a port that matches this one, and it appears
++		 * to be in-use (even if it doesn't have a type) we shouldn't
++		 * alter it underneath itself - the port may be open and
++		 * trying to do useful work.
++		 */
++		if (uart_users(state) != 0) {
++			ret = -EBUSY;
++			goto out;
++		}
++
++		/*
++		 * If the port is already initialised, don't touch it.
++		 */
++		if (state->port->type == PORT_UNKNOWN) {
++			state->port->iobase   = port->iobase;
++			state->port->membase  = port->membase;
++			state->port->irq      = port->irq;
++			state->port->uartclk  = port->uartclk;
++			state->port->fifosize = port->fifosize;
++			state->port->regshift = port->regshift;
++			state->port->iotype   = port->iotype;
++			state->port->flags    = port->flags;
++			state->port->line     = state - drv->state;
++			state->port->mapbase  = port->mapbase;
++
++			uart_configure_port(drv, state, state->port);
++		}
++
++		ret = state->port->line;
++	} else
++		ret = -ENOSPC;
++ out:
++	up(&port_sem);
++	return ret;
++}
++
++/**
++ *	uart_unregister_port - de-allocate a port
++ *	@drv: pointer to the uart low level driver structure for this port
++ *	@line: line index previously returned from uart_register_port()
++ *
++ *	Hang up the specified line associated with the low level driver,
++ *	and mark the port as unused.
++ */
++void uart_unregister_port(struct uart_driver *drv, int line)
++{
++	struct uart_state *state;
++
++	if (line < 0 || line >= drv->nr) {
++		printk(KERN_ERR "Attempt to unregister %s%d\n",
++			drv->normal_name, line);
++		return;
++	}
++
++	state = drv->state + line;
++
++	down(&port_sem);
++	uart_unconfigure_port(drv, state);
++	up(&port_sem);
++}
++
++EXPORT_SYMBOL(uart_write_wakeup);
++EXPORT_SYMBOL(uart_register_driver);
++EXPORT_SYMBOL(uart_unregister_driver);
++EXPORT_SYMBOL(uart_register_port);
++EXPORT_SYMBOL(uart_unregister_port);
++EXPORT_SYMBOL(uart_add_one_port);
++EXPORT_SYMBOL(uart_remove_one_port);
++
++MODULE_DESCRIPTION("Serial driver core");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/omaha.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,584 @@
++/*
++ *  linux/drivers/char/omaha.c
++ *
++ *  Driver for Omaha serial port
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright 1999-2002 ARM Limited
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id$
++ *
++ * This is a generic driver for ARM AMBA-type serial ports.  They
++ * have a lot of 16550-like features, but are not register compatable.
++ * Note that although they do have CTS, DCD and DSR inputs, they do
++ * not have an RI input, nor do they have DTR or RTS outputs.  If
++ * required, these have to be supplied via some other means (eg, GPIO)
++ * and hooked into this driver.
++ */
++  
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/circ_buf.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++
++#if defined(CONFIG_SERIAL_OMAHA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++
++#include <asm/hardware/serial_omaha.h>
++
++#define UART_NR		1
++
++#define SERIAL_OMAHA_MAJOR	204
++#define SERIAL_OMAHA_MINOR	32
++#define SERIAL_OMAHA_NR		UART_NR
++
++#define CALLOUT_OMAHA_NAME	"cuaom"
++#define CALLOUT_OMAHA_MAJOR	205
++#define CALLOUT_OMAHA_MINOR	32
++#define CALLOUT_OMAHA_NR	UART_NR
++
++static struct tty_driver normal, callout;
++static struct tty_struct *omaha_table[UART_NR];
++static struct termios *omaha_termios[UART_NR], *omaha_termios_locked[UART_NR];
++#ifdef SUPPORT_SYSRQ
++static struct console omaha_console;
++#endif
++
++#define OMAHA_ISR_PASS_LIMIT	256
++
++/*
++ * Access macros for the Omaha UARTs
++ */
++
++#define UART_GET_FR(p)		readb((p)->membase + OMAHA_UTRSTAT)
++#define UART_GET_CHAR(p)    	readb((p)->membase + OMAHA_URXH)
++#define UART_PUT_CHAR(p, c)	writel((c), (p)->membase + OMAHA_UTXH)
++#define UART_GET_RSR(p)		readb((p)->membase + OMAHA_UERSTAT)
++#define UART_FIFO_STATUS(p)	(readl((p)->membase + OMAHA_UFSTAT))
++#define UART_RX_DATA(s)		(((s) & OMAHA_RXFF_CNT) != 0)
++#define UART_TX_DATA(s)		(!((s) & OMAHA_TXFF))
++#define UART_TX_READY(s)	(((s) & OMAHA_UTX_EMPTY))
++#define UART_TX_EMPTY(p)	((UART_GET_FR(p) & OMAHA_UTXEMPTY) != 0)
++				      
++#define UART_DUMMY_RSR_RX	256
++#define UART_PORT_SIZE		64
++
++#define RX_IRQ(port)		((port)->irq)
++#define TX_IRQ(port)		((port)->irq + 5)
++
++/*
++ * Our private driver data mappings.
++ */
++#define drv_old_status	driver_priv
++
++static void omahauart_stop_tx(struct uart_port *port, u_int from_tty)
++{
++	disable_irq(TX_IRQ(port));
++}
++
++static void omahauart_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
++{
++	if (nonempty)
++		enable_irq(TX_IRQ(port));
++}
++
++static void omahauart_stop_rx(struct uart_port *port)
++{
++	disable_irq(RX_IRQ(port));
++}
++
++static void omahauart_enable_ms(struct uart_port *port)
++{
++	// Do nothing...
++}
++
++static void
++#ifdef SUPPORT_SYSRQ
++omahauart_rx_chars(struct uart_info *info, struct pt_regs *regs)
++#else
++omahauart_rx_chars(struct uart_info *info)
++#endif
++{
++	struct tty_struct *tty = info->tty;
++	volatile unsigned int status, data, ch, rsr, max_count = 256;
++	struct uart_port *port = info->port;
++
++	status = UART_FIFO_STATUS(port);
++	while (UART_RX_DATA(status) && max_count--) {
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
++			tty->flip.tqueue.routine((void *)tty);
++			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
++				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
++				return;
++			}
++		}
++
++		ch = UART_GET_CHAR(port);
++
++		*tty->flip.char_buf_ptr = ch;
++		*tty->flip.flag_buf_ptr = TTY_NORMAL;
++		port->icount.rx++;
++
++		/*
++		 * Note that the error handling code is
++		 * out of the main execution path
++		 */
++		rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
++		if (rsr & 0xf) {
++			if (rsr & OMAHA_UART_BREAK) {
++				rsr &= ~(OMAHA_UART_FRAME | OMAHA_UART_PARITY);
++				port->icount.brk++;
++				if (uart_handle_break(info, &omaha_console))
++					goto ignore_char;
++			} else if (rsr & OMAHA_UART_PARITY)
++				port->icount.parity++;
++			else if (rsr & OMAHA_UART_FRAME)
++				port->icount.frame++;
++			if (rsr & OMAHA_UART_OVERRUN)
++				port->icount.overrun++;
++
++			rsr &= port->read_status_mask;
++
++			if (rsr & OMAHA_UART_BREAK)
++				*tty->flip.flag_buf_ptr = TTY_BREAK;
++			else if (rsr & OMAHA_UART_PARITY)
++				*tty->flip.flag_buf_ptr = TTY_PARITY;
++			else if (rsr & OMAHA_UART_FRAME)
++				*tty->flip.flag_buf_ptr = TTY_FRAME;
++		}
++
++		if (uart_handle_sysrq_char(info, ch, regs))
++			goto ignore_char;
++
++		if ((rsr & port->ignore_status_mask) == 0) {
++			tty->flip.flag_buf_ptr++;
++			tty->flip.char_buf_ptr++;
++			tty->flip.count++;
++		}
++		if ((rsr & OMAHA_UART_OVERRUN) &&
++		    tty->flip.count < TTY_FLIPBUF_SIZE) {
++			/*
++			 * Overrun is special, since it's reported
++			 * immediately, and doesn't affect the current
++			 * character
++			 */
++			*tty->flip.char_buf_ptr++ = 0;
++			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
++			tty->flip.count++;
++		}
++	ignore_char:
++		status = UART_FIFO_STATUS(port);
++	}
++	tty_flip_buffer_push(tty);
++	return;
++}
++
++static void omahauart_tx_chars(struct uart_info *info)
++{
++	struct uart_port *port = info->port;
++	volatile unsigned int status;
++
++	if (port->x_char) {
++		UART_PUT_CHAR(port, port->x_char);
++		port->icount.tx++;
++		port->x_char = 0;
++		return;
++	}
++	if (info->xmit.head == info->xmit.tail
++	    || info->tty->stopped
++	    || info->tty->hw_stopped) {
++		omahauart_stop_tx(port, 0);
++		return;
++	}
++
++	status = UART_FIFO_STATUS(info->port);
++	
++	// FIll FIFO as far as possible
++	while(UART_TX_DATA(UART_FIFO_STATUS(info->port)))
++	{
++		UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
++		info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
++		port->icount.tx++;
++		if (info->xmit.head == info->xmit.tail)
++			break;
++	}
++
++	if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) <
++			WAKEUP_CHARS)
++		uart_event(info, EVT_WRITE_WAKEUP);
++
++	if (info->xmit.head == info->xmit.tail)
++		omahauart_stop_tx(info->port, 0);
++}
++
++static void omahauart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct uart_info *info = dev_id;
++	volatile unsigned int status, pass_counter = OMAHA_ISR_PASS_LIMIT;
++
++	status = UART_FIFO_STATUS(info->port);
++	do {
++		// TX if FIFO not full
++		if (UART_TX_DATA(status))
++			omahauart_tx_chars(info);
++		
++		if (pass_counter-- == 0)
++			break;
++
++		status = UART_FIFO_STATUS(info->port);
++	} while (UART_TX_DATA(status));
++}
++
++static void omahauart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct uart_info *info = dev_id;
++	volatile unsigned int status, pass_counter = OMAHA_ISR_PASS_LIMIT;
++
++	status = UART_FIFO_STATUS(info->port);
++	do {
++		if (UART_RX_DATA(status))
++#ifdef SUPPORT_SYSRQ
++			omahauart_rx_chars(info, regs);
++#else
++			omahauart_rx_chars(info);
++#endif
++		
++		if (pass_counter-- == 0)
++			break;
++
++		status = UART_FIFO_STATUS(info->port);
++	} while (UART_RX_DATA(status));
++}
++
++static u_int omahauart_tx_empty(struct uart_port *port)
++{
++	return UART_FIFO_STATUS(port) ? 0 : TIOCSER_TEMT;
++}
++
++static int omahauart_get_mctrl(struct uart_port *port)
++{
++	// Report no errors.
++
++	return 0;
++}
++
++static void omahauart_set_mctrl(struct uart_port *port, u_int mctrl)
++{
++	// Do nothing.
++}
++
++static void omahauart_break_ctl(struct uart_port *port, int break_state)
++{
++	// Do nothing.
++}
++
++static int omahauart_startup(struct uart_port *port, struct uart_info *info)
++{
++	unsigned int tmp;
++	int retval;
++
++	/*
++	 * Allocate the IRQs
++	 */
++	retval = request_irq(TX_IRQ(port), omahauart_int_tx, 0, "omaha_uart_tx", info);
++	if (retval)
++		return retval;
++
++	retval = request_irq(RX_IRQ(port), omahauart_int_rx, 0, "omaha_uart_rx", info);
++	
++	if (retval)
++	{
++		free_irq(TX_IRQ(port), info);
++		return retval;
++	}
++	
++	/*
++	 * initialise the old status of the modem signals
++	 */
++	info->drv_old_status = 0;
++
++	// Clear all errors
++	writel(0, port->membase + OMAHA_UERSTAT);
++	
++	// Enable FIFO, 16-byte watermark, also do reset (auto-clearing)
++	writel(0xF7, port->membase + OMAHA_UFCON);
++
++	// Level driven TX/RX ints, with rx timeout enabled
++	tmp = readl(port->membase + OMAHA_UCON);
++	tmp |= 0x280; // rx is pulse driven...
++	writel(tmp, port->membase + OMAHA_UCON);
++
++	return 0;
++}
++
++static void omahauart_shutdown(struct uart_port *port, struct uart_info *info)
++{
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(TX_IRQ(port), info);	/* TX interrupt */
++	free_irq(RX_IRQ(port), info);	/* RX interrupt */
++
++}
++
++static void omahauart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
++{
++	// Do nothing.
++}
++
++static const char *omahauart_type(struct uart_port *port)
++{
++	return port->type == PORT_OMAHA ? "OMAHA" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'
++ */
++static void omahauart_release_port(struct uart_port *port)
++{
++	release_mem_region(port->mapbase, UART_PORT_SIZE);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'
++ */
++static int omahauart_request_port(struct uart_port *port)
++{
++	return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_omaha")
++			!= NULL ? 0 : -EBUSY;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void omahauart_config_port(struct uart_port *port, int flags)
++{
++	if (flags & UART_CONFIG_TYPE) {
++		port->type = PORT_OMAHA;
++		omahauart_request_port(port);
++	}
++}
++
++/*
++ * verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int omahauart_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++	int ret = 0;
++	if (ser->type != PORT_UNKNOWN && ser->type != PORT_OMAHA)
++		ret = -EINVAL;
++	if (ser->irq < 0 || ser->irq >= NR_IRQS)
++		ret = -EINVAL;
++	if (ser->baud_base < 9600)
++		ret = -EINVAL;
++	return ret;
++}
++
++static struct uart_ops omaha_pops = {
++	.tx_empty	= omahauart_tx_empty,
++	.set_mctrl	= omahauart_set_mctrl,
++	.get_mctrl	= omahauart_get_mctrl,
++	.stop_tx	= omahauart_stop_tx,
++	.start_tx	= omahauart_start_tx,
++	.stop_rx	= omahauart_stop_rx,
++	.enable_ms	= omahauart_enable_ms,
++	.break_ctl	= omahauart_break_ctl,
++	.startup	= omahauart_startup,
++	.shutdown	= omahauart_shutdown,
++	.change_speed	= omahauart_change_speed,
++	.type		= omahauart_type,
++	.release_port	= omahauart_release_port,
++	.request_port	= omahauart_request_port,
++	.config_port	= omahauart_config_port,
++	.verify_port	= omahauart_verify_port,
++};
++
++static struct uart_port omaha_ports[UART_NR] = {
++	{
++		.membase	= (void *)IO_ADDRESS(OMAHA_UART0_BASE),
++		.mapbase	= OMAHA_UART0_BASE,
++		.iotype		= SERIAL_IO_MEM,
++		.irq		= OMAHA_INT_URXD0,
++		.uartclk	= 10000000,
++		.fifosize	= 8,
++		.unused		= { 4, 5 }, /*Udriver_priv: PORT_CTRLS(5, 4), */
++		.ops		= &omaha_pops,
++		.flags		= ASYNC_BOOT_AUTOCONF,
++	}
++};
++
++#ifdef CONFIG_SERIAL_OMAHA_CONSOLE
++static void omahauart_console_write(struct console *co, const char *s, u_int count)
++{
++	struct uart_port *port = omaha_ports + co->index;
++	unsigned int status;
++	int i;
++
++	/*
++	 *	First save the CR then disable the interrupts
++	 */
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++) {
++		do {
++			status = UART_GET_FR(port);
++		} while ((status & OMAHA_UTX_EMPTY) == 0);
++		UART_PUT_CHAR(port, s[i]);
++		if (s[i] == '\n') {
++			do {
++				status = UART_GET_FR(port);
++			} while ((status & OMAHA_UTX_EMPTY) == 0);
++			UART_PUT_CHAR(port, '\r');
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore the TCR
++	 */
++	do {
++		status = UART_GET_FR(port);
++	} while ((status & OMAHA_UTX_EMPTY) == 0);
++}
++
++static kdev_t omahauart_console_device(struct console *co)
++{
++	return MKDEV(SERIAL_OMAHA_MAJOR, SERIAL_OMAHA_MINOR + co->index);
++}
++
++static int omahauart_console_wait_key(struct console *co)
++{
++	struct uart_port *port = omaha_ports + co->index;
++	unsigned int status;
++
++	do {
++		status = UART_FIFO_STATUS(port);
++	} while (!UART_RX_DATA(status));
++	return UART_GET_CHAR(port);
++}
++
++static void __init
++omahauart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++	// Do nothing.
++}
++
++static int __init omahauart_console_setup(struct console *co, char *options)
++{
++	struct uart_port *port;
++	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.
++	 */
++	port = uart_get_console(omaha_ports, UART_NR, co);
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++	else
++		omahauart_console_get_options(port, &baud, &parity, &bits);
++
++	return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct console omaha_console = {
++	.write		= omahauart_console_write,
++	.device		= omahauart_console_device,
++	.wait_key	= omahauart_console_wait_key,
++	.setup		= omahauart_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++void __init omahauart_console_init(void)
++{
++	register_console(&omaha_console);
++}
++
++#define OMAHA_CONSOLE	&omaha_console
++#else
++#define OMAHA_CONSOLE	NULL
++#endif
++
++static struct uart_driver omaha_reg = {
++	.owner			= THIS_MODULE,
++	.normal_major		= SERIAL_OMAHA_MAJOR,
++#ifdef CONFIG_DEVFS_FS
++	.normal_name		= "ttyOM%d",
++	.callout_name		= "cuaom%d",
++#else
++	.normal_name		= "ttyOM",
++	.callout_name		= "cuaom",
++#endif
++	.normal_driver		= &normal,
++	.callout_major		= CALLOUT_OMAHA_MAJOR,
++	.callout_driver		= &callout,
++	.table			= omaha_table,
++	.termios		= omaha_termios,
++	.termios_locked		= omaha_termios_locked,
++	.minor			= SERIAL_OMAHA_MINOR,
++	.nr			= UART_NR,
++	.port			= omaha_ports,
++	.cons			= OMAHA_CONSOLE,
++};
++
++static int __init omahauart_init(void)
++{
++	return uart_register_driver(&omaha_reg);
++}
++
++static void __exit omahauart_exit(void)
++{
++	uart_unregister_driver(&omaha_reg);
++}
++
++module_init(omahauart_init);
++module_exit(omahauart_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/sa1100.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,904 @@
++/*
++ *  linux/drivers/char/serial_sa1100.c
++ *
++ *  Driver for SA11x0 serial ports
++ *
++ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
++ *
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id$
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/tty.h>
++#include <linux/ioport.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/hardware.h>
++#include <asm/mach/serial_sa1100.h>
++
++#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++
++/* We've been assigned a range on the "Low-density serial ports" major */
++#define SERIAL_SA1100_MAJOR	204
++#define CALLOUT_SA1100_MAJOR	205
++#define MINOR_START		5
++
++#define NR_PORTS		3
++
++#define SA1100_ISR_PASS_LIMIT	256
++
++/*
++ * Convert from ignore_status_mask or read_status_mask to UTSR[01]
++ */
++#define SM_TO_UTSR0(x)	((x) & 0xff)
++#define SM_TO_UTSR1(x)	((x) >> 8)
++#define UTSR0_TO_SM(x)	((x))
++#define UTSR1_TO_SM(x)	((x) << 8)
++
++#define UART_GET_UTCR0(sport)	__raw_readl((sport)->port.membase + UTCR0)
++#define UART_GET_UTCR1(sport)	__raw_readl((sport)->port.membase + UTCR1)
++#define UART_GET_UTCR2(sport)	__raw_readl((sport)->port.membase + UTCR2)
++#define UART_GET_UTCR3(sport)	__raw_readl((sport)->port.membase + UTCR3)
++#define UART_GET_UTSR0(sport)	__raw_readl((sport)->port.membase + UTSR0)
++#define UART_GET_UTSR1(sport)	__raw_readl((sport)->port.membase + UTSR1)
++#define UART_GET_CHAR(sport)	__raw_readl((sport)->port.membase + UTDR)
++
++#define UART_PUT_UTCR0(sport,v)	__raw_writel((v),(sport)->port.membase + UTCR0)
++#define UART_PUT_UTCR1(sport,v)	__raw_writel((v),(sport)->port.membase + UTCR1)
++#define UART_PUT_UTCR2(sport,v)	__raw_writel((v),(sport)->port.membase + UTCR2)
++#define UART_PUT_UTCR3(sport,v)	__raw_writel((v),(sport)->port.membase + UTCR3)
++#define UART_PUT_UTSR0(sport,v)	__raw_writel((v),(sport)->port.membase + UTSR0)
++#define UART_PUT_UTSR1(sport,v)	__raw_writel((v),(sport)->port.membase + UTSR1)
++#define UART_PUT_CHAR(sport,v)	__raw_writel((v),(sport)->port.membase + UTDR)
++
++/*
++ * This is the size of our serial port register set.
++ */
++#define UART_PORT_SIZE	0x24
++
++static struct tty_driver normal, callout;
++static struct tty_struct *sa1100_table[NR_PORTS];
++static struct termios *sa1100_termios[NR_PORTS], *sa1100_termios_locked[NR_PORTS];
++static int (*sa1100_open)(struct uart_port *);
++static void (*sa1100_close)(struct uart_port *);
++#ifdef SUPPORT_SYSRQ
++static struct console sa1100_console;
++#endif
++
++/*
++ * 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)
++
++struct sa1100_port {
++	struct uart_port	port;
++	struct timer_list	timer;
++	unsigned int		old_status;
++};
++
++/*
++ * Handle any change of modem status signal since we were last called.
++ */
++static void sa1100_mctrl_check(struct sa1100_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 sa1100_timeout(unsigned long data)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)data;
++	unsigned long flags;
++
++	if (sport->port.info) {
++		spin_lock_irqsave(&sport->port.lock, flags);
++		sa1100_mctrl_check(sport);
++		spin_unlock_irqrestore(&sport->port.lock, flags);
++
++		mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT);
++	}
++}
++
++/*
++ * interrupts disabled on entry
++ */
++static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++	u32 utcr3;
++
++	utcr3 = UART_GET_UTCR3(sport);
++	UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE);
++	sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS);
++}
++
++/*
++ * interrupts may not be disabled on entry
++ */
++static void sa1100_start_tx(struct uart_port *port, unsigned int tty_start)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++	unsigned long flags;
++	u32 utcr3;
++
++	spin_lock_irqsave(&sport->port.lock, flags);
++	utcr3 = UART_GET_UTCR3(sport);
++	sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS);
++	UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE);
++	spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
++/*
++ * Interrupts enabled
++ */
++static void sa1100_stop_rx(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++	u32 utcr3;
++
++	utcr3 = UART_GET_UTCR3(sport);
++	UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE);
++}
++
++/*
++ * Set the modem control timer to fire immediately.
++ */
++static void sa1100_enable_ms(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++
++	mod_timer(&sport->timer, jiffies);
++}
++
++static void
++sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
++{
++	struct tty_struct *tty = sport->port.info->tty;
++	unsigned int status, ch, flg, ignored = 0;
++
++	status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
++		 UTSR0_TO_SM(UART_GET_UTSR0(sport));
++	while (status & UTSR1_TO_SM(UTSR1_RNE)) {
++		ch = UART_GET_CHAR(sport);
++
++		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 & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR))
++			goto handle_error;
++
++		if (uart_handle_sysrq_char(&sport->port, ch, regs))
++			goto ignore_char;
++
++	error_return:
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++	ignore_char:
++		status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) |
++			 UTSR0_TO_SM(UART_GET_UTSR0(sport));
++	}
++ out:
++	tty_flip_buffer_push(tty);
++	return;
++
++ handle_error:
++	if (status & UTSR1_TO_SM(UTSR1_PRE))
++		sport->port.icount.parity++;
++	else if (status & UTSR1_TO_SM(UTSR1_FRE))
++		sport->port.icount.frame++;
++	if (status & UTSR1_TO_SM(UTSR1_ROR))
++		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 & UTSR1_TO_SM(UTSR1_PRE))
++		flg = TTY_PARITY;
++	else if (status & UTSR1_TO_SM(UTSR1_FRE))
++		flg = TTY_FRAME;
++
++	if (status & UTSR1_TO_SM(UTSR1_ROR)) {
++		/*
++		 * overrun does *not* affect the character
++		 * we read from the FIFO
++		 */
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++		ch = 0;
++		flg = TTY_OVERRUN;
++	}
++#ifdef SUPPORT_SYSRQ
++	sport->port.sysrq = 0;
++#endif
++	goto error_return;
++}
++
++static void sa1100_tx_chars(struct sa1100_port *sport)
++{
++	struct circ_buf *xmit = &sport->port.info->xmit;
++
++	if (sport->port.x_char) {
++		UART_PUT_CHAR(sport, sport->port.x_char);
++		sport->port.icount.tx++;
++		sport->port.x_char = 0;
++		return;
++	}
++
++	/*
++	 * Check the modem control lines before
++	 * transmitting anything.
++	 */
++	sa1100_mctrl_check(sport);
++
++	if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) {
++		sa1100_stop_tx(&sport->port, 0);
++		return;
++	}
++
++	/*
++	 * Tried using FIFO (not checking TNF) for fifo fill:
++	 * still had the '4 bytes repeated' problem.
++	 */
++	while (UART_GET_UTSR1(sport) & UTSR1_TNF) {
++		UART_PUT_CHAR(sport, 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))
++		sa1100_stop_tx(&sport->port, 0);
++}
++
++static void sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct sa1100_port *sport = dev_id;
++	unsigned int status, pass_counter = 0;
++
++	spin_lock(&sport->port.lock);
++	status = UART_GET_UTSR0(sport);
++	status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS;
++	do {
++		if (status & (UTSR0_RFS | UTSR0_RID)) {
++			/* Clear the receiver idle bit, if set */
++			if (status & UTSR0_RID)
++				UART_PUT_UTSR0(sport, UTSR0_RID);
++			sa1100_rx_chars(sport, regs);
++		}
++
++		/* Clear the relevant break bits */
++		if (status & (UTSR0_RBB | UTSR0_REB))
++			UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB));
++
++		if (status & UTSR0_RBB)
++			sport->port.icount.brk++;
++
++		if (status & UTSR0_REB)
++			uart_handle_break(&sport->port);
++
++		if (status & UTSR0_TFS)
++			sa1100_tx_chars(sport);
++		if (pass_counter++ > SA1100_ISR_PASS_LIMIT)
++			break;
++		status = UART_GET_UTSR0(sport);
++		status &= SM_TO_UTSR0(sport->port.read_status_mask) |
++			  ~UTSR0_TFS;
++	} while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
++	spin_unlock(&sport->port.lock);
++}
++
++/*
++ * Return TIOCSER_TEMT when transmitter is not busy.
++ */
++static unsigned int sa1100_tx_empty(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++
++	return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT;
++}
++
++static unsigned int sa1100_get_mctrl(struct uart_port *port)
++{
++	return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
++}
++
++static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl)
++{
++}
++
++/*
++ * Interrupts always disabled.
++ */
++static void sa1100_break_ctl(struct uart_port *port, int break_state)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++	unsigned long flags;
++	unsigned int utcr3;
++
++	spin_lock_irqsave(&sport->port.lock, flags);
++	utcr3 = UART_GET_UTCR3(sport);
++	if (break_state == -1)
++		utcr3 |= UTCR3_BRK;
++	else
++		utcr3 &= ~UTCR3_BRK;
++	UART_PUT_UTCR3(sport, utcr3);
++	spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
++static int sa1100_startup(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++	int retval;
++
++	/*
++	 * Allocate the IRQ
++	 */
++	retval = request_irq(sport->port.irq, sa1100_int, 0,
++			     "sa11x0-uart", sport);
++	if (retval)
++		return retval;
++
++	/*
++	 * If there is a specific "open" function
++	 * (to register control line interrupts)
++	 */
++	if (sa1100_open) {
++		retval = sa1100_open(port);
++		if (retval) {
++			free_irq(sport->port.irq, sport);
++			return retval;
++		}
++	}
++
++	/*
++	 * Finally, clear and enable interrupts
++	 */
++	UART_PUT_UTSR0(sport, -1);
++	UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE);
++
++	return 0;
++}
++
++static void sa1100_shutdown(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++
++	/*
++	 * Stop our timer.
++	 */
++	del_timer_sync(&sport->timer);
++
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(sport->port.irq, sport);
++
++	/*
++	 * If there is a specific "close" function (to unregister
++	 * control line interrupts)
++	 */
++	if (sa1100_close)
++		sa1100_close(port);
++
++	/*
++	 * Disable all interrupts, port and break condition.
++	 */
++	UART_PUT_UTCR3(sport, 0);
++}
++
++static void sa1100_change_speed(struct uart_port *port, unsigned int cflag, unsigned int iflag, unsigned int quot)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++	unsigned long flags;
++	unsigned int utcr0, old_utcr3;
++
++	if ((cflag & CSIZE) == CS8)
++		utcr0 = UTCR0_DSS;
++	else
++		utcr0 = 0;
++
++	if (cflag & CSTOPB)
++		utcr0 |= UTCR0_SBS;
++	if (cflag & PARENB) {
++		utcr0 |= UTCR0_PE;
++		if (!(cflag & PARODD))
++			utcr0 |= UTCR0_OES;
++	}
++
++	spin_lock_irqsave(&sport->port.lock, flags);
++
++	sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS);
++	sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR);
++	if (iflag & INPCK)
++		sport->port.read_status_mask |=
++				UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
++	if (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 (iflag & IGNPAR)
++		sport->port.ignore_status_mask |=
++				UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE);
++	if (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 (iflag & IGNPAR)
++			sport->port.ignore_status_mask |=
++				UTSR1_TO_SM(UTSR1_ROR);
++	}
++
++	del_timer_sync(&sport->timer);
++
++	/*
++	 * disable interrupts and drain transmitter
++	 */
++	old_utcr3 = UART_GET_UTCR3(sport);
++	UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE));
++
++	while (UART_GET_UTSR1(sport) & UTSR1_TBY)
++		barrier();
++
++	/* then, disable everything */
++	UART_PUT_UTCR3(sport, 0);
++
++	/* set the parity, stop bits and data size */
++	UART_PUT_UTCR0(sport, utcr0);
++
++	/* set the baud rate */
++	quot -= 1;
++	UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8));
++	UART_PUT_UTCR2(sport, (quot & 0xff));
++
++	UART_PUT_UTSR0(sport, -1);
++
++	UART_PUT_UTCR3(sport, old_utcr3);
++
++	if (UART_ENABLE_MS(&sport->port, cflag))
++		sa1100_enable_ms(&sport->port);
++
++	spin_unlock_irqrestore(&sport->port.lock, flags);
++}
++
++static const char *sa1100_type(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++
++	return sport->port.type == PORT_SA1100 ? "SA1100" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'.
++ */
++static void sa1100_release_port(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++
++	release_mem_region(sport->port.mapbase, UART_PORT_SIZE);
++}
++
++/*
++ * Request the memory region(s) being used by 'port'.
++ */
++static int sa1100_request_port(struct uart_port *port)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++
++	return request_mem_region(sport->port.mapbase, UART_PORT_SIZE,
++			"sa11x0-uart") != NULL ? 0 : -EBUSY;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void sa1100_config_port(struct uart_port *port, int flags)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++
++	if (flags & UART_CONFIG_TYPE &&
++	    sa1100_request_port(&sport->port) == 0)
++		sport->port.type = PORT_SA1100;
++}
++
++/*
++ * Verify the new serial_struct (for TIOCSSERIAL).
++ * The only change we allow are to the flags and type, and
++ * even then only between PORT_SA1100 and PORT_UNKNOWN
++ */
++static int sa1100_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++	struct sa1100_port *sport = (struct sa1100_port *)port;
++	int ret = 0;
++
++	if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100)
++		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;
++}
++
++static struct uart_ops sa1100_pops = {
++	.tx_empty	= sa1100_tx_empty,
++	.set_mctrl	= sa1100_set_mctrl,
++	.get_mctrl	= sa1100_get_mctrl,
++	.stop_tx	= sa1100_stop_tx,
++	.start_tx	= sa1100_start_tx,
++	.stop_rx	= sa1100_stop_rx,
++	.enable_ms	= sa1100_enable_ms,
++	.break_ctl	= sa1100_break_ctl,
++	.startup	= sa1100_startup,
++	.shutdown	= sa1100_shutdown,
++	.change_speed	= sa1100_change_speed,
++	.type		= sa1100_type,
++	.release_port	= sa1100_release_port,
++	.request_port	= sa1100_request_port,
++	.config_port	= sa1100_config_port,
++	.verify_port	= sa1100_verify_port,
++};
++
++static struct sa1100_port sa1100_ports[NR_PORTS];
++
++/*
++ * Setup the SA1100 serial ports.  Note that we don't include the IrDA
++ * port here since we have our own SIR/FIR driver (see drivers/net/irda)
++ *
++ * Note also that we support "console=ttySAx" where "x" is either 0 or 1.
++ * Which serial port this ends up being depends on the machine you're
++ * running this kernel on.  I'm not convinced that this is a good idea,
++ * but that's the way it traditionally works.
++ *
++ * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer
++ * used here.
++ */
++static void __init sa1100_init_ports(void)
++{
++	static int first = 1;
++	int i;
++
++	if (!first)
++		return;
++	first = 0;
++
++	for (i = 0; i < NR_PORTS; i++) {
++		sa1100_ports[i].port.uartclk   = 3686400;
++		sa1100_ports[i].port.ops       = &sa1100_pops;
++		sa1100_ports[i].port.fifosize  = 8;
++		sa1100_ports[i].port.line      = i;
++		sa1100_ports[i].port.iotype    = SERIAL_IO_MEM;
++		init_timer(&sa1100_ports[i].timer);
++		sa1100_ports[i].timer.function = sa1100_timeout;
++		sa1100_ports[i].timer.data     = (unsigned long)&sa1100_ports[i];
++	}
++
++	/*
++	 * make transmit lines outputs, so that when the port
++	 * is closed, the output is in the MARK state.
++	 */
++	PPDR |= PPC_TXD1 | PPC_TXD3;
++	PPSR |= PPC_TXD1 | PPC_TXD3;
++}
++
++void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns)
++{
++	if (fns->enable_ms)
++		sa1100_pops.enable_ms = fns->enable_ms;
++	if (fns->get_mctrl)
++		sa1100_pops.get_mctrl = fns->get_mctrl;
++	if (fns->set_mctrl)
++		sa1100_pops.set_mctrl = fns->set_mctrl;
++	sa1100_open          = fns->open;
++	sa1100_close         = fns->close;
++	sa1100_pops.pm       = fns->pm;
++	sa1100_pops.set_wake = fns->set_wake;
++}
++
++void __init sa1100_register_uart(int idx, int port)
++{
++	if (idx >= NR_PORTS) {
++		printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx);
++		return;
++	}
++
++	switch (port) {
++	case 1:
++		sa1100_ports[idx].port.membase = (void *)&Ser1UTCR0;
++		sa1100_ports[idx].port.mapbase = _Ser1UTCR0;
++		sa1100_ports[idx].port.irq     = IRQ_Ser1UART;
++		sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
++		break;
++
++	case 2:
++		sa1100_ports[idx].port.membase = (void *)&Ser2UTCR0;
++		sa1100_ports[idx].port.mapbase = _Ser2UTCR0;
++		sa1100_ports[idx].port.irq     = IRQ_Ser2ICP;
++		sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
++		break;
++
++	case 3:
++		sa1100_ports[idx].port.membase = (void *)&Ser3UTCR0;
++		sa1100_ports[idx].port.mapbase = _Ser3UTCR0;
++		sa1100_ports[idx].port.irq     = IRQ_Ser3UART;
++		sa1100_ports[idx].port.flags   = ASYNC_BOOT_AUTOCONF;
++		break;
++
++	default:
++		printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port);
++	}
++}
++
++
++#ifdef CONFIG_SERIAL_SA1100_CONSOLE
++
++/*
++ * Interrupts are disabled on entering
++ */
++static void
++sa1100_console_write(struct console *co, const char *s, unsigned int count)
++{
++	struct sa1100_port *sport = &sa1100_ports[co->index];
++	unsigned int old_utcr3, status, i;
++
++	/*
++	 *	First, save UTCR3 and then disable interrupts
++	 */
++	old_utcr3 = UART_GET_UTCR3(sport);
++	UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) |
++				UTCR3_TXE);
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++) {
++		do {
++			status = UART_GET_UTSR1(sport);
++		} while (!(status & UTSR1_TNF));
++		UART_PUT_CHAR(sport, s[i]);
++		if (s[i] == '\n') {
++			do {
++				status = UART_GET_UTSR1(sport);
++			} while (!(status & UTSR1_TNF));
++			UART_PUT_CHAR(sport, '\r');
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore UTCR3
++	 */
++	do {
++		status = UART_GET_UTSR1(sport);
++	} while (status & UTSR1_TBY);
++	UART_PUT_UTCR3(sport, old_utcr3);
++}
++
++static kdev_t sa1100_console_device(struct console *co)
++{
++	return MKDEV(SERIAL_SA1100_MAJOR, MINOR_START + co->index);
++}
++
++/*
++ * If the port was already initialised (eg, by a boot loader), try to determine
++ * the current setup.
++ */
++static void __init
++sa1100_console_get_options(struct sa1100_port *sport, int *baud,
++			   int *parity, int *bits)
++{
++	unsigned int utcr3;
++
++	utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE);
++	if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) {
++		/* ok, the port was enabled */
++		unsigned int utcr0, quot;
++
++		utcr0 = UART_GET_UTCR0(sport);
++
++		*parity = 'n';
++		if (utcr0 & UTCR0_PE) {
++			if (utcr0 & UTCR0_OES)
++				*parity = 'e';
++			else
++				*parity = 'o';
++		}
++
++		if (utcr0 & UTCR0_DSS)
++			*bits = 8;
++		else
++			*bits = 7;
++
++		quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8;
++		quot &= 0xfff;
++		*baud = sport->port.uartclk / (16 * (quot + 1));
++	}
++}
++
++static int __init
++sa1100_console_setup(struct console *co, char *options)
++{
++	struct sa1100_port *sport;
++	int baud = CONFIG_SA1100_DEFAULT_BAUDRATE;
++	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 = &sa1100_ports[co->index];
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++	else
++		sa1100_console_get_options(sport, &baud, &parity, &bits);
++
++	return uart_set_options(&sport->port, co, baud, parity, bits, flow);
++}
++
++static struct console sa1100_console = {
++	.name		= "ttySA",
++	.write		= sa1100_console_write,
++	.device		= sa1100_console_device,
++	.setup		= sa1100_console_setup,
++	.flags		= CON_PRINTBUFFER,
++	.index		= -1,
++};
++
++void __init sa1100_rs_console_init(void)
++{
++	sa1100_init_ports();
++	register_console(&sa1100_console);
++}
++
++#define SA1100_CONSOLE	&sa1100_console
++#else
++#define SA1100_CONSOLE	NULL
++#endif
++
++static struct uart_driver sa1100_reg = {
++	.owner			= THIS_MODULE,
++	.normal_major		= SERIAL_SA1100_MAJOR,
++#ifdef CONFIG_DEVFS_FS
++	.normal_name		= "ttySA%d",
++	.callout_name		= "cusa%d",
++#else
++	.normal_name		= "ttySA",
++	.callout_name		= "cusa",
++#endif
++	.normal_driver		= &normal,
++	.callout_major		= CALLOUT_SA1100_MAJOR,
++	.callout_driver		= &callout,
++	.table			= sa1100_table,
++	.termios		= sa1100_termios,
++	.termios_locked		= sa1100_termios_locked,
++	.minor			= MINOR_START,
++	.nr			= NR_PORTS,
++	.cons			= SA1100_CONSOLE,
++};
++
++static int __init sa1100_serial_init(void)
++{
++	int i, ret;
++
++	sa1100_init_ports();
++
++	ret = uart_register_driver(&sa1100_reg);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < NR_PORTS; i++)
++		uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port);
++
++	return 0;
++}
++
++static void __exit sa1100_serial_exit(void)
++{
++	int i;
++
++	for (i = 0; i < NR_PORTS; i++)
++		uart_remove_one_port(&sa1100_reg, &sa1100_ports[i].port);
++
++	uart_unregister_driver(&sa1100_reg);
++}
++
++module_init(sa1100_serial_init);
++module_exit(sa1100_serial_exit);
++
++EXPORT_NO_SYMBOLS;
++
++MODULE_AUTHOR("Deep Blue Solutions Ltd");
++MODULE_DESCRIPTION("SA1100 generic serial port driver");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/serial/uart00.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,903 @@
++/*
++ *  linux/drivers/serial/uart00.c
++ *
++ *  Driver for UART00 serial ports
++ *
++ *  Based on drivers/char/serial_amba.c, by ARM Limited & 
++ *                                          Deep Blue Solutions Ltd.
++ *  Copyright 2001 Altera 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
++ *
++ *  $Id$
++ *
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/major.h>
++#include <linux/string.h>
++#include <linux/fcntl.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/circ_buf.h>
++#include <linux/serial.h>
++#include <linux/console.h>
++#include <linux/sysrq.h>
++#include <linux/pld/pld_hotswap.h>
++#include <linux/proc_fs.h>
++
++#include <asm/system.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <asm/bitops.h>
++#include <asm/sizes.h>
++
++#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
++#define SUPPORT_SYSRQ
++#endif
++
++#include <linux/serial_core.h>
++#include <asm/arch/excalibur.h>
++#define UART00_TYPE (volatile unsigned int*)
++#include <asm/arch/uart00.h>
++#include <asm/arch/int_ctrl00.h>
++
++#undef DEBUG
++#define UART_NR		2
++
++#define SERIAL_UART00_NAME	"ttyUA"
++#define SERIAL_UART00_MAJOR	204
++#define SERIAL_UART00_MINOR	16 /* Temporary - will change in future */
++#define SERIAL_UART00_NR	UART_NR
++#define UART_PORT_SIZE 0x50
++
++#define CALLOUT_UART00_NAME	"cuaua"
++#define CALLOUT_UART00_MAJOR	205
++#define CALLOUT_UART00_MINOR	16      /* Temporary - will change in future */
++#define CALLOUT_UART00_NR	UART_NR
++
++static struct tty_driver normal, callout;
++static struct tty_struct *uart00_table[UART_NR];
++static struct termios *uart00_termios[UART_NR], *uart00_termios_locked[UART_NR];
++static struct console uart00_console;
++static struct uart_driver uart00_reg;
++
++
++#define UART00_ISR_PASS_LIMIT	256
++
++/*
++ * Access macros for the UART00 UARTs
++ */
++#define UART_GET_INT_STATUS(p)	inl(UART_ISR((p)->membase))
++#define UART_PUT_IES(p, c)      outl(c,UART_IES((p)->membase))
++#define UART_GET_IES(p)         inl(UART_IES((p)->membase))
++#define UART_PUT_IEC(p, c)      outl(c,UART_IEC((p)->membase))
++#define UART_GET_IEC(p)         inl(UART_IEC((p)->membase))
++#define UART_PUT_CHAR(p, c)     outl(c,UART_TD((p)->membase))
++#define UART_GET_CHAR(p)        inl(UART_RD((p)->membase))
++#define UART_GET_RSR(p)         inl(UART_RSR((p)->membase))
++#define UART_GET_RDS(p)         inl(UART_RDS((p)->membase))
++#define UART_GET_MSR(p)         inl(UART_MSR((p)->membase))
++#define UART_GET_MCR(p)         inl(UART_MCR((p)->membase))
++#define UART_PUT_MCR(p, c)      outl(c,UART_MCR((p)->membase))
++#define UART_GET_MC(p)          inl(UART_MC((p)->membase))
++#define UART_PUT_MC(p, c)       outl(c,UART_MC((p)->membase))
++#define UART_GET_TSR(p)         inl(UART_TSR((p)->membase))
++#define UART_GET_DIV_HI(p)	inl(UART_DIV_HI((p)->membase))
++#define UART_PUT_DIV_HI(p,c)	outl(c,UART_DIV_HI((p)->membase))
++#define UART_GET_DIV_LO(p)	inl(UART_DIV_LO((p)->membase))
++#define UART_PUT_DIV_LO(p,c)	outl(c,UART_DIV_LO((p)->membase))
++#define UART_RX_DATA(s)		((s) & UART_RSR_RX_LEVEL_MSK)
++#define UART_TX_READY(s)	(((s) & UART_TSR_TX_LEVEL_MSK) < 15)
++//#define UART_TX_EMPTY(p)	((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0)
++
++static void uart00_stop_tx(struct uart_port *port, u_int from_tty)
++{
++
++	UART_PUT_IEC(port, UART_IEC_TIE_MSK);
++}
++
++static void uart00_stop_rx(struct uart_port *port)
++{
++
++	UART_PUT_IEC(port, UART_IEC_RE_MSK);
++}
++
++static void uart00_enable_ms(struct uart_port *port)
++{
++
++	UART_PUT_IES(port, UART_IES_ME_MSK);
++}
++
++static void
++uart00_rx_chars(struct uart_port *port, struct pt_regs *regs)
++{
++	struct uart_info *info = port->info;
++	struct tty_struct *tty = info->tty;
++	unsigned int status, ch, rds, flg, ignored = 0;
++	
++
++	status = UART_GET_RSR(port);
++	while (UART_RX_DATA(status)) {
++
++		/* 
++		 * We need to read rds before reading the 
++		 * character from the fifo
++		 */
++		rds = UART_GET_RDS(port);
++		ch = UART_GET_CHAR(port);
++		port->icount.rx++;
++
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++
++		flg = TTY_NORMAL;
++
++		/*
++		 * Note that the error handling code is
++		 * out of the main execution path
++		 */
++		if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK|UART_RDS_PE_MSK))
++			goto handle_error;
++		if (uart_handle_sysrq_char(port, ch, regs))
++			goto ignore_char;
++
++	error_return:
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++	ignore_char:
++		status = UART_GET_RSR(port);
++	}
++out:
++	tty_flip_buffer_push(tty);
++	return;
++
++handle_error:
++	if (rds & UART_RDS_BI_MSK) {
++		status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK);
++		port->icount.brk++;
++
++#ifdef SUPPORT_SYSRQ
++		if (uart_handle_break(port))
++			goto ignore_char;
++#endif
++	} else if (rds & UART_RDS_PE_MSK)
++		port->icount.parity++;
++	else if (rds & UART_RDS_FE_MSK)
++		port->icount.frame++;
++	if (rds & UART_RDS_OE_MSK)
++		port->icount.overrun++;
++
++	if (rds & port->ignore_status_mask) {
++		if (++ignored > 100)
++			goto out;
++		goto ignore_char;
++	}
++	rds &= port->read_status_mask;
++
++	if (rds & UART_RDS_BI_MSK)
++		flg = TTY_BREAK;
++	else if (rds & UART_RDS_PE_MSK)
++		flg = TTY_PARITY;
++	else if (rds & UART_RDS_FE_MSK)
++		flg = TTY_FRAME;
++
++	if (rds & UART_RDS_OE_MSK) {
++		/*
++		 * CHECK: does overrun affect the current character?
++		 * ASSUMPTION: it does not.
++		 */
++		*tty->flip.flag_buf_ptr++ = flg;
++		*tty->flip.char_buf_ptr++ = ch;
++		tty->flip.count++;
++		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++			goto ignore_char;
++		ch = 0;
++		flg = TTY_OVERRUN;
++	}
++#ifdef SUPPORT_SYSRQ
++	port->sysrq = 0;
++#endif
++	goto error_return;
++}
++
++static void uart00_tx_chars(struct uart_port *port)
++{
++	int count;
++	struct uart_info *info = port->info;
++
++	if (port->x_char) {
++		while((UART_GET_TSR(port)& UART_TSR_TX_LEVEL_MSK)==15);
++		UART_PUT_CHAR(port, port->x_char);
++		port->icount.tx++;
++		port->x_char = 0;
++		
++		return;
++	}
++	if (info->xmit.head == info->xmit.tail
++	    || info->tty->stopped
++	    || info->tty->hw_stopped) {
++		uart00_stop_tx(port, 0);
++		return;
++	}
++
++	count = port->fifosize >> 1;
++	do {
++		while((UART_GET_TSR(port)& UART_TSR_TX_LEVEL_MSK)==15);
++		UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
++		info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
++		port->icount.tx++;
++		if (info->xmit.head == info->xmit.tail)
++			break;
++	} while (--count > 0);
++
++	if (CIRC_CNT(info->xmit.head,
++		     info->xmit.tail,
++		     UART_XMIT_SIZE) < WAKEUP_CHARS)
++		uart_write_wakeup(port);
++
++	if (info->xmit.head == info->xmit.tail)
++		uart00_stop_tx(port, 0);
++}
++
++static void uart00_start_tx(struct uart_port *port, u_int from_tty)
++{
++	UART_PUT_IES(port,UART_IES_TIE_MSK );		
++	uart00_tx_chars(port);
++}
++
++static void uart00_modem_status(struct uart_port *port)
++{
++	unsigned int status;
++	struct uart_icount *icount = &port->icount;
++	struct uart_info *info = port->info;
++
++	status = UART_GET_MSR(port);
++
++	if (!status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | 
++		       UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK))
++		return;
++
++	if (status & UART_MSR_DDCD_MSK) {
++		icount->dcd++;
++#ifdef CONFIG_HARD_PPS
++		if ((port->flags & ASYNC_HARDPPS_CD) &&
++		    (status & UART_MSR_DCD_MSK))
++			hardpps();
++#endif
++		if (info->flags & ASYNC_CHECK_CD) {
++			if (status & UART_MSR_DCD_MSK)
++				wake_up_interruptible(&info->open_wait);
++			else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
++				   (port->flags & ASYNC_CALLOUT_NOHUP))) {
++				if (info->tty)
++					tty_hangup(info->tty);
++			}
++		}
++	}
++
++	if (status & UART_MSR_DDSR_MSK)
++		icount->dsr++;
++
++	if (status & UART_MSR_DCTS_MSK) {
++		icount->cts++;
++
++		if (info->flags & ASYNC_CTS_FLOW) {
++			status &= UART_MSR_CTS_MSK;
++
++			if (info->tty->hw_stopped) {
++				if (status) {
++					info->tty->hw_stopped = 0;
++					port->ops->start_tx(port, 0);
++					uart_write_wakeup(port);
++				}
++			} else {
++				if (!status) {
++					info->tty->hw_stopped = 1;
++					port->ops->stop_tx(port, 0);
++				}
++			}
++		}
++	}
++	wake_up_interruptible(&info->delta_msr_wait);
++
++}
++
++static void uart00_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct uart_port *port = dev_id;
++	unsigned int status, pass_counter = 0;
++
++	status = UART_GET_INT_STATUS(port);
++	do {
++
++		if (status & UART_ISR_RI_MSK)
++			uart00_rx_chars(port, regs);
++		if (status & (UART_ISR_TI_MSK | UART_ISR_TII_MSK))
++			uart00_tx_chars(port);
++		if (status & UART_ISR_MI_MSK)
++			uart00_modem_status(port);
++		if (pass_counter++ > UART00_ISR_PASS_LIMIT)
++			break;
++
++		status = UART_GET_INT_STATUS(port);
++	} while (status);
++}
++
++static u_int uart00_tx_empty(struct uart_port *port)
++{
++	return UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK? 0 : TIOCSER_TEMT;
++}
++
++static u_int uart00_get_mctrl(struct uart_port *port)
++{
++	unsigned int result = 0;
++	unsigned int status;
++
++	status = UART_GET_MSR(port);
++	if (status & UART_MSR_DCD_MSK)
++		result |= TIOCM_CAR;
++	if (status & UART_MSR_DSR_MSK)
++		result |= TIOCM_DSR;
++	if (status & UART_MSR_CTS_MSK)
++		result |= TIOCM_CTS;
++	if (status & UART_MCR_RI_MSK)
++		result |= TIOCM_RNG;
++
++	return result;
++}
++
++static void uart00_set_mctrl(struct uart_port *port, u_int mctrl)
++{
++	unsigned char mcr = 0;
++
++	if (mctrl & TIOCM_RTS)
++		mcr |= UART_MCR_RTS_MSK;
++	if (mctrl & TIOCM_DTR)
++		mcr |= UART_MCR_DTR_MSK;
++	if (mctrl & TIOCM_LOOP)
++		mcr |= UART_MCR_LB_MSK;
++
++	UART_PUT_MCR(port, mcr);
++}
++
++static void uart00_break_ctl(struct uart_port *port, int break_state)
++{
++	unsigned int mcr;
++
++	mcr = UART_GET_MCR(port);
++	if (break_state == -1)
++		mcr |= UART_MCR_BR_MSK;
++	else
++		mcr &= ~UART_MCR_BR_MSK;
++	UART_PUT_MCR(port, mcr);
++}
++
++static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
++{
++	u_int quot;
++
++	/* Special case: B0 rate */
++	if (!baud)
++		baud = 9600;
++
++	quot = (port->uartclk / (16 * baud)-1)  ;
++
++	return quot;
++}
++static void uart00_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
++{
++	u_int uart_mc=0, old_ies;
++	unsigned long flags;
++
++#ifdef DEBUG
++	printk("uart00_set_cflag(0x%x) called\n", cflag);
++#endif
++	/* byte size and parity */
++	switch (cflag & CSIZE) {
++	case CS5: uart_mc = UART_MC_CLS_CHARLEN_5; break;
++	case CS6: uart_mc = UART_MC_CLS_CHARLEN_6; break;
++	case CS7: uart_mc = UART_MC_CLS_CHARLEN_7; break;
++	default:  uart_mc = UART_MC_CLS_CHARLEN_8; break; // CS8
++	}
++	if (cflag & CSTOPB)
++		uart_mc|= UART_MC_ST_TWO;
++	if (cflag & PARENB) {
++		uart_mc |= UART_MC_PE_MSK;
++		if (!(cflag & PARODD))
++			uart_mc |= UART_MC_EP_MSK;
++	}
++
++	port->read_status_mask = UART_RDS_OE_MSK;
++	if (iflag & INPCK)
++		port->read_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
++	if (iflag & (BRKINT | PARMRK))
++		port->read_status_mask |= UART_RDS_BI_MSK;
++
++	/*
++	 * Characters to ignore
++	 */
++	port->ignore_status_mask = 0;
++	if (iflag & IGNPAR)
++		port->ignore_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK;
++	if (iflag & IGNBRK) {
++		port->ignore_status_mask |= UART_RDS_BI_MSK;
++		/*
++		 * If we're ignoring parity and break indicators,
++		 * ignore overruns to (for real raw support).
++		 */
++		if (iflag & IGNPAR)
++			port->ignore_status_mask |= UART_RDS_OE_MSK;
++	}
++
++	/* first, disable everything */
++	save_flags(flags); cli();
++	old_ies = UART_GET_IES(port); 
++
++	if ((port->flags & ASYNC_HARDPPS_CD) ||
++	    (cflag & CRTSCTS) || !(cflag & CLOCAL))
++		old_ies |= UART_IES_ME_MSK;
++
++
++	/* Set baud rate */
++	UART_PUT_DIV_LO(port, (quot & 0xff));
++	UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
++   
++
++	UART_PUT_MC(port, uart_mc);
++	UART_PUT_IES(port, old_ies);
++
++	restore_flags(flags);
++}
++
++static int uart00_startup(struct uart_port *port)
++{
++	int retval;
++
++	/*
++	 * Allocate the IRQ
++	 */
++	retval = request_irq(port->irq, uart00_int, 0, "uart00", port);
++	if (retval)
++		return retval;
++
++	/*
++	 * Finally, enable interrupts. Use the TII interrupt to minimise 
++	 * the number of interrupts generated. If higher performance is 
++	 * needed, consider using the TI interrupt with a suitable FIFO
++	 * threshold
++	 */
++	UART_PUT_IES(port, UART_IES_RE_MSK | UART_IES_TIE_MSK);
++
++	return 0;
++}
++
++static void uart00_shutdown(struct uart_port *port)
++{
++	/*
++	 * disable all interrupts, disable the port
++	 */
++	UART_PUT_IEC(port, 0xff);
++
++	/* disable break condition and fifos */
++	UART_PUT_MCR(port, UART_GET_MCR(port) &~UART_MCR_BR_MSK);
++
++	/*
++	 * Free the interrupt
++	 */
++	free_irq(port->irq, port);
++}
++
++static const char *uart00_type(struct uart_port *port)
++{
++	return port->type == PORT_UART00 ? "Altera UART00" : NULL;
++}
++
++/*
++ * Release the memory region(s) being used by 'port'
++ */
++static void uart00_release_port(struct uart_port *port)
++{
++	release_mem_region(port->mapbase, UART_PORT_SIZE);
++
++#ifdef CONFIG_ARCH_CAMELOT
++	if(port->membase!=(void*)IO_ADDRESS(EXC_UART00_BASE)){
++		iounmap(port->membase);
++	}
++#endif
++}
++
++/*
++ * Request the memory region(s) being used by 'port'
++ */
++static int uart00_request_port(struct uart_port *port)
++{
++	int result;
++
++	result = request_mem_region(port->mapbase, UART_PORT_SIZE,
++				    "serial_uart00") != NULL ? 0 : -EBUSY;
++	if (result)
++		return result;
++
++	port->membase = ioremap(port->mapbase, SZ_4K);
++	if (!port->membase) {
++		printk(KERN_ERR "serial00: cannot map io memory\n");
++		release_mem_region(port->mapbase, UART_PORT_SIZE);
++	}
++
++	return port->membase ? 0 : -ENOMEM;
++}
++
++/*
++ * Configure/autoconfigure the port.
++ */
++static void uart00_config_port(struct uart_port *port, int flags)
++{
++	if (flags & UART_CONFIG_TYPE) {
++		if (uart00_request_port(port) == 0)
++			port->type = PORT_UART00;
++	}
++}
++
++/*
++ * verify the new serial_struct (for TIOCSSERIAL).
++ */
++static int uart00_verify_port(struct uart_port *port, struct serial_struct *ser)
++{
++	int ret = 0;
++	if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
++		ret = -EINVAL;
++	if (ser->irq < 0 || ser->irq >= NR_IRQS)
++		ret = -EINVAL;
++	if (ser->baud_base < 9600)
++		ret = -EINVAL;
++	return ret;
++}
++
++static struct uart_ops uart00_pops = {
++	tx_empty:	uart00_tx_empty,
++	set_mctrl:	uart00_set_mctrl,
++	get_mctrl:	uart00_get_mctrl,
++	stop_tx:	uart00_stop_tx,
++	start_tx:	uart00_start_tx,
++	stop_rx:	uart00_stop_rx,
++	enable_ms:	uart00_enable_ms,
++	break_ctl:	uart00_break_ctl,
++	startup:	uart00_startup,
++	shutdown:	uart00_shutdown,
++	change_speed:	uart00_change_speed,
++	type:		uart00_type,
++	release_port:	uart00_release_port,
++	request_port:	uart00_request_port,
++	config_port:	uart00_config_port,
++	verify_port:	uart00_verify_port,
++};
++
++static struct uart_port uart00_ports[UART_NR] = {
++
++#ifdef CONFIG_ARCH_CAMELOT
++{
++	.membase	= (void*)IO_ADDRESS(EXC_UART00_BASE),
++	.mapbase	=  EXC_UART00_BASE,
++	.iotype		= SERIAL_IO_MEM,
++	.irq		= IRQ_UART,
++	.uartclk	= EXC_AHB2_CLK_FREQUENCY,
++	.fifosize	= 16,
++	.ops		= &uart00_pops,
++	.flags		= ASYNC_BOOT_AUTOCONF,
++}
++#endif
++};
++
++#ifdef CONFIG_SERIAL_UART00_CONSOLE
++static void uart00_console_write(struct console *co, const char *s, unsigned count)
++{
++#ifdef CONFIG_ARCH_CAMELOT
++	struct uart_port *port = &uart00_ports[0];
++	unsigned int status, old_ies;
++	int i;
++
++	/*
++	 *	First save the CR then disable the interrupts
++	 */
++	old_ies = UART_GET_IES(port);
++	UART_PUT_IEC(port,0xff);
++
++	/*
++	 *	Now, do each character
++	 */
++	for (i = 0; i < count; i++) {
++		do {
++			status = UART_GET_TSR(port);
++		} while (!UART_TX_READY(status));
++		UART_PUT_CHAR(port, s[i]);
++		if (s[i] == '\n') {
++			do {
++				status = UART_GET_TSR(port);
++			} while (!UART_TX_READY(status));
++			UART_PUT_CHAR(port, '\r');
++		}
++	}
++
++	/*
++	 *	Finally, wait for transmitter to become empty
++	 *	and restore the IES
++	 */
++	do {
++		status = UART_GET_TSR(port);
++	} while (status & UART_TSR_TX_LEVEL_MSK);
++	UART_PUT_IES(port, old_ies);
++#endif
++}
++
++static kdev_t uart00_console_device(struct console *co)
++{
++	return MKDEV(SERIAL_UART00_MAJOR, SERIAL_UART00_MINOR + co->index);
++}
++
++static void /*__init*/ uart00_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
++{
++	u_int uart_mc, quot;
++	uart_mc= UART_GET_MC(port);
++
++	*parity = 'n';
++	if (uart_mc & UART_MC_PE_MSK) {
++		if (uart_mc & UART_MC_EP_MSK)
++			*parity = 'e';
++		else
++			*parity = 'o';
++	}
++
++	switch (uart_mc & UART_MC_CLS_MSK){
++
++	case UART_MC_CLS_CHARLEN_5:
++		*bits = 5;
++		break;
++	case UART_MC_CLS_CHARLEN_6:
++		*bits = 6;
++		break;
++	case UART_MC_CLS_CHARLEN_7:
++		*bits = 7;
++		break;
++	case UART_MC_CLS_CHARLEN_8:
++		*bits = 8;
++		break;
++	}
++	quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
++	*baud = port->uartclk / (16 *quot );
++}
++
++static int __init uart00_console_setup(struct console *co, char *options)
++{
++	struct uart_port *port;
++	int baud = 38400;
++	int bits = 8;
++	int parity = 'n';
++	int flow= 'n';
++
++#ifdef CONFIG_ARCH_CAMELOT
++	/*
++	 * Check whether an invalid uart number has been specified, and
++	 * if so, search for the first available port that does have
++	 * console support.
++	 */
++	port = &uart00_ports[0];
++	co->index = 0;
++#else
++	return -ENODEV;
++#endif
++
++	if (options)
++		uart_parse_options(options, &baud, &parity, &bits, &flow);
++	else
++		uart00_console_get_options(port, &baud, &parity, &bits);
++
++	return uart_set_options(port, co, baud, parity, bits, flow);
++}
++
++static struct console uart00_console = {
++	.name	= SERIAL_UART00_NAME,
++	.write	= uart00_console_write,
++	.device	= uart00_console_device,
++	.setup	= uart00_console_setup,
++	.flags	= CON_PRINTBUFFER,
++	.index	= 0,
++};
++
++void __init uart00_console_init(void)
++{
++	register_console(&uart00_console);
++}
++
++#define UART00_CONSOLE	&uart00_console
++#else
++#define UART00_CONSOLE	NULL
++#endif
++
++static struct uart_driver uart00_reg = {
++	.owner		= NULL,
++	.normal_major	= SERIAL_UART00_MAJOR,
++	.normal_name	= SERIAL_UART00_NAME,
++	.normal_driver	= &normal,
++	.callout_major	= CALLOUT_UART00_MAJOR,
++	.callout_name	= CALLOUT_UART00_NAME,
++	.callout_driver	= &callout,
++	.table		= uart00_table,
++	.termios	= uart00_termios,
++	.termios_locked	= uart00_termios_locked,
++	.minor		= SERIAL_UART00_MINOR,
++	.nr		= UART_NR,
++	.state		= NULL,
++	.cons		= UART00_CONSOLE,
++};
++
++struct dev_port_entry{
++	struct uart_port *port;
++};
++
++static struct dev_port_entry dev_port_map[UART_NR];
++
++#ifdef CONFIG_PLD_HOTSWAP
++/*
++ * Keep a mapping of dev_info addresses -> port lines to use when
++ * removing ports dev==NULL indicates unused entry
++ */
++
++struct uart00_ps_data{
++	unsigned int clk;
++	unsigned int fifosize;
++};
++
++int uart00_add_device(struct pldhs_dev_info* dev_info, void* dev_ps_data)
++{
++	struct uart00_ps_data* dev_ps=dev_ps_data;
++	struct uart_port * port;
++	int i,result;
++
++	i=0;
++	while(dev_port_map[i].port)
++		i++;
++
++	if(i==UART_NR){
++		printk(KERN_WARNING "uart00: Maximum number of ports reached\n");
++		return 0;
++	}
++
++	port=&uart00_ports[i];
++
++	printk("clk=%d fifo=%d\n",dev_ps->clk,dev_ps->fifosize);
++	port->membase=0;
++	port->mapbase=dev_info->base_addr;
++	port->iotype=SERIAL_IO_MEM;
++	port->irq=dev_info->irq;
++	port->uartclk=dev_ps->clk;
++	port->fifosize=dev_ps->fifosize;
++	port->ops=&uart00_pops;
++	port->line=i;
++	port->flags=ASYNC_BOOT_AUTOCONF;
++
++	result=uart_register_port(&uart00_reg, port);
++	if(result<0){
++		printk("uart_register_port returned %d\n",result);
++		return result;
++	}
++	dev_port_map[i].port=port;
++	printk("uart00: added device at %lx as ttyUA%d\n",dev_port_map[i].port->mapbase,i);
++	return 0;
++
++}
++
++int uart00_remove_devices(void)
++{
++	int i,result;
++
++
++	result=0;
++	for(i=1;i<UART_NR;i++){
++		if(dev_port_map[i].port){
++			uart_unregister_port(&uart00_reg,i);
++			dev_port_map[i].port=NULL;
++		}
++	}
++	return 0;
++
++}
++
++#ifdef CONFIG_PROC_FS
++
++
++int uart00_proc_read(char* buf,char** start,off_t offset,int count,int *eof,void *data){
++
++	int i,len=0;
++	struct uart_port *port;
++	int limit = count - 80;
++	char ps_data[80];
++	if(*start)
++		buf=*start;
++	for(i=0;(i<UART_NR)&&(len<limit);i++){
++		if(dev_port_map[i].port){
++			port=dev_port_map[i].port;
++			sprintf(ps_data,"clk, %dHz, fifo size, %dbytes",
++				port->uartclk,port->fifosize);
++			len+=PLDHS_READ_PROC_DATA(buf+len,"uart00",i,
++					 port->mapbase,port->irq,ps_data);
++
++		}
++	}
++	*eof=1;
++	return len;
++}
++
++
++
++#endif
++struct pld_hotswap_ops uart00_pldhs_ops={
++	.name		= "uart00",
++	.add_device	= uart00_add_device,
++	.remove_devices	= uart00_remove_devices,
++	.proc_read	= uart00_proc_read
++};
++
++#endif
++
++static int __init uart00_init(void)
++{
++	int ret;
++	int i;
++
++	ret = uart_register_driver(&uart00_reg);
++	if (ret) {
++		printk(KERN_ERR "uart00: Couldn't register driver\n");
++		return ret;
++	}
++
++	unregister_console(&uart00_console);
++
++	for(i=0;i<UART_NR;i++){
++		uart00_ports[i].ops=&uart00_pops;
++	}
++
++	printk(KERN_WARNING "uart00:Using temporary major/minor pairs - these WILL change in the future\n");
++
++#ifdef CONFIG_PLD_HOTSWAP
++	pldhs_register_driver(&uart00_pldhs_ops);
++#endif
++	for (i=0; i<UART_NR; i++)
++		uart_add_one_port(&uart00_reg,&uart00_ports[i]);
++
++	uart00_console.flags = 0;
++	register_console(&uart00_console);
++#ifdef CONFIG_ARCH_CAMELOT
++	dev_port_map[0].port=uart00_ports;
++#endif
++	return ret;
++}
++
++
++__initcall(uart00_init);
++
++
+--- linux-2.4.25/drivers/sound/.version~2.4.25-vrs2.patch
++++ linux-2.4.25/drivers/sound/.version
+-3.8s
+-0x030804
+--- linux-2.4.25/drivers/sound/Config.in~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/sound/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -131,6 +131,17 @@
+ dep_tristate '  VIA 82C686 Audio Codec' CONFIG_SOUND_VIA82CXXX $CONFIG_PCI
+ dep_mbool    '  VIA 82C686 MIDI' CONFIG_MIDI_VIA82CXXX $CONFIG_SOUND_VIA82CXXX
+ 
++if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
++   dep_tristate '  StrongARM-11x0 Sound Drivers' CONFIG_SOUND_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_SOUND
++   dep_tristate '    UDA1341 Stereo Codec' CONFIG_SOUND_UDA1341 $CONFIG_L3 $CONFIG_SOUND_SA1100 $CONFIG_SOUND
++   dep_tristate '      Assabet audio support' CONFIG_SOUND_ASSABET_UDA1341 $CONFIG_SA1100_ASSABET $CONFIG_SOUND_UDA1341
++   dep_tristate '      Compaq iPAQ audio support' CONFIG_SOUND_H3600_UDA1341 $CONFIG_SA1100_H3600 $CONFIG_SOUND_UDA1341
++   dep_tristate '      Pangolin audio support' CONFIG_SOUND_PANGOLIN_UDA1341 $CONFIG_SA1100_PANGOLIN $CONFIG_SOUND_UDA1341
++   dep_tristate '      SA1111 audio support' CONFIG_SOUND_SA1111_UDA1341 $CONFIG_SA1111 $CONFIG_SOUND_UDA1341
++   dep_tristate '    SA1111 AC97 Sound' CONFIG_SOUND_SA1111_AC97 $CONFIG_SA1111 $CONFIG_SOUND_SA1100
++   dep_tristate '    Generic DAC on the SA11x0 SSP port' CONFIG_SOUND_SA1100SSP $CONFIG_SOUND_SA1100
++fi
++
+ dep_tristate '  OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND
+ 
+ if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then
+@@ -220,14 +231,14 @@
+          bool '      Audio Excel DSP 16 (MPU401 emulation)' CONFIG_AEDSP16_MPU401
+       fi
+    fi
++	 
++fi
+ 
+-   if [ "$CONFIG_ARM" = "y" ]; then
+-      if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" ]; then
+-         dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
+-      fi
+-      dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER
++if [ "$CONFIG_ARM" = "y" ]; then
++   if [ "$CONFIG_ARCH_ACORN" = "y" -o "$CONFIG_ARCH_CLPS7500" = "y" -o "$CONFIG_ARCH_RISCSTATION" ]; then
++      dep_tristate '    VIDC 16-bit sound' CONFIG_SOUND_VIDC $CONFIG_SOUND_OSS
+    fi
+-
++   dep_tristate '    Netwinder WaveArtist' CONFIG_SOUND_WAVEARTIST $CONFIG_SOUND_OSS $CONFIG_ARCH_NETWINDER
+ fi
+ 
+ dep_tristate '  TV card (bt848) mixer support' CONFIG_SOUND_TVMIXER $CONFIG_SOUND $CONFIG_I2C
+--- linux-2.4.25/drivers/sound/Makefile~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/sound/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -10,7 +10,8 @@
+ export-objs	:=  ad1848.o audio_syms.o midi_syms.o mpu401.o \
+ 		    msnd.o opl3.o sb_common.o sequencer_syms.o \
+ 		    sound_core.o sound_syms.o uart401.o	\
+-		    nm256_audio.o ac97.o ac97_codec.o aci.o
++		    nm256_audio.o ac97.o ac97_codec.o aci.o \
++		    sa1100-audio.o
+ 
+ # Each configuration option enables a list of files.
+ 
+@@ -76,6 +77,14 @@
+ obj-$(CONFIG_SOUND_FORTE)	+= forte.o ac97_codec.o
+ obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
+ obj-$(CONFIG_SOUND_HARMONY)	+= harmony.o
++obj-$(CONFIG_SOUND_SA1100)	+= sa1100-audio.o
++obj-$(CONFIG_SOUND_UDA1341)	+= uda1341.o
++obj-$(CONFIG_SOUND_ASSABET_UDA1341) += assabet-uda1341.o
++obj-$(CONFIG_SOUND_PANGOLIN_UDA1341) += pangolin-uda1341.o
++obj-$(CONFIG_SOUND_H3600_UDA1341) += h3600-uda1341.o
++obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o
++obj-$(CONFIG_SOUND_SA1111_AC97)	+= sa1111-ac97.o ac97_codec.o
++obj-$(CONFIG_SOUND_SA1100SSP)	+= sa1100ssp.o
+ obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
+ obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
+ obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
+@@ -105,7 +114,6 @@
+   obj-y += dmasound/dmasound.o
+ endif
+ 
+-
+ # Declare multi-part drivers.
+ 
+ list-multi	:= sound.o gus.o pas2.o sb.o sb_lib.o vidc_mod.o \
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/assabet-uda1341.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,404 @@
++/*
++ * Glue audio driver for the SA1110 Assabet board & Philips UDA1341 codec.
++ *
++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * This is the machine specific part of the Assabet/UDA1341 support.
++ * This driver makes use of the UDA1341 and the sa1100-audio modules.
++ *
++ * History:
++ *
++ * 2000-05-21	Nicolas Pitre	Initial release.
++ *
++ * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on
++ * 				the former sa1100-uda1341.c driver.
++ *
++ * 2001-07-17	Nicolas Pitre	Supports 44100Hz and 22050Hz samplerate now.
++ *
++ * 2001-08-03	Russell King	Fix left/right channel swap.
++ *				Attempt to reduce power consumption when idle.
++ *
++ * 2001-09-23	Russell King	Remove old L3 bus driver.
++ *
++ * Please note that fiddling too much with MDREFR results in oopses, so we don't
++ * touch MDREFR unnecessarily, which means we don't touch it on close.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/errno.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/cpufreq.h>
++#include <linux/l3/l3.h>
++#include <linux/l3/uda1341.h>
++
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++#include <asm/arch/assabet.h>
++
++#include "sa1100-audio.h"
++
++/*
++ * Define this to fix the power drain on early Assabets
++ */
++#define FIX_POWER_DRAIN
++
++/*
++ * Debugging?
++ */
++#undef DEBUG
++
++
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++
++#define AUDIO_RATE_DEFAULT	44100
++
++/*
++ * Mixer (UDA1341) interface
++ */
++
++static struct l3_client uda1341;
++
++static int
++mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++	/*
++	 * We only accept mixer (type 'M') ioctls.
++	 */
++	if (_IOC_TYPE(cmd) != 'M')
++		return -EINVAL;
++
++	return l3_command(&uda1341, cmd, (void *)arg);
++}
++
++static struct file_operations assabet_mixer_fops = {
++	ioctl:		mixer_ioctl,
++	owner:		THIS_MODULE
++};
++
++
++/*
++ * Audio interface
++ */
++static long audio_samplerate = AUDIO_RATE_DEFAULT;
++
++/*
++ * FIXME: what about SFRM going high when SSP is disabled?
++ */
++static void assabet_set_samplerate(long val)
++{
++	struct uda1341_cfg cfg;
++	u_int clk_ref, clk_div;
++
++	/* We don't want to mess with clocks when frames are in flight */
++	Ser4SSCR0 &= ~SSCR0_SSE;
++	/* wait for any frame to complete */
++	udelay(125);
++
++	/*
++	 * Our clock source is derived from the CPLD on which we don't have
++	 * much control unfortunately.  This was intended for a fixed 48000 Hz
++	 * samplerate assuming a core clock of 221.2 MHz.  The CPLD appears
++	 * to divide the memory clock so there is a ratio of 4608 between
++	 * the core clock and the resulting samplerate (obtained by
++	 * measurements, the CPLD equations should confirm that).
++	 *
++	 * Still we can play with the SA1110's clock divisor for the SSP port
++	 * to get half the samplerate as well.
++	 *
++	 * Apparently the clock sent to the SA1110 for the SSP port is further
++	 * more divided from the clock sent to the UDA1341 (some people tried
++	 * to be too clever in their design, or simply failed to read the
++	 * SA1110 manual).  If it was the same clock we would have been able
++	 * to support a third samplerate with the UDA1341's 384FS mode.
++	 *
++	 * At least it would have been a minimum acceptable solution to be
++	 * able to set the CPLD divisor by software.  The iPAQ design is
++	 * certainly a better example to follow for a new design.
++	 */
++	clk_ref = cpufreq_get(0) * 1000 / 4608;
++	if (val > clk_ref*4/7) {
++		audio_samplerate = clk_ref;
++		cfg.fs = 256;
++		clk_div = SSCR0_SerClkDiv(2);
++	} else {
++		audio_samplerate = clk_ref/2;
++		cfg.fs = 512;
++		clk_div = SSCR0_SerClkDiv(4);
++	}
++
++	cfg.format = FMT_LSB16;
++	l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg);
++
++	Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
++}
++
++/*
++ * Initialise the Assabet audio driver.
++ *
++ * Note that we have to be careful with the order that we do things here;
++ * there is a D-type flip flop which is clocked from the SFRM line which
++ * indicates whether the same is for the left or right channel to the
++ * UDA1341.
++ *
++ * When you disable the SSP (by clearing SSCR0_SSE) it appears that the
++ * SFRM signal can float high.  When you re-enable the SSP, you clock the
++ * flip flop once, and end up swapping the left and right channels.
++ *
++ * The ASSABET_BCR_CODEC_RST line will force this flip flop into a known
++ * state, but this line resets other devices as well!
++ *
++ * In addition to the above, it appears that powering down the UDA1341 on
++ * early Assabets leaves the UDA_WS actively driving a logic '1' into the
++ * chip, wasting power!  (you can tell this by D11 being half-on).  We
++ * attempt to correct this by kicking the flip flop on init/open/close.
++ * We should probably do this on PM resume as well.
++ *
++ * (Note the ordering of ASSABET_BCR_AUDIO_ON, SFRM and ASSABET_BCR_CODEC_RST
++ * is important).
++ */
++static void assabet_audio_init(void *dummy)
++{
++	unsigned long flags;
++	unsigned int mdrefr;
++
++	local_irq_save(flags);
++
++	/*
++	 * Enable the power for the UDA1341 before driving any signals.
++	 * We leave the audio amp (LM4880) disabled for now.
++	 */
++	ASSABET_BCR_set(ASSABET_BCR_AUDIO_ON);
++
++#ifdef FIX_POWER_DRAIN
++	GPSR = GPIO_SSP_SFRM;
++	GPCR = GPIO_SSP_SFRM;
++#endif
++
++	ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
++	ASSABET_BCR_clear(ASSABET_BCR_STEREO_LB);
++
++	/*
++	 * Setup the SSP uart.
++	 */
++	PPAR |= PPAR_SPR;
++	Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(2);
++	Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
++	GAFR |= GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_CLK;
++	GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
++	GPDR &= ~(GPIO_SSP_RXD | GPIO_SSP_CLK);
++	Ser4SSCR0 |= SSCR0_SSE;
++
++	/*
++	 * Only give SFRM to the SSP after it has been enabled.
++	 */
++	GAFR |= GPIO_SSP_SFRM;
++
++	/*
++	 * The assabet board uses the SDRAM clock as the source clock for
++	 * audio. This is supplied to the SA11x0 from the CPLD on pin 19.
++	 * At 206MHz we need to run the audio clock (SDRAM bank 2)
++	 * at half speed. This clock will scale with core frequency so
++	 * the audio sample rate will also scale. The CPLD on Assabet
++	 * will need to be programmed to match the core frequency.
++	 */
++	mdrefr = MDREFR;
++	if ((mdrefr & (MDREFR_K2DB2 | MDREFR_K2RUN | MDREFR_EAPD |
++		       MDREFR_KAPD)) != (MDREFR_K2DB2 | MDREFR_K2RUN)) {
++		mdrefr |= MDREFR_K2DB2 | MDREFR_K2RUN;
++		mdrefr &= ~(MDREFR_EAPD | MDREFR_KAPD);
++		MDREFR = mdrefr;
++		(void) MDREFR;
++	}
++	local_irq_restore(flags);
++
++	/* Wait for the UDA1341 to wake up */
++	mdelay(1);
++
++	l3_open(&uda1341);
++
++	assabet_set_samplerate(audio_samplerate);
++
++	/* Enable the audio power */
++	ASSABET_BCR_clear(ASSABET_BCR_QMUTE | ASSABET_BCR_SPK_OFF);
++}
++
++/*
++ * Shutdown the Assabet audio driver.
++ *
++ * We have to be careful about the SFRM line here for the same reasons
++ * described in the initialisation comments above.  This basically means
++ * that we must hand the SSP pins back to the GPIO module before disabling
++ * the SSP.
++ *
++ * In addition, to reduce power drain, we toggle the SFRM line once so
++ * that the UDA_WS line is at logic 0.
++ *
++ * We can't clear ASSABET_BCR_CODEC_RST without knowing if the UCB1300 or
++ * ADV7171 driver is still active.  If it is, then we still need to play
++ * games, so we might as well leave ASSABET_BCR_CODEC_RST set.
++ */
++static void assabet_audio_shutdown(void *dummy)
++{
++	ASSABET_BCR_set(ASSABET_BCR_STEREO_LB | ASSABET_BCR_QMUTE |
++			ASSABET_BCR_SPK_OFF);
++
++	l3_close(&uda1341);
++
++	GAFR &= ~(GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM);
++	Ser4SSCR0 = 0;
++
++#ifdef FIX_POWER_DRAIN
++	GPSR = GPIO_SSP_SFRM;
++	GPCR = GPIO_SSP_SFRM;
++#endif
++
++	/* disable the audio power */
++	ASSABET_BCR_clear(ASSABET_BCR_AUDIO_ON);
++}
++
++static int assabet_audio_ioctl( struct inode *inode, struct file *file,
++				uint cmd, ulong arg)
++{
++	long val;
++	int ret = 0;
++
++	/*
++	 * These are platform dependent ioctls which are not handled by the
++	 * generic sa1100-audio module.
++	 */
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *) arg);
++		if (ret)
++			return ret;
++		/* the UDA1341 is stereo only */
++		ret = (val == 0) ? -EINVAL : 1;
++		return put_user(ret, (int *) arg);
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		/* the UDA1341 is stereo only */
++		return put_user(2, (long *) arg);
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (long *) arg);
++		if (ret) break;
++		assabet_set_samplerate(val);
++		/* fall through */
++
++	case SOUND_PCM_READ_RATE:
++		return put_user(audio_samplerate, (long *) arg);
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		/* we can do signed 16-bit only */
++		return put_user(AFMT_S16_LE, (long *) arg);
++
++	default:
++		/* Maybe this is meant for the mixer (As per OSS Docs) */
++		return mixer_ioctl(inode, file, cmd, arg);
++	}
++
++	return ret;
++}
++
++static audio_stream_t output_stream, input_stream;
++
++static audio_state_t audio_state = {
++	output_stream:	&output_stream,
++	output_dma:	DMA_Ser4SSPWr,
++	output_id:	"Assabet UDA1341 out",
++	input_stream:	&input_stream,
++	input_dma:	DMA_Ser4SSPRd,
++	input_id:	"Assabet UDA1341 in",
++	need_tx_for_rx:	1,
++	hw_init:	assabet_audio_init,
++	hw_shutdown:	assabet_audio_shutdown,
++	client_ioctl:	assabet_audio_ioctl,
++	sem:		__MUTEX_INITIALIZER(audio_state.sem),
++};
++
++static int assabet_audio_open(struct inode *inode, struct file *file)
++{
++	return sa1100_audio_attach(inode, file, &audio_state);
++}
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to sa1100_audio_attach().
++ */
++static struct file_operations assabet_audio_fops = {
++	open:		assabet_audio_open,
++	owner:		THIS_MODULE
++};
++
++
++static int audio_dev_id, mixer_dev_id;
++
++static int __init assabet_uda1341_init(void)
++{
++	int ret;
++
++	if (!machine_is_assabet())
++		return -ENODEV;
++
++	ret = l3_attach_client(&uda1341, "l3-bit-sa1100-gpio", "uda1341");
++	if (ret)
++		goto out;
++
++	/* register devices */
++	audio_dev_id = register_sound_dsp(&assabet_audio_fops, -1);
++	mixer_dev_id = register_sound_mixer(&assabet_mixer_fops, -1);
++
++#ifdef FIX_POWER_DRAIN
++	{
++		unsigned long flags;
++		local_irq_save(flags);
++		ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
++		GPSR = GPIO_SSP_SFRM;
++		GPDR |= GPIO_SSP_SFRM;
++		GPCR = GPIO_SSP_SFRM;
++		local_irq_restore(flags);
++	}
++#endif
++
++	printk(KERN_INFO "Sound: Assabet UDA1341: dsp id %d mixer id %d\n",
++		audio_dev_id, mixer_dev_id);
++	return 0;
++
++release_l3:
++	l3_detach_client(&uda1341);
++out:
++	return ret;
++}
++
++static void __exit assabet_uda1341_exit(void)
++{
++	unregister_sound_dsp(audio_dev_id);
++	unregister_sound_mixer(mixer_dev_id);
++	l3_detach_client(&uda1341);
++}
++
++module_init(assabet_uda1341_init);
++module_exit(assabet_uda1341_exit);
++
++MODULE_AUTHOR("Nicolas Pitre");
++MODULE_DESCRIPTION("Glue audio driver for the SA1110 Assabet board & Philips UDA1341 codec.");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/h3600-uda1341.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,352 @@
++/*
++ * Glue audio driver for the Compaq iPAQ H3600 & Philips UDA1341 codec.
++ *
++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * This is the machine specific part of the Compaq iPAQ (aka Bitsy) support.
++ * This driver makes use of the UDA1341 and the sa1100-audio modules.
++ *
++ * History:
++ *
++ * 2000-05-21	Nicolas Pitre	Initial UDA1341 driver release.
++ *
++ * 2000-07-??	George France	Bitsy support.
++ *
++ * 2000-12-13	Deborah Wallach Fixed power handling for iPAQ/h3600
++ *
++ * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on
++ *				the former sa1100-uda1341.c driver.
++ *
++ * 2001-07-13	Nicolas Pitre	Fixes for all supported samplerates.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/errno.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/l3/l3.h>
++#include <linux/l3/uda1341.h>
++
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++//#include <asm/arch/h3600_hal.h>
++
++#include "sa1100-audio.h"
++
++
++#undef DEBUG
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++
++#define AUDIO_NAME		"Bitsy_UDA1341"
++
++#define AUDIO_RATE_DEFAULT	44100
++
++
++static struct l3_client uda1341;
++
++static int
++mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++	/*
++	 * We only accept mixer (type 'M') ioctls.
++	 */
++	if (_IOC_TYPE(cmd) != 'M')
++		return -EINVAL;
++
++	return l3_command(&uda1341, cmd, (void *)arg);
++}
++
++static struct file_operations h3600_mixer_fops = {
++	ioctl:		mixer_ioctl,
++	owner:		THIS_MODULE
++};
++
++
++/*
++ * Audio interface
++ */
++
++static long audio_samplerate = AUDIO_RATE_DEFAULT;
++
++/*
++ * Stop-gap solution until rest of hh.org HAL stuff is merged.
++ */
++#define GPIO_H3600_CLK_SET0		GPIO_GPIO (12)
++#define GPIO_H3600_CLK_SET1		GPIO_GPIO (13)
++static void h3600_set_audio_clock(long val)
++{
++	switch (val) {
++	case 24000: case 32000: case 48000:	/* 00: 12.288 MHz */
++		GPCR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
++		break;
++
++	case 22050: case 29400: case 44100:	/* 01: 11.2896 MHz */
++		GPSR = GPIO_H3600_CLK_SET0;
++		GPCR = GPIO_H3600_CLK_SET1;
++		break;
++
++	case 8000: case 10666: case 16000:	/* 10: 4.096 MHz */
++		GPCR = GPIO_H3600_CLK_SET0;
++		GPSR = GPIO_H3600_CLK_SET1;
++		break;
++
++	case 10985: case 14647: case 21970:	/* 11: 5.6245 MHz */
++		GPSR = GPIO_H3600_CLK_SET0 | GPIO_H3600_CLK_SET1;
++		break;
++	}
++}
++
++static void h3600_set_samplerate(long val)
++{
++	struct uda1341_cfg cfg;
++	int clk_div = 0;
++
++	/* We don't want to mess with clocks when frames are in flight */
++	Ser4SSCR0 &= ~SSCR0_SSE;
++	/* wait for any frame to complete */
++	udelay(125);
++
++	/*
++	 * We have the following clock sources:
++	 * 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz
++	 * Those can be divided either by 256, 384 or 512.
++	 * This makes up 12 combinations for the following samplerates...
++	 */
++	if (val >= 48000)
++		val = 48000;
++	else if (val >= 44100)
++		val = 44100;
++	else if (val >= 32000)
++		val = 32000;
++	else if (val >= 29400)
++		val = 29400;
++	else if (val >= 24000)
++		val = 24000;
++	else if (val >= 22050)
++		val = 22050;
++	else if (val >= 21970)
++		val = 21970;
++	else if (val >= 16000)
++		val = 16000;
++	else if (val >= 14647)
++		val = 14647;
++	else if (val >= 10985)
++		val = 10985;
++	else if (val >= 10666)
++		val = 10666;
++	else
++		val = 8000;
++
++	/* Set the external clock generator */
++	h3600_set_audio_clock(val);
++
++	/* Select the clock divisor */
++	switch (val) {
++	case 8000:
++	case 10985:
++	case 22050:
++	case 24000:
++		cfg.fs = 512;
++		clk_div = SSCR0_SerClkDiv(16);
++		break;
++	case 16000:
++	case 21970:
++	case 44100:
++	case 48000:
++		cfg.fs = 256;
++		clk_div = SSCR0_SerClkDiv(8);
++		break;
++	case 10666:
++	case 14647:
++	case 29400:
++	case 32000:
++		cfg.fs = 384;
++		clk_div = SSCR0_SerClkDiv(12);
++		break;
++	}
++
++	cfg.format = FMT_LSB16;
++	l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg);
++	Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
++	audio_samplerate = val;
++}
++
++static void h3600_audio_init(void *dummy)
++{
++	unsigned long flags;
++
++	/* Setup the uarts */
++	local_irq_save(flags);
++	GAFR |= (GPIO_SSP_CLK);
++	GPDR &= ~(GPIO_SSP_CLK);
++	Ser4SSCR0 = 0;
++	Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(8);
++	Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
++	Ser4SSCR0 |= SSCR0_SSE;
++
++	/* Enable the audio power */
++
++	clr_h3600_egpio(IPAQ_EGPIO_CODEC_NRESET);
++	set_h3600_egpio(IPAQ_EGPIO_AUDIO_ON);
++	set_h3600_egpio(IPAQ_EGPIO_QMUTE);
++	local_irq_restore(flags);
++
++	/* external clock configuration */
++	h3600_set_samplerate(audio_samplerate);
++
++	/* Wait for the UDA1341 to wake up */
++	set_h3600_egpio(IPAQ_EGPIO_CODEC_NRESET);
++	mdelay(1);
++
++	/* make the left and right channels unswapped (flip the WS latch ) */
++	Ser4SSDR = 0;
++
++	/* Initialize the UDA1341 internal state */
++	l3_open(&uda1341);
++
++	clr_h3600_egpio(IPAQ_EGPIO_QMUTE);
++}
++
++static void h3600_audio_shutdown(void *dummy)
++{
++	/* disable the audio power and all signals leading to the audio chip */
++	l3_close(&uda1341);
++	Ser4SSCR0 = 0;
++	clr_h3600_egpio(IPAQ_EGPIO_CODEC_NRESET);
++	clr_h3600_egpio(IPAQ_EGPIO_AUDIO_ON);
++	clr_h3600_egpio(IPAQ_EGPIO_QMUTE);
++}
++
++static int h3600_audio_ioctl(struct inode *inode, struct file *file,
++			     uint cmd, ulong arg)
++{
++	long val;
++	int ret = 0;
++
++	/*
++	 * These are platform dependent ioctls which are not handled by the
++	 * generic sa1100-audio module.
++	 */
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *) arg);
++		if (ret)
++			return ret;
++		/* the UDA1341 is stereo only */
++		ret = (val == 0) ? -EINVAL : 1;
++		return put_user(ret, (int *) arg);
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		/* the UDA1341 is stereo only */
++		return put_user(2, (long *) arg);
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (long *) arg);
++		if (ret) break;
++		h3600_set_samplerate(val);
++		/* fall through */
++
++	case SOUND_PCM_READ_RATE:
++		return put_user(audio_samplerate, (long *) arg);
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		/* we can do 16-bit only */
++		return put_user(AFMT_S16_LE, (long *) arg);
++
++	default:
++		/* Maybe this is meant for the mixer (As per OSS Docs) */
++		return mixer_ioctl(inode, file, cmd, arg);
++	}
++
++	return ret;
++}
++
++static audio_stream_t output_stream, input_stream;
++
++static audio_state_t audio_state = {
++	output_stream:	&output_stream,
++	output_dma:	DMA_Ser4SSPWr,
++	output_id:	"UDA1341 out",
++	input_stream:	&input_stream,
++	input_dma:	DMA_Ser4SSPRd,
++	input_id:	"UDA1341 in",
++	need_tx_for_rx: 1,
++	hw_init:	h3600_audio_init,
++	hw_shutdown:	h3600_audio_shutdown,
++	client_ioctl:	h3600_audio_ioctl,
++	sem:		__MUTEX_INITIALIZER(audio_state.sem),
++};
++
++static int h3600_audio_open(struct inode *inode, struct file *file)
++{
++	return sa1100_audio_attach(inode, file, &audio_state);
++}
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to sa1100_audio_attach().
++ */
++static struct file_operations h3600_audio_fops = {
++	open:		h3600_audio_open,
++	owner:		THIS_MODULE
++};
++
++
++static int audio_dev_id, mixer_dev_id;
++
++static int __init h3600_uda1341_init(void)
++{
++	int ret;
++
++	if (!machine_is_h3xxx())
++		return -ENODEV;
++
++	ret = l3_attach_client(&uda1341, "l3-bit-sa1100-gpio", "uda1341");
++	if (ret)
++		goto out;
++
++	/* register devices */
++	audio_dev_id = register_sound_dsp(&h3600_audio_fops, -1);
++	mixer_dev_id = register_sound_mixer(&h3600_mixer_fops, -1);
++
++	printk( KERN_INFO "iPAQ audio support initialized\n" );
++	return 0;
++
++release_l3:
++	l3_detach_client(&uda1341);
++out:
++	return ret;
++}
++
++static void __exit h3600_uda1341_exit(void)
++{
++	unregister_sound_dsp(audio_dev_id);
++	unregister_sound_mixer(mixer_dev_id);
++	l3_detach_client(&uda1341);
++}
++
++module_init(h3600_uda1341_init);
++module_exit(h3600_uda1341_exit);
++
++MODULE_AUTHOR("Nicolas Pitre, George France");
++MODULE_DESCRIPTION("Glue audio driver for the Compaq iPAQ H3600 & Philips UDA1341 codec.");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/pangolin-uda1341.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,322 @@
++/*
++ * Glue audio driver for the SA1110 Pangolin board & Philips UDA1341 codec.
++ *
++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * This is the machine specific part of the Pangolin/UDA1341 support.
++ * This driver makes use of the UDA1341 and the sa1100-audio modules.
++ *
++ * History:
++ *
++ * 2000-05-21	Nicolas Pitre	Initial release.
++ *
++ * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on
++ * 				the former sa1100-uda1341.c driver.
++ *
++ * 2001-07-17	Nicolas Pitre	Supports 44100Hz and 22050Hz samplerate now.
++ *
++ * 2001-08-06	Richard Fan		Pangolin Support
++ *
++ * 2001-09-23	Russell King	Update inline with Assabet driver
++ *				Remove old L3 bus driver
++ *
++ * Note: this should probably be merged with the Assabet audio driver,
++ * and become the "SDRAM-clock driven" SA1100 audio driver.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/errno.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/l3/l3.h>
++#include <linux/l3/uda1341.h>
++
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++
++#include "sa1100-audio.h"
++
++/*
++ * Debugging?
++ */
++#undef DEBUG
++
++
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++
++#define AUDIO_RATE_DEFAULT	44100
++
++#define QmutePin             GPIO_GPIO(4)
++#define SpeakerOffPin        GPIO_GPIO(5)
++
++/*
++ * Mixer (UDA1341) interface
++ */
++
++static struct l3_client uda1341;
++
++static int
++mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++	/*
++	 * We only accept mixer (type 'M') ioctls.
++	 */
++	if (_IOC_TYPE(cmd) != 'M')
++		return -EINVAL;
++
++	return l3_command(&uda1341, cmd, (void *)arg);
++}
++
++static struct file_operations pangolin_mixer_fops = {
++	ioctl:		mixer_ioctl,
++	owner:		THIS_MODULE
++};
++
++
++/*
++ * Audio interface
++ */
++static long audio_samplerate = AUDIO_RATE_DEFAULT;
++
++static void pangolin_set_samplerate(long val)
++{
++	struct uda1341_cfg cfg;
++	int clk_div;
++
++	/* We don't want to mess with clocks when frames are in flight */
++	Ser4SSCR0 &= ~SSCR0_SSE;
++	/* wait for any frame to complete */
++	udelay(125);
++
++	/*
++	 * Our clock source is derived from the CPLD on which we don't have
++	 * much control unfortunately.  This was intended for a fixed 44100Hz
++	 * samplerate assuming a core clock of 206 MHz.  Still we can play
++	 * with the SA1110's clock divisor for the SSP port to get a 22050Hz
++	 * samplerate.
++	 *
++	 * Apparently the clock sent to the SA1110 for the SSP port is
++	 * divided from the clock sent to the UDA1341 (some people tried to
++	 * be too clever in their design, or simply failed to read the SA1110
++	 * manual).  If it was the same source we would have been able to
++	 * support a third samplerate.
++	 *
++	 * At least it would have been a minimum acceptable solution to be
++	 * able to set the CPLD divisor by software.  The iPAQ design is
++	 * certainly a better example to follow for a new design.
++	 */
++	if (val >= 44100) {
++		audio_samplerate = 44100;
++		cfg.fs = 256;
++		clk_div = SSCR0_SerClkDiv(2);
++	} else {
++		audio_samplerate = 22050;
++		cfg.fs = 512;
++		clk_div = SSCR0_SerClkDiv(4);
++	}
++
++	cfg.format = FMT_LSB16;
++	l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg);
++
++	Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE;
++}
++
++static void pangolin_audio_init(void *dummy)
++{
++	unsigned long flags;
++	unsigned int mdrefr;
++
++	local_irq_save(flags);
++
++	/*
++	 * Setup the SSP uart.
++	 */
++	PPAR |= PPAR_SPR;
++	Ser4SSCR0 = SSCR0_DataSize(16) + SSCR0_TI + SSCR0_SerClkDiv(2);
++	Ser4SSCR1 = SSCR1_SClkIactL + SSCR1_SClk1P + SSCR1_ExtClk;
++	GAFR |= GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK | GPIO_SSP_CLK |
++		GPIO_SSP_SFRM;
++	GPDR |= GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM;
++	GPDR &= ~(GPIO_SSP_RXD | GPIO_SSP_CLK);
++	Ser4SSCR0 |= SSCR0_SSE;
++
++	GAFR &= ~(SpeakerOffPin | QmutePin);
++	GPDR |=  (SpeakerOffPin | QmutePin);
++	GPCR = SpeakerOffPin;
++
++	/*
++	 * The assabet board uses the SDRAM clock as the source clock for
++	 * audio. This is supplied to the SA11x0 from the CPLD on pin 19.
++	 * At 206MHz we need to run the audio clock (SDRAM bank 2)
++	 * at half speed. This clock will scale with core frequency so
++	 * the audio sample rate will also scale. The CPLD on Assabet
++	 * will need to be programmed to match the core frequency.
++	 */
++	mdrefr = MDREFR;
++	if ((mdrefr & (MDREFR_K2DB2 | MDREFR_K2RUN | MDREFR_EAPD |
++		       MDREFR_KAPD)) != (MDREFR_K2DB2 | MDREFR_K2RUN)) {
++		mdrefr |= MDREFR_K2DB2 | MDREFR_K2RUN;
++		mdrefr &= ~(MDREFR_EAPD | MDREFR_KAPD);
++		MDREFR = mdrefr;
++		(void) MDREFR;
++	}
++	local_irq_restore(flags);
++
++	/* Wait for the UDA1341 to wake up */
++	mdelay(100);
++
++	l3_open(&uda1341);
++
++	pangolin_set_samplerate(audio_samplerate);
++
++	GPCR = QmutePin;
++}
++
++static void pangolin_audio_shutdown(void *dummy)
++{
++	GPSR = QmutePin;
++
++	l3_close(&uda1341);
++
++	Ser4SSCR0 = 0;
++	MDREFR &= ~(MDREFR_K2DB2 | MDREFR_K2RUN);
++}
++
++static int pangolin_audio_ioctl( struct inode *inode, struct file *file,
++				uint cmd, ulong arg)
++{
++	long val;
++	int ret = 0;
++
++	/*
++	 * These are platform dependent ioctls which are not handled by the
++	 * generic sa1100-audio module.
++	 */
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *) arg);
++		if (ret)
++			return ret;
++		/* the UDA1341 is stereo only */
++		ret = (val == 0) ? -EINVAL : 1;
++		return put_user(ret, (int *) arg);
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		/* the UDA1341 is stereo only */
++		return put_user(2, (long *) arg);
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (long *) arg);
++		if (ret) break;
++		pangolin_set_samplerate(val);
++		/* fall through */
++
++	case SOUND_PCM_READ_RATE:
++		return put_user(audio_samplerate, (long *) arg);
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		/* we can do signed 16-bit only */
++		return put_user(AFMT_S16_LE, (long *) arg);
++
++	default:
++		/* Maybe this is meant for the mixer (As per OSS Docs) */
++		return mixer_ioctl(inode, file, cmd, arg);
++	}
++
++	return ret;
++}
++
++static audio_stream_t output_stream, input_stream;
++
++static audio_state_t audio_state = {
++	output_stream:	&output_stream,
++	output_dma:	DMA_Ser4SSPWr,
++	output_id:	"Pangolin UDA1341 out",
++	input_stream:	&input_stream,
++	input_dma:	DMA_Ser4SSPRd,
++	input_id:	"Pangolin UDA1341 in",
++	need_tx_for_rx:	1,
++	hw_init:	pangolin_audio_init,
++	hw_shutdown:	pangolin_audio_shutdown,
++	client_ioctl:	pangolin_audio_ioctl,
++	sem:		__MUTEX_INITIALIZER(audio_state.sem),
++};
++
++static int pangolin_audio_open(struct inode *inode, struct file *file)
++{
++	return sa1100_audio_attach(inode, file, &audio_state);
++}
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to sa1100_audio_attach().
++ */
++static struct file_operations pangolin_audio_fops = {
++	open:		pangolin_audio_open,
++	owner:		THIS_MODULE
++};
++
++
++static int audio_dev_id, mixer_dev_id;
++
++static int __init pangolin_uda1341_init(void)
++{
++	unsigned long flags;
++	int ret;
++
++	if (!machine_is_pangolin())
++		return -ENODEV;
++
++	ret = l3_attach_client(&uda1341, "l3-bit-sa1100-gpio", "uda1341");
++	if (ret)
++		goto out;
++
++	/* register devices */
++	audio_dev_id = register_sound_dsp(&pangolin_audio_fops, -1);
++	mixer_dev_id = register_sound_mixer(&pangolin_mixer_fops, -1);
++
++	local_irq_save(flags);
++	GAFR &= ~(SpeakerOffPin | QmutePin);
++	GPDR |=  (SpeakerOffPin | QmutePin);
++	local_irq_restore(flags);
++
++	printk(KERN_INFO "Pangolin UDA1341 audio driver initialized\n");
++	return 0;
++
++release_l3:
++	l3_detach_client(&uda1341);
++out:
++	return ret;
++}
++
++static void __exit pangolin_uda1341_exit(void)
++{
++	unregister_sound_dsp(audio_dev_id);
++	unregister_sound_mixer(mixer_dev_id);
++	l3_detach_client(&uda1341);
++}
++
++module_init(pangolin_uda1341_init);
++module_exit(pangolin_uda1341_exit);
++
++MODULE_AUTHOR("Nicolas Pitre");
++MODULE_DESCRIPTION("Glue audio driver for the SA1110 Pangolin board & Philips UDA1341 codec.");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/sa1100-audio.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,976 @@
++/*
++ * Common audio handling for the SA11x0 processor
++ *
++ * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ *
++ * This module handles the generic buffering/DMA/mmap audio interface for
++ * codecs connected to the SA1100 chip.  All features depending on specific
++ * hardware implementations like supported audio formats or samplerates are
++ * relegated to separate specific modules.
++ *
++ *
++ * History:
++ *
++ * 2000-05-21	Nicolas Pitre	Initial release.
++ *
++ * 2000-06-10	Erik Bunce	Add initial poll support.
++ *
++ * 2000-08-22	Nicolas Pitre	Removed all DMA stuff. Now using the
++ * 				generic SA1100 DMA interface.
++ *
++ * 2000-11-30	Nicolas Pitre	- Validation of opened instances;
++ * 				- Power handling at open/release time instead
++ * 				  of driver load/unload;
++ *
++ * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on
++ * 				the former sa1100-uda1341.c driver.
++ *
++ * 2001-07-22	Nicolas Pitre	- added mmap() and realtime support
++ * 				- corrected many details to better comply
++ * 				  with the OSS API
++ *
++ * 2001-10-19	Nicolas Pitre	- brought DMA registration processing
++ * 				  into this module for better ressource
++ * 				  management.  This also fixes a bug
++ * 				  with the suspend/resume logic.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/poll.h>
++#include <linux/pm.h>
++#include <linux/errno.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/sysrq.h>
++
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/hardware.h>
++#include <asm/semaphore.h>
++#include <asm/dma.h>
++
++#include "sa1100-audio.h"
++
++
++#undef DEBUG 
++/* #define DEBUG 1 */
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++
++#define AUDIO_NAME		"sa1100-audio"
++#define AUDIO_NBFRAGS_DEFAULT	8
++#define AUDIO_FRAGSIZE_DEFAULT	8192
++
++#define NEXT_BUF(_s_,_b_) { \
++	(_s_)->_b_##_idx++; \
++	(_s_)->_b_##_idx %= (_s_)->nbfrags; \
++	(_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; }
++
++#define AUDIO_ACTIVE(state)	((state)->rd_ref || (state)->wr_ref)
++
++/*
++ * This function frees all buffers
++ */
++
++static void audio_clear_buf(audio_stream_t * s)
++{
++	DPRINTK("audio_clear_buf\n");
++
++	/* ensure DMA won't run anymore */
++	s->active = 0;
++	s->stopped = 0;
++	sa1100_dma_flush_all(s->dma_ch);
++
++	if (s->buffers) {
++		int frag;
++		for (frag = 0; frag < s->nbfrags; frag++) {
++			if (!s->buffers[frag].master)
++				continue;
++			consistent_free(s->buffers[frag].start,
++					s->buffers[frag].master,
++					s->buffers[frag].dma_addr);
++		}
++		kfree(s->buffers);
++		s->buffers = NULL;
++	}
++
++	s->buf_idx = 0;
++	s->buf = NULL;
++}
++
++
++/*
++ * This function allocates the buffer structure array and buffer data space
++ * according to the current number of fragments and fragment size.
++ */
++
++static int audio_setup_buf(audio_stream_t * s)
++{
++	int frag;
++	int dmasize = 0;
++	char *dmabuf = NULL;
++	dma_addr_t dmaphys = 0;
++
++	if (s->buffers)
++		return -EBUSY;
++
++	s->buffers = (audio_buf_t *)
++		kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
++	if (!s->buffers)
++		goto err;
++	memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
++
++	for (frag = 0; frag < s->nbfrags; frag++) {
++		audio_buf_t *b = &s->buffers[frag];
++
++		/*
++		 * Let's allocate non-cached memory for DMA buffers.
++		 * We try to allocate all memory at once.
++		 * If this fails (a common reason is memory fragmentation),
++		 * then we allocate more smaller buffers.
++		 */
++		if (!dmasize) {
++			dmasize = (s->nbfrags - frag) * s->fragsize;
++			do {
++			  	dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA,
++							  dmasize,
++							  &dmaphys);
++				if (!dmabuf)
++					dmasize -= s->fragsize;
++			} while (!dmabuf && dmasize);
++			if (!dmabuf)
++				goto err;
++			b->master = dmasize;
++			memzero(dmabuf, dmasize);
++		}
++
++		b->start = dmabuf;
++		b->dma_addr = dmaphys;
++		b->stream = s;
++		sema_init(&b->sem, 1);
++		DPRINTK("buf %d: start %p dma %p\n", frag, b->start,
++			b->dma_addr);
++
++		dmabuf += s->fragsize;
++		dmaphys += s->fragsize;
++		dmasize -= s->fragsize;
++	}
++
++	s->buf_idx = 0;
++	s->buf = &s->buffers[0];
++	s->bytecount = 0;
++	s->getptrCount = 0;
++	s->fragcount = 0;
++
++	return 0;
++
++err:
++	printk(AUDIO_NAME ": unable to allocate audio memory\n ");
++	audio_clear_buf(s);
++	return -ENOMEM;
++}
++
++
++/*
++ * This function yanks all buffers from the DMA code's control and
++ * resets them ready to be used again.
++ */
++
++static void audio_reset_buf(audio_stream_t * s)
++{
++	int frag;
++
++	s->active = 0;
++	s->stopped = 0;
++	sa1100_dma_flush_all(s->dma_ch);
++	if (s->buffers) {
++		for (frag = 0; frag < s->nbfrags; frag++) {
++			audio_buf_t *b = &s->buffers[frag];
++			b->size = 0;
++			sema_init(&b->sem, 1);
++		}
++	}
++	s->bytecount = 0;
++	s->getptrCount = 0;
++	s->fragcount = 0;
++}
++
++
++/*
++ * DMA callback functions
++ */
++
++static void audio_dmaout_done_callback(void *buf_id, int size)
++{
++	audio_buf_t *b = (audio_buf_t *) buf_id;
++	audio_stream_t *s = b->stream;
++
++	/* Accounting */
++	s->bytecount += size;
++	s->fragcount++;
++
++	/* Recycle buffer */
++	if (s->mapped)
++		sa1100_dma_queue_buffer(s->dma_ch, buf_id,
++					b->dma_addr, s->fragsize);
++	else
++		up(&b->sem);
++
++	/* And any process polling on write. */
++	wake_up(&s->wq);
++}
++
++static void audio_dmain_done_callback(void *buf_id, int size)
++{
++	audio_buf_t *b = (audio_buf_t *) buf_id;
++	audio_stream_t *s = b->stream;
++
++	/* Accounting */
++	s->bytecount += size;
++	s->fragcount++;
++
++	/* Recycle buffer */
++	if (s->mapped) {
++		sa1100_dma_queue_buffer(s->dma_ch, buf_id,
++					b->dma_addr, s->fragsize);
++	} else {
++		b->size = size;
++		up(&b->sem);
++	}
++
++	/* And any process polling on write. */
++	wake_up(&s->wq);
++}
++
++static int audio_sync(struct file *file)
++{
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	audio_stream_t *s = state->output_stream;
++	audio_buf_t *b;
++
++	DPRINTK("audio_sync\n");
++
++	if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped)
++		return 0;
++
++	/*
++	 * Send current buffer if it contains data.  Be sure to send
++	 * a full sample count.
++	 */
++	b = s->buf;
++	if (b->size &= ~3) {
++		down(&b->sem);
++		sa1100_dma_queue_buffer(s->dma_ch, (void *) b,
++					b->dma_addr, b->size);
++		b->size = 0;
++		NEXT_BUF(s, buf);
++	}
++
++	/*
++	 * Let's wait for the last buffer we sent i.e. the one before the
++	 * current buf_idx.  When we acquire the semaphore, this means either:
++	 * - DMA on the buffer completed or
++	 * - the buffer was already free thus nothing else to sync.
++	 */
++	b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags);
++	if (down_interruptible(&b->sem))
++		return -EINTR;
++	up(&b->sem);
++	return 0;
++}
++
++
++static int audio_write(struct file *file, const char *buffer,
++		       size_t count, loff_t * ppos)
++{
++	const char *buffer0 = buffer;
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	audio_stream_t *s = state->output_stream;
++	int chunksize, ret = 0;
++
++	DPRINTK("audio_write: count=%d\n", count);
++
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++	if (s->mapped)
++		return -ENXIO;
++	if (!s->buffers && audio_setup_buf(s))
++		return -ENOMEM;
++
++	while (count > 0) {
++		audio_buf_t *b = s->buf;
++
++		/* Wait for a buffer to become free */
++		if (file->f_flags & O_NONBLOCK) {
++			ret = -EAGAIN;
++			if (down_trylock(&b->sem))
++				break;
++		} else {
++			ret = -ERESTARTSYS;
++			if (down_interruptible(&b->sem))
++				break;
++		}
++
++		/* Feed the current buffer */
++		chunksize = s->fragsize - b->size;
++		if (chunksize > count)
++			chunksize = count;
++		DPRINTK("write %d to %d\n", chunksize, s->buf_idx);
++		if (copy_from_user(b->start + b->size, buffer, chunksize)) {
++			up(&b->sem);
++			return -EFAULT;
++		}
++		b->size += chunksize;
++		buffer += chunksize;
++		count -= chunksize;
++		if (b->size < s->fragsize) {
++			up(&b->sem);
++			break;
++		}
++
++		/* Send current buffer to dma */
++		s->active = 1;
++		sa1100_dma_queue_buffer(s->dma_ch, (void *) b,
++					b->dma_addr, b->size);
++		b->size = 0;	/* indicate that the buffer has been sent */
++		NEXT_BUF(s, buf);
++	}
++
++	if ((buffer - buffer0))
++		ret = buffer - buffer0;
++	DPRINTK("audio_write: return=%d\n", ret);
++	return ret;
++}
++
++
++static inline void audio_check_tx_spin(audio_state_t *state)
++{
++	/*
++	 * With some codecs like the Philips UDA1341 we must ensure
++	 * there is an output stream at any time while recording since
++	 * this is how the UDA1341 gets its clock from the SA1100.
++	 * So while there is no playback data to send, the output DMA
++	 * will spin with all zeroes.  We use the cache flush special
++	 * area for that.
++	 */
++	if (state->need_tx_for_rx && !state->tx_spinning) {
++		sa1100_dma_set_spin(state->output_stream->dma_ch,
++				    (dma_addr_t)FLUSH_BASE_PHYS, 2048);
++		state->tx_spinning = 1;
++	}
++}
++
++
++static void audio_prime_dma(audio_stream_t *s)
++{
++	int i;
++
++	s->active = 1;
++	for (i = 0; i < s->nbfrags; i++) {
++		audio_buf_t *b = s->buf;
++		down(&b->sem);
++		sa1100_dma_queue_buffer(s->dma_ch, (void *) b,
++					b->dma_addr, s->fragsize);
++		NEXT_BUF(s, buf);
++	}
++}
++
++
++static int audio_read(struct file *file, char *buffer,
++		      size_t count, loff_t * ppos)
++{
++	char *buffer0 = buffer;
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	audio_stream_t *s = state->input_stream;
++	int chunksize, ret = 0;
++
++	DPRINTK("audio_read: count=%d\n", count);
++
++	if (ppos != &file->f_pos)
++		return -ESPIPE;
++	if (s->mapped)
++		return -ENXIO;
++
++	if (!s->active) {
++		if (!s->buffers && audio_setup_buf(s))
++			return -ENOMEM;
++		audio_check_tx_spin(state);
++		audio_prime_dma(s);
++	}
++
++	while (count > 0) {
++		audio_buf_t *b = s->buf;
++
++		/* Wait for a buffer to become full */
++		if (file->f_flags & O_NONBLOCK) {
++			ret = -EAGAIN;
++			if (down_trylock(&b->sem))
++				break;
++		} else {
++			ret = -ERESTARTSYS;
++			if (down_interruptible(&b->sem))
++				break;
++		}
++
++		/* Grab data from the current buffer */
++		chunksize = b->size;
++		if (chunksize > count)
++			chunksize = count;
++		DPRINTK("read %d from %d\n", chunksize, s->buf_idx);
++		if (copy_to_user(buffer,
++				 b->start + s->fragsize - b->size,
++				 chunksize)) {
++			up(&b->sem);
++			return -EFAULT;
++		}
++		b->size -= chunksize;
++		buffer += chunksize;
++		count -= chunksize;
++		if (b->size > 0) {
++			up(&b->sem);
++			break;
++		}
++
++		/* Make current buffer available for DMA again */
++		sa1100_dma_queue_buffer(s->dma_ch, (void *) b,
++					b->dma_addr, s->fragsize);
++		NEXT_BUF(s, buf);
++	}
++
++	if ((buffer - buffer0))
++		ret = buffer - buffer0;
++	DPRINTK("audio_read: return=%d\n", ret);
++	return ret;
++}
++
++
++static int audio_mmap(struct file *file, struct vm_area_struct *vma)
++{
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	audio_stream_t *s;
++	unsigned long size, vma_addr;
++	int i, ret;
++
++	if (vma->vm_pgoff != 0)
++		return -EINVAL;
++
++	if (vma->vm_flags & VM_WRITE) {
++		if (!state->wr_ref)
++			return -EINVAL;;
++		s = state->output_stream;
++	} else if (vma->vm_flags & VM_READ) {
++		if (!state->rd_ref)
++			return -EINVAL;
++		s = state->input_stream;
++	} else return -EINVAL;
++
++	if (s->mapped)
++		return -EINVAL;
++	size = vma->vm_end - vma->vm_start;
++	if (size != s->fragsize * s->nbfrags)
++		return -EINVAL;
++	if (!s->buffers && audio_setup_buf(s))
++		return -ENOMEM;
++	vma_addr = vma->vm_start;
++	for (i = 0; i < s->nbfrags; i++) {
++		audio_buf_t *buf = &s->buffers[i];
++		if (!buf->master)
++			continue;
++		ret = remap_page_range(vma_addr, buf->dma_addr, buf->master, vma->vm_page_prot);
++		if (ret)
++			return ret;
++		vma_addr += buf->master;
++	}
++	s->mapped = 1;
++
++	return 0;
++}
++
++
++static unsigned int audio_poll(struct file *file,
++			       struct poll_table_struct *wait)
++{
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	audio_stream_t *is = state->input_stream;
++	audio_stream_t *os = state->output_stream;
++	unsigned int mask = 0;
++	int i;
++
++	DPRINTK("audio_poll(): mode=%s%s\n",
++		(file->f_mode & FMODE_READ) ? "r" : "",
++		(file->f_mode & FMODE_WRITE) ? "w" : "");
++
++	if (file->f_mode & FMODE_READ) {
++		/* Start audio input if not already active */
++		if (!is->active) {
++			if (!is->buffers && audio_setup_buf(is))
++				return -ENOMEM;
++			audio_check_tx_spin(state);
++			audio_prime_dma(is);
++		}
++		poll_wait(file, &is->wq, wait);
++	}
++
++	if (file->f_mode & FMODE_WRITE) {
++		if (!os->buffers && audio_setup_buf(os))
++			return -ENOMEM;
++		poll_wait(file, &os->wq, wait);
++	}
++
++	if (file->f_mode & FMODE_READ) {
++		if (is->mapped) {
++/* if the buffer is mapped assume we care that there are more bytes available than 
++   when we last asked using SNDCTL_DSP_GETxPTR */
++			if (is->bytecount != is->getptrCount)
++				mask |= POLLIN | POLLRDNORM;
++		} else {
++			for (i = 0; i < is->nbfrags; i++) {
++				if (atomic_read(&is->buffers[i].sem.count) > 0) {
++					mask |= POLLIN | POLLRDNORM;
++					break;
++				}
++			}
++		}
++	}
++	if (file->f_mode & FMODE_WRITE) {
++		if (os->mapped) {
++			if (os->bytecount != os->getptrCount)
++				mask |= POLLOUT | POLLWRNORM;
++		} else {
++			for (i = 0; i < os->nbfrags; i++) {
++				if (atomic_read(&os->buffers[i].sem.count) > 0) {
++					mask |= POLLOUT | POLLWRNORM;
++					break;
++				}
++			}
++		}
++	}
++
++	DPRINTK("audio_poll() returned mask of %s%s\n",
++		(mask & POLLIN) ? "r" : "",
++		(mask & POLLOUT) ? "w" : "");
++
++	return mask;
++}
++
++
++static loff_t audio_llseek(struct file *file, loff_t offset, int origin)
++{
++	return -ESPIPE;
++}
++
++
++static int audio_set_fragments(audio_stream_t *s, int val)
++{
++	if (s->active)
++		return -EBUSY;
++	if (s->buffers)
++		audio_clear_buf(s);
++	s->nbfrags = (val >> 16) & 0x7FFF;
++	val &= 0xffff;
++	if (val < 4)
++		val = 4;
++	if (val > 15)
++		val = 15;
++	s->fragsize = 1 << val;
++	if (s->nbfrags < 2)
++		s->nbfrags = 2;
++	if (s->nbfrags * s->fragsize > 128 * 1024)
++		s->nbfrags = 128 * 1024 / s->fragsize;
++	if (audio_setup_buf(s))
++		return -ENOMEM;
++	return val|(s->nbfrags << 16);
++}
++
++static int audio_ioctl(struct inode *inode, struct file *file,
++		       uint cmd, ulong arg)
++{
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	audio_stream_t *os = state->output_stream;
++	audio_stream_t *is = state->input_stream;
++	long val;
++
++	/* dispatch based on command */
++	switch (cmd) {
++	case OSS_GETVERSION:
++		return put_user(SOUND_VERSION, (int *)arg);
++
++	case SNDCTL_DSP_GETBLKSIZE:
++		if (file->f_mode & FMODE_WRITE)
++			return put_user(os->fragsize, (int *)arg);
++		else
++			return put_user(is->fragsize, (int *)arg);
++
++	case SNDCTL_DSP_GETCAPS:
++		val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;
++		if (is && os)
++			val |= DSP_CAP_DUPLEX;
++		return put_user(val, (int *)arg);
++
++	case SNDCTL_DSP_SETFRAGMENT:
++		if (get_user(val, (long *) arg))
++			return -EFAULT;
++		if (file->f_mode & FMODE_READ) {
++			int ret = audio_set_fragments(is, val);
++			if (ret < 0)
++				return ret;
++			ret = put_user(ret, (int *)arg);
++			if (ret)
++				return ret;
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			int ret = audio_set_fragments(os, val);
++			if (ret < 0)
++				return ret;
++			ret = put_user(ret, (int *)arg);
++			if (ret)
++				return ret;
++		}
++		return 0;
++
++	case SNDCTL_DSP_SYNC:
++		return audio_sync(file);
++
++	case SNDCTL_DSP_SETDUPLEX:
++		return 0;
++
++	case SNDCTL_DSP_POST:
++		return 0;
++
++	case SNDCTL_DSP_GETTRIGGER:
++		val = 0;
++		if (file->f_mode & FMODE_READ && is->active && !is->stopped)
++			val |= PCM_ENABLE_INPUT;
++		if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
++			val |= PCM_ENABLE_OUTPUT;
++		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) {
++				if (!is->active) {
++					if (!is->buffers && audio_setup_buf(is))
++						return -ENOMEM;
++					audio_prime_dma(is);
++				}
++				audio_check_tx_spin(state);
++				if (is->stopped) {
++					is->stopped = 0;
++					sa1100_dma_resume(is->dma_ch);
++				}
++			} else {
++				sa1100_dma_stop(is->dma_ch);
++				is->stopped = 1;
++			}
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			if (val & PCM_ENABLE_OUTPUT) {
++				if (!os->active) {
++					if (!os->buffers && audio_setup_buf(os))
++						return -ENOMEM;
++					if (os->mapped)
++						audio_prime_dma(os);
++				}
++				if (os->stopped) {
++					os->stopped = 0;
++					sa1100_dma_resume(os->dma_ch);
++				}
++			} else {
++				sa1100_dma_stop(os->dma_ch);
++				os->stopped = 1;
++			}
++		}
++		return 0;
++
++	case SNDCTL_DSP_GETOPTR:
++	case SNDCTL_DSP_GETIPTR:
++	    {
++		count_info inf = { 0, };
++		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
++		audio_buf_t *b;
++		dma_addr_t ptr;
++		int bytecount, offset, flags;
++
++		if ((s == is && !(file->f_mode & FMODE_READ)) ||
++		    (s == os && !(file->f_mode & FMODE_WRITE)))
++			return -EINVAL;
++		if (s->active) {
++			save_flags_cli(flags);
++			if (sa1100_dma_get_current(s->dma_ch, (void *)&b, &ptr) == 0) {
++				offset = ptr - b->dma_addr;
++				inf.ptr = (b - s->buffers) * s->fragsize + offset;
++			} else offset = 0;
++			bytecount = s->bytecount + offset;
++			s->getptrCount = s->bytecount;	/* so poll can tell if it changes */
++			inf.blocks = s->fragcount;
++			s->fragcount = 0;
++			restore_flags(flags);
++			if (bytecount < 0)
++				bytecount = 0;
++			inf.bytes = bytecount;
++		}
++		return copy_to_user((void *)arg, &inf, sizeof(inf));
++	    }
++
++	case SNDCTL_DSP_GETOSPACE:
++	    {
++		audio_buf_info inf = { 0, };
++		int i;
++
++		if (!(file->f_mode & FMODE_WRITE))
++			return -EINVAL;
++		if (!os->buffers && audio_setup_buf(os))
++			return -ENOMEM;
++		for (i = 0; i < os->nbfrags; i++) {
++			if (atomic_read(&os->buffers[i].sem.count) > 0) {
++				if (os->buffers[i].size == 0)
++					inf.fragments++;
++				inf.bytes += os->fragsize - os->buffers[i].size;
++			}
++		}
++		inf.fragstotal = os->nbfrags;
++		inf.fragsize = os->fragsize;
++		return copy_to_user((void *)arg, &inf, sizeof(inf));
++	    }
++
++	case SNDCTL_DSP_GETISPACE:
++	    {
++		audio_buf_info inf = { 0, };
++		int i;
++
++		if (!(file->f_mode & FMODE_READ))
++			return -EINVAL;
++		if (!is->buffers && audio_setup_buf(is))
++			return -ENOMEM;
++		for (i = 0; i < is->nbfrags; i++) {
++			if (atomic_read(&is->buffers[i].sem.count) > 0) {
++				if (is->buffers[i].size == is->fragsize)
++					inf.fragments++;
++				inf.bytes += is->buffers[i].size;
++			}
++		}
++		inf.fragstotal = is->nbfrags;
++		inf.fragsize = is->fragsize;
++		return copy_to_user((void *)arg, &inf, sizeof(inf));
++	    }
++
++	case SNDCTL_DSP_NONBLOCK:
++		file->f_flags |= O_NONBLOCK;
++		return 0;
++
++	case SNDCTL_DSP_RESET:
++		if (file->f_mode & FMODE_READ) {
++			if (state->tx_spinning) {
++				sa1100_dma_set_spin(os->dma_ch, 0, 0);
++				state->tx_spinning = 0;
++			}
++			audio_reset_buf(is);
++		}
++		if (file->f_mode & FMODE_WRITE) {
++			audio_reset_buf(os);
++		}
++		return 0;
++
++	default:
++		/*
++		 * Let the client of this module handle the
++		 * non generic ioctls
++		 */
++		return state->client_ioctl(inode, file, cmd, arg);
++	}
++
++	return 0;
++}
++
++
++static int audio_release(struct inode *inode, struct file *file)
++{
++	audio_state_t *state = (audio_state_t *)file->private_data;
++	DPRINTK("audio_release\n");
++
++	down(&state->sem);
++
++	if (file->f_mode & FMODE_READ) {
++		if (state->tx_spinning) {
++			sa1100_dma_set_spin(state->output_stream->dma_ch, 0, 0);
++			state->tx_spinning = 0;
++		}
++		audio_clear_buf(state->input_stream);
++		if (!state->skip_dma_init) {
++			sa1100_free_dma(state->input_stream->dma_ch);
++			if (state->need_tx_for_rx && !state->wr_ref)
++				sa1100_free_dma(state->output_stream->dma_ch);
++		}
++		state->rd_ref = 0;
++	}
++
++	if (file->f_mode & FMODE_WRITE) {
++		audio_sync(file);
++		audio_clear_buf(state->output_stream);
++		if (!state->skip_dma_init)
++			if (!state->need_tx_for_rx || !state->rd_ref)
++				sa1100_free_dma(state->output_stream->dma_ch);
++		state->wr_ref = 0;
++	}
++
++	if (!AUDIO_ACTIVE(state)) {
++	       if (state->hw_shutdown)
++		       state->hw_shutdown(state->data);
++#ifdef CONFIG_PM
++	       pm_unregister(state->pm_dev);
++#endif
++	}
++
++	up(&state->sem);
++	return 0;
++}
++
++
++#ifdef CONFIG_PM
++
++static int audio_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
++{
++	audio_state_t *state = (audio_state_t *)pm_dev->data;
++
++	switch (req) {
++	case PM_SUSPEND: /* enter D1-D3 */
++		if (state->output_stream)
++			sa1100_dma_sleep(state->output_stream->dma_ch);
++		if (state->input_stream)
++			sa1100_dma_sleep(state->input_stream->dma_ch);
++		if (AUDIO_ACTIVE(state) && state->hw_shutdown)
++			state->hw_shutdown(state->data);
++		break;
++	case PM_RESUME:  /* enter D0 */
++		if (AUDIO_ACTIVE(state) && state->hw_init)
++			state->hw_init(state->data);
++		if (state->input_stream)
++			sa1100_dma_wakeup(state->input_stream->dma_ch);
++		if (state->output_stream)
++			sa1100_dma_wakeup(state->output_stream->dma_ch);
++		break;
++	}
++	return 0;
++}
++
++#endif
++
++
++int sa1100_audio_attach(struct inode *inode, struct file *file,
++			  audio_state_t *state)
++{
++	int err, need_tx_dma;
++
++	DPRINTK("audio_open\n");
++
++	down(&state->sem);
++
++	/* access control */
++	err = -ENODEV;
++	if ((file->f_mode & FMODE_WRITE) && !state->output_stream)
++		goto out;
++	if ((file->f_mode & FMODE_READ) && !state->input_stream)
++		goto out;
++	err = -EBUSY;
++	if ((file->f_mode & FMODE_WRITE) && state->wr_ref)
++		goto out;
++	if ((file->f_mode & FMODE_READ) && state->rd_ref)
++		goto out;
++	err = -EINVAL;
++	if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !state->output_stream)
++		goto out;
++
++	/* request DMA channels */
++	if (state->skip_dma_init)
++		goto skip_dma;
++	need_tx_dma = ((file->f_mode & FMODE_WRITE) ||
++		       ((file->f_mode & FMODE_READ) && state->need_tx_for_rx));
++	if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx))
++		need_tx_dma = 0;
++	if (need_tx_dma) {
++		err = sa1100_request_dma(&state->output_stream->dma_ch,
++					 state->output_id,
++					 state->output_dma);
++		if (err)
++			goto out;
++	}
++	if (file->f_mode & FMODE_READ) {
++		err = sa1100_request_dma(&state->input_stream->dma_ch,
++					 state->input_id,
++					 state->input_dma);
++		if (err) {
++			if (need_tx_dma)
++				sa1100_free_dma(state->output_stream->dma_ch);
++			goto out;
++		}
++	}
++skip_dma:
++
++	/* now complete initialisation */
++	if (!AUDIO_ACTIVE(state)) {
++		if (state->hw_init)
++			state->hw_init(state->data);
++#ifdef CONFIG_PM
++		state->pm_dev = pm_register(PM_SYS_DEV, 0, audio_pm_callback);
++		if (state->pm_dev)
++			state->pm_dev->data = state;
++#endif
++	}
++
++	if ((file->f_mode & FMODE_WRITE)) {
++		state->wr_ref = 1;
++		audio_clear_buf(state->output_stream);
++		state->output_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT;
++		state->output_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT;
++		state->output_stream->mapped = 0;
++		sa1100_dma_set_callback(state->output_stream->dma_ch,
++					audio_dmaout_done_callback);
++		init_waitqueue_head(&state->output_stream->wq);
++	}
++	if (file->f_mode & FMODE_READ) {
++		state->rd_ref = 1;
++		audio_clear_buf(state->input_stream);
++		state->input_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT;
++		state->input_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT;
++		state->input_stream->mapped = 0;
++		sa1100_dma_set_callback(state->input_stream->dma_ch,
++					audio_dmain_done_callback);
++		init_waitqueue_head(&state->input_stream->wq);
++	}
++
++	file->private_data	= state;
++	file->f_op->release	= audio_release;
++	file->f_op->write	= audio_write;
++	file->f_op->read	= audio_read;
++	file->f_op->mmap	= audio_mmap;
++	file->f_op->poll	= audio_poll;
++	file->f_op->ioctl	= audio_ioctl;
++	file->f_op->llseek	= audio_llseek;
++	err = 0;
++
++out:
++	up(&state->sem);
++	return err;
++}
++
++EXPORT_SYMBOL(sa1100_audio_attach);
++
++MODULE_AUTHOR("Nicolas Pitre");
++MODULE_DESCRIPTION("Common audio handling for the SA11x0 processor");
++MODULE_LICENSE("GPL");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/sa1100-audio.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,68 @@
++/*
++ * Common audio handling for the SA11x0
++ *
++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++
++
++/*
++ * Buffer Management
++ */
++
++typedef struct {
++	int size;		/* buffer size */
++	char *start;		/* points to actual buffer */
++	dma_addr_t dma_addr;	/* physical buffer address */
++	struct semaphore sem;	/* down before touching the buffer */
++	int master;		/* owner for buffer allocation, contain size when true */
++	struct audio_stream_s *stream;	/* owning stream */
++} audio_buf_t;
++
++typedef struct audio_stream_s {
++	audio_buf_t *buffers;	/* pointer to audio buffer structures */
++	audio_buf_t *buf;	/* current buffer used by read/write */
++	u_int buf_idx;		/* index for the pointer above... */
++	u_int fragsize;		/* fragment i.e. buffer size */
++	u_int nbfrags;		/* nbr of fragments i.e. buffers */
++	int bytecount;		/* nbr of processed bytes */
++	int getptrCount;	/* value of bytecount last time anyone asked via GETxPTR */
++	int fragcount;		/* nbr of fragment transitions */
++	dmach_t dma_ch;		/* DMA channel ID */
++	wait_queue_head_t wq;	/* for poll */
++	int mapped:1;		/* mmap()'ed buffers */
++	int active:1;		/* actually in progress */
++	int stopped:1;		/* might be active but stopped */
++} audio_stream_t;
++
++/*
++ * State structure for one instance
++ */
++
++typedef struct {
++	audio_stream_t *output_stream;
++	audio_stream_t *input_stream;
++	dma_device_t output_dma;
++	dma_device_t input_dma;
++	char *output_id;
++	char *input_id;
++	int rd_ref:1;		/* open reference for recording */
++	int wr_ref:1;		/* open reference for playback */
++	int need_tx_for_rx:1;	/* if data must be sent while receiving */
++	int tx_spinning:1;	/* tx spinning active */
++	int skip_dma_init:1;	/* hack for the SA1111 */
++	void *data;
++	void (*hw_init)(void *);
++	void (*hw_shutdown)(void *);
++	int (*client_ioctl)(struct inode *, struct file *, uint, ulong);
++	struct pm_dev *pm_dev;
++	struct semaphore sem;	/* to protect against races in attach() */
++} audio_state_t;
++
++/*
++ * Functions exported by this module
++ */
++extern int sa1100_audio_attach( struct inode *inode, struct file *file,
++				audio_state_t *state);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/sa1100ssp.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,182 @@
++/*
++ * Glue audio driver for a simple DAC on the SA1100's SSP port
++ *
++ * Copyright (c) 2001 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * History:
++ *
++ * 2001-06-04	Nicolas Pitre	Initial release.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/errno.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++
++#include "sa1100-audio.h"
++
++
++#undef DEBUG
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++
++#define AUDIO_NAME		"SA1100 SSP audio"
++
++#define AUDIO_FMT		AFMT_S16_LE
++#define AUDIO_CHANNELS		2
++
++static int sample_rate = 44100;
++
++
++static void ssp_audio_init(void)
++{
++	if (machine_is_lart()) {
++		unsigned long flags;
++		local_irq_save(flags);
++
++		/* LART has the SSP port rewired to GPIO 10-13, 19 */
++		/* alternate functions for the GPIOs */
++		GAFR |= ( GPIO_SSP_TXD | GPIO_SSP_RXD | GPIO_SSP_SCLK |
++			  GPIO_SSP_SFRM | GPIO_SSP_CLK );
++
++		/* Set the direction: 10, 12, 13 output; 11, 19 input */
++		GPDR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM );
++		GPDR &= ~( GPIO_SSP_RXD | GPIO_SSP_CLK );
++
++		/* enable SSP pin swap */
++		PPAR |= PPAR_SPR;
++
++		local_irq_restore(flags);
++	}
++
++	/* turn on the SSP */
++	Ser4SSCR0 = 0;
++	Ser4SSCR0 = (SSCR0_DataSize(16) | SSCR0_TI | SSCR0_SerClkDiv(2) |
++		     SSCR0_SSE);
++	Ser4SSCR1 = (SSCR1_SClkIactL | SSCR1_SClk1P | SSCR1_ExtClk);
++}
++
++static void ssp_audio_shutdown(void)
++{
++	Ser4SSCR0 = 0;
++}
++
++static int ssp_audio_ioctl( struct inode *inode, struct file *file,
++			    uint cmd, ulong arg)
++{
++	long val;
++	int ret = 0;
++
++	/*
++	 * These are platform dependent ioctls which are not handled by the
++	 * generic sa1100-audio module.
++	 */
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *) arg);
++		if (ret)
++			return ret;
++		/* Simple standard DACs are stereo only */
++		ret = (val == 0) ? -EINVAL : 1;
++		return put_user(ret, (int *) arg);
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		/* Simple standard DACs are stereo only */
++		return put_user(AUDIO_CHANNELS, (long *) arg);
++
++	case SNDCTL_DSP_SPEED:
++	case SOUND_PCM_READ_RATE:
++		/* We assume the clock doesn't change */
++		return put_user(sample_rate, (long *) arg);
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		/* Simple standard DACs are 16-bit only */
++		return put_user(AUDIO_FMT, (long *) arg);
++
++	default:
++		return -EINVAL;
++	}
++
++	return ret;
++}
++
++static audio_stream_t output_stream;
++
++static audio_state_t audio_state = {
++	output_stream:	&output_stream,
++	output_dma:	DMA_Ser4SSPWr,
++	output_id:	"Generic SSP sound",
++	hw_init:	ssp_audio_init,
++	hw_shutdown:	ssp_audio_shutdown,
++	client_ioctl:	ssp_audio_ioctl,
++	sem:		__MUTEX_INITIALIZER(audio_state.sem),
++};
++
++static int ssp_audio_open(struct inode *inode, struct file *file)
++{
++	return sa1100_audio_attach(inode, file, &audio_state);
++}
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to sa1100_audio_attach().
++ */
++static struct file_operations ssp_audio_fops = {
++	open:		ssp_audio_open,
++	owner:		THIS_MODULE
++};
++
++static int audio_dev_id;
++
++static int __init sa1100ssp_audio_init(void)
++{
++	int ret;
++
++	if (!machine_is_lart()) {
++		printk(KERN_ERR AUDIO_NAME ": no support for this SA-1100 design!\n");
++		/* look at ssp_audio_init() for specific initialisations */
++		return -ENODEV;
++	}
++
++	/* register devices */
++	audio_dev_id = register_sound_dsp(&ssp_audio_fops, -1);
++
++	printk( KERN_INFO AUDIO_NAME " initialized\n" );
++	return 0;
++}
++
++static void __exit sa1100ssp_audio_exit(void)
++{
++	unregister_sound_dsp(audio_dev_id);
++}
++
++module_init(sa1100ssp_audio_init);
++module_exit(sa1100ssp_audio_exit);
++
++MODULE_AUTHOR("Nicolas Pitre");
++MODULE_DESCRIPTION("Glue audio driver for a simple DAC on the SA1100's SSP port");
++
++MODULE_PARM(sample_rate, "i");
++MODULE_PARM_DESC(sample_rate, "Sample rate of the audio DAC, default is 44100");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/sa1111-ac97.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,518 @@
++/*
++ * Glue audio driver for the CS4205 and CS4201 AC'97 codecs.
++ * largely based on the framework provided by sa1111-uda1341.c.
++ *
++ * Copyright (c) 2002 Bertrik Sikken (bertrik.sikken@technolution.nl)
++ * Copyright (c) 2002 Robert Whaley (rwhaley@applieddata.net)
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * This driver makes use of the ac97_codec module (for mixer registers)
++ * and the sa1100-audio module (for DMA).
++ *
++ * History:
++ *
++ * 2002-04-04	Initial version.
++ * 2002-04-10	Updated mtd_audio_init to improve choppy sound
++ *              and hanging sound issue.
++ * 2002-05-16   Updated for ADS Bitsy+ Robert Whaley
++ * 2002-06-28   Cleanup and added retry for read register timeouts
++ * 2002-08-14   Updated for ADS AGC Robert Whaley
++ * 2002-12-26   Cleanup, remove CONFIG_PM (it's handled by sa1100-audio.c)
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/errno.h>
++#include <linux/proc_fs.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/ac97_codec.h>
++
++#include <asm/semaphore.h>
++#include <asm/uaccess.h>
++#include <asm/dma.h>
++#include <asm/hardware/sa1111.h>
++
++#include "sa1100-audio.h"
++
++/* SAC FIFO depth, low nibble is transmit fifo, high nibble is receive FIFO */
++#define SAC_FIFO_DEPTH		0x77
++
++// #define DEBUG
++
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++/*
++	Our codec data
++*/
++static struct ac97_codec ac97codec;
++static int audio_dev_id, mixer_dev_id;
++static audio_stream_t output_stream, input_stream;
++
++/* proc info */
++
++struct proc_dir_entry *ac97_ps;
++
++static int sa1111_ac97_set_adc_rate(long rate);
++static void sa1111_ac97_write_reg(struct ac97_codec *dev, u8 reg, u16 val);
++static u16 sa1111_ac97_read_reg(struct ac97_codec *dev, u8 reg);
++
++static int
++mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++	/*
++	 * We only accept mixer (type 'M') ioctls.
++	 */
++	if (_IOC_TYPE(cmd) != 'M') {
++		return -EINVAL;
++	}
++
++	/* pass the ioctl to the ac97 mixer */
++	return ac97codec.mixer_ioctl(&ac97codec, cmd, arg);
++}
++
++
++static struct file_operations sa1111_ac97_mixer_fops = {
++	ioctl:		mixer_ioctl,
++	owner:		THIS_MODULE
++};
++
++static void sa1111_ac97_power_off(void *dummy)
++{
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++	/* turn off audio and audio amp */
++	ADS_CPLD_PCON |= (ADS_PCON_AUDIO_ON | ADS_PCON_AUDIOPA_ON);
++
++	/* make GPIO11 high impeadence */
++	GPDR &= ~GPIO_GPIO11;
++
++	/* disable SACR0 so we can make these pins high impeadence */
++	SACR0 &= ~SACR0_ENB;
++
++	/* make BIT_CLK, SDATA_OUT, and SYNC high impeadence */
++	PC_DDR |= (GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
++
++#endif
++
++#ifdef CONFIG_SA1100_ADSAGC
++	/* turn off audio and audio amp */
++	ADS_CR1 &= ~(ADS_CR1_CODEC | ADS_CR1_AMP);
++
++	/* disable SACR0 so we can make these pins high impeadence */
++	SACR0 &= ~SACR0_ENB;
++
++	/* make BIT_CLK, SDATA_OUT, and SYNC high impeadence */
++	PC_DDR |= (GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
++
++#endif
++}
++
++
++static void sa1111_ac97_power_on(void *dummy)
++{
++	int ret, i;
++
++	/* disable L3 */
++	SACR1 = 0;
++
++	SKPCR |= (SKPCR_ACCLKEN);	/* enable ac97 clock */
++	udelay(50);
++
++	/* BIT_CLK is input to SA1111, DMA thresholds 9 (both dirs) */
++	SACR0 |= SACR0_BCKD | (SAC_FIFO_DEPTH << 8);
++
++	/* reset SAC registers */
++	SACR0 &= ~SACR0_RST;
++	udelay(50);
++	SACR0 |= SACR0_RST;
++	udelay(50);
++	SACR0 &= ~SACR0_RST;
++
++	/* setup SA1111 to use AC'97 */
++	SBI_SKCR |= SKCR_SELAC;		/* select ac97 */
++	udelay(50);
++
++	/* issue a cold AC97 reset */
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++
++	/* initialize reset line */
++	GAFR &= ~GPIO_GPIO11;
++	GPDR |= GPIO_GPIO11;
++	GPSR = GPIO_GPIO11;
++
++	/* turn on audio and audio amp */
++	ADS_CPLD_PCON &= ~(ADS_PCON_AUDIO_ON | ADS_PCON_AUDIOPA_ON);
++	mdelay(5);
++
++	/* reset by lowering the reset pin momentarily */
++	DPRINTK("reseting codec via GPIO11\n");
++	GPCR = GPIO_GPIO11;
++	udelay(5);
++	GPSR = GPIO_GPIO11;
++	udelay(10);
++
++#endif
++#ifdef CONFIG_SA1100_ADSAGC
++
++	/* turn on audio and audio amp */
++	DPRINTK("before turning on power.  ADS_CR1: %x\n", ADS_CR1);
++	ADS_CR1 |= (ADS_CR1_AMP | ADS_CR1_CODEC);
++	DPRINTK("after turnning on power.  ADS_CR1: %x\n", ADS_CR1);
++	mdelay(5);
++
++	/* reset by lowering the reset pin momentarily */
++	DPRINTK("reseting codec via CPLD\n");
++	ADS_CR1 |= ADS_CR1_AUDIO_RST;
++	DPRINTK("after reset1.  ADS_CR1: %x\n", ADS_CR1);
++	udelay(5);
++	ADS_CR1 &= ~ADS_CR1_AUDIO_RST;
++	DPRINTK("after reset2.  ADS_CR1: %x\n", ADS_CR1);
++	udelay(10);
++
++#endif
++	SACR2 = 0;
++	udelay(50);
++
++	DPRINTK("before SW reset:  SACR2: %x\n", SACR2);
++	SACR2 = SACR2_RESET;
++	DPRINTK("after SW reset:  SACR2: %x\n", SACR2);
++	udelay(50);
++
++	/* set AC97 slot 3 and 4 (PCM out) to valid */
++	SACR2 = (SACR2_RESET | SACR2_TS3V | SACR2_TS4V);
++
++	/* enable SAC */
++	SACR0 |= SACR0_ENB;
++
++	i = 100;
++	while (!(SASR1 & SASR1_CRDY)) {
++		if (!i--) {
++			printk("Didn't get CRDY.  SASR1=%x SKID=%x\n", SASR1, SBI_SKID);
++			break;
++		}
++		udelay(50);
++	}
++
++	if (!(ret = ac97_probe_codec(&ac97codec))) {
++		printk("ac97_probe_codec failed  (%d)\n", ret);
++		return;
++	}
++
++	/* mic ADC on, disable VRA, disable VRM */
++	sa1111_ac97_write_reg(&ac97codec, AC97_EXTENDED_STATUS, 0x0200);
++}
++
++
++/*
++ * Audio interface
++ */
++
++
++static int sa1111_ac97_audio_ioctl(struct inode *inode, struct file *file,
++			     uint cmd, ulong arg)
++{
++	long val;
++	int ret = 0;
++
++	DPRINTK("sa1111_ac97_audio_ioctl\n");
++
++	/*
++	 * These are platform dependent ioctls which are not handled by the
++	 * generic sa1100-audio module.
++	 */
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *) arg);
++		if (ret) {
++			return ret;
++		}
++		/* the cs42xx is stereo only */
++		ret = (val == 0) ? -EINVAL : 1;
++		return put_user(ret, (int *) arg);
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		/* the cs42xx is stereo only */
++		return put_user(2, (long *) arg);
++
++#define SA1100_AC97_IOCTL_EXTRAS
++
++#ifdef SA1100_AC97_IOCTL_EXTRAS
++
++#define SNDCTL_DSP_AC97_CMD _SIOWR('P', 99, int)
++#define SNDCTL_DSP_INPUT_SPEED _SIOWR('P', 98, int)
++#define SOUND_PCM_READ_INPUT_RATE _SIOWR('P', 97, int)
++
++	case SNDCTL_DSP_AC97_CMD:
++
++		ret = get_user(val, (long *) arg);
++		if (ret) {
++			break;
++		}
++		sa1111_ac97_write_reg(&ac97codec, (u8) ((val & 0xff000000) >> 24), (u16) (val & 0xffff));
++		return 0;
++
++
++	case SNDCTL_DSP_INPUT_SPEED:
++		ret = get_user(val, (long *) arg);
++		// acc code here to set the speed
++		if (ret) {
++			break;
++		}
++		// note that this only changes the ADC rate, not the
++		// rate of the DAC.
++		ret = sa1111_ac97_set_adc_rate(val);
++		if (ret)
++		  break;
++		return put_user(val, (long *) arg);
++
++	case SOUND_PCM_READ_INPUT_RATE:
++
++		return put_user((long) sa1111_ac97_read_reg(&ac97codec, 0x32), (long *) arg);
++
++
++#endif
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (long *) arg);
++		if (ret) {
++			break;
++		}
++
++	case SOUND_PCM_READ_RATE:
++		/* only 48 kHz playback is supported by the SA1111 */
++		return put_user(48000L, (long *) arg);
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		/* we can do 16-bit only */
++		return put_user(AFMT_S16_LE, (long *) arg);
++
++	default:
++		/* Maybe this is meant for the mixer (As per OSS Docs) */
++		return mixer_ioctl(inode, file, cmd, arg);
++	}
++
++	return ret;
++}
++
++
++static audio_state_t audio_state = {
++	output_stream:	&output_stream,
++	input_stream:	&input_stream,
++	skip_dma_init:	1,  /* done locally */
++	hw_init:        sa1111_ac97_power_on,
++	hw_shutdown:	sa1111_ac97_power_off,
++	client_ioctl:	sa1111_ac97_audio_ioctl,
++	sem:			__MUTEX_INITIALIZER(audio_state.sem),
++};
++
++
++static int sa1111_ac97_audio_open(struct inode *inode, struct file *file)
++{
++	return sa1100_audio_attach(inode, file, &audio_state);
++}
++
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to sa1100_audio_attach().
++ */
++static struct file_operations sa1111_ac97_audio_fops = {
++	open:		sa1111_ac97_audio_open,
++	owner:		THIS_MODULE
++};
++
++
++static void sa1111_ac97_write_reg(struct ac97_codec *dev, u8 reg, u16 val)
++{
++	int i;
++
++	/* reset status bits */
++	SASCR = SASCR_DTS;
++
++	/* write command and data registers */
++	ACCAR = reg << 12;
++	ACCDR = val << 4;
++
++	/* wait for data to be transmitted */
++	i = 0;
++	while ((SASR1 & SASR1_CADT) == 0) {
++		udelay(50);
++		if (++i > 10) {
++			DPRINTK("sa1111_ac97_write_reg failed (data not transmitted. SASR1: %x)\n", SASR1);
++			break;
++		}
++	}
++
++	DPRINTK("<%03d> sa1111_ac97_write_reg, [%02X]=%04X\n", i, reg, val);
++}
++
++
++static u16 sa1111_ac97_read_reg(struct ac97_codec *dev, u8 reg)
++{
++	u16		val;
++	int		i;
++	int		retry = 10;
++
++	do {
++		/* reset status bits */
++		SASCR = SASCR_RDD | SASCR_STO;
++
++		/* write command register */
++		ACCAR = (reg | 0x80) << 12;
++		ACCDR = 0;
++
++		/* wait for SADR bit in SASR1 */
++		i = 0;
++		while ((SASR1 & SASR1_SADR) == 0) {
++			udelay(50);
++			if (++i > 10) {
++				DPRINTK("<---> sa1111_ac97_read_reg failed\n");
++				retry--;
++				break;
++			}
++			if ((SASR1 & SASR1_RSTO) != 0) {
++				DPRINTK("sa1111_ac97_read_reg *timeout*\n");
++				retry--;
++				break;
++			}
++		}
++
++	} while ((SASR1 & SASR1_SADR) == 0 && retry > 0);
++
++	val = ACSDR >> 4;
++
++	DPRINTK("<%03d> sa1111_ac97_read_reg, [%02X]=%04X\n", i, reg, val);
++	return val;
++}
++
++
++/* wait for codec ready */
++static void sa1111_ac97_ready(struct ac97_codec *dev)
++{
++	int i;
++	u16	val;
++
++	i = 0;
++	while ((SASR1 & SASR1_CRDY) == 0) {
++		udelay(50);
++		if (++i > 10) {
++			DPRINTK("sa1111_ac97_ready failed\n");
++			return;
++		}
++	}
++	DPRINTK("codec_ready bit took %d cycles\n", i);
++
++	/* Wait for analog parts of codec to initialise */
++	i = 0;
++	do {
++		val = sa1111_ac97_read_reg(&ac97codec, AC97_POWER_CONTROL);
++		if (++i > 100) {
++			break;
++		}
++		mdelay(10);
++	} while ((val & 0xF) != 0xF || val == 0xFFFF);
++
++	/* the cs42xx typically takes 150 ms to initialise */
++
++	DPRINTK("analog init took %d cycles\n", i);
++}
++
++
++static int __init sa1111_ac97_init(void)
++{
++	int ret;
++
++	// SBI_SKCR |= SKCR_RCLKEN;
++
++	DPRINTK("sa1111_ac97_init\n");
++
++	/* install the ac97 mixer module */
++	ac97codec.codec_read	= sa1111_ac97_read_reg;
++	ac97codec.codec_write 	= sa1111_ac97_write_reg;
++	ac97codec.codec_wait 	= sa1111_ac97_ready;
++
++	/* Acquire and initialize DMA */
++	ret = sa1111_sac_request_dma(&output_stream.dma_ch, "SA1111 audio out",
++				     SA1111_SAC_XMT_CHANNEL);
++	if (ret < 0) {
++		printk("DMA request for SAC output failed\n");
++		return ret;
++	}
++
++	ret = sa1111_sac_request_dma(&input_stream.dma_ch, "SA1111 audio in",
++				     SA1111_SAC_RCV_CHANNEL);
++	if (ret < 0) {
++		printk("DMA request for SAC input failed\n");
++		sa1100_free_dma(output_stream.dma_ch);
++		return ret;
++	}
++	/* register devices */
++	audio_dev_id = register_sound_dsp(&sa1111_ac97_audio_fops, -1);
++	mixer_dev_id = register_sound_mixer(&sa1111_ac97_mixer_fops, -1);
++
++
++	/* setup proc entry */
++	ac97_ps = create_proc_read_entry ("driver/sa1111-ac97", 0, NULL,
++					  ac97_read_proc, &ac97codec);
++
++	return 0;
++}
++
++
++static void __exit sa1111_ac97_exit(void)
++{
++	SKPCR &= ~SKPCR_ACCLKEN;		/* disable ac97 clock */
++	SBI_SKCR &= ~SKCR_SELAC;		/* deselect ac97 */
++
++	unregister_sound_dsp(audio_dev_id);
++	unregister_sound_mixer(mixer_dev_id);
++	sa1100_free_dma(output_stream.dma_ch);
++	sa1100_free_dma(input_stream.dma_ch);
++}
++
++static int sa1111_ac97_set_adc_rate(long rate)
++{
++
++  // note this only changes the rate of the ADC, the DAC is fixed at 48K.
++  // this is due to limitations of the SA1111 chip
++
++  u16 code = rate;
++
++  switch (rate) {
++  case  8000:
++  case 11025:
++  case 16000:
++  case 22050:
++  case 32000:
++  case 44100:
++  case 48000:
++    break;
++  default:
++    return -1;
++  }
++  sa1111_ac97_write_reg(&ac97codec, 0x2A, 0x0001);
++  sa1111_ac97_write_reg(&ac97codec, 0x32, code);
++  return 0;
++}
++
++module_init(sa1111_ac97_init);
++module_exit(sa1111_ac97_exit);
++
++MODULE_AUTHOR("Bertrik Sikken, Technolution B.V., Netherlands");
++MODULE_DESCRIPTION("Glue audio driver for AC'97 codec");
++MODULE_LICENSE("GPL");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/sa1111-uda1341.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,282 @@
++/*
++ * Glue audio driver for the SA1111 compagnon chip & Philips UDA1341 codec.
++ *
++ * Copyright (c) 2000 John Dorsey
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * History:
++ *
++ * 2000-09-04	John Dorsey	SA-1111 Serial Audio Controller support
++ * 				was initially added to the sa1100-uda1341.c
++ * 				driver.
++ *
++ * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on
++ * 				the former sa1100-uda1341.c driver.
++ *
++ * 2001-09-23	Russell King	Remove old L3 bus driver.
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/sound.h>
++#include <linux/soundcard.h>
++#include <linux/ioport.h>
++#include <linux/pm.h>
++#include <linux/l3/l3.h>
++#include <linux/l3/uda1341.h>
++
++#include <asm/semaphore.h>
++#include <asm/mach-types.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/dma.h>
++#include <asm/arch/assabet.h>
++#include <asm/hardware/sa1111.h>
++
++#include "sa1100-audio.h"
++
++#undef DEBUG
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++
++/*
++ * Definitions
++ */
++
++#define AUDIO_RATE_DEFAULT	22050
++
++#define AUDIO_CLK_BASE		561600
++
++
++
++/*
++ * Mixer interface
++ */
++
++static struct l3_client uda1341;
++
++static int
++mixer_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
++{
++	/*
++	 * We only accept mixer (type 'M') ioctls.
++	 */
++	if (_IOC_TYPE(cmd) != 'M')
++		return -EINVAL;
++
++	return l3_command(&uda1341, cmd, (void *)arg);
++}
++
++static struct file_operations uda1341_mixer_fops = {
++	ioctl:		mixer_ioctl,
++	owner:		THIS_MODULE
++};
++
++
++/*
++ * Audio interface
++ */
++
++static int audio_clk_div = (AUDIO_CLK_BASE + AUDIO_RATE_DEFAULT/2)/AUDIO_RATE_DEFAULT;
++
++static void sa1111_audio_init(void *dummy)
++{
++#ifdef CONFIG_ASSABET_NEPONSET
++	if (machine_is_assabet()) {
++		/* Select I2S audio (instead of AC-Link) */
++		AUD_CTL = AUD_SEL_1341;
++	}
++#endif
++#ifdef CONFIG_SA1100_JORNADA720
++	if (machine_is_jornada720()) {
++		/* LDD4 is speaker, LDD3 is microphone */
++		PPSR &= ~(PPC_LDD3 | PPC_LDD4);
++		PPDR |= PPC_LDD3 | PPC_LDD4;
++		PPSR |= PPC_LDD4; /* enable speaker */
++		PPSR |= PPC_LDD3; /* enable microphone */
++	}
++#endif
++
++	SBI_SKCR &= ~SKCR_SELAC;
++
++	/* Enable the I2S clock and L3 bus clock: */
++	SKPCR |= (SKPCR_I2SCLKEN | SKPCR_L3CLKEN);
++
++	/* Activate and reset the Serial Audio Controller */
++	SACR0 |= (SACR0_ENB | SACR0_RST);
++	mdelay(5);
++	SACR0 &= ~SACR0_RST;
++
++	/* For I2S, BIT_CLK is supplied internally. The "SA-1111
++	 * Specification Update" mentions that the BCKD bit should
++	 * be interpreted as "0 = output". Default clock divider
++	 * is 22.05kHz.
++	 *
++	 * Select I2S, L3 bus. "Recording" and "Replaying"
++	 * (receive and transmit) are enabled.
++	 */
++	SACR1 = SACR1_L3EN;
++	SKAUD = audio_clk_div - 1;
++
++	/* Initialize the UDA1341 internal state */
++	l3_open(&uda1341);
++}
++
++static void sa1111_audio_shutdown(void *dummy)
++{
++	l3_close(&uda1341);
++	SACR0 &= ~SACR0_ENB;
++}
++
++static int sa1111_audio_ioctl( struct inode *inode, struct file *file,
++				uint cmd, ulong arg)
++{
++	long val;
++	int ret = 0;
++
++	switch (cmd) {
++	case SNDCTL_DSP_STEREO:
++		ret = get_user(val, (int *) arg);
++		if (ret)
++			return ret;
++		/* the UDA1341 is stereo only */
++		ret = (val == 0) ? -EINVAL : 1;
++		return put_user(ret, (int *) arg);
++
++	case SNDCTL_DSP_CHANNELS:
++	case SOUND_PCM_READ_CHANNELS:
++		/* the UDA1341 is stereo only */
++		return put_user(2, (long *) arg);
++
++	case SNDCTL_DSP_SPEED:
++		ret = get_user(val, (long *) arg);
++		if (ret) break;
++		if (val < 8000) val = 8000;
++		if (val > 48000) val = 48000;
++		audio_clk_div = (AUDIO_CLK_BASE + val/2)/val;
++		SKAUD = audio_clk_div - 1;
++		/* fall through */
++
++	case SOUND_PCM_READ_RATE:
++		return put_user(AUDIO_CLK_BASE/audio_clk_div, (long *) arg);
++
++	case SNDCTL_DSP_SETFMT:
++	case SNDCTL_DSP_GETFMTS:
++		/* we can do 16-bit only */
++		return put_user(AFMT_S16_LE, (long *) arg);
++
++	default:
++		/* Maybe this is meant for the mixer (as per OSS Docs) */
++		return mixer_ioctl(inode, file, cmd, arg);
++	}
++
++	return ret;
++}
++
++static audio_stream_t output_stream, input_stream;
++
++static audio_state_t audio_state = {
++	output_stream:	&output_stream,
++	input_stream:	&input_stream,
++	skip_dma_init:	1,  /* done locally */
++	hw_init:	sa1111_audio_init,
++	hw_shutdown:	sa1111_audio_shutdown,
++	client_ioctl:	sa1111_audio_ioctl,
++	sem:		__MUTEX_INITIALIZER(audio_state.sem),
++};
++
++static int sa1111_audio_open(struct inode *inode, struct file *file)
++{
++        return sa1100_audio_attach(inode, file, &audio_state);
++}
++
++/*
++ * Missing fields of this structure will be patched with the call
++ * to sa1100_audio_attach().
++ */
++static struct file_operations sa1111_audio_fops = {
++	open:		sa1111_audio_open,
++	owner:		THIS_MODULE
++};
++
++static int audio_dev_id, mixer_dev_id;
++
++static int __init sa1111_uda1341_init(void)
++{
++	struct uda1341_cfg cfg;
++	int ret;
++
++	if ( !(	(machine_is_assabet() && machine_has_neponset()) ||
++		machine_is_jornada720() ||
++		machine_is_badge4() ))
++		return -ENODEV;
++
++	if (!request_mem_region(_SACR0, 512, "sound"))
++		return -EBUSY;
++
++	ret = l3_attach_client(&uda1341, "l3-sa1111", "uda1341");
++	if (ret)
++		goto out;
++
++	/* Acquire and initialize DMA */
++	ret = sa1111_sac_request_dma(&output_stream.dma_ch, "SA1111 audio out",
++				     SA1111_SAC_XMT_CHANNEL);
++	if (ret < 0)
++		goto release_l3;
++	
++	ret = sa1111_sac_request_dma(&input_stream.dma_ch, "SA1111 audio in",
++				     SA1111_SAC_RCV_CHANNEL);
++	if (ret < 0)
++		goto release_dma;
++
++	cfg.fs     = 256;
++	cfg.format = FMT_I2S;
++	l3_command(&uda1341, L3_UDA1341_CONFIGURE, &cfg);
++
++	/* register devices */
++	audio_dev_id = register_sound_dsp(&sa1111_audio_fops, -1);
++	mixer_dev_id = register_sound_mixer(&uda1341_mixer_fops, -1);
++
++	printk(KERN_INFO "Sound: SA1111 UDA1341: dsp id %d mixer id %d\n",
++		audio_dev_id, mixer_dev_id);
++	return 0;
++
++release_dma:
++	sa1100_free_dma(output_stream.dma_ch);
++release_l3:
++	l3_detach_client(&uda1341);
++out:
++	release_mem_region(_SACR0, 512);
++	return ret;
++}
++
++static void __exit sa1111_uda1341_exit(void)
++{
++	unregister_sound_dsp(audio_dev_id);
++	unregister_sound_mixer(mixer_dev_id);
++	sa1100_free_dma(output_stream.dma_ch);
++	sa1100_free_dma(input_stream.dma_ch);
++	l3_detach_client(&uda1341);
++
++	release_mem_region(_SACR0, 512);
++}
++
++module_init(sa1111_uda1341_init);
++module_exit(sa1111_uda1341_exit);
++
++MODULE_AUTHOR("John Dorsey, Nicolas Pitre");
++MODULE_DESCRIPTION("Glue audio driver for the SA1111 compagnon chip & Philips UDA1341 codec.");
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/sound/uda1341.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,511 @@
++/*
++ * Philips UDA1341 mixer device driver
++ *
++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
++ *
++ * Portions are Copyright (C) 2000 Lernout & Hauspie Speech Products, N.V.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * History:
++ *
++ * 2000-05-21	Nicolas Pitre	Initial release.
++ *
++ * 2000-08-19	Erik Bunce	More inline w/ OSS API and UDA1341 docs
++ * 				including fixed AGC and audio source handling
++ *
++ * 2000-11-30	Nicolas Pitre	- More mixer functionalities.
++ *
++ * 2001-06-03	Nicolas Pitre	Made this file a separate module, based on
++ * 				the former sa1100-uda1341.c driver.
++ *
++ * 2001-08-13	Russell King	Re-written as part of the L3 interface
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/ioctl.h>
++#include <linux/soundcard.h>
++#include <linux/l3/l3.h>
++#include <linux/l3/uda1341.h>
++
++#include <asm/uaccess.h>
++
++#define DEF_VOLUME	65
++
++/*
++ * UDA1341 L3 address and command types
++ */
++#define UDA1341_L3ADDR		5
++#define UDA1341_DATA0		(UDA1341_L3ADDR << 2 | 0)
++#define UDA1341_DATA1		(UDA1341_L3ADDR << 2 | 1)
++#define UDA1341_STATUS		(UDA1341_L3ADDR << 2 | 2)
++
++struct uda1341_regs {
++	unsigned char	stat0;
++#define STAT0			0x00
++#define STAT0_RST		(1 << 6)
++#define STAT0_SC_MASK		(3 << 4)
++#define STAT0_SC_512FS		(0 << 4)
++#define STAT0_SC_384FS		(1 << 4)
++#define STAT0_SC_256FS		(2 << 4)
++#define STAT0_IF_MASK		(7 << 1)
++#define STAT0_IF_I2S		(0 << 1)
++#define STAT0_IF_LSB16		(1 << 1)
++#define STAT0_IF_LSB18		(2 << 1)
++#define STAT0_IF_LSB20		(3 << 1)
++#define STAT0_IF_MSB		(4 << 1)
++#define STAT0_IF_LSB16MSB	(5 << 1)
++#define STAT0_IF_LSB18MSB	(6 << 1)
++#define STAT0_IF_LSB20MSB	(7 << 1)
++#define STAT0_DC_FILTER		(1 << 0)
++
++	unsigned char	stat1;
++#define STAT1			0x80
++#define STAT1_DAC_GAIN		(1 << 6)	/* gain of DAC */
++#define STAT1_ADC_GAIN		(1 << 5)	/* gain of ADC */
++#define STAT1_ADC_POL		(1 << 4)	/* polarity of ADC */
++#define STAT1_DAC_POL		(1 << 3)	/* polarity of DAC */
++#define STAT1_DBL_SPD		(1 << 2)	/* double speed playback */
++#define STAT1_ADC_ON		(1 << 1)	/* ADC powered */
++#define STAT1_DAC_ON		(1 << 0)	/* DAC powered */
++
++	unsigned char	data0_0;
++#define DATA0			0x00
++#define DATA0_VOLUME_MASK	0x3f
++#define DATA0_VOLUME(x)		(x)
++
++	unsigned char	data0_1;
++#define DATA1			0x40
++#define DATA1_BASS(x)		((x) << 2)
++#define DATA1_BASS_MASK		(15 << 2)
++#define DATA1_TREBLE(x)		((x))
++#define DATA1_TREBLE_MASK	(3)
++
++	unsigned char	data0_2;
++#define DATA2			0x80
++#define DATA2_PEAKAFTER		(1 << 5)
++#define DATA2_DEEMP_NONE	(0 << 3)
++#define DATA2_DEEMP_32KHz	(1 << 3)
++#define DATA2_DEEMP_44KHz	(2 << 3)
++#define DATA2_DEEMP_48KHz	(3 << 3)
++#define DATA2_MUTE		(1 << 2)
++#define DATA2_FILTER_FLAT	(0 << 0)
++#define DATA2_FILTER_MIN	(1 << 0)
++#define DATA2_FILTER_MAX	(3 << 0)
++
++#define EXTADDR(n)		(0xc0 | (n))
++#define EXTDATA(d)		(0xe0 | (d))
++
++	unsigned char	ext0;
++#define EXT0			0
++#define EXT0_CH1_GAIN(x)	(x)
++
++	unsigned char	ext1;
++#define EXT1			1
++#define EXT1_CH2_GAIN(x)	(x)
++
++	unsigned char	ext2;
++#define EXT2			2
++#define EXT2_MIC_GAIN_MASK	(7 << 2)
++#define EXT2_MIC_GAIN(x)	((x) << 2)
++#define EXT2_MIXMODE_DOUBLEDIFF	(0)
++#define EXT2_MIXMODE_CH1	(1)
++#define EXT2_MIXMODE_CH2	(2)
++#define EXT2_MIXMODE_MIX	(3)
++
++	unsigned char	ext4;
++#define EXT4			4
++#define EXT4_AGC_ENABLE		(1 << 4)
++#define EXT4_INPUT_GAIN_MASK	(3)
++#define EXT4_INPUT_GAIN(x)	((x) & 3)
++
++	unsigned char	ext5;
++#define EXT5			5
++#define EXT5_INPUT_GAIN(x)	((x) >> 2)
++
++	unsigned char	ext6;
++#define EXT6			6
++#define EXT6_AGC_CONSTANT_MASK	(7 << 2)
++#define EXT6_AGC_CONSTANT(x)	((x) << 2)
++#define EXT6_AGC_LEVEL_MASK	(3)
++#define EXT6_AGC_LEVEL(x)	(x)
++};
++
++#define REC_MASK	(SOUND_MASK_LINE | SOUND_MASK_MIC)
++#define DEV_MASK	(REC_MASK | SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE)
++
++struct uda1341 {
++	struct uda1341_regs regs;
++	int		active;
++	unsigned short	volume;
++	unsigned short	bass;
++	unsigned short	treble;
++	unsigned short	line;
++	unsigned short	mic;
++	int		mod_cnt;
++};
++
++#define ADD_FIELD(reg,field)				\
++		*p++ = reg | uda->regs.field
++
++#define ADD_EXTFIELD(reg,field)				\
++		*p++ = EXTADDR(reg);			\
++		*p++ = EXTDATA(uda->regs.field);
++
++static void uda1341_sync(struct l3_client *clnt)
++{
++	struct uda1341 *uda = clnt->driver_data;
++	char buf[24], *p = buf;
++
++	ADD_FIELD(STAT0, stat0);
++	ADD_FIELD(STAT1, stat1);
++
++	if (p != buf)
++		l3_write(clnt, UDA1341_STATUS, buf, p - buf);
++
++	p = buf;
++	ADD_FIELD(DATA0, data0_0);
++	ADD_FIELD(DATA1, data0_1);
++	ADD_FIELD(DATA2, data0_2);
++	ADD_EXTFIELD(EXT0, ext0);
++	ADD_EXTFIELD(EXT1, ext1);
++	ADD_EXTFIELD(EXT2, ext2);
++	ADD_EXTFIELD(EXT4, ext4);
++	ADD_EXTFIELD(EXT5, ext5);
++	ADD_EXTFIELD(EXT6, ext6);
++
++	if (p != buf)
++		l3_write(clnt, UDA1341_DATA0, buf, p - buf);
++}
++
++static void uda1341_cmd_init(struct l3_client *clnt)
++{
++	struct uda1341 *uda = clnt->driver_data;
++	char buf[2];
++
++	uda->active = 1;
++
++	buf[0] = uda->regs.stat0 | STAT0_RST;
++	buf[1] = uda->regs.stat0;
++
++	l3_write(clnt, UDA1341_STATUS, buf, 2);
++
++	/* resend all parameters */
++	uda1341_sync(clnt);
++}
++
++static int uda1341_configure(struct l3_client *clnt, struct uda1341_cfg *conf)
++{
++	struct uda1341 *uda = clnt->driver_data;
++	int ret = 0;
++
++	uda->regs.stat0 &= ~(STAT0_SC_MASK | STAT0_IF_MASK);
++
++	switch (conf->fs) {
++	case 512: uda->regs.stat0 |= STAT0_SC_512FS;	break;
++	case 384: uda->regs.stat0 |= STAT0_SC_384FS;	break;
++	case 256: uda->regs.stat0 |= STAT0_SC_256FS;	break;
++	default:  ret = -EINVAL;			break;
++	}
++
++	switch (conf->format) {
++	case FMT_I2S:		uda->regs.stat0 |= STAT0_IF_I2S;	break;
++	case FMT_LSB16:		uda->regs.stat0 |= STAT0_IF_LSB16;	break;
++	case FMT_LSB18:		uda->regs.stat0 |= STAT0_IF_LSB18;	break;
++	case FMT_LSB20:		uda->regs.stat0 |= STAT0_IF_LSB20;	break;
++	case FMT_MSB:		uda->regs.stat0 |= STAT0_IF_MSB;	break;
++	case FMT_LSB16MSB:	uda->regs.stat0 |= STAT0_IF_LSB16MSB;	break;
++	case FMT_LSB18MSB:	uda->regs.stat0 |= STAT0_IF_LSB18MSB;	break;
++	case FMT_LSB20MSB:	uda->regs.stat0 |= STAT0_IF_LSB20MSB;	break;
++	}
++
++	if (ret == 0 && uda->active) {
++		char buf = uda->regs.stat0 | STAT0;
++		l3_write(clnt, UDA1341_STATUS, &buf, 1);
++	}
++	return ret;
++}
++
++static int uda1341_update_direct(struct l3_client *clnt, int cmd, void *arg)
++{
++	struct uda1341 *uda = clnt->driver_data;
++	struct l3_gain *v = arg;
++	char newreg;
++	int val;
++
++	switch (cmd) {
++	case L3_SET_VOLUME: /* set volume.  val =  0 to 100 => 62 to 1 */
++		uda->regs.data0_0 = DATA0_VOLUME(62 - ((v->left * 61) / 100));
++		newreg = uda->regs.data0_0 | DATA0;
++		break;
++
++	case L3_SET_BASS:   /* set bass.    val = 50 to 100 => 0 to 12 */
++		val = v->left - 50;
++		if (val < 0)
++			val = 0;
++		uda->regs.data0_1 &= ~DATA1_BASS_MASK;
++		uda->regs.data0_1 |= DATA1_BASS((val * 12) / 50);
++		newreg = uda->regs.data0_1 | DATA1;
++		break;
++
++	case L3_SET_TREBLE: /* set treble.  val = 50 to 100 => 0 to 3 */
++		val = v->left - 50;
++		if (val < 0)
++			val = 0;
++		uda->regs.data0_1 &= ~DATA1_TREBLE_MASK;
++		uda->regs.data0_1 |= DATA1_TREBLE((val * 3) / 50);
++		newreg = uda->regs.data0_1 | DATA1;
++		break;
++
++	default:
++		return -EINVAL;
++	}		
++
++	if (uda->active)
++		l3_write(clnt, UDA1341_DATA0, &newreg, 1);
++	return 0;
++}
++
++static int uda1341_update_indirect(struct l3_client *clnt, int cmd, void *arg)
++{
++	struct uda1341 *uda = clnt->driver_data;
++	struct l3_gain *gain = arg;
++	struct l3_agc *agc = arg;
++	char buf[8], *p = buf;
++	int val, ret = 0;
++
++	switch (cmd) {
++	case L3_SET_GAIN:
++		val = 31 - (gain->left * 31 / 100);
++		switch (gain->channel) {
++		case 1:
++			uda->regs.ext0 = EXT0_CH1_GAIN(val);
++			ADD_EXTFIELD(EXT0, ext0);
++			break;
++
++		case 2:
++			uda->regs.ext1 = EXT1_CH2_GAIN(val);
++			ADD_EXTFIELD(EXT1, ext1);
++			break;
++
++		default:
++			ret = -EINVAL;
++		}
++		break;
++
++	case L3_INPUT_AGC:
++		if (agc->channel == 2) {
++			if (agc->enable)
++				uda->regs.ext4 |= EXT4_AGC_ENABLE;
++			else
++				uda->regs.ext4 &= ~EXT4_AGC_ENABLE;
++#if 0
++			agc->level
++			agc->attack
++			agc->decay
++#endif
++			ADD_EXTFIELD(EXT4, ext4);
++		} else
++			ret = -EINVAL;
++		break;
++
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	if (ret == 0 && uda->active)
++		l3_write(clnt, UDA1341_DATA0, buf, p - buf);
++
++	return ret;
++}
++
++static int uda1341_mixer_ioctl(struct l3_client *clnt, int cmd, void *arg)
++{
++	struct uda1341 *uda = clnt->driver_data;
++	struct l3_gain gain;
++	int val, nr = _IOC_NR(cmd), ret = 0;
++
++	if (cmd == SOUND_MIXER_INFO) {
++		struct mixer_info mi;
++
++		strncpy(mi.id, "UDA1341", sizeof(mi.id));
++		strncpy(mi.name, "Philips UDA1341", sizeof(mi.name));
++		mi.modify_counter = uda->mod_cnt;
++		return copy_to_user(arg, &mi, sizeof(mi));
++	}
++
++	if (_IOC_DIR(cmd) & _IOC_WRITE) {
++		ret = get_user(val, (int *)arg);
++		if (ret)
++			goto out;
++
++		gain.left    = val & 255;
++		gain.right   = val >> 8;
++		gain.channel = 0;
++
++		switch (nr) {
++		case SOUND_MIXER_VOLUME:
++			uda->volume = val;
++			uda->mod_cnt++;
++			uda1341_update_direct(clnt, L3_SET_VOLUME, &gain);
++			break;
++
++		case SOUND_MIXER_BASS:
++			uda->bass = val;
++			uda->mod_cnt++;
++			uda1341_update_direct(clnt, L3_SET_BASS, &gain);
++			break;
++
++		case SOUND_MIXER_TREBLE:
++			uda->treble = val;
++			uda->mod_cnt++;
++			uda1341_update_direct(clnt, L3_SET_TREBLE, &gain);
++			break;
++
++		case SOUND_MIXER_LINE:
++			uda->line = val;
++			gain.channel = 1;
++			uda->mod_cnt++;
++			uda1341_update_indirect(clnt, L3_SET_GAIN, &gain);
++			break;
++
++		case SOUND_MIXER_MIC:
++			uda->mic = val;
++			gain.channel = 2;
++			uda->mod_cnt++;
++			uda1341_update_indirect(clnt, L3_SET_GAIN, &gain);
++			break;
++
++		case SOUND_MIXER_RECSRC:
++			break;
++
++		default:
++			ret = -EINVAL;
++		}
++	}
++
++	if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
++		int nr = _IOC_NR(cmd);
++		ret = 0;
++
++		switch (nr) {
++		case SOUND_MIXER_VOLUME:     val = uda->volume;	break;
++		case SOUND_MIXER_BASS:       val = uda->bass;	break;
++		case SOUND_MIXER_TREBLE:     val = uda->treble;	break;
++		case SOUND_MIXER_LINE:       val = uda->line;	break;
++		case SOUND_MIXER_MIC:        val = uda->mic;	break;
++		case SOUND_MIXER_RECSRC:     val = REC_MASK;	break;
++		case SOUND_MIXER_RECMASK:    val = REC_MASK;	break;
++		case SOUND_MIXER_DEVMASK:    val = DEV_MASK;	break;
++		case SOUND_MIXER_CAPS:       val = 0;		break;
++		case SOUND_MIXER_STEREODEVS: val = 0;		break;
++		default:	val = 0;     ret = -EINVAL;	break;
++		}
++
++		if (ret == 0)
++			ret = put_user(val, (int *)arg);
++	}
++out:
++	return ret;
++}
++
++static int uda1341_attach(struct l3_client *clnt)
++{
++	struct uda1341 *uda;
++
++	uda = kmalloc(sizeof(*uda), GFP_KERNEL);
++	if (!uda)
++		return -ENOMEM;
++
++	memset(uda, 0, sizeof(*uda));
++
++	uda->volume = DEF_VOLUME | DEF_VOLUME << 8;
++	uda->bass   = 50 | 50 << 8;
++	uda->treble = 50 | 50 << 8;
++	uda->line   = 88 | 88 << 8;
++	uda->mic    = 88 | 88 << 8;
++
++	uda->regs.stat0   = STAT0_SC_256FS | STAT0_IF_LSB16;
++	uda->regs.stat1   = STAT1_DAC_GAIN | STAT1_ADC_GAIN |
++			    STAT1_ADC_ON | STAT1_DAC_ON;
++	uda->regs.data0_0 = DATA0_VOLUME(62 - ((DEF_VOLUME * 61) / 100));
++	uda->regs.data0_1 = DATA1_BASS(0) | DATA1_TREBLE(0);
++	uda->regs.data0_2 = DATA2_PEAKAFTER | DATA2_DEEMP_NONE |
++			    DATA2_FILTER_MAX;
++	uda->regs.ext0    = EXT0_CH1_GAIN(4);
++	uda->regs.ext1    = EXT1_CH2_GAIN(4);
++	uda->regs.ext2    = EXT2_MIXMODE_MIX | EXT2_MIC_GAIN(4);
++	uda->regs.ext4    = EXT4_AGC_ENABLE | EXT4_INPUT_GAIN(0);
++	uda->regs.ext5    = EXT5_INPUT_GAIN(0);
++	uda->regs.ext6    = EXT6_AGC_CONSTANT(3) | EXT6_AGC_LEVEL(0);
++
++	clnt->driver_data = uda;
++
++	return 0;
++}
++
++static void uda1341_detach(struct l3_client *clnt)
++{
++	kfree(clnt->driver_data);
++}
++
++static int
++uda1341_command(struct l3_client *clnt, int cmd, void *arg)
++{
++	int ret = -EINVAL;
++
++	if (_IOC_TYPE(cmd) == 'M')
++		ret = uda1341_mixer_ioctl(clnt, cmd, arg);
++	else if (cmd == L3_UDA1341_CONFIGURE)
++		ret = uda1341_configure(clnt, arg);
++
++	return ret;
++}
++
++static int uda1341_open(struct l3_client *clnt)
++{
++	uda1341_cmd_init(clnt);
++	return 0;
++}
++
++static void uda1341_close(struct l3_client *clnt)
++{
++	struct uda1341 *uda = clnt->driver_data;
++	uda->active = 0;
++}
++
++static struct l3_ops uda1341_ops = {
++	open:		uda1341_open,
++	command:	uda1341_command,
++	close:		uda1341_close,
++};
++
++static struct l3_driver uda1341 = {
++	name:		UDA1341_NAME,
++	attach_client:	uda1341_attach,
++	detach_client:	uda1341_detach,
++	ops:		&uda1341_ops,
++	owner:		THIS_MODULE,
++};
++
++static int __init uda1341_init(void)
++{
++	return l3_add_driver(&uda1341);
++}
++
++static void __exit uda1341_exit(void)
++{
++	l3_del_driver(&uda1341);
++}
++
++module_init(uda1341_init);
++module_exit(uda1341_exit);
++
++MODULE_AUTHOR("Nicolas Pitre");
++MODULE_DESCRIPTION("Philips UDA1341 CODEC driver");
+--- linux-2.4.25/drivers/sound/vidc.c~2.4.25-vrs2.patch	2001-10-11 18:43:30.000000000 +0200
++++ linux-2.4.25/drivers/sound/vidc.c	2004-03-31 17:15:09.000000000 +0200
+@@ -40,6 +40,7 @@
+ #endif
+ 
+ #define VIDC_SOUND_CLOCK	(250000)
++#define VIDC_SOUND_CLOCK_EXT	(176400)
+ 
+ /*
+  * When using SERIAL SOUND mode (external DAC), the number of physical
+@@ -192,28 +193,43 @@
+ 	return vidc_audio_format;
+ }
+ 
++#define my_abs(i) ((i)<0 ? -(i) : (i))
++
+ static int vidc_audio_set_speed(int dev, int rate)
+ {
+ 	if (rate) {
+-		unsigned int hwctrl, hwrate;
++		unsigned int hwctrl, hwrate, hwrate_ext, rate_int, rate_ext;
+ 		unsigned int newsize, new2size;
+ 
+-		/*
+-		 * If we have selected 44.1kHz, use the DAC clock.
+-		 */
+-		if (0 && rate == 44100) {
+-			hwctrl = 0x00000002;
++		hwctrl = 0x00000003;
++
++		/* Using internal clock */
++		hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1;
++		if (hwrate < 3)
+ 			hwrate = 3;
+-		} else {
+-			hwctrl = 0x00000003;
++		if (hwrate > 255)
++			hwrate = 255;
+ 
+-			hwrate = (((VIDC_SOUND_CLOCK * 2) / rate) + 1) >> 1;
+-			if (hwrate < 3)
+-				hwrate = 3;
+-			if (hwrate > 255)
+-				hwrate = 255;
++		/* Using exernal clock */
++		hwrate_ext = (((VIDC_SOUND_CLOCK_EXT * 2) / rate) + 1) >> 1;
++		if (hwrate_ext < 3)
++			hwrate_ext = 3;
++		if (hwrate_ext > 255)
++			hwrate_ext = 255;
+ 
+-			rate = VIDC_SOUND_CLOCK / hwrate;
++		rate_int = VIDC_SOUND_CLOCK / hwrate;
++		rate_ext = VIDC_SOUND_CLOCK_EXT / hwrate_ext;
++
++		/* Chose between external and internal clock */
++		if (my_abs(rate_ext-rate) < my_abs(rate_int-rate)) {
++			/*printk("VIDC: external %d %d %d\n", rate, rate_ext, hwrate_ext);*/
++			hwrate=hwrate_ext;
++			hwctrl=0x00000002;
++			rate=rate_ext;
++		} else {
++			/*printk("VIDC: internal %d %d %d\n", rate, rate_int, hwrate);*/
++			hwctrl=0x00000003;
++			rate=rate_int;
+ 		}
+ 
+ 		vidc_writel(0xb0000000 | (hwrate - 2));
+@@ -225,13 +241,14 @@
+ 		if (newsize > 4096)
+ 			newsize = 4096;
+ 		for (new2size = 128; new2size < newsize; new2size <<= 1);
+-			if (new2size - newsize > newsize - (new2size >> 1))
+-				new2size >>= 1;
++		if (new2size - newsize > newsize - (new2size >> 1))
++			new2size >>= 1;
+ 		if (new2size > 4096) {
+ 			printk(KERN_ERR "VIDC: error: dma buffer (%d) %d > 4K\n",
+ 				newsize, new2size);
+ 			new2size = 4096;
+ 		}
++		/*printk("VIDC: dma size %d\n", new2size);*/
+ 		dma_bufsize = new2size;
+ 		vidc_audio_rate = rate;
+ 	}
+--- linux-2.4.25/drivers/sound/waveartist.c~2.4.25-vrs2.patch	2001-10-25 22:53:52.000000000 +0200
++++ linux-2.4.25/drivers/sound/waveartist.c	2004-03-31 17:15:09.000000000 +0200
+@@ -247,17 +247,15 @@
+ 		printk("\n");
+ 	}
+ 
+-	if (inb(io_base + STATR) & CMD_RF) {
+-		int old_data;
+-
+-		/* flush the port
+-		 */
++	/*
++	 * flush any stale command data from the port.
++	 */
++	while (inb(io_base + STATR) & CMD_RF) {
++		unsigned int old_data;
+ 
+ 		old_data = inw(io_base + CMDR);
+-
+-		if (debug_flg & DEBUG_CMD)
+-			printk("flushed %04X...", old_data);
+-
++		printk("waveartist: flushing stale command data: 0x%04x pc=%p\n",
++		       old_data, __builtin_return_address(0));
+ 		udelay(10);
+ 	}
+ 
+@@ -287,16 +285,19 @@
+ 			resp[i] = inw(io_base + CMDR);
+ 	}
+ 
+-	if (debug_flg & DEBUG_CMD) {
+-		if (!timed_out) {
+-			printk("waveartist_cmd: resp=");
++	if (debug_flg & DEBUG_CMD && !timed_out) {
++		printk("waveartist_cmd: resp=");
+ 
+-			for (i = 0; i < nr_resp; i++)
+-				printk("%04X ", resp[i]);
++		for (i = 0; i < nr_resp; i++)
++			printk("%04X ", resp[i]);
++		printk("\n");
++	}
+ 
+-			printk("\n");
+-		} else
+-			printk("waveartist_cmd: timed out\n");
++	if (timed_out) {
++		printk(KERN_ERR "waveartist_cmd: command timed out:");
++		for (i = 0; i < nr_cmd; i++)
++			printk(" %04x", cmd[i]);
++		printk("\n");
+ 	}
+ 
+ 	return timed_out ? 1 : 0;
+@@ -495,7 +496,6 @@
+ 	    audio_devs[dev]->flags & DMA_AUTOMODE &&
+ 	    intrflag &&
+ 	    count == devc->xfer_count) {
+-		devc->audio_mode |= PCM_ENABLE_INPUT;
+ 		return;	/*
+ 			 * Auto DMA mode on. No need to react
+ 			 */
+@@ -571,9 +571,6 @@
+ 	wavnc_port_info	*portc = (wavnc_port_info *) audio_devs[dev]->portc;
+ 	unsigned int	speed, bits;
+ 
+-	if (devc->audio_mode)
+-		return 0;
+-
+ 	speed = waveartist_get_speed(portc);
+ 	bits  = waveartist_get_bits(portc);
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,11 @@
++
++mainmenu_option next_comment
++comment 'Synchronous Serial Interface'
++tristate 'Synchronous Serial Interface Support' CONFIG_SSI
++
++comment 'SSI Bus Drivers'
++dep_tristate '  CLPS711X SSI support' CONFIG_SSI_CLPS711X $CONFIG_SSI $CONFIG_ARCH_CLPS711X
++
++comment 'SSI Device Drivers'
++dep_tristate '  JUNO keyboard support' CONFIG_SSI_JUNO $CONFIG_SSI
++endmenu
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,50 @@
++#
++# Makefile for the SSI drivers
++#
++# Note! Dependencies are done automagically by 'make dep', which also
++# removes any old dependencies. DON'T put your own dependencies here
++# unless it's something special (ie not a .c file).
++#
++# Note 2! The CFLAGS definition is now inherited from the
++# parent makefile.
++#
++
++O_TARGET	:= ssi.o
++
++obj-y		:=
++obj-m		:=
++obj-n		:=
++obj-		:=
++
++export-objs	:=
++list-multi	:=
++
++obj-$(CONFIG_SSI)		+= ssi_core.o
++obj-$(CONFIG_SSI_CLPS711X)	+= clps711x_ssi1.o
++obj-y				+= juno.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are intermediate files used to build the multi's.
++
++multi-y		:= $(filter $(list-multi), $(obj-y))
++multi-m		:= $(filter $(list-multi), $(obj-m))
++int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular; remove from modular.
++
++obj-m		:= $(filter-out $(obj-y), $(obj-m))
++int-m		:= $(filter-out $(int-y), $(int-m))
++
++# Take multi-part drivers out of obj-y and put components in.
++
++obj-y		:= $(filter-out $(list-multi), $(obj-y)) $(int-y)
++
++# Translate to Rules.make lists.
++
++O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
++OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
++M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/README	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,86 @@
++		Synchronous Serial Interface bus driver
++		---------------------------------------
++
++   EEEEE X   X PPPP  EEEEE RRRR  IIIII M   M EEEEE N   N TTTTT  AAA  L
++   E      X X  P   P E     R   R   I   MM MM E     NN  N   T   A   A L
++   EEEE    X   PPPP  EEEE  RRRR    I   M M M EEEE  N N N   T   AAAAA L
++   E      X X  P     E     R R     I   M   M E     N  NN   T   A   A L
++   EEEEE X   X P     EEEEE R  R  IIIII M   M EEEEE N   N   T   A   A LLLLL
++
++This directory holds the SSI bus drivers.  Basically, a SSI bus consists
++of the following signals:
++
++	stxd	Transmit data
++	srxd	Receive data
++	sclk	Clock
++	sfrm	Frame
++		Chip selects (1 - n)
++
++There may be more than one device on a SSI bus, and each device can
++have different timing requirements.  There are several frame formats:
++
++1. Texas Instruments Synchronous Serial Frame format
++
++   sclk ____~_~_~_~_~_~_~_~____
++   sfrm ____~~_________________
++   stxd ------bn..........b0---
++   srxd ------bn..........b0---
++
++   - data latched in on the falling edge of the clock
++   - data shifted out on the rising edge of the clock
++
++2. Motorola SPI frame format
++
++   sclk ______~_~_~_~_~_~_~____
++   sfrm ~~~~________________~~~
++   stxd -----bn..........b0----
++   srxd ----.bn..........b0----
++
++   - data latched in on the rising edge of the clock
++   - data shifted out on the falling edge of the clock, or falling edge
++     of sfrm
++
++3. National Microwire format
++
++   sclk ______~_~_~_~_~_~_~_~_~_~_~_~_~_____
++   sfrm ~~~~_____________________________~~~
++   stxd -----bn......b0---------------------
++   srxd -----------------bn..........b0.----
++
++   - data latched in on the rising edge of the clock
++   - data shifted out on the falling edge of the clock
++   - half duplex, one clock between transmission and reception
++
++Types of devices
++----------------
++
++The following types of devices can be found on a SSP bus:
++
++	Sound chips
++	Keyboard devices
++	Touch screen devices
++
++Keyboard
++--------
++
++TX:
++0. Format: cfglen = 8, framelen = 8, clkpol = 1, clk < 250kHz
++1. select device
++2. keyboard responds asserting key_atn
++3. wait 0.1ms to 5ms
++4. transmit data byte
++5. wait >= 150us
++6. repeat step 4 until all data sent
++7. deselect device
++8. keyboard responds de-asserting key_atn
++9. wait >= 120us
++
++RX:
++0. Format: cfglen = 8, framelen = 8, clkpol = 1, clk < 250kHz
++1. keyboard asserts key_atn
++2. select device after 0.1ms < 5ms
++3. read data byte
++4. wait 150us
++5. if key_atn still asserted, goto 3
++6. deselect device
++7. wait >= 120us
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/clps711x_ssi1.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,237 @@
++/*
++ *  linux/drivers/ssi/clps711x_ssi1.c
++ *
++ * SSI bus driver for the CLPS711x SSI1 bus.  We support EP7212
++ * extensions as well.
++ *
++ * Frame sizes can be between 4 and 24 bits.
++ * Config sizes can be between 4 and 16 bits.
++ */
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++
++#include <asm/mach-types.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/hardware/ep7212.h>
++
++#include "ssi_bus.h"
++#include "ssi_dev.h"
++
++#define EP7212
++
++/*
++ * Port E on the P720T is used for the SPI bus chip selects
++ *  0 - Keyboard
++ *  1 - Touch screen
++ *  2 - CS4224 ADC/DAC
++ *  7 - idle
++ */
++
++#if 0
++/*
++ * we place in the transmit buffer:
++ *  <control>
++ * received data (binary):
++ *  0xxxxxxxxxxxx000
++ * where 'x' is the value
++ */
++struct ssi_dev ads7846_dev = {
++	name:		"ADS7846",
++	id:		1,
++	proto:		SSI_SPI,
++	cfglen:		8,
++	framelen:	24,
++	clkpol:		0,
++	clkfreq:	2500000,
++};
++
++/*
++ * we place in the transmit buffer:
++ *  write: <20> <map> <data>...
++ * received data discarded
++ */
++struct ssi_dev cs4224_dev = {
++	name:		"CS4224",
++	id:		2,
++	proto:		SSI_SPI,
++	cfglen:		8,
++	framelen:	8,
++	clkpol:		0,
++	clkfreq:	6000000,
++};
++#endif
++
++/*
++ * Supplement with whatever method your board requires
++ */
++static void ssi1_select_id(int id)
++{
++	if (machine_is_p720t()) {
++		clps_writel(7, PEDDR);
++		clps_writel(id, PEDR);
++	}
++}
++
++/*
++ * Select the specified device.  The upper layers will have already
++ * checked that the bus transmit queue is idle.  We need to make sure
++ * that the interface itself is idle.
++ */
++static int ssi1_select(struct ssi_bus *bus, struct ssi_dev *dev)
++{
++	u_int id = dev ? dev->id : 7;
++	u_int val;
++
++	/*
++	 * Make sure that the interface is idle
++	 */
++	do {
++		val = clps_readl(SYSFLG1);
++	} while (val & SYSFLG1_SSIBUSY);
++
++	ssi1_select_id(7);
++
++	if (dev) {
++		/*
++		 * Select clock frequency.  This is very rough,
++		 * and assumes that we're operating in PLL mode.
++		 */
++		val = clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK;
++//		if (dev->clkfreq <= 16000)		/* <16kHz */
++//			val |= SYSCON1_ADCKSEL(0);
++//		else if (dev->clkfreq < 64000)		/* <64kHz */
++//			val |= SYSCON1_ADCKSEL(1);
++//		else if (dev->clkfreq < 128000)		/* <128kHz */
++			val |= SYSCON1_ADCKSEL(2);
++//		else					/* >= 128kHz */
++//			val |= SYSCON1_ADCKSEL(3);
++		clps_writel(val, SYSCON1);
++
++		bus->cfglen	= dev->cfglen;
++		bus->framelen	= dev->framelen;
++		bus->clkpol	= dev->clkpol;
++		bus->proto	= dev->proto;
++
++#ifdef EP7212
++		/*
++		 * Set the clock edge according to the device.
++		 * (set clkpol if the device reads data on the
++		 * falling edge of the clock signal).
++		 */
++		val = ep_readl(SYSCON3) & ~SYSCON3_ADCCKNSEN;
++		if (bus->clkpol && dev->proto != SSI_USAR)
++			val |= SYSCON3_ADCCKNSEN;
++		ep_writel(val, SYSCON3);
++#endif
++
++		/*
++		 * Select the device
++		 */
++		ssi1_select_id(id);
++
++#ifdef EP7212
++		/*
++		 * If we are doing USAR, wait 30us, then set
++		 * the clock line low.
++		 */
++		if (dev->proto == SSI_USAR) {
++			udelay(150);
++
++			val |= SYSCON3_ADCCKNSEN;
++			ep_writel(val, SYSCON3);
++		}
++#endif
++	}
++
++	return 0;
++}
++
++static void ssi1_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct ssi_bus *bus = (struct ssi_bus *)dev_id;
++
++	/*
++	 * Read the data word and queue it.
++	 */
++	ssi_core_rcv(bus, clps_readl(SYNCIO));
++}
++
++/*
++ * Enable transmission and/or of some bytes
++ */
++static int ssi1_trans(struct ssi_bus *bus, u_int data)
++{
++	u_int syncio;
++
++#ifdef EP7212
++	data <<= 32 - bus->cfglen;
++	syncio = bus->cfglen | bus->framelen << 7 | data;
++#else
++	syncio = data | bus->framelen << 8;
++#endif
++
++	clps_writel(syncio, SYNCIO);
++	clps_writel(syncio | SYNCIO_TXFRMEN, SYNCIO);
++	return 0;
++}
++
++/*
++ * Initialise the SSI bus.
++ */
++static int ssi1_bus_init(struct ssi_bus *bus)
++{
++	int retval, val;
++
++	retval = request_irq(IRQ_SSEOTI, ssi1_int, 0, "ssi1", bus);
++	if (retval)
++		return retval;
++
++#ifdef EP7212
++	/*
++	 * EP7212 only!  Set the configuration command length.
++	 * On the CLPS711x chips, it is fixed at 8 bits.
++	 */
++	val = ep_readl(SYSCON3);
++	val |= SYSCON3_ADCCON;
++	ep_writel(val, SYSCON3);
++#endif
++
++	ssi1_select(bus, NULL);
++
++	PLD_SPI |= PLD_SPI_EN;
++
++	return 0;
++}
++
++static void ssi1_bus_exit(struct ssi_bus *bus)
++{
++	ssi1_select(bus, NULL);
++
++	PLD_SPI &= ~PLD_SPI_EN;
++
++	free_irq(IRQ_SSEOTI, bus);
++}
++
++struct ssi_bus clps711x_ssi1_bus = {
++	name:	"clps711x_ssi1",
++	init:	ssi1_bus_init,
++	exit:	ssi1_bus_exit,
++	select:	ssi1_select,
++	trans:	ssi1_trans,
++};
++
++static int __init clps711x_ssi1_init(void)
++{
++	return ssi_register_bus(&clps711x_ssi1_bus);
++}
++
++static void __exit clps711x_ssi1_exit(void)
++{
++	ssi_unregister_bus(&clps711x_ssi1_bus);
++}
++
++module_init(clps711x_ssi1_init);
++module_exit(clps711x_ssi1_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/juno.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,131 @@
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/arch/syspld.h>
++
++#include "ssi_bus.h"
++#include "ssi_dev.h"
++
++extern struct ssi_bus clps711x_ssi1_bus;
++
++static u_int recvbuf[16];
++static volatile u_int ptr, rxed;
++
++static inline void juno_enable_irq(void)
++{
++	enable_irq(IRQ_EINT1);
++}
++
++static inline void juno_disable_irq(void)
++{
++	disable_irq(IRQ_EINT1);
++}
++
++static void juno_rcv(struct ssi_dev *dev, u_int data)
++{
++	if (ptr < 16) {
++		recvbuf[ptr] = data;
++		ptr++;
++	} else
++		printk("juno_rcv: %04x\n", data);
++	rxed = 1;
++}
++
++static void juno_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++	struct ssi_dev *dev = dev_id;
++
++	printk("juno_irq\n");
++
++	ssi_select_device(dev->bus, dev);
++
++	ptr = 0;
++	do {
++		rxed = 0;
++		ssi_transmit_data(dev, 0xff);
++		while (rxed == 0);
++		udelay(150);
++	} while (PLD_INT & PLD_INT_KBD_ATN);
++
++	ssi_select_device(dev->bus, NULL);
++
++	{ int i;
++	  printk("juno_rcv: ");
++	  for (i = 0; i < ptr; i++)
++	  	printk("%04x ", recvbuf[i]);
++	  printk("\n");
++	}
++}
++
++static void juno_command(struct ssi_dev *dev, int cmd, int data)
++{
++	ssi_transmit_data(dev, cmd);
++	mdelay(1);
++	ssi_transmit_data(dev, data);
++	mdelay(1);
++	ssi_transmit_data(dev, 0xa0 ^ 0xc0);
++	mdelay(1);
++}
++
++static int juno_dev_init(struct ssi_dev *dev)
++{
++	int retval;
++
++	PLD_KBD |= PLD_KBD_EN;
++	ptr = 16;
++
++	mdelay(20);
++
++	retval = request_irq(IRQ_EINT1, juno_irq, 0, dev->name, dev);
++	if (retval)
++		return retval;
++
++	juno_disable_irq();
++
++	if (ssi_select_device(dev->bus, dev) != 0) {
++		printk("juno: ssi_select_dev failed\n");
++		return -EBUSY;
++	}
++
++	mdelay(1);
++
++	juno_command(dev, 0x80, 0x20);
++
++	ssi_select_device(dev->bus, NULL);
++
++	juno_enable_irq();
++
++	return 0;
++}
++
++static struct ssi_dev juno_dev = {
++	name:		"Juno",
++	id:		0,
++	proto:		SSI_USAR,
++	cfglen:		8,
++	framelen:	8,
++	clkpol:		1,
++	clkfreq:	250000,
++	rcv:		juno_rcv,
++	init:		juno_dev_init,
++};
++
++static int __init juno_init(void)
++{
++	return ssi_register_device(&clps711x_ssi1_bus, &juno_dev);
++}
++
++static void __exit juno_exit(void)
++{
++	ssi_unregister_device(&juno_dev);
++}
++
++module_init(juno_init);
++module_exit(juno_exit);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/ssi_bus.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,21 @@
++#include <linux/circ_buf.h>
++
++struct ssi_dev;
++
++struct ssi_bus {
++	u_char		cfglen;
++	u_char		framelen;
++	u_char		clkpol;
++	u_char		proto;
++	struct ssi_dev	*dev;		/* current device */
++	int		(*select)(struct ssi_bus *, struct ssi_dev *);
++	int		(*trans)(struct ssi_bus *, u_int data);
++	int		(*init)(struct ssi_bus *);
++	void		(*exit)(struct ssi_bus *);
++	char		*name;
++	u_int		devices;
++};
++
++extern int ssi_core_rcv(struct ssi_bus *bus, u_int data);
++extern int ssi_register_bus(struct ssi_bus *bus);
++extern int ssi_unregister_bus(struct ssi_bus *bus);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/ssi_core.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,175 @@
++/*
++ *  linux/drivers/ssi/ssi_core.c
++ *
++ * This file provides a common framework to allow multiple SSI devices
++ * to work together on a single SSI bus.
++ *
++ * You can use this in two ways:
++ *  1. select the device, queue up data, flush the data to the device,
++ *     (optionally) purge the received data, deselect the device.
++ *  2. select the device, queue up one data word, flush to the device
++ *     read data word, queue up next data word, flush to the device...
++ *     deselect the device.
++ */
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/malloc.h>
++#include <linux/init.h>
++
++#include <asm/errno.h>
++
++#include "ssi_bus.h"
++#include "ssi_dev.h"
++
++#define DEBUG
++
++/**
++ *	ssi_core_rcv - pass received SSI data to the device
++ *	@bus: the bus that the data was received from
++ *	@data: the data word that was received
++ *
++ *	This function is intended to be called by SSI bus device
++ *	drivers to pass received data to the device driver.
++ */
++int ssi_core_rcv(struct ssi_bus *bus, u_int data)
++{
++	struct ssi_dev *dev = bus->dev;
++
++	if (dev && dev->rcv)
++		dev->rcv(dev, data);
++
++	return 0;
++}
++
++/**
++ *	ssi_transmit_data - queue SSI data for later transmission
++ *	@dev: device requesting data to be transmitted
++ *	@data: data word to be transmitted.
++ *
++ *	Queue one data word of SSI data for later transmission.
++ */
++int ssi_transmit_data(struct ssi_dev *dev, u_int data)
++{
++	struct ssi_bus *bus = dev->bus;
++
++	/*
++	 * Make sure that we currently own the bus
++	 */
++	if (bus->dev != dev)
++		BUG();
++
++	bus->trans(bus, data);
++	return 0;
++}
++
++/**
++ *	ssi_select_device - select a SSI device for later transactions
++ *	@dev: device to be selected
++ */
++int ssi_select_device(struct ssi_bus *bus, struct ssi_dev *dev)
++{
++	int retval;
++
++#ifdef DEBUG
++	printk("SSI: selecting device %s on bus %s\n",
++		dev ? dev->name : "<none>", bus->name);
++#endif
++
++	/*
++	 * Select the device if it wasn't already selected.
++	 */
++	retval = 0;
++	if (bus->dev != dev) {
++		retval = bus->select(bus, dev);
++		bus->dev = dev;
++	}
++
++	return retval;
++}
++
++/**
++ *	ssi_register_device - register a SSI device with a SSI bus
++ *	@bus: bus
++ *	@dev: SSI device
++ */
++int ssi_register_device(struct ssi_bus *bus, struct ssi_dev *dev)
++{
++	int retval;
++
++	dev->bus = bus;
++	bus->devices++;
++	retval = dev->init(dev);
++	if (retval != 0) {
++		dev->bus = NULL;
++		bus->devices--;
++	} else {
++#ifdef DEBUG
++		printk("SSI: registered new device %s on bus %s\n", dev->name, bus->name);
++#endif
++	}
++	return retval;
++}
++
++/**
++ *	ssi_unregister_device - unregister a SSI device from a SSI bus
++ *	@dev: SSI device
++ */
++int ssi_unregister_device(struct ssi_dev *dev)
++{
++	struct ssi_bus *bus = dev->bus;
++
++	if (bus->dev == dev)
++		bus->dev = NULL;
++
++	dev->bus = NULL;
++	bus->devices--;
++#ifdef DEBUG
++	printk("SSI: unregistered device %s on bus %s\n", dev->name, bus->name);
++#endif
++	return 0;
++}
++
++/**
++ *	ssi_register_bus - register a SSI bus driver
++ *	@bus: bus
++ */
++int ssi_register_bus(struct ssi_bus *bus)
++{
++	int retval;
++
++	retval = bus->init(bus);
++	if (retval == 0) {
++		bus->devices = 0;
++#ifdef DEBUG
++		printk("SSI: registered new bus %s\n", bus->name);
++#endif
++	}
++
++	return retval;
++}
++
++/**
++ *	ssi_unregister_bus - unregister a SSI bus driver
++ *	@bus: bus
++ */
++int ssi_unregister_bus(struct ssi_bus *bus)
++{
++	int retval = -EBUSY;
++	if (bus->devices == 0) {
++		retval = 0;
++	}
++	return retval;
++}
++
++static int __init ssi_init(void)
++{
++	return 0;
++}
++
++static void __exit ssi_exit(void)
++{
++}
++
++module_init(ssi_init);
++module_exit(ssi_exit);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/ssi/ssi_dev.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,21 @@
++struct ssi_bus;
++
++#define SSI_SPI		1
++#define SSI_MICROWIRE	2
++#define SSI_TISSF	3
++#define SSI_USAR	4
++
++struct ssi_dev {
++	char		*name;
++	u_int		id;
++	u_int		clkfreq;
++	u_char		cfglen;
++	u_char		framelen;
++	u_char		clkpol;
++	u_char		proto;
++	void		(*rcv)(struct ssi_dev *, u_int);
++	int		(*init)(struct ssi_dev *);
++	struct ssi_bus	*bus;
++};
++
++
+--- linux-2.4.25/drivers/usb/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/usb/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -4,7 +4,13 @@
+ mainmenu_option next_comment
+ comment 'USB support'
+ 
+-dep_tristate 'Support for USB' CONFIG_USB $CONFIG_PCI
++# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
++if [ "$CONFIG_PCI" = "y" -o "$CONFIG_SA1111" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
++   tristate 'Support for USB' CONFIG_USB
++else
++   define_bool CONFIG_USB n
++fi
++
+ if [ "$CONFIG_USB" = "y" -o  "$CONFIG_USB" = "m" ]; then
+    bool '  USB verbose debug messages' CONFIG_USB_DEBUG
+ 
+--- linux-2.4.25/drivers/usb/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/usb/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -74,6 +74,14 @@
+ 
+ subdir-$(CONFIG_USB_OHCI)	+= host
+ ifeq ($(CONFIG_USB_OHCI),y)
++	obj-y += host/usb-ohci.o host/usb-ohci-pci.o
++endif
++subdir-$(CONFIG_USB_OHCI_SA1111)+= host
++ifeq ($(CONFIG_USB_OHCI),y)
++	obj-y += host/usb-ohci.o host/usb-ohci-sa1111.o
++endif
++subdir-$(CONFIG_USB_OHCI_AT91)	+= host
++ifeq ($(CONFIG_USB_OHCI_AT91),y)
+ 	obj-y += host/usb-ohci.o
+ endif
+ 
+@@ -85,8 +93,6 @@
+ obj-$(CONFIG_USB_KBD)		+= usbkbd.o
+ obj-$(CONFIG_USB_AIPTEK)	+= aiptek.o
+ obj-$(CONFIG_USB_WACOM)		+= wacom.o
+-obj-$(CONFIG_USB_KBTAB)		+= kbtab.o
+-obj-$(CONFIG_USB_POWERMATE)	+= powermate.o
+ 
+ obj-$(CONFIG_USB_SCANNER)	+= scanner.o
+ obj-$(CONFIG_USB_ACM)		+= acm.o
+--- linux-2.4.25/drivers/usb/hcd.c~2.4.25-vrs2.patch	2003-06-13 16:51:36.000000000 +0200
++++ linux-2.4.25/drivers/usb/hcd.c	2004-03-31 17:15:09.000000000 +0200
+@@ -96,7 +96,7 @@
+ /* used when updating hcd data */
+ static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+ 
+-static struct usb_operations hcd_operations;
++/*static*/ struct usb_operations hcd_operations;
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+@@ -1203,13 +1203,21 @@
+ 	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+ 	if (usb_pipecontrol (urb->pipe))
+ 		urb->setup_dma = pci_map_single (
++#ifdef CONFIG_PCI
+ 				hcd->pdev,
++#else
++				NULL,
++#endif
+ 				urb->setup_packet,
+ 				sizeof (struct usb_ctrlrequest),
+ 				PCI_DMA_TODEVICE);
+ 	if (urb->transfer_buffer_length != 0)
+ 		urb->transfer_dma = pci_map_single (
++#ifdef CONFIG_PCI
+ 				hcd->pdev,
++#else
++				NULL,
++#endif
+ 				urb->transfer_buffer,
+ 				urb->transfer_buffer_length,
+ 				usb_pipein (urb->pipe)
+@@ -1422,7 +1430,7 @@
+ 	return 0;
+ }
+ 
+-static struct usb_operations hcd_operations = {
++/*static*/ struct usb_operations hcd_operations = {
+ 	allocate:		hcd_alloc_dev,
+ 	get_frame_number:	hcd_get_frame_number,
+ 	submit_urb:		hcd_submit_urb,
+@@ -1432,7 +1440,7 @@
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
++/*static*/ void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+ {
+ 	struct usb_hcd		*hcd = __hcd;
+ 	int			start = hcd->state;
+@@ -1481,11 +1489,23 @@
+ 
+ 	// NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
+ 	if (usb_pipecontrol (urb->pipe))
+-		pci_unmap_single (hcd->pdev, urb->setup_dma,
++		pci_unmap_single (
++#ifdef CONFIG_PCI
++				hcd->pdev,
++#else
++				NULL,
++#endif
++				urb->setup_dma,
+ 				sizeof (struct usb_ctrlrequest),
+ 				PCI_DMA_TODEVICE);
+ 	if (urb->transfer_buffer_length != 0)
+-		pci_unmap_single (hcd->pdev, urb->transfer_dma,
++		pci_unmap_single (
++#ifdef CONFIG_PCI
++				hcd->pdev,
++#else
++				NULL,
++#endif
++				urb->transfer_dma,
+ 				urb->transfer_buffer_length,
+ 				usb_pipein (urb->pipe)
+ 				    ? PCI_DMA_FROMDEVICE
+--- linux-2.4.25/drivers/usb/host/Config.in~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/usb/host/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -12,8 +12,13 @@
+    define_bool CONFIG_USB_UHCI_ALT n
+ fi
+ dep_tristate '  OHCI (Compaq, iMacs, OPTi, SiS, ALi, ...) support' CONFIG_USB_OHCI $CONFIG_USB
++dep_tristate '  SA1111 OHCI-compatible host interface support' CONFIG_USB_OHCI_SA1111 $CONFIG_USB
+ if [ "$CONFIG_ARM" = "y" -o "$CONFIG_X86" = "y" -a "$CONFIG_X86_64" != "y" ]; then
+    # Cypress embedded USB controller on StrongARM or on x86 in PC/104
+    dep_tristate '  SL811HS Alternate (x86, StrongARM, isosynchronous mode)' CONFIG_USB_SL811HS_ALT $CONFIG_USB $CONFIG_EXPERIMENTAL
+    dep_tristate '  SL811HS (x86, StrongARM) support, old driver' CONFIG_USB_SL811HS $CONFIG_USB $CONFIG_EXPERIMENTAL
+ fi
++if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then
++   dep_tristate '  AT91RM9200 OHCI-compatible host interface support' CONFIG_USB_OHCI_AT91 $CONFIG_USB
++fi
++
+--- linux-2.4.25/drivers/usb/host/Makefile~2.4.25-vrs2.patch	2003-11-28 19:26:20.000000000 +0100
++++ linux-2.4.25/drivers/usb/host/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -8,9 +8,11 @@
+ obj-$(CONFIG_USB_EHCI_HCD)			+= ehci-hcd.o
+ obj-$(CONFIG_USB_UHCI_ALT)			+= uhci.o
+ obj-$(CONFIG_USB_UHCI)				+= usb-uhci.o
+-obj-$(CONFIG_USB_OHCI)				+= usb-ohci.o
++obj-$(CONFIG_USB_OHCI)				+= usb-ohci.o usb-ohci-pci.o
+ obj-$(CONFIG_USB_SL811HS_ALT)  			+= sl811.o
+ obj-$(CONFIG_USB_SL811HS)  			+= hc_sl811.o
++obj-$(CONFIG_USB_OHCI_SA1111)			+= usb-ohci.o usb-ohci-sa1111.o
++obj-$(CONFIG_USB_OHCI_AT91)			+= usb-ohci.o
+ 
+ # Extract lists of the multi-part drivers.
+ # The 'int-*' lists are the intermediate files used to build the multi's.
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/usb/host/usb-ohci-pci.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,436 @@
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>  /* for in_interrupt() */
++#undef DEBUG
++#include <linux/usb.h>
++
++#include "usb-ohci.h"
++
++#ifdef CONFIG_PMAC_PBOOK
++#include <asm/machdep.h>
++#include <asm/pmac_feature.h>
++#include <asm/pci-bridge.h>
++#ifndef CONFIG_PM
++#define CONFIG_PM
++#endif
++#endif
++
++
++/*-------------------------------------------------------------------------*/
++
++/* Increment the module usage count, start the control thread and
++ * return success. */
++
++static struct pci_driver ohci_pci_driver;
++extern spinlock_t usb_ed_lock;
++int __devinit
++hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,
++	    const char *name, const char *slot_name);
++extern void hc_remove_ohci(ohci_t *ohci);
++
++static int __devinit
++hc_found_ohci (struct pci_dev *dev, int irq,
++	void *mem_base, const struct pci_device_id *id)
++{
++	unsigned long flags = id->driver_data;
++	
++	printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
++	
++	/* Check for NSC87560. We have to look at the bridge (fn1) to identify
++	   the USB (fn2). This quirk might apply to more or even all NSC stuff
++	   I don't know.. */
++	   
++	if(dev->vendor == PCI_VENDOR_ID_NS)
++	{
++		struct pci_dev *fn1  = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
++		if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO)
++			flags |= OHCI_QUIRK_SUCKYIO;
++		
++	}
++	
++	if (flags & OHCI_QUIRK_SUCKYIO)
++		printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
++	if (flags & OHCI_QUIRK_AMD756)
++		printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
++
++	return hc_add_ohci(dev, irq, mem_base, flags,
++			   ohci_pci_driver.name, dev->slot_name);
++}
++
++/*-------------------------------------------------------------------------*/
++
++#ifdef	CONFIG_PM
++
++/* controller died; cleanup debris, then restart */
++/* must not be called from interrupt context */
++
++static void hc_restart (ohci_t *ohci)
++{
++	int temp;
++	int i;
++
++	if (ohci->pci_latency)
++		pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
++
++	ohci->disabled = 1;
++	ohci->sleeping = 0;
++	if (ohci->bus->root_hub)
++		usb_disconnect (&ohci->bus->root_hub);
++	
++	/* empty the interrupt branches */
++	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
++	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
++	
++	/* no EDs to remove */
++	ohci->ed_rm_list [0] = NULL;
++	ohci->ed_rm_list [1] = NULL;
++
++	/* empty control and bulk lists */	 
++	ohci->ed_isotail     = NULL;
++	ohci->ed_controltail = NULL;
++	ohci->ed_bulktail    = NULL;
++
++	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
++		err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
++	} else
++		dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
++}
++
++#endif	/* CONFIG_PM */
++
++/*-------------------------------------------------------------------------*/
++
++/* configured so that an OHCI device is always provided */
++/* always called with process context; sleeping is OK */
++
++static int __devinit
++ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
++{
++	unsigned long mem_resource, mem_len;
++	void *mem_base;
++	int status;
++
++	if (pci_enable_device(dev) < 0)
++		return -ENODEV;
++
++        if (!dev->irq) {
++        	err("found OHCI device with no IRQ assigned. check BIOS settings!");
++        	pci_disable_device (dev);
++   	        return -ENODEV;
++        }
++	
++	/* we read its hardware registers as memory */
++	mem_resource = pci_resource_start(dev, 0);
++	mem_len = pci_resource_len(dev, 0);
++	if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
++		dbg ("controller already in use");
++		pci_disable_device (dev);
++		return -EBUSY;
++	}
++
++	mem_base = ioremap_nocache (mem_resource, mem_len);
++	if (!mem_base) {
++		err("Error mapping OHCI memory");
++		release_mem_region (mem_resource, mem_len);
++		pci_disable_device (dev);
++		return -EFAULT;
++	}
++
++	/* controller writes into our memory */
++	pci_set_master (dev);
++
++	status = hc_found_ohci (dev, dev->irq, mem_base, id);
++	if (status < 0) {
++		iounmap (mem_base);
++		release_mem_region (mem_resource, mem_len);
++		pci_disable_device (dev);
++	}
++	return status;
++} 
++
++/*-------------------------------------------------------------------------*/
++
++/* may be called from interrupt context [interface spec] */
++/* may be called without controller present */
++/* may be called with controller, bus, and devices active */
++
++static void __devexit
++ohci_pci_remove (struct pci_dev *dev)
++{
++	ohci_t		*ohci = (ohci_t *) pci_get_drvdata(dev);
++
++	dbg ("remove %s controller usb-%s%s%s",
++		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
++		dev->slot_name,
++		ohci->disabled ? " (disabled)" : "",
++		in_interrupt () ? " in interrupt" : ""
++		);
++
++	hc_remove_ohci(ohci);
++
++	release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
++	pci_disable_device (dev);
++}
++
++
++#ifdef	CONFIG_PM
++
++/*-------------------------------------------------------------------------*/
++
++static int
++ohci_pci_suspend (struct pci_dev *dev, u32 state)
++{
++	ohci_t			*ohci = (ohci_t *) pci_get_drvdata(dev);
++	unsigned long		flags;
++	u16 cmd;
++
++	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
++		dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
++			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
++		return -EIO;
++	}
++
++	/* act as if usb suspend can always be used */
++	info ("USB suspend: usb-%s", dev->slot_name);
++	ohci->sleeping = 1;
++
++	/* First stop processing */
++  	spin_lock_irqsave (&usb_ed_lock, flags);
++	ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
++	writel (ohci->hc_control, &ohci->regs->control);
++	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
++	(void) readl (&ohci->regs->intrstatus);
++  	spin_unlock_irqrestore (&usb_ed_lock, flags);
++
++	/* Wait a frame or two */
++	mdelay(1);
++	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
++		mdelay (1);
++		
++#ifdef CONFIG_PMAC_PBOOK
++	if (_machine == _MACH_Pmac)
++		disable_irq (ohci->irq);
++	/* else, 2.4 assumes shared irqs -- don't disable */
++#endif
++	/* Enable remote wakeup */
++	writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
++
++	/* Suspend chip and let things settle down a bit */
++	ohci->hc_control = OHCI_USB_SUSPEND;
++	writel (ohci->hc_control, &ohci->regs->control);
++	(void) readl (&ohci->regs->control);
++	mdelay (500); /* No schedule here ! */
++	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
++		case OHCI_USB_RESET:
++			dbg("Bus in reset phase ???");
++			break;
++		case OHCI_USB_RESUME:
++			dbg("Bus in resume phase ???");
++			break;
++		case OHCI_USB_OPER:
++			dbg("Bus in operational phase ???");
++			break;
++		case OHCI_USB_SUSPEND:
++			dbg("Bus suspended");
++			break;
++	}
++	/* In some rare situations, Apple's OHCI have happily trashed
++	 * memory during sleep. We disable it's bus master bit during
++	 * suspend
++	 */
++	pci_read_config_word (dev, PCI_COMMAND, &cmd);
++	cmd &= ~PCI_COMMAND_MASTER;
++	pci_write_config_word (dev, PCI_COMMAND, cmd);
++#ifdef CONFIG_PMAC_PBOOK
++	{
++	   	struct device_node	*of_node;
++
++		/* Disable USB PAD & cell clock */
++		of_node = pci_device_to_OF_node (ohci->ohci_dev);
++		if (of_node)
++			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
++	}
++#endif
++	return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int
++ohci_pci_resume (struct pci_dev *dev)
++{
++	ohci_t		*ohci = (ohci_t *) pci_get_drvdata(dev);
++	int		temp;
++	unsigned long	flags;
++
++	/* guard against multiple resumes */
++	atomic_inc (&ohci->resume_count);
++	if (atomic_read (&ohci->resume_count) != 1) {
++		err ("concurrent PCI resumes for usb-%s", dev->slot_name);
++		atomic_dec (&ohci->resume_count);
++		return 0;
++	}
++
++#ifdef CONFIG_PMAC_PBOOK
++	{
++		struct device_node *of_node;
++
++		/* Re-enable USB PAD & cell clock */
++		of_node = pci_device_to_OF_node (ohci->ohci_dev);
++		if (of_node)
++			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
++	}
++#endif
++
++	/* did we suspend, or were we powered off? */
++	ohci->hc_control = readl (&ohci->regs->control);
++	temp = ohci->hc_control & OHCI_CTRL_HCFS;
++
++#ifdef DEBUG
++	/* the registers may look crazy here */
++	ohci_dump_status (ohci);
++#endif
++
++	/* Re-enable bus mastering */
++	pci_set_master(ohci->ohci_dev);
++	
++	switch (temp) {
++
++	case OHCI_USB_RESET:	// lost power
++		info ("USB restart: usb-%s", dev->slot_name);
++		hc_restart (ohci);
++		break;
++
++	case OHCI_USB_SUSPEND:	// host wakeup
++	case OHCI_USB_RESUME:	// remote wakeup
++		info ("USB continue: usb-%s from %s wakeup", dev->slot_name,
++			(temp == OHCI_USB_SUSPEND)
++				? "host" : "remote");
++		ohci->hc_control = OHCI_USB_RESUME;
++		writel (ohci->hc_control, &ohci->regs->control);
++		(void) readl (&ohci->regs->control);
++		mdelay (20); /* no schedule here ! */
++		/* Some controllers (lucent) need a longer delay here */
++		mdelay (15);
++		temp = readl (&ohci->regs->control);
++		temp = ohci->hc_control & OHCI_CTRL_HCFS;
++		if (temp != OHCI_USB_RESUME) {
++			err ("controller usb-%s won't resume", dev->slot_name);
++			ohci->disabled = 1;
++			return -EIO;
++		}
++
++		/* Some chips likes being resumed first */
++		writel (OHCI_USB_OPER, &ohci->regs->control);
++		(void) readl (&ohci->regs->control);
++		mdelay (3);
++
++		/* Then re-enable operations */
++		spin_lock_irqsave (&usb_ed_lock, flags);
++		ohci->disabled = 0;
++		ohci->sleeping = 0;
++		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
++		if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
++			if (ohci->ed_controltail)
++				ohci->hc_control |= OHCI_CTRL_CLE;
++			if (ohci->ed_bulktail)
++				ohci->hc_control |= OHCI_CTRL_BLE;
++		}
++		writel (ohci->hc_control, &ohci->regs->control);
++		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
++		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
++		/* Check for a pending done list */
++		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
++		(void) readl (&ohci->regs->intrdisable);
++		spin_unlock_irqrestore (&usb_ed_lock, flags);
++#ifdef CONFIG_PMAC_PBOOK
++		if (_machine == _MACH_Pmac)
++			enable_irq (ohci->irq);
++#endif
++		if (ohci->hcca->done_head)
++			dl_done_list (ohci, dl_reverse_done_list (ohci));
++		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
++		writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
++		writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
++		break;
++
++	default:
++		warn ("odd PCI resume for usb-%s", dev->slot_name);
++	}
++
++	/* controller is operational, extra resumes are harmless */
++	atomic_dec (&ohci->resume_count);
++
++	return 0;
++}
++
++#endif	/* CONFIG_PM */
++
++
++/*-------------------------------------------------------------------------*/
++
++static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
++
++	/*
++	 * AMD-756 [Viper] USB has a serious erratum when used with
++	 * lowspeed devices like mice.
++	 */
++	vendor:		0x1022,
++	device:		0x740c,
++	subvendor:	PCI_ANY_ID,
++	subdevice:	PCI_ANY_ID,
++
++	driver_data:	OHCI_QUIRK_AMD756,
++
++} , {
++
++	/* handle any USB OHCI controller */
++	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x10),
++	class_mask: 	~0,
++
++	/* no matter who makes it */
++	vendor:		PCI_ANY_ID,
++	device:		PCI_ANY_ID,
++	subvendor:	PCI_ANY_ID,
++	subdevice:	PCI_ANY_ID,
++
++	}, { /* end: all zeroes */ }
++};
++
++MODULE_DEVICE_TABLE (pci, ohci_pci_ids);
++
++static struct pci_driver ohci_pci_driver = {
++	name:		"usb-ohci",
++	id_table:	&ohci_pci_ids [0],
++
++	probe:		ohci_pci_probe,
++	remove:		__devexit_p(ohci_pci_remove),
++
++#ifdef	CONFIG_PM
++	suspend:	ohci_pci_suspend,
++	resume:		ohci_pci_resume,
++#endif	/* PM */
++};
++
++ 
++/*-------------------------------------------------------------------------*/
++
++static int __init ohci_hcd_init (void) 
++{
++	return pci_module_init (&ohci_pci_driver);
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void __exit ohci_hcd_cleanup (void) 
++{	
++	pci_unregister_driver (&ohci_pci_driver);
++}
++
++module_init (ohci_hcd_init);
++module_exit (ohci_hcd_cleanup);
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/usb/host/usb-ohci-sa1111.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,118 @@
++/*
++ *  linux/drivers/usb/usb-ohci-sa1111.c
++ *
++ *  The outline of this code was taken from Brad Parkers <brad@heeltoe.com>
++ *  original OHCI driver modifications, and reworked into a cleaner form
++ *  by Russell King <rmk@arm.linux.org.uk>.
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/usb.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <asm/pci.h>
++#include <asm/arch/assabet.h>
++#include <asm/arch/badge4.h>
++#include <asm/hardware/sa1111.h>
++
++#include "usb-ohci.h"
++
++int __devinit
++hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,
++	    const char *name, const char *slot_name);
++extern void hc_remove_ohci(ohci_t *ohci);
++
++static ohci_t *sa1111_ohci;
++
++static void __init sa1111_ohci_configure(void)
++{
++	unsigned int usb_rst = 0;
++
++	if (machine_is_xp860() ||
++	    machine_has_neponset() ||
++	    machine_is_accelent_sa() ||
++	    machine_is_pfs168() ||
++	    machine_is_badge4())
++		usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
++
++	/*
++	 * Configure the power sense and control lines.  Place the USB
++	 * host controller in reset.
++	 */
++	USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
++
++	/*
++	 * Now, carefully enable the USB clock, and take
++	 * the USB host controller out of reset.
++	 */
++	SKPCR |= SKPCR_UCLKEN;
++	udelay(11);
++	USB_RESET = usb_rst;
++}
++
++static int __init sa1111_ohci_init(void)
++{
++	int ret;
++
++	/*
++	 * Request memory resources.
++	 */
++//	if (!request_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT, "usb-ohci"))
++//		return -EBUSY;
++
++	sa1111_ohci_configure();
++
++	/*
++	 * Initialise the generic OHCI driver.
++	 */
++	ret = hc_add_ohci(SA1111_FAKE_PCIDEV, NIRQHCIM,
++			  (void *)&USB_OHCI_OP_BASE, 0, &sa1111_ohci,
++			  "usb-ohci", "sa1111");
++
++//	if (ret)
++//		release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
++
++#ifdef CONFIG_SA1100_BADGE4
++	if (machine_is_badge4() && (!ret)) {
++		/* found the controller, so now power the bus */
++		badge4_set_5V(BADGE4_5V_USB, 1);
++	}
++#endif
++
++	return ret;
++}
++
++static void __exit sa1111_ohci_exit(void)
++{
++	hc_remove_ohci(sa1111_ohci);
++
++	/*
++	 * Put the USB host controller into reset.
++	 */
++	USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
++
++	/*
++	 * Stop the USB clock.
++	 */
++	SKPCR &= ~SKPCR_UCLKEN;
++
++	/*
++	 * Release memory resources.
++	 */
++//	release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
++
++#ifdef CONFIG_SA1100_BADGE4
++	if (machine_is_badge4()) {
++		badge4_set_5V(BADGE4_5V_USB, 0);
++	}
++#endif
++}
++
++module_init(sa1111_ohci_init);
++module_exit(sa1111_ohci_exit);
+--- linux-2.4.25/drivers/usb/host/usb-ohci.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/usb/host/usb-ohci.c	2004-03-31 17:15:09.000000000 +0200
+@@ -12,7 +12,6 @@
+  * 
+  * History:
+  *
+- * 2002/10/22 OHCI_USB_OPER for ALi lockup in IBM i1200 (ALEX <thchou@ali>)
+  * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
+  *	load failure (Matthew Frederickson)
+  * 2002/01/20 async unlink fixes:  return -EINPROGRESS (per spec) and
+@@ -81,16 +80,6 @@
+ 
+ #include "../hcd.h"
+ 
+-#ifdef CONFIG_PMAC_PBOOK
+-#include <asm/machdep.h>
+-#include <asm/pmac_feature.h>
+-#include <asm/pci-bridge.h>
+-#ifndef CONFIG_PM
+-#define CONFIG_PM
+-#endif
+-#endif
+-
+-
+ /*
+  * Version Information
+  */
+@@ -98,14 +87,10 @@
+ #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
+ #define DRIVER_DESC "USB OHCI Host Controller Driver"
+ 
+-/* For initializing controller (mask in an HCFS mode too) */
+-#define	OHCI_CONTROL_INIT \
+-	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+-
+ #define OHCI_UNLINK_TIMEOUT	(HZ / 10)
+ 
+ static LIST_HEAD (ohci_hcd_list);
+-static spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
++spinlock_t usb_ed_lock = SPIN_LOCK_UNLOCKED;
+ 
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -443,7 +428,7 @@
+ 
+ static void ohci_dump (ohci_t *controller, int verbose)
+ {
+-	dbg ("OHCI controller usb-%s state", controller->ohci_dev->slot_name);
++	dbg ("OHCI controller usb-%s state", controller->slot_name);
+ 
+ 	// dumps some of the state we know about
+ 	ohci_dump_status (controller);
+@@ -557,7 +542,7 @@
+ 	int i, size = 0;
+ 	unsigned long flags;
+ 	int bustime = 0;
+-	int mem_flags = GFP_ATOMIC;
++	int mem_flags = ALLOC_FLAGS;
+ 	
+ 	if (!urb->dev || !urb->dev->bus)
+ 		return -ENODEV;
+@@ -702,6 +687,9 @@
+ 	if (urb->timeout) {
+ 		struct list_head	*entry;
+ 
++		// FIXME:  usb-uhci uses relative timeouts (like this),
++		// while uhci uses absolute ones (probably better).
++		// Pick one solution and change the affected drivers.
+ 		urb->timeout += jiffies;
+ 
+ 		list_for_each (entry, &ohci->timeout_list) {
+@@ -715,7 +703,6 @@
+ 
+ 		/* drive timeouts by SF (messy, but works) */
+ 		writel (OHCI_INTR_SF, &ohci->regs->intrenable);	
+-		(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+ 	}
+ #endif
+ 
+@@ -790,10 +777,8 @@
+ 
+ 				/* wait until all TDs are deleted */
+ 				set_current_state(TASK_UNINTERRUPTIBLE);
+-				while (timeout && (urb->status == USB_ST_URB_PENDING)) {
++				while (timeout && (urb->status == USB_ST_URB_PENDING))
+ 					timeout = schedule_timeout (timeout);
+-					set_current_state(TASK_UNINTERRUPTIBLE);
+-				}
+ 				set_current_state(TASK_RUNNING);
+ 				remove_wait_queue (&unlink_wakeup, &wait); 
+ 				if (urb->status == USB_ST_URB_PENDING) {
+@@ -864,7 +849,7 @@
+   				if (ed->state == ED_OPER) {
+ 					/* driver on that interface didn't unlink an urb */
+ 					dbg ("driver usb-%s dev %d ed 0x%x unfreed URB",
+-						ohci->ohci_dev->slot_name, usb_dev->devnum, i);
++						ohci->slot_name, usb_dev->devnum, i);
+ 					ep_unlink (ohci, ed);
+ 				}
+   				ep_rm_ed (usb_dev, ed);
+@@ -909,7 +894,7 @@
+ 			} else {
+ 				/* likely some interface's driver has a refcount bug */
+ 				err ("bus %s devnum %d deletion in interrupt",
+-					ohci->ohci_dev->slot_name, usb_dev->devnum);
++					ohci->slot_name, usb_dev->devnum);
+ 				BUG ();
+ 			}
+ 		}
+@@ -1294,7 +1279,6 @@
+ 		/* enable SOF interrupt */
+ 		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+ 		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+-		(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+ 	}
+ }
+ 
+@@ -1316,7 +1300,11 @@
+ 		err("internal OHCI error: TD index > length");
+ 		return;
+ 	}
+-	
++#ifdef CONFIG_SA1111
++	if (data & (1 << 20))
++		panic("td_fill: A20 = 1: %08x\n", data);
++#endif
++
+ 	/* use this td as the next dummy */
+ 	td_pt = urb_priv->td [index];
+ 	td_pt->hwNextTD = 0;
+@@ -1415,7 +1403,6 @@
+ 			if (!ohci->sleeping) {
+ 				wmb();
+ 				writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+-				(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+ 			}
+ 			break;
+ 
+@@ -1444,7 +1431,6 @@
+ 			if (!ohci->sleeping) {
+ 				wmb();
+ 				writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+-				(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+ 			}
+ 			break;
+ 
+@@ -1826,7 +1812,7 @@
+ 	num_ports = roothub_a (ohci) & RH_A_NDP; 
+ 	if (num_ports > MAX_ROOT_PORTS) {
+ 		err ("bogus NDP=%d for OHCI usb-%s", num_ports,
+-			ohci->ohci_dev->slot_name);
++			ohci->slot_name);
+ 		err ("rereads as NDP=%d",
+ 			readl (&ohci->regs->roothub.a) & RH_A_NDP);
+ 		/* retry later; "should not happen" */
+@@ -2174,16 +2160,12 @@
+ 	writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ 
+ 	dbg("USB HC reset_hc usb-%s: ctrl = 0x%x ;",
+-		ohci->ohci_dev->slot_name,
++		ohci->slot_name,
+ 		readl (&ohci->regs->control));
+ 
+   	/* Reset USB (needed by some controllers) */
+ 	writel (0, &ohci->regs->control);
+-
+-	/* Force a state change from USBRESET to USBOPERATIONAL for ALi */
+-	(void) readl (&ohci->regs->control);	/* PCI posting */
+-	writel (ohci->hc_control = OHCI_USB_OPER, &ohci->regs->control);
+-
++      	
+ 	/* HC Reset requires max 10 ms delay */
+ 	writel (OHCI_HCR,  &ohci->regs->cmdstatus);
+ 	while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
+@@ -2252,8 +2234,6 @@
+ 	writel (RH_HS_LPSC, &ohci->regs->roothub.status);
+ #endif	/* OHCI_USE_NPS */
+ 
+-	(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+-
+ 	// POTPGT delay is bits 24-31, in 2 ms units.
+ 	mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
+  
+@@ -2332,14 +2312,14 @@
+ 	/* interrupt for some other device? */
+ 	} else if ((ints &= readl (&regs->intrenable)) == 0) {
+ 		return;
+-	} 
++	}
+ 
+ 	// dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no));
+ 
+ 	if (ints & OHCI_INTR_UE) {
+ 		ohci->disabled++;
+ 		err ("OHCI Unrecoverable Error, controller usb-%s disabled",
+-			ohci->ohci_dev->slot_name);
++			ohci->slot_name);
+ 		// e.g. due to PCI Master/Target Abort
+ 
+ #ifdef	DEBUG
+@@ -2355,30 +2335,24 @@
+   
+ 	if (ints & OHCI_INTR_WDH) {
+ 		writel (OHCI_INTR_WDH, &regs->intrdisable);	
+-		(void)readl (&regs->intrdisable); /* PCI posting flush */
+ 		dl_done_list (ohci, dl_reverse_done_list (ohci));
+ 		writel (OHCI_INTR_WDH, &regs->intrenable); 
+-		(void)readl (&regs->intrdisable); /* PCI posting flush */
+ 	}
+   
+ 	if (ints & OHCI_INTR_SO) {
+ 		dbg("USB Schedule overrun");
+ 		writel (OHCI_INTR_SO, &regs->intrenable); 	 
+-		(void)readl (&regs->intrdisable); /* PCI posting flush */
+ 	}
+ 
+ 	// FIXME:  this assumes SOF (1/ms) interrupts don't get lost...
+ 	if (ints & OHCI_INTR_SF) { 
+ 		unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
+ 		writel (OHCI_INTR_SF, &regs->intrdisable);	
+-		(void)readl (&regs->intrdisable); /* PCI posting flush */
+ 		if (ohci->ed_rm_list[!frame] != NULL) {
+ 			dl_del_list (ohci, !frame);
+ 		}
+-		if (ohci->ed_rm_list[frame] != NULL) {
++		if (ohci->ed_rm_list[frame] != NULL)
+ 			writel (OHCI_INTR_SF, &regs->intrenable);	
+-			(void)readl (&regs->intrdisable); /* PCI posting flush */
+-		}
+ 	}
+ 
+ 	if (!list_empty (&ohci->timeout_list)) {
+@@ -2392,7 +2366,6 @@
+ 
+ 	writel (ints, &regs->intrstatus);
+ 	writel (OHCI_INTR_MIE, &regs->intrenable);	
+-	(void)readl (&regs->intrdisable); /* PCI posting flush */
+ }
+ 
+ /*-------------------------------------------------------------------------*/
+@@ -2423,7 +2396,9 @@
+ 	ohci->regs = mem_base;   
+ 
+ 	ohci->ohci_dev = dev;
++#ifdef CONFIG_PCI
+ 	pci_set_drvdata(dev, ohci);
++#endif
+  
+ 	INIT_LIST_HEAD (&ohci->ohci_hcd_list);
+ 	list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
+@@ -2451,7 +2426,7 @@
+ 
+ static void hc_release_ohci (ohci_t * ohci)
+ {	
+-	dbg ("USB HC release ohci usb-%s", ohci->ohci_dev->slot_name);
++	dbg ("USB HC release ohci usb-%s", ohci->slot_name);
+ 
+ 	/* disconnect all devices */    
+ 	if (ohci->bus->root_hub)
+@@ -2464,7 +2439,9 @@
+ 		free_irq (ohci->irq, ohci);
+ 		ohci->irq = -1;
+ 	}
+-	pci_set_drvdata(ohci->ohci_dev, NULL);
++#ifdef CONFIG_PCI
++	pci_set_drvdata(ohci->ohci_dev, 0);
++#endif
+ 	if (ohci->bus) {
+ 		if (ohci->bus->busnum != -1)
+ 			usb_deregister_bus (ohci->bus);
+@@ -2487,17 +2464,15 @@
+ 
+ /*-------------------------------------------------------------------------*/
+ 
+-/* Increment the module usage count, start the control thread and
+- * return success. */
+-
+-static struct pci_driver ohci_pci_driver;
+- 
+-static int __devinit
+-hc_found_ohci (struct pci_dev *dev, int irq,
+-	void *mem_base, const struct pci_device_id *id)
++/*
++ * Host bus independent add one OHCI host controller.
++ */
++int __devinit
++hc_add_ohci(struct pci_dev *dev, int irq, void *mem_base, unsigned long flags,
++	    const char *name, const char *slot_name)
+ {
+-	ohci_t * ohci;
+ 	char buf[8], *bufp = buf;
++	ohci_t * ohci;
+ 	int ret;
+ 
+ #ifndef __sparc__
+@@ -2507,34 +2482,17 @@
+ #endif
+ 	printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
+ 		(unsigned long)	mem_base, bufp);
+-	printk(KERN_INFO __FILE__ ": usb-%s, %s\n", dev->slot_name, dev->name);
+-    
++
+ 	ohci = hc_alloc_ohci (dev, mem_base);
+ 	if (!ohci) {
+ 		return -ENOMEM;
+ 	}
++	ohci->slot_name = slot_name;
+ 	if ((ret = ohci_mem_init (ohci)) < 0) {
+ 		hc_release_ohci (ohci);
+ 		return ret;
+ 	}
+-	ohci->flags = id->driver_data;
+-	
+-	/* Check for NSC87560. We have to look at the bridge (fn1) to identify
+-	   the USB (fn2). This quirk might apply to more or even all NSC stuff
+-	   I don't know.. */
+-	   
+-	if(dev->vendor == PCI_VENDOR_ID_NS)
+-	{
+-		struct pci_dev *fn1  = pci_find_slot(dev->bus->number, PCI_DEVFN(PCI_SLOT(dev->devfn), 1));
+-		if(fn1 && fn1->vendor == PCI_VENDOR_ID_NS && fn1->device == PCI_DEVICE_ID_NS_87560_LIO)
+-			ohci->flags |= OHCI_QUIRK_SUCKYIO;
+-		
+-	}
+-	
+-	if (ohci->flags & OHCI_QUIRK_SUCKYIO)
+-		printk (KERN_INFO __FILE__ ": Using NSC SuperIO setup\n");
+-	if (ohci->flags & OHCI_QUIRK_AMD756)
+-		printk (KERN_INFO __FILE__ ": AMD756 erratum 4 workaround\n");
++	ohci->flags = flags;
+ 
+ 	if (hc_reset (ohci) < 0) {
+ 		hc_release_ohci (ohci);
+@@ -2543,13 +2501,11 @@
+ 
+ 	/* FIXME this is a second HC reset; why?? */
+ 	writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
+-	(void)readl (&ohci->regs->intrdisable); /* PCI posting flush */
+ 	wait_ms (10);
+ 
+ 	usb_register_bus (ohci->bus);
+ 	
+-	if (request_irq (irq, hc_interrupt, SA_SHIRQ,
+-			ohci_pci_driver.name, ohci) != 0) {
++	if (request_irq (irq, hc_interrupt, SA_SHIRQ, name, ohci) != 0) {
+ 		err ("request interrupt %s failed", bufp);
+ 		hc_release_ohci (ohci);
+ 		return -EBUSY;
+@@ -2557,7 +2513,7 @@
+ 	ohci->irq = irq;     
+ 
+ 	if (hc_start (ohci) < 0) {
+-		err ("can't start usb-%s", dev->slot_name);
++		err ("can't start usb-%s", ohci->slot_name);
+ 		hc_release_ohci (ohci);
+ 		return -EBUSY;
+ 	}
+@@ -2568,114 +2524,11 @@
+ 	return 0;
+ }
+ 
+-/*-------------------------------------------------------------------------*/
+-
+-#ifdef	CONFIG_PM
+-
+-/* controller died; cleanup debris, then restart */
+-/* must not be called from interrupt context */
+-
+-static void hc_restart (ohci_t *ohci)
+-{
+-	int temp;
+-	int i;
+-
+-	if (ohci->pci_latency)
+-		pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
+-
+-	ohci->disabled = 1;
+-	ohci->sleeping = 0;
+-	if (ohci->bus->root_hub)
+-		usb_disconnect (&ohci->bus->root_hub);
+-	
+-	/* empty the interrupt branches */
+-	for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0;
+-	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table[i] = 0;
+-	
+-	/* no EDs to remove */
+-	ohci->ed_rm_list [0] = NULL;
+-	ohci->ed_rm_list [1] = NULL;
+-
+-	/* empty control and bulk lists */	 
+-	ohci->ed_isotail     = NULL;
+-	ohci->ed_controltail = NULL;
+-	ohci->ed_bulktail    = NULL;
+-
+-	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
+-		err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
+-	} else
+-		dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
+-}
+-
+-#endif	/* CONFIG_PM */
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* configured so that an OHCI device is always provided */
+-/* always called with process context; sleeping is OK */
+-
+-static int __devinit
+-ohci_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+-{
+-	unsigned long mem_resource, mem_len;
+-	void *mem_base;
+-	int status;
+-
+-	if (pci_enable_device(dev) < 0)
+-		return -ENODEV;
+-
+-        if (!dev->irq) {
+-        	err("found OHCI device with no IRQ assigned. check BIOS settings!");
+-		pci_disable_device (dev);
+-   	        return -ENODEV;
+-        }
+-	
+-	/* we read its hardware registers as memory */
+-	mem_resource = pci_resource_start(dev, 0);
+-	mem_len = pci_resource_len(dev, 0);
+-	if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
+-		dbg ("controller already in use");
+-		pci_disable_device (dev);
+-		return -EBUSY;
+-	}
+-
+-	mem_base = ioremap_nocache (mem_resource, mem_len);
+-	if (!mem_base) {
+-		err("Error mapping OHCI memory");
+-		release_mem_region (mem_resource, mem_len);
+-		pci_disable_device (dev);
+-		return -EFAULT;
+-	}
+-
+-	/* controller writes into our memory */
+-	pci_set_master (dev);
+-
+-	status = hc_found_ohci (dev, dev->irq, mem_base, id);
+-	if (status < 0) {
+-		iounmap (mem_base);
+-		release_mem_region (mem_resource, mem_len);
+-		pci_disable_device (dev);
+-	}
+-	return status;
+-} 
+-
+-/*-------------------------------------------------------------------------*/
+-
+-/* may be called from interrupt context [interface spec] */
+-/* may be called without controller present */
+-/* may be called with controller, bus, and devices active */
+-
+-static void __devexit
+-ohci_pci_remove (struct pci_dev *dev)
++/*
++ * Host bus independent remove one OHCI host controller.
++ */
++void __devexit hc_remove_ohci(ohci_t *ohci)
+ {
+-	ohci_t		*ohci = pci_get_drvdata(dev);
+-
+-	dbg ("remove %s controller usb-%s%s%s",
+-		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
+-		dev->slot_name,
+-		ohci->disabled ? " (disabled)" : "",
+-		in_interrupt () ? " in interrupt" : ""
+-		);
+ #ifdef	DEBUG
+ 	ohci_dump (ohci, 1);
+ #endif
+@@ -2692,270 +2545,8 @@
+ 			&ohci->regs->control);
+ 
+ 	hc_release_ohci (ohci);
+-
+-	release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
+-	pci_disable_device (dev);
+ }
+ 
+-
+-#ifdef	CONFIG_PM
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static int
+-ohci_pci_suspend (struct pci_dev *dev, u32 state)
+-{
+-	ohci_t			*ohci = pci_get_drvdata(dev);
+-	unsigned long		flags;
+-	u16 cmd;
+-
+-	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+-		dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
+-			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
+-		return -EIO;
+-	}
+-
+-	/* act as if usb suspend can always be used */
+-	info ("USB suspend: usb-%s", dev->slot_name);
+-	ohci->sleeping = 1;
+-
+-	/* First stop processing */
+-  	spin_lock_irqsave (&usb_ed_lock, flags);
+-	ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+-	writel (ohci->hc_control, &ohci->regs->control);
+-	writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+-	(void) readl (&ohci->regs->intrstatus);
+-  	spin_unlock_irqrestore (&usb_ed_lock, flags);
+-
+-	/* Wait a frame or two */
+-	mdelay(1);
+-	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+-		mdelay (1);
+-		
+-#ifdef CONFIG_PMAC_PBOOK
+-	if (_machine == _MACH_Pmac)
+-		disable_irq (ohci->irq);
+-	/* else, 2.4 assumes shared irqs -- don't disable */
+-#endif
+-	/* Enable remote wakeup */
+-	writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
+-
+-	/* Suspend chip and let things settle down a bit */
+-	ohci->hc_control = OHCI_USB_SUSPEND;
+-	writel (ohci->hc_control, &ohci->regs->control);
+-	(void) readl (&ohci->regs->control);
+-	mdelay (500); /* No schedule here ! */
+-	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+-		case OHCI_USB_RESET:
+-			dbg("Bus in reset phase ???");
+-			break;
+-		case OHCI_USB_RESUME:
+-			dbg("Bus in resume phase ???");
+-			break;
+-		case OHCI_USB_OPER:
+-			dbg("Bus in operational phase ???");
+-			break;
+-		case OHCI_USB_SUSPEND:
+-			dbg("Bus suspended");
+-			break;
+-	}
+-	/* In some rare situations, Apple's OHCI have happily trashed
+-	 * memory during sleep. We disable it's bus master bit during
+-	 * suspend
+-	 */
+-	pci_read_config_word (dev, PCI_COMMAND, &cmd);
+-	cmd &= ~PCI_COMMAND_MASTER;
+-	pci_write_config_word (dev, PCI_COMMAND, cmd);
+-#ifdef CONFIG_PMAC_PBOOK
+-	{
+-	   	struct device_node	*of_node;
+-
+-		/* Disable USB PAD & cell clock */
+-		of_node = pci_device_to_OF_node (ohci->ohci_dev);
+-		if (of_node)
+-			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+-	}
+-#endif
+-	return 0;
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static int
+-ohci_pci_resume (struct pci_dev *dev)
+-{
+-	ohci_t		*ohci = pci_get_drvdata(dev);
+-	int		temp;
+-	unsigned long	flags;
+-
+-	/* guard against multiple resumes */
+-	atomic_inc (&ohci->resume_count);
+-	if (atomic_read (&ohci->resume_count) != 1) {
+-		err ("concurrent PCI resumes for usb-%s", dev->slot_name);
+-		atomic_dec (&ohci->resume_count);
+-		return 0;
+-	}
+-
+-#ifdef CONFIG_PMAC_PBOOK
+-	{
+-		struct device_node *of_node;
+-
+-		/* Re-enable USB PAD & cell clock */
+-		of_node = pci_device_to_OF_node (ohci->ohci_dev);
+-		if (of_node)
+-			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+-	}
+-#endif
+-
+-	/* did we suspend, or were we powered off? */
+-	ohci->hc_control = readl (&ohci->regs->control);
+-	temp = ohci->hc_control & OHCI_CTRL_HCFS;
+-
+-#ifdef DEBUG
+-	/* the registers may look crazy here */
+-	ohci_dump_status (ohci);
+-#endif
+-
+-	/* Re-enable bus mastering */
+-	pci_set_master(ohci->ohci_dev);
+-	
+-	switch (temp) {
+-
+-	case OHCI_USB_RESET:	// lost power
+-		info ("USB restart: usb-%s", dev->slot_name);
+-		hc_restart (ohci);
+-		break;
+-
+-	case OHCI_USB_SUSPEND:	// host wakeup
+-	case OHCI_USB_RESUME:	// remote wakeup
+-		info ("USB continue: usb-%s from %s wakeup", dev->slot_name,
+-			(temp == OHCI_USB_SUSPEND)
+-				? "host" : "remote");
+-		ohci->hc_control = OHCI_USB_RESUME;
+-		writel (ohci->hc_control, &ohci->regs->control);
+-		(void) readl (&ohci->regs->control);
+-		mdelay (20); /* no schedule here ! */
+-		/* Some controllers (lucent) need a longer delay here */
+-		mdelay (15);
+-		temp = readl (&ohci->regs->control);
+-		temp = ohci->hc_control & OHCI_CTRL_HCFS;
+-		if (temp != OHCI_USB_RESUME) {
+-			err ("controller usb-%s won't resume", dev->slot_name);
+-			ohci->disabled = 1;
+-			return -EIO;
+-		}
+-
+-		/* Some chips likes being resumed first */
+-		writel (OHCI_USB_OPER, &ohci->regs->control);
+-		(void) readl (&ohci->regs->control);
+-		mdelay (3);
+-
+-		/* Then re-enable operations */
+-		spin_lock_irqsave (&usb_ed_lock, flags);
+-		ohci->disabled = 0;
+-		ohci->sleeping = 0;
+-		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+-		if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
+-			if (ohci->ed_controltail)
+-				ohci->hc_control |= OHCI_CTRL_CLE;
+-			if (ohci->ed_bulktail)
+-				ohci->hc_control |= OHCI_CTRL_BLE;
+-		}
+-		writel (ohci->hc_control, &ohci->regs->control);
+-		writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+-		writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+-		/* Check for a pending done list */
+-		writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);	
+-		(void) readl (&ohci->regs->intrdisable);
+-		spin_unlock_irqrestore (&usb_ed_lock, flags);
+-#ifdef CONFIG_PMAC_PBOOK
+-		if (_machine == _MACH_Pmac)
+-			enable_irq (ohci->irq);
+-#endif
+-		if (ohci->hcca->done_head)
+-			dl_done_list (ohci, dl_reverse_done_list (ohci));
+-		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+-		writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+-		writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+-		break;
+-
+-	default:
+-		warn ("odd PCI resume for usb-%s", dev->slot_name);
+-	}
+-
+-	/* controller is operational, extra resumes are harmless */
+-	atomic_dec (&ohci->resume_count);
+-
+-	return 0;
+-}
+-
+-#endif	/* CONFIG_PM */
+-
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static const struct pci_device_id __devinitdata ohci_pci_ids [] = { {
+-
+-	/*
+-	 * AMD-756 [Viper] USB has a serious erratum when used with
+-	 * lowspeed devices like mice.
+-	 */
+-	vendor:		0x1022,
+-	device:		0x740c,
+-	subvendor:	PCI_ANY_ID,
+-	subdevice:	PCI_ANY_ID,
+-
+-	driver_data:	OHCI_QUIRK_AMD756,
+-
+-} , {
+-
+-	/* handle any USB OHCI controller */
+-	class: 		((PCI_CLASS_SERIAL_USB << 8) | 0x10),
+-	class_mask: 	~0,
+-
+-	/* no matter who makes it */
+-	vendor:		PCI_ANY_ID,
+-	device:		PCI_ANY_ID,
+-	subvendor:	PCI_ANY_ID,
+-	subdevice:	PCI_ANY_ID,
+-
+-	}, { /* end: all zeroes */ }
+-};
+-
+-MODULE_DEVICE_TABLE (pci, ohci_pci_ids);
+-
+-static struct pci_driver ohci_pci_driver = {
+-	name:		"usb-ohci",
+-	id_table:	&ohci_pci_ids [0],
+-
+-	probe:		ohci_pci_probe,
+-	remove:		__devexit_p(ohci_pci_remove),
+-
+-#ifdef	CONFIG_PM
+-	suspend:	ohci_pci_suspend,
+-	resume:		ohci_pci_resume,
+-#endif	/* PM */
+-};
+-
+- 
+-/*-------------------------------------------------------------------------*/
+-
+-static int __init ohci_hcd_init (void) 
+-{
+-	return pci_module_init (&ohci_pci_driver);
+-}
+-
+-/*-------------------------------------------------------------------------*/
+-
+-static void __exit ohci_hcd_cleanup (void) 
+-{	
+-	pci_unregister_driver (&ohci_pci_driver);
+-}
+-
+-module_init (ohci_hcd_init);
+-module_exit (ohci_hcd_cleanup);
+-
+-
+ MODULE_AUTHOR( DRIVER_AUTHOR );
+ MODULE_DESCRIPTION( DRIVER_DESC );
+ MODULE_LICENSE("GPL");
+--- linux-2.4.25/drivers/usb/host/usb-ohci.h~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/usb/host/usb-ohci.h	2004-03-31 17:15:09.000000000 +0200
+@@ -386,6 +386,7 @@
+ 	struct ohci_regs * regs;	/* OHCI controller's memory */
+ 	struct list_head ohci_hcd_list;	/* list of all ohci_hcd */
+ 
++	struct ohci * next; 		// chain of ohci device contexts
+ 	struct list_head timeout_list;
+ 	// struct list_head urb_list; 	// list of all pending urbs
+ 	// spinlock_t urb_list_lock; 	// lock to keep consistency 
+@@ -403,6 +404,7 @@
+ 
+ 	/* PCI device handle, settings, ... */
+ 	struct pci_dev	*ohci_dev;
++	const char	*slot_name;
+ 	u8		pci_latency;
+ 	struct pci_pool	*td_cache;
+ 	struct pci_pool	*dev_cache;
+@@ -448,7 +450,7 @@
+ #endif
+  
+ #ifndef CONFIG_PCI
+-#	error "usb-ohci currently requires PCI-based controllers"
++//#	error "usb-ohci currently requires PCI-based controllers"
+ 	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
+ #endif
+ 
+@@ -641,3 +643,6 @@
+ 	pci_pool_free (hc->dev_cache, dev, dev->dma);
+ }
+ 
++/* For initializing controller (mask in an HCFS mode too) */
++#define	OHCI_CONTROL_INIT \
++	(OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
+--- linux-2.4.25/drivers/video/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/video/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -30,13 +30,28 @@
+          tristate '  Permedia3 support (EXPERIMENTAL)' CONFIG_FB_PM3
+       fi
+    fi
+-   if [ "$CONFIG_ARCH_ACORN" = "y" ]; then
+-      bool '  Acorn VIDC support' CONFIG_FB_ACORN
+-   fi
+-   dep_tristate '  Cyber2000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI
+-   if [ "$CONFIG_ARCH_SA1100" = "y" ]; then
+-      bool '  SA-1100 LCD support' CONFIG_FB_SA1100
++   if [ "$CONFIG_ARM" = "y" ]; then
++     if [ "$CONFIG_ARCH_ACORN" -o "$CONFIG_ARCH_RISCSTATION" ]; then
++  	bool '  Acorn VIDC support' CONFIG_FB_ACORN
++     else
++	define_bool CONFIG_FB_ACORN n
++     fi
++     dep_bool '  Anakin LCD support' CONFIG_FB_ANAKIN $CONFIG_ARCH_ANAKIN
++     dep_bool '  CLPS711X LCD support' CONFIG_FB_CLPS711X $CONFIG_ARCH_CLPS711X
++     dep_bool '  SA-1100 LCD support' CONFIG_FB_SA1100 $CONFIG_ARCH_SA1100
++     dep_bool '  MX1ADS LCD support' CONFIG_FB_DBMX1 $CONFIG_ARCH_MX1ADS
++     if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF" = "y" ]; then
++        choice 'CerfBoard LCD Display Size' \
++		"3.8_Color		CONFIG_CERF_LCD_38_A \
++		 3.8_Mono		CONFIG_CERF_LCD_38_B \
++		 5.7		CONFIG_CERF_LCD_57_A \
++		 7.2		CONFIG_CERF_LCD_72_A" 5.7
++     fi
++     if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF_CPLD" = "y" ]; then
++       bool 'Cerfboard Backlight (CerfPDA)' CONFIG_SA1100_CERF_LCD_BACKLIGHT
++     fi
+    fi
++   dep_tristate '  CyberPro 2000/2010/5000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI
+    if [ "$CONFIG_APOLLO" = "y" ]; then
+       define_bool CONFIG_FB_APOLLO y
+    fi
+@@ -265,7 +280,7 @@
+ 	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
+ 	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+ 	   "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y"  -o \
+-	   "$CONFIG_FB_TX3912" = "y" ]; then
++	   "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" ]; then
+ 	 define_tristate CONFIG_FBCON_MFB y
+       else
+ 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
+@@ -273,19 +288,20 @@
+ 	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
+ 	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+ 	      "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+-	      "$CONFIG_FB_TX3912" = "m" ]; then
++	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_CLPS711X" = "m"  ]; then
+ 	    define_tristate CONFIG_FBCON_MFB m
+ 	 fi
+       fi
+       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
+ 	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \
+-	   "$CONFIG_FB_TX3912" = "y" ]; then
++	   "$CONFIG_FB_TX3912" = "y"  -o "$CONFIG_FB_CLPS711X" = "y" -o \
++           "$CONFIG_FB_DBMX1" = "y" ]; then
+ 	 define_tristate CONFIG_FBCON_CFB2 y
+ 	 define_tristate CONFIG_FBCON_CFB4 y
+       else
+ 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
+ 	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \
+-	      "$CONFIG_FB_TX3912" = "m" ]; then
++	      "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_CLPS711X" = "m" ]; then
+ 	    define_tristate CONFIG_FBCON_CFB2 m
+ 	    define_tristate CONFIG_FBCON_CFB4 m
+ 	 fi
+@@ -312,7 +328,8 @@
+ 	   "$CONFIG_FB_TX3912" = "y" -o \
+ 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+ 	   "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \
+-	   "$CONFIG_FB_INTEL" = "y" ]; then
++	   "$CONFIG_FB_INTEL" = "y" -o \
++           "$CONFIG_FB_DBMX1" = "y" ]; then
+ 	 define_tristate CONFIG_FBCON_CFB8 y
+       else
+ 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
+@@ -354,7 +371,9 @@
+ 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_3DFX" = "y"  -o \
+ 	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
+ 	   "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \
+-	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" ]; then
++	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \
++	   "$CONFIG_FB_ANAKIN" = "y" -o \
++           "$CONFIG_FB_DBMX1" = "y" ]; then
+ 	 define_tristate CONFIG_FBCON_CFB16 y
+       else
+ 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
+@@ -509,6 +528,9 @@
+ 	 if [ "$CONFIG_AMIGA" = "y" ]; then
+ 	    define_bool CONFIG_FONT_PEARL_8x8 y
+ 	 fi
++	 if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_RISCSTATION" = "y" ]; then
++	    define_bool CONFIG_FONT_ACORN_8x8 y
++	 fi
+ 	 if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_ACORN" = "y" ]; then
+ 	    define_bool CONFIG_FONT_ACORN_8x8 y
+ 	 fi
+--- linux-2.4.25/drivers/video/Makefile~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/video/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -55,6 +55,7 @@
+ obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
+ obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o
+ obj-$(CONFIG_FB_CT65550)          += chipsfb.o
++obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o
+ obj-$(CONFIG_FB_CYBER)            += cyberfb.o
+ obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
+ obj-$(CONFIG_FB_SGIVW)            += sgivwfb.o
+@@ -68,7 +69,7 @@
+ obj-$(CONFIG_FB_TRIDENT)          += tridentfb.o fbgen.o
+ obj-$(CONFIG_FB_S3TRIO)           += S3triofb.o
+ obj-$(CONFIG_FB_TGA)              += tgafb.o fbgen.o
+-obj-$(CONFIG_FB_VESA)             += vesafb.o 
++obj-$(CONFIG_FB_VESA)             += vesafb.o
+ obj-$(CONFIG_FB_VGA16)            += vga16fb.o fbcon-vga-planes.o
+ obj-$(CONFIG_FB_VIRGE)            += virgefb.o
+ obj-$(CONFIG_FB_G364)             += g364fb.o
+@@ -126,14 +127,16 @@
+ 
+ obj-$(CONFIG_FB_SUN3)             += sun3fb.o
+ obj-$(CONFIG_FB_BWTWO)            += bwtwofb.o
+-obj-$(CONFIG_FB_HGA)              += hgafb.o  
++obj-$(CONFIG_FB_HGA)              += hgafb.o
+ obj-$(CONFIG_FB_SA1100)           += sa1100fb.o
+-obj-$(CONFIG_FB_VIRTUAL)          += vfb.o  
++obj-$(CONFIG_FB_DBMX1)            += dbmx1fb.o
++obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
+ obj-$(CONFIG_FB_HIT)              += hitfb.o fbgen.o
+ obj-$(CONFIG_FB_E1355)            += epson1355fb.o fbgen.o
+ obj-$(CONFIG_FB_E1356)            += epson1356fb.o
+ obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
+ obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
++obj-$(CONFIG_FB_ANAKIN)           += anakinfb.o
+ 
+ # Generic Low Level Drivers
+ 
+@@ -169,4 +172,3 @@
+ 	    -e 's/dfont\(_uni.*\]\)/promfont\1 __initdata/' > promcon_tbl.c
+ 
+ promcon_tbl.o: promcon_tbl.c $(TOPDIR)/include/linux/types.h
+-
+--- linux-2.4.25/drivers/video/acornfb.c~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/drivers/video/acornfb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -752,11 +752,12 @@
+ 	}
+ #endif
+ #ifdef FBCON_HAS_CFB16
+-	if (bpp == 16 && regno < 16) {
++	if (bpp == 16) {
+ 		int i;
+ 
+-		current_par.cmap.cfb16[regno] =
+-				regno | regno << 5 | regno << 10;
++		if (regno < 16)
++			current_par.cmap.cfb16[regno] =
++					regno | regno << 5 | regno << 10;
+ 
+ 		pal.p = 0;
+ 		vidc_writel(0x10000000);
+@@ -1215,7 +1216,7 @@
+ 				p.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green;
+ 				p.vidc20.blue  = current_par.palette[(i >> 2) & 31].vidc20.blue;
+ 			}
+-			acornfb_palette_write(i, current_par.palette[i]);
++			acornfb_palette_write(i, p);
+ 		}
+ 	} else
+ #endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/anakinfb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,221 @@
++/*
++ *  linux/drivers/video/anakinfb.c
++ *
++ *  Copyright (C) 2001 Aleph One Ltd. for Acunia N.V.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Changelog:
++ *   23-Apr-2001 TTC	Created
++ */
++
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/module.h>
++
++#include <asm/io.h>
++
++#include <video/fbcon.h>
++#include <video/fbcon-cfb16.h>
++
++static u16 colreg[16];
++static int currcon = 0;
++static struct fb_info fb_info;
++static struct display display;
++
++static int
++anakinfb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
++			u_int *transp, struct fb_info *info)
++{
++	if (regno > 15)
++		return 1;
++
++	*red = colreg[regno] & 0xf800;
++	*green = colreg[regno] & 0x7e0 << 5;
++	*blue = colreg[regno] & 0x1f << 11;
++	*transp = 0;
++	return 0;
++}
++
++static int
++anakinfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++			u_int transp, struct fb_info *info)
++{
++	if (regno > 15)
++		return 1;
++
++	colreg[regno] = (red & 0xf800) | (green & 0xfc00 >> 5) |
++			(blue & 0xf800 >> 11);
++	return 0;
++}
++
++static int
++anakinfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
++{
++	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
++	strcpy(fix->id, "AnakinFB");
++	fix->smem_start = VGA_START;
++	fix->smem_len = VGA_SIZE;
++	fix->type = FB_TYPE_PACKED_PIXELS;
++	fix->type_aux = 0;
++	fix->visual = FB_VISUAL_TRUECOLOR;
++	fix->xpanstep = 0;
++	fix->ypanstep = 0;
++	fix->ywrapstep = 0;
++        fix->line_length = 400 * 2;
++	fix->accel = FB_ACCEL_NONE;
++	return 0;
++}
++        
++static int
++anakinfb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++	memset(var, 0, sizeof(struct fb_var_screeninfo));
++	var->xres = 400;
++	var->yres = 234;
++	var->xres_virtual = 400;
++	var->yres_virtual = 234;
++	var->xoffset = 0;
++	var->yoffset = 0;
++	var->bits_per_pixel = 16;
++	var->grayscale = 0;
++	var->red.offset = 11;
++	var->red.length = 5;
++	var->green.offset = 5;
++	var->green.length = 6;
++	var->blue.offset = 0;
++	var->blue.length = 5;
++	var->transp.offset = 0;
++	var->transp.length = 0;
++	var->nonstd = 0;
++	var->activate = FB_ACTIVATE_NOW;
++	var->height = -1;
++	var->width = -1;
++	var->pixclock = 0;
++	var->left_margin = 0;
++	var->right_margin = 0;
++	var->upper_margin = 0;
++	var->lower_margin = 0;
++	var->hsync_len = 0;
++	var->vsync_len = 0;
++	var->sync = 0;
++	var->vmode = FB_VMODE_NONINTERLACED;
++	return 0;
++}
++
++static int
++anakinfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++	return -EINVAL;
++}
++
++static int
++anakinfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
++			struct fb_info *info)
++{
++	if (con == currcon)
++		return fb_get_cmap(cmap, kspc, anakinfb_getcolreg, info);
++	else if (fb_display[con].cmap.len)
++		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
++	else
++		fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2);
++	return 0;
++}
++
++static int
++anakinfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
++			struct fb_info *info)
++{
++	int err;
++
++	if (!fb_display[con].cmap.len) {
++		if ((err = fb_alloc_cmap(&fb_display[con].cmap, 16, 0)))
++			return err;
++	}
++	if (con == currcon)
++		return fb_set_cmap(cmap, kspc, anakinfb_setcolreg, info);
++	else
++		fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
++	return 0;
++}
++
++static int
++anakinfb_switch_con(int con, struct fb_info *info)
++{ 
++	currcon = con;
++	return 0;
++
++}
++
++static int
++anakinfb_updatevar(int con, struct fb_info *info)
++{
++	return 0;
++}
++
++static void
++anakinfb_blank(int blank, struct fb_info *info)
++{
++	/*
++	 * TODO: use I2C to blank/unblank the screen
++	 */
++}
++
++static struct fb_ops anakinfb_ops = {
++	owner:		THIS_MODULE,
++	fb_get_fix:	anakinfb_get_fix,
++	fb_get_var:	anakinfb_get_var,
++	fb_set_var:	anakinfb_set_var,
++	fb_get_cmap:	anakinfb_get_cmap,
++	fb_set_cmap:	anakinfb_set_cmap,
++};
++
++int __init
++anakinfb_init(void)
++{
++	memset(&fb_info, 0, sizeof(struct fb_info));
++	strcpy(fb_info.modename, "AnakinFB");
++	fb_info.node = -1;
++	fb_info.flags = FBINFO_FLAG_DEFAULT;
++	fb_info.fbops = &anakinfb_ops;
++	fb_info.disp = &display;
++	strcpy(fb_info.fontname, "VGA8x16");
++	fb_info.changevar = NULL;
++	fb_info.switch_con = &anakinfb_switch_con;
++	fb_info.updatevar = &anakinfb_updatevar;
++	fb_info.blank = &anakinfb_blank;
++
++	memset(&display, 0, sizeof(struct display));
++	anakinfb_get_var(&display.var, 0, &fb_info);
++	display.screen_base = ioremap(VGA_START, VGA_SIZE);
++	display.visual = FB_VISUAL_TRUECOLOR;
++	display.type = FB_TYPE_PACKED_PIXELS;
++	display.type_aux = 0;
++	display.ypanstep = 0;
++	display.ywrapstep = 0;
++	display.line_length = 400 * 2;
++	display.can_soft_blank = 1;
++	display.inverse = 0;
++
++#ifdef FBCON_HAS_CFB16
++	display.dispsw = &fbcon_cfb16;
++	display.dispsw_data = colreg;
++#else
++	display.dispsw = &fbcon_dummy;
++#endif
++
++	if (register_framebuffer(&fb_info) < 0)
++		return -EINVAL;
++
++	MOD_INC_USE_COUNT;
++	return 0;
++}
++
++MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>");
++MODULE_DESCRIPTION("Anakin framebuffer driver");
++MODULE_SUPPORTED_DEVICE("fb");
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/clps711xfb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,677 @@
++/*
++ *  linux/drivers/video/clps711xfb.c
++ *
++ *  Copyright (C) 2000-2001 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * 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
++ *
++ *  Framebuffer driver for the CLPS7111 and EP7212 processors.
++ */
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/fb.h>
++#include <linux/init.h>
++#include <linux/proc_fs.h>
++#include <linux/delay.h>
++
++#include <video/fbcon.h>
++#include <video/fbcon-cfb4.h>
++#include <video/fbcon-cfb2.h>
++#include <video/fbcon-mfb.h>
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++#include <asm/uaccess.h>
++
++#include <asm/hardware/clps7111.h>
++#include <asm/arch/syspld.h>
++
++static struct clps7111fb_info {
++	struct fb_info		fb;
++	int			currcon;
++} *cfb;
++
++#define CMAP_MAX_SIZE	16
++
++/* The /proc entry for the backlight. */
++static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL;
++
++static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
++		int count, int *eof, void *data);
++static int clps7111fb_proc_backlight_write(struct file *file, 
++		const char *buffer, unsigned long count, void *data);
++
++/*
++ * LCD AC Prescale.  This comes from the LCD panel manufacturers specifications.
++ * This determines how many clocks + 1 of CL1 before the M signal toggles.
++ * The number of lines on the display must not be divisible by this number.
++ */
++static unsigned int lcd_ac_prescale = 13;
++
++/*
++ *    Set a single color register. Return != 0 for invalid regno.
++ */
++static int
++clps7111fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++		     u_int transp, struct fb_info *info)
++{
++	unsigned int level, mask, shift, pal;
++
++	if (regno >= (1 << info->var.bits_per_pixel))
++		return 1;
++
++	/* gray = 0.30*R + 0.58*G + 0.11*B */
++	level = (red * 77 + green * 151 + blue * 28) >> 20;
++
++	/*
++	 * On an LCD, a high value is dark, while a low value is light. 
++	 * So we invert the level.
++	 *
++	 * This isn't true on all machines, so we only do it on EDB7211.
++	 *  --rmk
++	 */
++	if (machine_is_edb7211() || machine_is_guidea07()) {
++		level = 15 - level;
++	}
++
++	shift = 4 * (regno & 7);
++	level <<= shift;
++	mask  = 15 << shift;
++	level &= mask;
++
++	regno = regno < 8 ? PALLSW : PALMSW;
++
++	pal = clps_readl(regno);
++	pal = (pal & ~mask) | level;
++	clps_writel(pal, regno);
++
++	return 0;
++}
++		    
++/*
++ * Set the colormap
++ */
++static int
++clps7111fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
++		    struct fb_info *info)
++{
++	struct clps7111fb_info *cfb = (struct clps7111fb_info *)info;
++	struct fb_cmap *dcmap = &fb_display[con].cmap;
++	int err = 0;
++
++	/* no colormap allocated? */
++	if (!dcmap->len)
++		err = fb_alloc_cmap(dcmap, CMAP_MAX_SIZE, 0);
++
++	if (!err && con == cfb->currcon) {
++		err = fb_set_cmap(cmap, kspc, clps7111fb_setcolreg, &cfb->fb);
++		dcmap = &cfb->fb.cmap;
++	}
++
++	if (!err)
++		fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
++
++	return err;
++}
++
++/*
++ *    Set the User Defined Part of the Display
++ */
++static int
++clps7111fb_set_var(struct fb_var_screeninfo *var, int con,
++		   struct fb_info *info)
++{
++	struct display *display;
++	unsigned int lcdcon, syscon, pixclock;
++	int chgvar = 0;
++
++	if (var->activate & FB_ACTIVATE_TEST)
++		return 0;
++
++	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
++		return -EINVAL;
++
++	if (cfb->fb.var.xres != var->xres)
++		chgvar = 1;
++	if (cfb->fb.var.yres != var->yres)
++		chgvar = 1;
++	if (cfb->fb.var.xres_virtual != var->xres_virtual)
++		chgvar = 1;
++	if (cfb->fb.var.yres_virtual != var->yres_virtual)
++		chgvar = 1;
++	if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
++		chgvar = 1;
++
++	if (con < 0) {
++		display = cfb->fb.disp;
++		chgvar = 0;
++	} else {
++		display = fb_display + con;
++	}
++
++	var->transp.msb_right	= 0;
++	var->transp.offset	= 0;
++	var->transp.length	= 0;
++	var->red.msb_right	= 0;
++	var->red.offset		= 0;
++	var->red.length		= var->bits_per_pixel;
++	var->green		= var->red;
++	var->blue		= var->red;
++
++	switch (var->bits_per_pixel) {
++#ifdef FBCON_HAS_MFB
++	case 1:
++		cfb->fb.fix.visual	= FB_VISUAL_MONO01;
++		display->dispsw		= &fbcon_mfb;
++		display->dispsw_data	= NULL;
++		break;
++#endif
++#ifdef FBCON_HAS_CFB2
++	case 2:
++		cfb->fb.fix.visual	= FB_VISUAL_PSEUDOCOLOR;
++		display->dispsw		= &fbcon_cfb2;
++		display->dispsw_data	= NULL;
++		break;
++#endif
++#ifdef FBCON_HAS_CFB4
++	case 4:
++		cfb->fb.fix.visual	= FB_VISUAL_PSEUDOCOLOR;
++		display->dispsw		= &fbcon_cfb4;
++		display->dispsw_data	= NULL;
++		break;
++#endif
++	default:
++		return -EINVAL;
++	}
++
++	display->next_line	= var->xres_virtual * var->bits_per_pixel / 8;
++
++	cfb->fb.fix.line_length = display->next_line;
++
++	display->screen_base	= cfb->fb.screen_base;
++	display->line_length	= cfb->fb.fix.line_length;
++	display->visual		= cfb->fb.fix.visual;
++	display->type		= cfb->fb.fix.type;
++	display->type_aux	= cfb->fb.fix.type_aux;
++	display->ypanstep	= cfb->fb.fix.ypanstep;
++	display->ywrapstep	= cfb->fb.fix.ywrapstep;
++	display->can_soft_blank = 1;
++	display->inverse	= 0;
++
++	cfb->fb.var		= *var;
++	cfb->fb.var.activate	&= ~FB_ACTIVATE_ALL;
++
++	/*
++	 * Update the old var.  The fbcon drivers still use this.
++	 * Once they are using cfb->fb.var, this can be dropped.
++	 *                                      --rmk
++	 */
++	display->var		= cfb->fb.var;
++
++	/*
++	 * If we are setting all the virtual consoles, also set the
++	 * defaults used to create new consoles.
++	 */
++	if (var->activate & FB_ACTIVATE_ALL)
++		cfb->fb.disp->var = cfb->fb.var;
++
++	if (chgvar && info && cfb->fb.changevar)
++		cfb->fb.changevar(con);
++
++	lcdcon = (var->xres_virtual * var->yres_virtual * var->bits_per_pixel) / 128 - 1;
++	lcdcon |= ((var->xres_virtual / 16) - 1) << 13;
++	lcdcon |= lcd_ac_prescale << 25;
++
++	/*
++	 * Calculate pixel prescale value from the pixclock.  This is:
++	 *  36.864MHz / pixclock_mhz - 1.
++	 * However, pixclock is in picoseconds, so this ends up being:
++	 *  36864000 * pixclock_ps / 10^12 - 1
++	 * and this will overflow the 32-bit math.  We perform this as
++	 * (9 * 4096000 == 36864000):
++	 *  pixclock_ps * 9 * (4096000 / 10^12) - 1
++	 */
++	pixclock = 9 * info->var.pixclock / 244140 - 1;
++	lcdcon |= pixclock << 19;
++
++	if (info->var.bits_per_pixel == 4)
++		lcdcon |= LCDCON_GSMD;
++	if (info->var.bits_per_pixel >= 2)
++		lcdcon |= LCDCON_GSEN;
++
++	/*
++	 * LCDCON must only be changed while the LCD is disabled
++	 */
++	syscon = clps_readl(SYSCON1);
++	clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
++	clps_writel(lcdcon, LCDCON);
++	clps_writel(syscon | SYSCON1_LCDEN, SYSCON1);
++
++	fb_set_cmap(&cfb->fb.cmap, 1, clps7111fb_setcolreg, &cfb->fb);
++
++	return 0;
++}
++
++/*
++ * Get the currently displayed virtual consoles colormap.
++ */
++static int
++gen_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
++{
++	fb_copy_cmap(&info->cmap, cmap, kspc ? 0 : 2);
++	return 0;
++}
++
++/*
++ * Get the currently displayed virtual consoles fixed part of the display.
++ */
++static int
++gen_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
++{
++	*fix = info->fix;
++	return 0;
++}
++
++/*
++ * Get the current user defined part of the display.
++ */
++static int
++gen_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++	*var = info->var;
++	return 0;
++}
++
++static struct fb_ops clps7111fb_ops = {
++	owner:		THIS_MODULE,
++	fb_set_var:	clps7111fb_set_var,
++	fb_set_cmap:	clps7111fb_set_cmap,
++	fb_get_fix:	gen_get_fix,
++	fb_get_var:	gen_get_var,
++	fb_get_cmap:	gen_get_cmap,
++};
++
++static int clps7111fb_switch(int con, struct fb_info *info)
++{
++	struct clps7111fb_info *cfb = (struct clps7111fb_info *)info;
++	struct display *disp;
++	struct fb_cmap *cmap;
++
++	if (cfb->currcon >= 0) {
++		disp = fb_display + cfb->currcon;
++
++		/*
++		 * Save the old colormap and video mode.
++		 */
++		disp->var = cfb->fb.var;
++		if (disp->cmap.len)
++			fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
++	}
++
++	cfb->currcon = con;
++	disp = fb_display + con;
++
++	/*
++	 * Install the new colormap and change the video mode.  By default,
++	 * fbcon sets all the colormaps and video modes to the default
++	 * values at bootup.
++	 */
++	if (disp->cmap.len)
++		cmap = &disp->cmap;
++	else
++		cmap = fb_default_cmap(CMAP_MAX_SIZE);
++
++	fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
++
++	cfb->fb.var = disp->var;
++	cfb->fb.var.activate = FB_ACTIVATE_NOW;
++
++	clps7111fb_set_var(&cfb->fb.var, con, &cfb->fb);
++
++	return 0;
++}
++
++static int clps7111fb_updatevar(int con, struct fb_info *info)
++{
++	return -EINVAL;
++}
++
++static void clps7111fb_blank(int blank, struct fb_info *info)
++{
++    	if (blank) {
++		if (machine_is_edb7211()) {
++			/* Turn off the LCD backlight. */
++			clps_writeb(clps_readb(PDDR) & ~EDB_PD3_LCDBL, PDDR);
++
++			/* Power off the LCD DC-DC converter. */
++			clps_writeb(clps_readb(PDDR) & ~EDB_PD1_LCD_DC_DC_EN, PDDR);
++
++			/* Delay for a little while (half a second). */
++			udelay(100);
++
++			/* Power off the LCD panel. */
++			clps_writeb(clps_readb(PDDR) & ~EDB_PD2_LCDEN, PDDR);
++
++			/* Power off the LCD controller. */
++			clps_writel(clps_readl(SYSCON1) & ~SYSCON1_LCDEN, 
++					SYSCON1);
++		}
++	} else {
++		if (machine_is_edb7211()) {
++			/* Power up the LCD controller. */
++			clps_writel(clps_readl(SYSCON1) | SYSCON1_LCDEN,
++					SYSCON1);
++
++			/* Power up the LCD panel. */
++			clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);
++
++			/* Delay for a little while. */
++			udelay(100);
++
++			/* Power up the LCD DC-DC converter. */
++			clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN,
++						PDDR);
++
++			/* Turn on the LCD backlight. */
++			clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR);
++		}
++	}
++}
++
++static int 
++clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
++		int count, int *eof, void *data)
++{
++	/* We need at least two characters, one for the digit, and one for
++	 * the terminating NULL. */
++	if (count < 2) 
++		return -EINVAL;
++
++	if (machine_is_edb7211()) {
++		return sprintf(page, "%d\n", 
++				(clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0);
++	}
++
++	return 0;
++}
++
++static int 
++clps7111fb_proc_backlight_write(struct file *file, const char *buffer, 
++		unsigned long count, void *data)
++{
++	unsigned char char_value;
++	int value;
++
++	if (count < 1) {
++		return -EINVAL;
++	}
++
++	if (copy_from_user(&char_value, buffer, 1)) 
++		return -EFAULT;
++
++	value = char_value - '0';
++
++	if (machine_is_edb7211()) {
++		unsigned char port_d;
++
++		port_d = clps_readb(PDDR);
++
++		if (value) {
++			port_d |= EDB_PD3_LCDBL;
++		} else {
++			port_d &= ~EDB_PD3_LCDBL;
++		}
++
++		clps_writeb(port_d, PDDR);
++	}
++
++	return count;
++}
++
++static void __init clps711x_guess_lcd_params(struct fb_info *info)
++{
++	unsigned int lcdcon, syscon, size;
++	unsigned long phys_base = PHYS_OFFSET;
++	void *virt_base = (void *)PAGE_OFFSET;
++
++	info->var.xres_virtual	 = 640;
++	info->var.yres_virtual	 = 240;
++	info->var.bits_per_pixel = 4;
++	info->var.activate	 = FB_ACTIVATE_NOW;
++	info->var.height	 = -1;
++	info->var.width		 = -1;
++	info->var.pixclock	 = 93006; /* 10.752MHz pixel clock */
++
++	/*
++	 * If the LCD controller is already running, decode the values
++	 * in LCDCON to xres/yres/bpp/pixclock/acprescale
++	 */
++	syscon = clps_readl(SYSCON1);
++	if (syscon & SYSCON1_LCDEN) {
++		lcdcon = clps_readl(LCDCON);
++
++		/*
++		 * Decode GSMD and GSEN bits to bits per pixel
++		 * (in cs89712 docs, GSEN is GSMD1, GSMD is GSMD2)
++		 */
++		switch (lcdcon & (LCDCON_GSMD | LCDCON_GSEN)) {
++		case LCDCON_GSMD | LCDCON_GSEN:
++			info->var.bits_per_pixel = 4;
++			break;
++
++		case LCDCON_GSEN:
++			info->var.bits_per_pixel = 2;
++			break;
++
++		default:
++			info->var.bits_per_pixel = 1;
++			break;
++		}
++
++		/*
++		 * Decode xres/yres
++		 */
++		info->var.xres_virtual = (((lcdcon >> 13) & 0x3f) + 1) * 16;
++		info->var.yres_virtual = (((lcdcon & 0x1fff) + 1) * 128) /
++					  (info->var.xres_virtual *
++					   info->var.bits_per_pixel);
++
++		/*
++		 * Calculate pixclock
++		 */
++		info->var.pixclock = (((lcdcon >> 19) & 0x3f) + 1) * 244140 / 9;
++
++		/*
++		 * Grab AC prescale
++		 */
++		lcd_ac_prescale = (lcdcon >> 25) & 0x1f;
++	}
++
++	info->var.xres = info->var.xres_virtual;
++	info->var.yres = info->var.yres_virtual;
++	info->var.grayscale = info->var.bits_per_pixel > 1;
++
++	size = info->var.xres * info->var.yres * info->var.bits_per_pixel / 8;
++
++	/*
++	 * Might be worth checking to see if we can use the on-board
++	 * RAM if size here...
++	 * CLPS7110 - no on-board SRAM
++	 * EP7212   - 38400 bytes
++	 */
++	if (size <= 38400) {
++		printk(KERN_INFO "CLPS711xFB: could use on-board SRAM?\n");
++	}
++
++	if ((syscon & SYSCON1_LCDEN) == 0) {
++		/*
++		 * The display isn't running.  Ensure that
++		 * the display memory is empty.
++		 */
++		memset(virt_base, 0, size);
++	}
++
++	info->screen_base    = virt_base;
++	info->fix.smem_start = phys_base;
++	info->fix.smem_len   = PAGE_ALIGN(size);
++	info->fix.type       = FB_TYPE_PACKED_PIXELS;
++}
++
++/* this function initializes the LCD registers as required by the Guide A07
++*/
++int __init clps711xfb_guidea07_init(void)
++{
++	unsigned long videomem, videosize;
++	unsigned int lcdcon, syscon;
++
++	//LCDCON must only be changed while the LCD is disabled
++	syscon = clps_readl(SYSCON1);
++	clps_writel(syscon & ~SYSCON1_LCDEN, SYSCON1);
++
++	printk(KERN_INFO "CLPS711xFB: setting up cs89712 SRAM as QVGA video framebuffer\n");
++	clps_writel(0x6, FBADDR); //internal SRAM location
++	videomem = (unsigned long)ioremap(SRAM_START, SRAM_SIZE);
++	if (!videomem) {
++		printk("ioremap failed!\n");
++		kfree(cfb);
++		return -EIO;
++	}
++
++	videosize = (320*240 * 4 / 8);  //ie. 38400 or 0x9600
++	memset((void *)videomem, 0, videosize); //clear the vid memory
++
++	cfb->fb.screen_base     = (void *)videomem;
++	cfb->fb.fix.smem_start  = SRAM_START; //must be physical address
++	cfb->fb.fix.smem_len    = videosize;
++
++	cfb->fb.var.grayscale   = 1;
++        cfb->fb.var.bits_per_pixel = 4;
++	cfb->fb.var.xres_virtual = 320;
++	cfb->fb.var.activate	 = FB_ACTIVATE_NOW;
++
++	// change to 4bpp mode
++	lcdcon = clps_readl(LCDCON);
++	lcdcon |= LCDCON_GSMD | LCDCON_GSEN; //4bpp
++        //lcdcon |= 5 << 19;	//pixel prescale value (pixclock)
++	//lcdcon |= 13 << 25;	//AC prescale value
++	clps_writel(lcdcon, LCDCON);
++
++	//reenable LCD
++	clps_writel(syscon | SYSCON1_LCDEN, SYSCON1);
++
++	return 0;
++}
++
++int __init clps711xfb_init(void)
++{
++	int err = -ENOMEM;
++
++	cfb = kmalloc(sizeof(*cfb) + sizeof(struct display), GFP_KERNEL);
++	if (!cfb)
++		goto out;
++
++	memset(cfb, 0, sizeof(*cfb) + sizeof(struct display));
++	strcpy(cfb->fb.fix.id, "clps7111");
++
++	cfb->currcon		= -1;
++	cfb->fb.screen_base	= (void *)PAGE_OFFSET;
++	cfb->fb.fix.smem_start	= PAGE_OFFSET;
++	cfb->fb.fix.smem_len	= 0x14000;
++	cfb->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
++
++	cfb->fb.fbops		= &clps7111fb_ops;
++	cfb->fb.changevar	= NULL;
++	cfb->fb.switch_con	= clps7111fb_switch;
++	cfb->fb.updatevar	= clps7111fb_updatevar;
++	cfb->fb.blank		= clps7111fb_blank;
++	cfb->fb.flags		= FBINFO_FLAG_DEFAULT;
++	cfb->fb.disp		= (struct display *)(cfb + 1);
++
++	clps711x_guess_lcd_params(&cfb->fb);
++
++	if (machine_is_guidea07()) {
++		clps711xfb_guidea07_init();
++	}
++
++	if (machine_is_fortunet()) {
++		cfb->fb.fix.smem_len = 0x20000;
++	}
++
++	fb_alloc_cmap(&cfb->fb.cmap, CMAP_MAX_SIZE, 0);
++
++	/* Register the /proc entries. */
++	clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
++		&proc_root);
++	if (clps7111fb_backlight_proc_entry == NULL) {
++		printk("Couldn't create the /proc entry for the backlight.\n");
++		return -EINVAL;
++	}
++
++	clps7111fb_backlight_proc_entry->read_proc = 
++		&clps7111fb_proc_backlight_read;
++	clps7111fb_backlight_proc_entry->write_proc = 
++		&clps7111fb_proc_backlight_write;
++
++	/*
++	 * Power up the LCD
++	 */
++	if (machine_is_p720t()) {
++		PLD_LCDEN = PLD_LCDEN_EN;
++		PLD_PWR |= (PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON);
++	}
++
++	if (machine_is_edb7211()) {
++		/* Power up the LCD panel. */
++		clps_writeb(clps_readb(PDDR) | EDB_PD2_LCDEN, PDDR);
++
++		/* Delay for a little while. */
++		udelay(100);
++
++		/* Power up the LCD DC-DC converter. */
++		clps_writeb(clps_readb(PDDR) | EDB_PD1_LCD_DC_DC_EN, PDDR);
++
++		/* Turn on the LCD backlight. */
++		clps_writeb(clps_readb(PDDR) | EDB_PD3_LCDBL, PDDR);
++	}
++
++	clps7111fb_set_var(&cfb->fb.var, -1, &cfb->fb);
++	err = register_framebuffer(&cfb->fb);
++
++out:	return err;
++}
++
++static void __exit clps711xfb_exit(void)
++{
++	unregister_framebuffer(&cfb->fb);
++	kfree(cfb);
++
++	/*
++	 * Power down the LCD
++	 */
++	if (machine_is_p720t()) {
++		PLD_LCDEN = 0;
++		PLD_PWR &= ~(PLD_S4_ON|PLD_S3_ON|PLD_S2_ON|PLD_S1_ON);
++	}
++}
++
++#ifdef MODULE
++module_init(clps711xfb_init);
++#endif
++module_exit(clps711xfb_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("CLPS711x framebuffer driver");
++MODULE_LICENSE("GPL");
+--- linux-2.4.25/drivers/video/cyber2000fb.c~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/drivers/video/cyber2000fb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1,7 +1,7 @@
+ /*
+  *  linux/drivers/video/cyber2000fb.c
+  *
+- *  Copyright (C) 1998-2000 Russell King
++ *  Copyright (C) 1998-2002 Russell King
+  *
+  *  MIPS and 50xx clock support
+  *  Copyright (C) 2001 Bradley D. LaRonde <brad@ltc.com>
+@@ -13,22 +13,28 @@
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  *
+- * Intergraphics CyberPro 2000, 2010 and 5000 frame buffer device
++ * Integraphics CyberPro 2000, 2010 and 5000 frame buffer device
+  *
+  * Based on cyberfb.c.
+  *
+- * Note that we now use the new fbcon fix, var and cmap scheme.  We do still
+- * have to check which console is the currently displayed one however, since
+- * especially for the colourmap stuff.  Once fbcon has been fully migrated,
+- * we can kill the last 5 references to cfb->currcon.
++ * Note that we now use the new fbcon fix, var and cmap scheme.  We do
++ * still have to check which console is the currently displayed one
++ * however, especially for the colourmap stuff.
+  *
+- * We also use the new hotplug PCI subsystem.  I'm not sure if there are any
+- * such cards, but I'm erring on the side of caution.  We don't want to go
+- * pop just because someone does have one.
++ * We also use the new hotplug PCI subsystem.  I'm not sure if there
++ * are any such cards, but I'm erring on the side of caution.  We don't
++ * want to go pop just because someone does have one.
+  *
+- * Note that this doesn't work fully in the case of multiple CyberPro cards
+- * with grabbers.  We currently can only attach to the first CyberPro card
+- * found.
++ * Note that this doesn't work fully in the case of multiple CyberPro
++ * cards with grabbers.  We currently can only attach to the first
++ * CyberPro card found.
++ *
++ * When we're in truecolour mode, we power down the LUT RAM as a power
++ * saving feature.  Also, when we enter any of the powersaving modes
++ * (except soft blanking) we power down the RAMDACs.  This saves about
++ * 1W, which is roughly 8% of the power consumption of a NetWinder
++ * (which, incidentally, is about the same saving as a 2.5in hard disk
++ * entering standby mode.)
+  */
+ #include <linux/config.h>
+ #include <linux/module.h>
+@@ -55,20 +61,16 @@
+ #include <video/fbcon-cfb24.h>
+ #include <video/fbcon-cfb32.h>
+ 
+-/*
+- * Define this if you don't want RGB565, but RGB555 for 16bpp displays.
+- */
+-/*#define CFB16_IS_CFB15*/
+-
+ #include "cyber2000fb.h"
+ 
+ struct cfb_info {
+ 	struct fb_info		fb;
+ 	struct display_switch	*dispsw;
++	struct display		*display;
+ 	struct pci_dev		*dev;
+ 	unsigned char 		*region;
+ 	unsigned char		*regs;
+-	signed int		currcon;
++	u_int			id;
+ 	int			func_use_count;
+ 	u_long			ref_ps;
+ 
+@@ -81,10 +83,16 @@
+ 		u8 red, green, blue;
+ 	} palette[NR_PALETTE];
+ 
++	u_char			mem_ctl0;
+ 	u_char			mem_ctl1;
+ 	u_char			mem_ctl2;
+ 	u_char			mclk_mult;
+ 	u_char			mclk_div;
++	/*
++	 * RAMDAC control register is both of these or'ed together
++	 */
++	u_char			ramdac_ctrl;
++	u_char			ramdac_powerdown;
+ };
+ 
+ static char default_font_storage[40];
+@@ -144,7 +152,7 @@
+ {
+ 	int count = 100000;
+ 
+-	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & 0x80) {
++	while (cyber2000fb_readb(CO_REG_CONTROL, cfb) & CO_CTRL_BUSY) {
+ 		if (!count--) {
+ 			debug_printf("accel_wait timed out\n");
+ 			cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+@@ -154,24 +162,23 @@
+ 	}
+ }
+ 
+-static void cyber2000_accel_setup(struct display *p)
++static void cyber2000_accel_setup(struct display *display)
+ {
+-	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
++	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+ 
+-	cfb->dispsw->setup(p);
++	cfb->dispsw->setup(display);
+ }
+ 
+ static void
+-cyber2000_accel_bmove(struct display *p, int sy, int sx, int dy, int dx,
++cyber2000_accel_bmove(struct display *display, int sy, int sx, int dy, int dx,
+ 		      int height, int width)
+ {
+-	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
+-	struct fb_var_screeninfo *var = &p->fb_info->var;
++	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
++	struct fb_var_screeninfo *var = &display->var;
+ 	u_long src, dst;
+-	u_int fh, fw;
+-	int cmd = CO_CMD_L_PATTERN_FGCOL;
++	u_int fh, fw, cmd = CO_CMD_L_PATTERN_FGCOL;
+ 
+-	fw    = fontwidth(p);
++	fw    = fontwidth(display);
+ 	sx    *= fw;
+ 	dx    *= fw;
+ 	width *= fw;
+@@ -183,7 +190,7 @@
+ 		cmd |= CO_CMD_L_INC_LEFT;
+ 	}
+ 
+-	fh     = fontheight(p);
++	fh     = fontheight(display);
+ 	sy     *= fh;
+ 	dy     *= fh;
+ 	height *= fh;
+@@ -199,227 +206,265 @@
+ 	dst    = dx + dy * var->xres_virtual;
+ 
+ 	cyber2000_accel_wait(cfb);
+-	cyber2000fb_writeb(0x00,  CO_REG_CONTROL, cfb);
+-	cyber2000fb_writeb(0x03,  CO_REG_FORE_MIX, cfb);
+-	cyber2000fb_writew(width, CO_REG_WIDTH, cfb);
++	cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
++	cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb);
++	cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb);
+ 
+-	if (var->bits_per_pixel != 24) {
+-		cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+-		cyber2000fb_writel(src, CO_REG_SRC_PTR, cfb);
+-	} else {
+-		cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
+-		cyber2000fb_writeb(dst,     CO_REG_X_PHASE, cfb);
+-		cyber2000fb_writel(src * 3, CO_REG_SRC_PTR, cfb);
++	if (var->bits_per_pixel == 24) {
++		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
++		dst *= 3;
++		src *= 3;
+ 	}
+ 
+-	cyber2000fb_writew(height, CO_REG_HEIGHT, cfb);
+-	cyber2000fb_writew(cmd,    CO_REG_CMD_L, cfb);
+-	cyber2000fb_writew(0x2800, CO_REG_CMD_H, cfb);
++	cyber2000fb_writel(src, CO_REG_SRC1_PTR, cfb);
++	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
++	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
++	cyber2000fb_writew(cmd, CO_REG_CMD_L, cfb);
++	cyber2000fb_writew(CO_CMD_H_FGSRCMAP|CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
+ }
+ 
+ static void
+-cyber2000_accel_clear(struct vc_data *conp, struct display *p, int sy, int sx,
+-		      int height, int width)
++cyber2000_accel_clear(struct vc_data *conp, struct display *display, int sy,
++		      int sx, int height, int width)
+ {
+-	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
+-	struct fb_var_screeninfo *var = &p->fb_info->var;
++	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
++	struct fb_var_screeninfo *var = &display->var;
+ 	u_long dst;
+ 	u_int fw, fh;
+-	u32 bgx = attr_bgcol_ec(p, conp);
++	u32 bgx = attr_bgcol_ec(display, conp);
+ 
+-	fw = fontwidth(p);
+-	fh = fontheight(p);
++	fw = fontwidth(display);
++	fh = fontheight(display);
+ 
+ 	dst    = sx * fw + sy * var->xres_virtual * fh;
+ 	width  = width * fw - 1;
+ 	height = height * fh - 1;
+ 
+ 	cyber2000_accel_wait(cfb);
+-	cyber2000fb_writeb(0x00,   CO_REG_CONTROL,  cfb);
+-	cyber2000fb_writeb(0x03,   CO_REG_FORE_MIX, cfb);
+-	cyber2000fb_writew(width,  CO_REG_WIDTH,    cfb);
+-	cyber2000fb_writew(height, CO_REG_HEIGHT,   cfb);
+-
+-	switch (var->bits_per_pixel) {
+-	case 15:
+-	case 16:
+-		bgx = ((u16 *)p->dispsw_data)[bgx];
+-	case 8:
+-		cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+-		break;
++	cyber2000fb_writeb(0x00, CO_REG_CONTROL, cfb);
++	cyber2000fb_writew(width, CO_REG_PIXWIDTH, cfb);
++	cyber2000fb_writew(height, CO_REG_PIXHEIGHT, cfb);
+ 
+-	case 24:
+-		cyber2000fb_writel(dst * 3, CO_REG_DEST_PTR, cfb);
++	if (var->bits_per_pixel == 24) {
+ 		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
+-		bgx = ((u32 *)p->dispsw_data)[bgx];
+-		break;
+-
+-	case 32:
+-		bgx = ((u32 *)p->dispsw_data)[bgx];
+-		cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
+-		break;
++		dst *= 3;
+ 	}
+ 
+-	cyber2000fb_writel(bgx, CO_REG_FOREGROUND, cfb);
++	if (var->bits_per_pixel == 16)
++		bgx = ((u16 *)display->dispsw_data)[bgx];
++	else if (var->bits_per_pixel >= 24)
++		bgx = ((u32 *)display->dispsw_data)[bgx];
++
++	cyber2000fb_writel(bgx, CO_REG_FGCOLOUR, cfb);
++	cyber2000fb_writel(dst, CO_REG_DEST_PTR, cfb);
++	cyber2000fb_writeb(CO_FG_MIX_SRC, CO_REG_FGMIX, cfb);
+ 	cyber2000fb_writew(CO_CMD_L_PATTERN_FGCOL, CO_REG_CMD_L, cfb);
+-	cyber2000fb_writew(0x0800, CO_REG_CMD_H, cfb);
++	cyber2000fb_writew(CO_CMD_H_BLITTER, CO_REG_CMD_H, cfb);
+ }
+ 
+ static void
+-cyber2000_accel_putc(struct vc_data *conp, struct display *p, int c,
++cyber2000_accel_putc(struct vc_data *conp, struct display *display, int c,
+ 		     int yy, int xx)
+ {
+-	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
++	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+ 
+ 	cyber2000_accel_wait(cfb);
+-	cfb->dispsw->putc(conp, p, c, yy, xx);
++	cfb->dispsw->putc(conp, display, c, yy, xx);
+ }
+ 
+ static void
+-cyber2000_accel_putcs(struct vc_data *conp, struct display *p,
++cyber2000_accel_putcs(struct vc_data *conp, struct display *display,
+ 		      const unsigned short *s, int count, int yy, int xx)
+ {
+-	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
++	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+ 
+ 	cyber2000_accel_wait(cfb);
+-	cfb->dispsw->putcs(conp, p, s, count, yy, xx);
++	cfb->dispsw->putcs(conp, display, s, count, yy, xx);
+ }
+ 
+-static void cyber2000_accel_revc(struct display *p, int xx, int yy)
++static void cyber2000_accel_revc(struct display *display, int xx, int yy)
+ {
+-	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
++	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+ 
+ 	cyber2000_accel_wait(cfb);
+-	cfb->dispsw->revc(p, xx, yy);
++	cfb->dispsw->revc(display, xx, yy);
+ }
+ 
+ static void
+-cyber2000_accel_clear_margins(struct vc_data *conp, struct display *p,
++cyber2000_accel_clear_margins(struct vc_data *conp, struct display *display,
+ 			      int bottom_only)
+ {
+-	struct cfb_info *cfb = (struct cfb_info *)p->fb_info;
++	struct cfb_info *cfb = (struct cfb_info *)display->fb_info;
+ 
+-	cfb->dispsw->clear_margins(conp, p, bottom_only);
++	cfb->dispsw->clear_margins(conp, display, bottom_only);
+ }
+ 
+ static struct display_switch fbcon_cyber_accel = {
+-	setup:		cyber2000_accel_setup,
+-	bmove:		cyber2000_accel_bmove,
+-	clear:		cyber2000_accel_clear,
+-	putc:		cyber2000_accel_putc,
+-	putcs:		cyber2000_accel_putcs,
+-	revc:		cyber2000_accel_revc,
+-	clear_margins:	cyber2000_accel_clear_margins,
+-	fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(16)
++	.setup		= cyber2000_accel_setup,
++	.bmove		= cyber2000_accel_bmove,
++	.clear		= cyber2000_accel_clear,
++	.putc		= cyber2000_accel_putc,
++	.putcs		= cyber2000_accel_putcs,
++	.revc		= cyber2000_accel_revc,
++	.clear_margins	= cyber2000_accel_clear_margins,
++	.fontwidthmask	= FONTWIDTH(8)|FONTWIDTH(16)
+ };
+ 
++static inline u32 convert_bitfield(u_int val, struct fb_bitfield *bf)
++{
++	u_int mask = (1 << bf->length) - 1;
++
++	return (val >> (16 - bf->length) & mask) << bf->offset;
++}
++
+ /*
+  *    Set a single color register. Return != 0 for invalid regno.
+  */
+ static int
+-cyber2000_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+-		    u_int transp, struct fb_info *info)
++cyber2000fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++		      u_int transp, struct fb_info *info)
+ {
+ 	struct cfb_info *cfb = (struct cfb_info *)info;
++	struct fb_var_screeninfo *var = &cfb->display->var;
++	u32 pseudo_val;
++	int ret = 1;
+ 
+-	u_int alpha = transp ^ 0xFFFF;
+-
+-	if (regno >= NR_PALETTE)
++	switch (cfb->fb.fix.visual) {
++	default:
+ 		return 1;
+ 
+-	red   >>= 8;
+-	green >>= 8;
+-	blue  >>= 8;
+-	alpha >>= 8;
++#ifdef FBCON_HAS_CFB8
++	/*
++	 * Pseudocolour:
++	 *         8     8
++	 * pixel --/--+--/-->  red lut  --> red dac
++	 *            |  8
++	 *            +--/--> green lut --> green dac
++	 *            |  8
++	 *            +--/-->  blue lut --> blue dac
++	 */
++	case FB_VISUAL_PSEUDOCOLOR:
++		if (regno >= NR_PALETTE)
++			return 1;
+ 
+-	cfb->palette[regno].red   = red;
+-	cfb->palette[regno].green = green;
+-	cfb->palette[regno].blue  = blue;
++		red >>= 8;
++		green >>= 8;
++		blue >>= 8;
++
++		cfb->palette[regno].red   = red;
++		cfb->palette[regno].green = green;
++		cfb->palette[regno].blue  = blue;
+ 
+-	switch (cfb->fb.var.bits_per_pixel) {
+-#ifdef FBCON_HAS_CFB8
+-	case 8:
+ 		cyber2000fb_writeb(regno, 0x3c8, cfb);
+-		cyber2000fb_writeb(red,   0x3c9, cfb);
++		cyber2000fb_writeb(red, 0x3c9, cfb);
+ 		cyber2000fb_writeb(green, 0x3c9, cfb);
+-		cyber2000fb_writeb(blue,  0x3c9, cfb);
+-		break;
++		cyber2000fb_writeb(blue, 0x3c9, cfb);
++		return 0;
+ #endif
+ 
+-#ifdef FBCON_HAS_CFB16
+-	case 16:
+-#ifndef CFB16_IS_CFB15
+-		if (regno < 64) {
+-			/* write green */
++	/*
++	 * Direct colour:
++	 *          n     rl
++	 *  pixel --/--+--/-->  red lut  --> red dac
++	 *             |  gl
++	 *             +--/--> green lut --> green dac
++	 *             |  bl
++	 *             +--/-->  blue lut --> blue dac
++	 * n = bpp, rl = red length, gl = green length, bl = blue length
++	 */
++	case FB_VISUAL_DIRECTCOLOR:
++		red >>= 8;
++		green >>= 8;
++		blue >>= 8;
++
++		if (var->green.length == 6 && regno < 64) {
++			cfb->palette[regno << 2].green = green;
++
++			/*
++			 * The 6 bits of the green component are applied
++			 * to the high 6 bits of the LUT.
++			 */
+ 			cyber2000fb_writeb(regno << 2, 0x3c8, cfb);
+ 			cyber2000fb_writeb(cfb->palette[regno >> 1].red, 0x3c9, cfb);
+ 			cyber2000fb_writeb(green, 0x3c9, cfb);
+ 			cyber2000fb_writeb(cfb->palette[regno >> 1].blue, 0x3c9, cfb);
++
++			green = cfb->palette[regno << 3].green;
++
++			ret = 0;
+ 		}
+ 
+-		if (regno < 32) {
+-			/* write red,blue */
++		if (var->green.length >= 5 && regno < 32) {
++			cfb->palette[regno << 3].red   = red;
++			cfb->palette[regno << 3].green = green;
++			cfb->palette[regno << 3].blue  = blue;
++
++			/*
++			 * The 5 bits of each colour component are
++			 * applied to the high 5 bits of the LUT.
++			 */
+ 			cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
+ 			cyber2000fb_writeb(red, 0x3c9, cfb);
+-			cyber2000fb_writeb(cfb->palette[regno << 1].green, 0x3c9, cfb);
++			cyber2000fb_writeb(green, 0x3c9, cfb);
+ 			cyber2000fb_writeb(blue, 0x3c9, cfb);
++			ret = 0;
+ 		}
+ 
+-		if (regno < 16)
+-			((u16 *)cfb->fb.pseudo_palette)[regno] =
+-				((red   << 8) & 0xf800) |
+-				((green << 3) & 0x07e0) |
+-				((blue  >> 3));
+-		break;
+-#endif
++		if (var->green.length == 4 && regno < 16) {
++			cfb->palette[regno << 4].red   = red;
++			cfb->palette[regno << 4].green = green;
++			cfb->palette[regno << 4].blue  = blue;
+ 
+-	case 15:
+-		if (regno < 32) {
+-			cyber2000fb_writeb(regno << 3, 0x3c8, cfb);
++			/*
++			 * The 5 bits of each colour component are
++			 * applied to the high 5 bits of the LUT.
++			 */
++			cyber2000fb_writeb(regno << 4, 0x3c8, cfb);
+ 			cyber2000fb_writeb(red, 0x3c9, cfb);
+ 			cyber2000fb_writeb(green, 0x3c9, cfb);
+ 			cyber2000fb_writeb(blue, 0x3c9, cfb);
++			ret = 0;
+ 		}
+-		if (regno < 16)
+-			((u16 *)cfb->fb.pseudo_palette)[regno] =
+-				((red   << 7) & 0x7c00) |
+-				((green << 2) & 0x03e0) |
+-				((blue  >> 3));
+-		break;
+-
+-#endif
+-
+-#ifdef FBCON_HAS_CFB24
+-	case 24:
+-		cyber2000fb_writeb(regno, 0x3c8, cfb);
+-		cyber2000fb_writeb(red,   0x3c9, cfb);
+-		cyber2000fb_writeb(green, 0x3c9, cfb);
+-		cyber2000fb_writeb(blue,  0x3c9, cfb);
+ 
+-		if (regno < 16)
+-			((u32 *)cfb->fb.pseudo_palette)[regno] =
+-				(red << 16) | (green << 8) | blue;
++		/*
++		 * Since this is only used for the first 16 colours, we
++		 * don't have to care about overflowing for regno >= 32
++		 */
++		pseudo_val = regno << var->red.offset |
++			     regno << var->green.offset |
++			     regno << var->blue.offset;
+ 		break;
+-#endif
+ 
+-#ifdef FBCON_HAS_CFB32
+-	case 32:
+-		cyber2000fb_writeb(regno, 0x3c8, cfb);
+-		cyber2000fb_writeb(red,   0x3c9, cfb);
+-		cyber2000fb_writeb(green, 0x3c9, cfb);
+-		cyber2000fb_writeb(blue,  0x3c9, cfb);
+-
+-		if (regno < 16)
+-			((u32 *)cfb->fb.pseudo_palette)[regno] =
+-				(alpha << 24) | (red << 16) | (green << 8) | blue;
++	/*
++	 * True colour:
++	 *          n     rl
++	 *  pixel --/--+--/--> red dac
++	 *             |  gl
++	 *             +--/--> green dac
++	 *             |  bl
++	 *             +--/--> blue dac
++	 * n = bpp, rl = red length, gl = green length, bl = blue length
++	 */
++	case FB_VISUAL_TRUECOLOR:
++		pseudo_val = convert_bitfield(transp ^ 0xffff, &var->transp);
++		pseudo_val |= convert_bitfield(red, &var->red);
++		pseudo_val |= convert_bitfield(green, &var->green);
++		pseudo_val |= convert_bitfield(blue, &var->blue);
+ 		break;
+-#endif
++	}
+ 
+-	default:
+-		return 1;
++	/*
++	 * Now set our pseudo palette for the CFB16/24/32 drivers.
++	 */
++	if (regno < 16) {
++		if (var->bits_per_pixel == 16)
++			((u16 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
++		else
++			((u32 *)cfb->fb.pseudo_palette)[regno] = pseudo_val;
++		ret = 0;
+ 	}
+ 
+-	return 0;
++	return ret;
+ }
+ 
+ struct par_info {
+@@ -428,8 +473,8 @@
+ 	 */
+ 	u_char	clock_mult;
+ 	u_char	clock_div;
+-	u_char	visualid;
+-	u_char	pixformat;
++	u_char	extseqmisc;
++	u_char	co_pixfmt;
+ 	u_char	crtc_ofl;
+ 	u_char	crtc[19];
+ 	u_int	width;
+@@ -439,8 +484,7 @@
+ 	/*
+ 	 * Other
+ 	 */
+-	u_char	palette_ctrl;
+-	u_int	vmode;
++	u_char	ramdac;
+ };
+ 
+ static const u_char crtc_idx[] = {
+@@ -449,6 +493,18 @@
+ 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
+ };
+ 
++static void cyber2000fb_write_ramdac_ctrl(struct cfb_info *cfb)
++{
++	unsigned int i;
++	unsigned int val = cfb->ramdac_ctrl | cfb->ramdac_powerdown;
++
++	cyber2000fb_writeb(0x56, 0x3ce, cfb);
++	i = cyber2000fb_readb(0x3cf, cfb);
++	cyber2000fb_writeb(i | 4, 0x3cf, cfb);
++	cyber2000fb_writeb(val, 0x3c6, cfb);
++	cyber2000fb_writeb(i, 0x3cf, cfb);
++}
++
+ static void cyber2000fb_set_timing(struct cfb_info *cfb, struct par_info *hw)
+ {
+ 	u_int i;
+@@ -480,7 +536,7 @@
+ 	for (i = 0x0a; i < 0x10; i++)
+ 		cyber2000_crtcw(i, 0, cfb);
+ 
+-	cyber2000_grphw(0x11, hw->crtc_ofl, cfb);
++	cyber2000_grphw(EXT_CRT_VRTOFL, hw->crtc_ofl, cfb);
+ 	cyber2000_grphw(0x00, 0x00, cfb);
+ 	cyber2000_grphw(0x01, 0x00, cfb);
+ 	cyber2000_grphw(0x02, 0x00, cfb);
+@@ -501,30 +557,17 @@
+ 	cyber2000_attrw(0x13, 0x00, cfb);
+ 	cyber2000_attrw(0x14, 0x00, cfb);
+ 
+-	/* woody: set the interlaced bit... */
+-	/* FIXME: what about doublescan? */
+-	cyber2000fb_writeb(0x11, 0x3ce, cfb);
+-	i = cyber2000fb_readb(0x3cf, cfb);
+-	if (hw->vmode == FB_VMODE_INTERLACED)
+-		i |= 0x20;
+-	else
+-		i &= ~0x20;
+-	cyber2000fb_writeb(i, 0x3cf, cfb);
+-
+ 	/* PLL registers */
+-	cyber2000_grphw(DCLK_MULT, hw->clock_mult, cfb);
+-	cyber2000_grphw(DCLK_DIV,  hw->clock_div, cfb);
+-	cyber2000_grphw(MCLK_MULT, cfb->mclk_mult, cfb);
+-	cyber2000_grphw(MCLK_DIV,  cfb->mclk_div, cfb);
++	cyber2000_grphw(EXT_DCLK_MULT, hw->clock_mult, cfb);
++	cyber2000_grphw(EXT_DCLK_DIV,  hw->clock_div, cfb);
++	cyber2000_grphw(EXT_MCLK_MULT, cfb->mclk_mult, cfb);
++	cyber2000_grphw(EXT_MCLK_DIV,  cfb->mclk_div, cfb);
+ 	cyber2000_grphw(0x90, 0x01, cfb);
+ 	cyber2000_grphw(0xb9, 0x80, cfb);
+ 	cyber2000_grphw(0xb9, 0x00, cfb);
+ 
+-	cyber2000fb_writeb(0x56, 0x3ce, cfb);
+-	i = cyber2000fb_readb(0x3cf, cfb);
+-	cyber2000fb_writeb(i | 4, 0x3cf, cfb);
+-	cyber2000fb_writeb(hw->palette_ctrl, 0x3c6, cfb);
+-	cyber2000fb_writeb(i,    0x3cf, cfb);
++	cfb->ramdac_ctrl = hw->ramdac;
++	cyber2000fb_write_ramdac_ctrl(cfb);
+ 
+ 	cyber2000fb_writeb(0x20, 0x3c0, cfb);
+ 	cyber2000fb_writeb(0xff, 0x3c6, cfb);
+@@ -532,31 +575,32 @@
+ 	cyber2000_grphw(0x14, hw->fetch, cfb);
+ 	cyber2000_grphw(0x15, ((hw->fetch >> 8) & 0x03) |
+ 			      ((hw->pitch >> 4) & 0x30), cfb);
+-	cyber2000_grphw(0x77, hw->visualid, cfb);
++	cyber2000_grphw(EXT_SEQ_MISC, hw->extseqmisc, cfb);
+ 
+-	/* make sure we stay in linear mode */
+-	cyber2000_grphw(0x33, 0x0d, cfb);
++//	cyber2000_grphw(EXT_BIU_MISC, EXT_BIU_MISC_LIN_ENABLE |
++//				      EXT_BIU_MISC_COP_ENABLE |
++//				      EXT_BIU_MISC_COP_BFC, cfb);
+ 
+ 	/*
+ 	 * Set up accelerator registers
+ 	 */
+ 	cyber2000fb_writew(hw->width,     CO_REG_SRC_WIDTH,  cfb);
+ 	cyber2000fb_writew(hw->width,     CO_REG_DEST_WIDTH, cfb);
+-	cyber2000fb_writeb(hw->pixformat, CO_REG_PIX_FORMAT, cfb);
++	cyber2000fb_writeb(hw->co_pixfmt, CO_REG_PIXFMT, cfb);
+ }
+ 
+ static inline int
+ cyber2000fb_update_start(struct cfb_info *cfb, struct fb_var_screeninfo *var)
+ {
+-	u_int base;
+-
+-	base = var->yoffset * var->xres_virtual + var->xoffset;
++	u_int base = var->yoffset * var->xres_virtual + var->xoffset;
+ 
+-	/* have to be careful, because bits_per_pixel might be 15
+-	   in this version of the driver -- dok@directfb.org 2002/06/13 */
+-	base *= (var->bits_per_pixel + 7) >> 3;
++	base *= var->bits_per_pixel;
+ 
+-	base >>= 2;
++	/*
++	 * Convert to bytes and shift two extra bits because DAC
++	 * can only start on 4 byte aligned data.
++	 */
++	base >>= 5;
+ 
+ 	if (base >= 1 << 20)
+ 		return -EINVAL;
+@@ -576,27 +620,20 @@
+ 		     struct fb_info *info)
+ {
+ 	struct cfb_info *cfb = (struct cfb_info *)info;
+-	struct fb_cmap *dcmap = &fb_display[con].cmap;
++	struct display *display = fb_display + con;
++	struct fb_cmap *dcmap = &display->cmap;
+ 	int err = 0;
+ 
+ 	/* no colormap allocated? */
+-	if (!dcmap->len) {
+-		int size;
+-
+-		if (cfb->fb.var.bits_per_pixel == 16)
+-			size = 32;
+-		else
+-			size = 256;
+-
+-		err = fb_alloc_cmap(dcmap, size, 0);
+-	}
++	if (!dcmap->len)
++		err = fb_alloc_cmap(dcmap, 256, 0);
+ 
+ 	/*
+ 	 * we should be able to remove this test once fbcon has been
+ 	 * "improved" --rmk
+ 	 */
+-	if (!err && con == cfb->currcon) {
+-		err = fb_set_cmap(cmap, kspc, cyber2000_setcolreg, &cfb->fb);
++	if (!err && display == cfb->display) {
++		err = fb_set_cmap(cmap, kspc, cyber2000fb_setcolreg, &cfb->fb);
+ 		dcmap = &cfb->fb.cmap;
+ 	}
+ 
+@@ -672,8 +709,9 @@
+ 	hw->crtc[16] = Vblankend;
+ 	hw->crtc[18] = 0xff;
+ 
+-	/* overflow - graphics reg 0x11 */
+-	/* 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
++	/*
++	 * overflow - graphics reg 0x11
++	 * 0=VTOTAL:10 1=VDEND:10 2=VRSTART:10 3=VBSTART:10
+ 	 * 4=LINECOMP:10 5-IVIDEO 6=FIXCNT
+ 	 */
+ 	hw->crtc_ofl =
+@@ -681,7 +719,12 @@
+ 		BIT(Vdispend,   10, 0x01,  1) |
+ 		BIT(Vsyncstart, 10, 0x01,  2) |
+ 		BIT(Vblankstart,10, 0x01,  3) |
+-		1 << 4;
++		EXT_CRT_VRTOFL_LINECOMP10;
++
++	/* woody: set the interlaced bit... */
++	/* FIXME: what about doublescan? */
++	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
++		hw->crtc_ofl |= EXT_CRT_VRTOFL_INTERLACE;
+ 
+ 	return 0;
+ }
+@@ -787,7 +830,7 @@
+ 	vco = ref_ps * best_div1 / best_mult;
+ 	if ((ref_ps == 40690) && (vco < 5556))
+ 		/* Set VFSEL when VCO > 180MHz (5.556 ps). */
+-		hw->clock_div |= DCLK_DIV_VFSEL;
++		hw->clock_div |= EXT_DCLK_DIV_VFSEL;
+ 
+ 	return 0;
+ }
+@@ -801,58 +844,131 @@
+ cyber2000fb_decode_var(struct fb_var_screeninfo *var, struct cfb_info *cfb,
+ 		       struct par_info *hw)
+ {
++	unsigned int mem;
+ 	int err;
+ 
+ 	hw->width = var->xres_virtual;
+-	hw->palette_ctrl = 0x06;
+-	hw->vmode = var->vmode;
++	hw->ramdac = RAMDAC_VREFEN | RAMDAC_DAC8BIT;
++
++	var->transp.msb_right	= 0;
++	var->red.msb_right	= 0;
++	var->green.msb_right	= 0;
++	var->blue.msb_right	= 0;
+ 
+ 	switch (var->bits_per_pixel) {
+ #ifdef FBCON_HAS_CFB8
+ 	case 8:	/* PSEUDOCOLOUR, 256 */
+-		hw->pixformat		= PIXFORMAT_8BPP;
+-		hw->visualid		= VISUALID_256;
++		hw->co_pixfmt		= CO_PIXFMT_8BPP;
+ 		hw->pitch		= hw->width >> 3;
++		hw->extseqmisc		= EXT_SEQ_MISC_8;
++
++		var->transp.offset	= 0;
++		var->transp.length	= 0;
++		var->red.offset		= 0;
++		var->red.length		= 8;
++		var->green.offset	= 0;
++		var->green.length	= 8;
++		var->blue.offset	= 0;
++		var->blue.length	= 8;
+ 		break;
+ #endif
+ #ifdef FBCON_HAS_CFB16
+-	case 16:/* DIRECTCOLOUR, 64k */
+-#ifndef CFB16_IS_CFB15
+-		hw->pixformat		= PIXFORMAT_16BPP;
+-		hw->visualid		= VISUALID_64K;
+-		hw->pitch		= hw->width >> 2;
+-		hw->palette_ctrl	|= 0x10;
+-		break;
+-#endif
+-	case 15:/* DIRECTCOLOUR, 32k */
+-		hw->pixformat		= PIXFORMAT_16BPP;
+-		hw->visualid		= VISUALID_32K;
++	case 16:/* DIRECTCOLOUR, 64k or 32k */
++		hw->co_pixfmt		= CO_PIXFMT_16BPP;
+ 		hw->pitch		= hw->width >> 2;
+-		hw->palette_ctrl	|= 0x10;
+-		break;
+ 
++		switch (var->green.length) {
++		case 6: /* RGB565, 64k */
++			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB565;
++
++			var->transp.offset	= 0;
++			var->transp.length	= 0;
++			var->red.offset		= 11;
++			var->red.length		= 5;
++			var->green.offset	= 5;
++			var->green.length	= 6;
++			var->blue.offset	= 0;
++			var->blue.length	= 5;
++			break;
++
++		default:
++		case 5: /* RGB555, 32k */
++			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB555;
++
++			var->transp.offset	= 0;
++			var->transp.length	= 0;
++			var->red.offset		= 10;
++			var->red.length		= 5;
++			var->green.offset	= 5;
++			var->green.length	= 5;
++			var->blue.offset	= 0;
++			var->blue.length	= 5;
++			break;
++
++		case 4: /* RGB444, 4k + transparency? */
++			hw->extseqmisc		= EXT_SEQ_MISC_16_RGB444;
++
++			var->transp.offset	= 12;
++			var->transp.length	= 4;
++			var->red.offset		= 8;
++			var->red.length		= 4;
++			var->green.offset	= 4;
++			var->green.length	= 4;
++			var->blue.offset	= 0;
++			var->blue.length	= 4;
++			break;
++		}
++		break;
+ #endif
+ #ifdef FBCON_HAS_CFB24
+ 	case 24:/* TRUECOLOUR, 16m */
+-		hw->pixformat		= PIXFORMAT_24BPP;
+-		hw->visualid		= VISUALID_16M;
++		hw->co_pixfmt		= CO_PIXFMT_24BPP;
+ 		hw->width		*= 3;
+ 		hw->pitch		= hw->width >> 3;
+-		hw->palette_ctrl	|= 0x10;
++		hw->ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
++		hw->extseqmisc		= EXT_SEQ_MISC_24_RGB888;
++
++		var->transp.offset	= 0;
++		var->transp.length	= 0;
++		var->red.offset		= 16;
++		var->red.length		= 8;
++		var->green.offset	= 8;
++		var->green.length	= 8;
++		var->blue.offset	= 0;
++		var->blue.length	= 8;
+ 		break;
+ #endif
+ #ifdef FBCON_HAS_CFB32
+ 	case 32:/* TRUECOLOUR, 16m */
+-		hw->pixformat		= PIXFORMAT_32BPP;
+-		hw->visualid		= VISUALID_16M_32;
++		hw->co_pixfmt		= CO_PIXFMT_32BPP;
+ 		hw->pitch		= hw->width >> 1;
+-		hw->palette_ctrl	|= 0x10;
++		hw->ramdac		|= (RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
++		hw->extseqmisc		= EXT_SEQ_MISC_32;
++
++		var->transp.offset	= 24;
++		var->transp.length	= 8;
++		var->red.offset		= 16;
++		var->red.length		= 8;
++		var->green.offset	= 8;
++		var->green.length	= 8;
++		var->blue.offset	= 0;
++		var->blue.length	= 8;
+ 		break;
+ #endif
+ 	default:
+ 		return -EINVAL;
+ 	}
+ 
++	mem = var->xres_virtual * var->yres_virtual * (var->bits_per_pixel / 8);
++	if (mem > cfb->fb.fix.smem_len)
++		var->yres_virtual = cfb->fb.fix.smem_len * 8 /
++			(var->bits_per_pixel * var->xres_virtual);
++
++	if (var->yres > var->yres_virtual)
++		var->yres = var->yres_virtual;
++	if (var->xres > var->xres_virtual)
++		var->xres = var->xres_virtual;
++
+ 	err = cyber2000fb_decode_clock(hw, cfb, var);
+ 	if (err)
+ 		return err;
+@@ -880,7 +996,7 @@
+ 	struct cfb_info *cfb = (struct cfb_info *)info;
+ 	struct display *display;
+ 	struct par_info hw;
+-	int err, chgvar = 0;
++	int err, chgvar;
+ 
+ 	/*
+ 	 * CONUPDATE and SMOOTH_XPAN are equal.  However,
+@@ -888,11 +1004,11 @@
+ 	 */
+ 	if (var->vmode & FB_VMODE_CONUPDATE) {
+ 		var->vmode |= FB_VMODE_YWRAP;
+-		var->xoffset = cfb->fb.var.xoffset;
+-		var->yoffset = cfb->fb.var.yoffset;
++		var->xoffset = cfb->display->var.xoffset;
++		var->yoffset = cfb->display->var.yoffset;
+ 	}
+ 
+-	err = cyber2000fb_decode_var(var, (struct cfb_info *)info, &hw);
++	err = cyber2000fb_decode_var(var, cfb, &hw);
+ 	if (err)
+ 		return err;
+ 
+@@ -902,105 +1018,61 @@
+ 	if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ 		return -EINVAL;
+ 
+-	if (cfb->fb.var.xres != var->xres)
+-		chgvar = 1;
+-	if (cfb->fb.var.yres != var->yres)
+-		chgvar = 1;
+-	if (cfb->fb.var.xres_virtual != var->xres_virtual)
+-		chgvar = 1;
+-	if (cfb->fb.var.yres_virtual != var->yres_virtual)
+-		chgvar = 1;
+-	if (cfb->fb.var.bits_per_pixel != var->bits_per_pixel)
+-		chgvar = 1;
+-
+ 	if (con < 0) {
+ 		display = cfb->fb.disp;
+-		chgvar = 0;
+ 	} else {
+ 		display = fb_display + con;
+ 	}
+ 
+-	var->red.msb_right	= 0;
+-	var->green.msb_right	= 0;
+-	var->blue.msb_right	= 0;
++	chgvar = cfb->fb.var.xres != var->xres ||
++		 cfb->fb.var.yres != var->yres ||
++		 cfb->fb.var.xres_virtual != var->xres_virtual ||
++		 cfb->fb.var.yres_virtual != var->yres_virtual ||
++		 cfb->fb.var.bits_per_pixel != var->bits_per_pixel;
++
++	if (memcmp(&cfb->fb.var.red, &var->red, sizeof(var->red)) ||
++	    memcmp(&cfb->fb.var.green, &var->green, sizeof(var->green)) ||
++	    memcmp(&cfb->fb.var.blue, &var->blue, sizeof(var->blue)))
++		chgvar = 1;
++
++	if (con < 0)
++		chgvar = 0;
++
++	/*
++	 * If we are setting all the virtual consoles, also set the
++	 * defaults used to create new consoles.
++	 */
++	err = var->activate;
++	var->activate = FB_ACTIVATE_NOW;
++	if (err & FB_ACTIVATE_ALL)
++		cfb->fb.disp->var = *var;
++
++	cfb->fb.var = *var;
++	cfb->fb.fix.line_length	= var->xres_virtual * var->bits_per_pixel / 8;
+ 
+ 	switch (var->bits_per_pixel) {
+ #ifdef FBCON_HAS_CFB8
+ 	case 8:	/* PSEUDOCOLOUR, 256 */
+-		var->red.offset		= 0;
+-		var->red.length		= 8;
+-		var->green.offset	= 0;
+-		var->green.length	= 8;
+-		var->blue.offset	= 0;
+-		var->blue.length	= 8;
+-
+-		cfb->fb.fix.visual	= FB_VISUAL_PSEUDOCOLOR;
+ 		cfb->dispsw		= &fbcon_cfb8;
+ 		display->dispsw_data	= NULL;
+-		display->next_line	= var->xres_virtual;
+ 		break;
+ #endif
+ #ifdef FBCON_HAS_CFB16
+-	case 16:/* DIRECTCOLOUR, 64k */
+-#ifndef CFB16_IS_CFB15
+-		var->red.offset		= 11;
+-		var->red.length		= 5;
+-		var->green.offset	= 5;
+-		var->green.length	= 6;
+-		var->blue.offset	= 0;
+-		var->blue.length	= 5;
+-
+-		cfb->fb.fix.visual	= FB_VISUAL_DIRECTCOLOR;
++	case 16:/* DIRECTCOLOUR */
+ 		cfb->dispsw		= &fbcon_cfb16;
+ 		display->dispsw_data	= cfb->fb.pseudo_palette;
+-		display->next_line	= var->xres_virtual * 2;
+-		break;
+-#endif
+-	case 15:/* DIRECTCOLOUR, 32k */
+-		var->bits_per_pixel	= 15;
+-		var->red.offset		= 10;
+-		var->red.length		= 5;
+-		var->green.offset	= 5;
+-		var->green.length	= 5;
+-		var->blue.offset	= 0;
+-		var->blue.length	= 5;
+-
+-		cfb->fb.fix.visual	= FB_VISUAL_DIRECTCOLOR;
+-		cfb->dispsw		= &fbcon_cfb16;
+-		display->dispsw_data	= cfb->fb.pseudo_palette;
+-		display->next_line	= var->xres_virtual * 2;
+ 		break;
+ #endif
+ #ifdef FBCON_HAS_CFB24
+ 	case 24:/* TRUECOLOUR, 16m */
+-		var->red.offset		= 16;
+-		var->red.length		= 8;
+-		var->green.offset	= 8;
+-		var->green.length	= 8;
+-		var->blue.offset	= 0;
+-		var->blue.length	= 8;
+-
+-		cfb->fb.fix.visual	= FB_VISUAL_TRUECOLOR;
+ 		cfb->dispsw		= &fbcon_cfb24;
+ 		display->dispsw_data	= cfb->fb.pseudo_palette;
+-		display->next_line	= var->xres_virtual * 3;
+ 		break;
+ #endif
+ #ifdef FBCON_HAS_CFB32
+ 	case 32:/* TRUECOLOUR, 16m */
+-		var->transp.offset	= 24;
+-		var->transp.length	= 8;
+-		var->red.offset		= 16;
+-		var->red.length		= 8;
+-		var->green.offset	= 8;
+-		var->green.length	= 8;
+-		var->blue.offset	= 0;
+-		var->blue.length	= 8;
+-
+-		cfb->fb.fix.visual	= FB_VISUAL_TRUECOLOR;
+ 		cfb->dispsw		= &fbcon_cfb32;
+ 		display->dispsw_data	= cfb->fb.pseudo_palette;
+-		display->next_line	= var->xres_virtual * 4;
+ 		break;
+ #endif
+ 	default:/* in theory this should never happen */
+@@ -1010,15 +1082,27 @@
+ 		break;
+ 	}
+ 
++	/*
++	 * 8bpp displays are always pseudo colour.
++	 * 16bpp and above are direct colour or true colour, depending
++	 * on whether the RAMDAC palettes are bypassed.  (Direct colour
++	 * has palettes, true colour does not.)
++	 */
++	if (var->bits_per_pixel == 8)
++		cfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
++	else if (hw.ramdac & RAMDAC_BYPASS)
++		cfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
++	else
++		cfb->fb.fix.visual = FB_VISUAL_DIRECTCOLOR;
++
+ 	if (var->accel_flags & FB_ACCELF_TEXT && cfb->dispsw != &fbcon_dummy)
+ 		display->dispsw = &fbcon_cyber_accel;
+ 	else
+ 		display->dispsw = cfb->dispsw;
+ 
+-	cfb->fb.fix.line_length	= display->next_line;
+-
+ 	display->screen_base	= cfb->fb.screen_base;
+ 	display->line_length	= cfb->fb.fix.line_length;
++	display->next_line	= cfb->fb.fix.line_length;
+ 	display->visual		= cfb->fb.fix.visual;
+ 	display->type		= cfb->fb.fix.type;
+ 	display->type_aux	= cfb->fb.fix.type_aux;
+@@ -1026,31 +1110,15 @@
+ 	display->ywrapstep	= cfb->fb.fix.ywrapstep;
+ 	display->can_soft_blank = 1;
+ 	display->inverse	= 0;
++	display->var		= *var;
+ 
+-	cfb->fb.var = *var;
+-	cfb->fb.var.activate &= ~FB_ACTIVATE_ALL;
+-
+-	/*
+-	 * Update the old var.  The fbcon drivers still use this.
+-	 * Once they are using cfb->fb.var, this can be dropped.
+-	 *					--rmk
+-	 */
+-	display->var = cfb->fb.var;
+-
+-	/*
+-	 * If we are setting all the virtual consoles, also set the
+-	 * defaults used to create new consoles.
+-	 */
+-	if (var->activate & FB_ACTIVATE_ALL)
+-		cfb->fb.disp->var = cfb->fb.var;
++	cyber2000fb_set_timing(cfb, &hw);
++	cyber2000fb_update_start(cfb, var);
++	fb_set_cmap(&cfb->fb.cmap, 1, cyber2000fb_setcolreg, &cfb->fb);
+ 
+-	if (chgvar && info && cfb->fb.changevar)
++	if (chgvar && cfb->fb.changevar)
+ 		cfb->fb.changevar(con);
+ 
+-	cyber2000fb_update_start(cfb, var);
+-	cyber2000fb_set_timing(cfb, &hw);
+-	fb_set_cmap(&cfb->fb.cmap, 1, cyber2000_setcolreg, &cfb->fb);
+-
+ 	return 0;
+ }
+ 
+@@ -1072,18 +1140,18 @@
+ 
+ 	if (var->xoffset > (var->xres_virtual - var->xres))
+ 		return -EINVAL;
+-	if (y_bottom > cfb->fb.var.yres_virtual)
++	if (y_bottom > cfb->display->var.yres_virtual)
+ 		return -EINVAL;
+ 
+ 	if (cyber2000fb_update_start(cfb, var))
+ 		return -EINVAL;
+ 
+-	cfb->fb.var.xoffset = var->xoffset;
+-	cfb->fb.var.yoffset = var->yoffset;
++	cfb->display->var.xoffset = var->xoffset;
++	cfb->display->var.yoffset = var->yoffset;
+ 	if (var->vmode & FB_VMODE_YWRAP) {
+-		cfb->fb.var.vmode |= FB_VMODE_YWRAP;
++		cfb->display->var.vmode |= FB_VMODE_YWRAP;
+ 	} else {
+-		cfb->fb.var.vmode &= ~FB_VMODE_YWRAP;
++		cfb->display->var.vmode &= ~FB_VMODE_YWRAP;
+ 	}
+ 
+ 	return 0;
+@@ -1106,22 +1174,18 @@
+ static int cyber2000fb_switch(int con, struct fb_info *info)
+ {
+ 	struct cfb_info *cfb = (struct cfb_info *)info;
+-	struct display *disp;
++	struct display *display = cfb->display;
+ 	struct fb_cmap *cmap;
+ 
+-	if (cfb->currcon >= 0) {
+-		disp = fb_display + cfb->currcon;
+-
++	if (display) {
+ 		/*
+ 		 * Save the old colormap and video mode.
+ 		 */
+-		disp->var = cfb->fb.var;
+-		if (disp->cmap.len)
+-			fb_copy_cmap(&cfb->fb.cmap, &disp->cmap, 0);
++		if (display->cmap.len)
++			fb_copy_cmap(&cfb->fb.cmap, &display->cmap, 0);
+ 	}
+ 
+-	cfb->currcon = con;
+-	disp = fb_display + con;
++	cfb->display = display = fb_display + con;
+ 
+ 	/*
+ 	 * Install the new colormap and change the video mode.  By default,
+@@ -1132,73 +1196,88 @@
+ 	 * depth of the new video mode.  For now, we leave it at its
+ 	 * default 256 entry.
+ 	 */
+-	if (disp->cmap.len)
+-		cmap = &disp->cmap;
++	if (display->cmap.len)
++		cmap = &display->cmap;
+ 	else
+-		cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
++		cmap = fb_default_cmap(1 << display->var.bits_per_pixel);
+ 
+ 	fb_copy_cmap(cmap, &cfb->fb.cmap, 0);
+ 
+-	cfb->fb.var = disp->var;
+-	cfb->fb.var.activate = FB_ACTIVATE_NOW;
+-
+-	cyber2000fb_set_var(&cfb->fb.var, con, &cfb->fb);
++	display->var.activate = FB_ACTIVATE_NOW;
++	cyber2000fb_set_var(&display->var, con, &cfb->fb);
+ 
+ 	return 0;
+ }
+ 
+ /*
+  *    (Un)Blank the display.
++ *
++ *  Blank the screen if blank_mode != 0, else unblank. If
++ *  blank == NULL then the caller blanks by setting the CLUT
++ *  (Color Look Up Table) to all black. Return 0 if blanking
++ *  succeeded, != 0 if un-/blanking failed due to e.g. a
++ *  video mode which doesn't support it. Implements VESA
++ *  suspend and powerdown modes on hardware that supports
++ *  disabling hsync/vsync:
++ *    blank_mode == 2: suspend vsync
++ *    blank_mode == 3: suspend hsync
++ *    blank_mode == 4: powerdown
++ *
++ *  wms...Enable VESA DMPS compatible powerdown mode
++ *  run "setterm -powersave powerdown" to take advantage
+  */
+ static void cyber2000fb_blank(int blank, struct fb_info *info)
+ {
+ 	struct cfb_info *cfb = (struct cfb_info *)info;
++	unsigned int sync = 0;
+ 	int i;
+ 
+-	/*
+-	 *  Blank the screen if blank_mode != 0, else unblank. If
+-	 *  blank == NULL then the caller blanks by setting the CLUT
+-	 *  (Color Look Up Table) to all black. Return 0 if blanking
+-	 *  succeeded, != 0 if un-/blanking failed due to e.g. a
+-	 *  video mode which doesn't support it. Implements VESA
+-	 *  suspend and powerdown modes on hardware that supports
+-	 *  disabling hsync/vsync:
+-	 *    blank_mode == 2: suspend vsync
+-	 *    blank_mode == 3: suspend hsync
+-	 *    blank_mode == 4: powerdown
+-	 *
+-	 *  wms...Enable VESA DMPS compatible powerdown mode
+-	 *  run "setterm -powersave powerdown" to take advantage
+-	 */
+-     
+ 	switch (blank) {
+ 	case 4:	/* powerdown - both sync lines down */
+-    		cyber2000_grphw(0x16, 0x05, cfb);
++		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_0;
+ 		break;	
+ 	case 3:	/* hsync off */
+-    		cyber2000_grphw(0x16, 0x01, cfb);
++		sync = EXT_SYNC_CTL_VS_NORMAL | EXT_SYNC_CTL_HS_0;
+ 		break;	
+ 	case 2:	/* vsync off */
+-    		cyber2000_grphw(0x16, 0x04, cfb);
+-		break;	
++		sync = EXT_SYNC_CTL_VS_0 | EXT_SYNC_CTL_HS_NORMAL;
++		break;
+ 	case 1:	/* soft blank */
+-		cyber2000_grphw(0x16, 0x00, cfb);
++	default: /* unblank */
++		break;
++	}
++
++	cyber2000_grphw(EXT_SYNC_CTL, sync, cfb);
++
++	if (blank <= 1) {
++		/* turn on ramdacs */
++		cfb->ramdac_powerdown &= ~(RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN);
++		cyber2000fb_write_ramdac_ctrl(cfb);
++	}
++
++	/*
++	 * Soft blank/unblank the display.
++	 */
++	if (blank) {	/* soft blank */
+ 		for (i = 0; i < NR_PALETTE; i++) {
+ 			cyber2000fb_writeb(i, 0x3c8, cfb);
+ 			cyber2000fb_writeb(0, 0x3c9, cfb);
+ 			cyber2000fb_writeb(0, 0x3c9, cfb);
+ 			cyber2000fb_writeb(0, 0x3c9, cfb);
+ 		}
+-		break;
+-	default: /* unblank */
+-		cyber2000_grphw(0x16, 0x00, cfb);
++	} else {	/* unblank */
+ 		for (i = 0; i < NR_PALETTE; i++) {
+ 			cyber2000fb_writeb(i, 0x3c8, cfb);
+ 			cyber2000fb_writeb(cfb->palette[i].red, 0x3c9, cfb);
+ 			cyber2000fb_writeb(cfb->palette[i].green, 0x3c9, cfb);
+ 			cyber2000fb_writeb(cfb->palette[i].blue, 0x3c9, cfb);
+ 		}
+-		break;
++	}
++
++	if (blank >= 2) {
++		/* turn off ramdacs */
++		cfb->ramdac_powerdown |= RAMDAC_DACPWRDN | RAMDAC_BYPASS | RAMDAC_RAMPWRDN;
++		cyber2000fb_write_ramdac_ctrl(cfb);
+ 	}
+ }
+ 
+@@ -1233,51 +1312,61 @@
+ }
+ 
+ static struct fb_ops cyber2000fb_ops = {
+-	owner:		THIS_MODULE,
+-	fb_set_var:	cyber2000fb_set_var,
+-	fb_set_cmap:	cyber2000fb_set_cmap,
+-	fb_pan_display:	cyber2000fb_pan_display,
+-	fb_get_fix:	gen_get_fix,
+-	fb_get_var:	gen_get_var,
+-	fb_get_cmap:	gen_get_cmap,
++	.owner		= THIS_MODULE,
++	.fb_set_var	= cyber2000fb_set_var,
++	.fb_set_cmap	= cyber2000fb_set_cmap,
++	.fb_pan_display	= cyber2000fb_pan_display,
++	.fb_get_fix	= gen_get_fix,
++	.fb_get_var	= gen_get_var,
++	.fb_get_cmap	= gen_get_cmap,
+ };
+ 
+ /*
++ * This is the only "static" reference to the internal data structures
++ * of this driver.  It is here solely at the moment to support the other
++ * CyberPro modules external to this driver.
++ */
++static struct cfb_info		*int_cfb_info;
++
++/*
+  * Enable access to the extended registers
+  */
+-static void cyber2000fb_enable_extregs(struct cfb_info *cfb)
++void cyber2000fb_enable_extregs(struct cfb_info *cfb)
+ {
+ 	cfb->func_use_count += 1;
+ 
+ 	if (cfb->func_use_count == 1) {
+ 		int old;
+ 
+-		old = cyber2000_grphr(FUNC_CTL, cfb);
+-		cyber2000_grphw(FUNC_CTL, old | FUNC_CTL_EXTREGENBL, cfb);
++		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
++		old |= EXT_FUNC_CTL_EXTREGENBL;
++		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
+ 	}
+ }
+ 
+ /*
+  * Disable access to the extended registers
+  */
+-static void cyber2000fb_disable_extregs(struct cfb_info *cfb)
++void cyber2000fb_disable_extregs(struct cfb_info *cfb)
+ {
+ 	if (cfb->func_use_count == 1) {
+ 		int old;
+ 
+-		old = cyber2000_grphr(FUNC_CTL, cfb);
+-		cyber2000_grphw(FUNC_CTL, old & ~FUNC_CTL_EXTREGENBL, cfb);
++		old = cyber2000_grphr(EXT_FUNC_CTL, cfb);
++		old &= ~EXT_FUNC_CTL_EXTREGENBL;
++		cyber2000_grphw(EXT_FUNC_CTL, old, cfb);
+ 	}
+ 
+-	cfb->func_use_count -= 1;
++	if (cfb->func_use_count == 0)
++		printk(KERN_ERR "disable_extregs: count = 0\n");
++	else
++		cfb->func_use_count -= 1;
+ }
+ 
+-/*
+- * This is the only "static" reference to the internal data structures
+- * of this driver.  It is here solely at the moment to support the other
+- * CyberPro modules external to this driver.
+- */
+-static struct cfb_info		*int_cfb_info;
++void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var)
++{
++	memcpy(var, &cfb->display->var, sizeof(struct fb_var_screeninfo));
++}
+ 
+ /*
+  * Attach a capture/tv driver to the core CyberX0X0 driver.
+@@ -1311,164 +1400,102 @@
+ 
+ EXPORT_SYMBOL(cyber2000fb_attach);
+ EXPORT_SYMBOL(cyber2000fb_detach);
++EXPORT_SYMBOL(cyber2000fb_enable_extregs);
++EXPORT_SYMBOL(cyber2000fb_disable_extregs);
++EXPORT_SYMBOL(cyber2000fb_get_fb_var);
+ 
+ /*
+  * These parameters give
+  * 640x480, hsync 31.5kHz, vsync 60Hz
+  */
+ static struct fb_videomode __devinitdata cyber2000fb_default_mode = {
+-	refresh:	60,
+-	xres:		640,
+-	yres:		480,
+-	pixclock:	39722,
+-	left_margin:	56,
+-	right_margin:	16,
+-	upper_margin:	34,
+-	lower_margin:	9,
+-	hsync_len:	88,
+-	vsync_len:	2,
+-	sync:		FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+-	vmode:		FB_VMODE_NONINTERLACED
++	.refresh	= 60,
++	.xres		= 640,
++	.yres		= 480,
++	.pixclock	= 39722,
++	.left_margin	= 56,
++	.right_margin	= 16,
++	.upper_margin	= 34,
++	.lower_margin	= 9,
++	.hsync_len	= 88,
++	.vsync_len	= 2,
++	.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++	.vmode		= FB_VMODE_NONINTERLACED
+ };
+ 
++/* static register programming for all chips */
+ static char igs_regs[] __devinitdata = {
+-					0x12, 0x00,	0x13, 0x00,
+-					0x16, 0x00,
+-			0x31, 0x00,	0x32, 0x00,
+-	0x50, 0x00,	0x51, 0x00,	0x52, 0x00,	0x53, 0x00,
+-	0x54, 0x00,	0x55, 0x00,	0x56, 0x00,	0x57, 0x01,
+-	0x58, 0x00,	0x59, 0x00,	0x5a, 0x00,
+-	0x70, 0x0b,					0x73, 0x30,
+-	0x74, 0x0b,	0x75, 0x17,	0x76, 0x00,	0x7a, 0xc8
++	EXT_CRT_IRQ,		0,
++	EXT_CRT_TEST,		0,
++	EXT_SYNC_CTL,		0,
++	EXT_SEG_WRITE_PTR,	0,
++	EXT_SEG_READ_PTR,	0,
++	EXT_BIU_MISC,		EXT_BIU_MISC_LIN_ENABLE |
++				EXT_BIU_MISC_COP_ENABLE |
++				EXT_BIU_MISC_COP_BFC,
++	EXT_FUNC_CTL,		0,
++	CURS_H_START,		0,
++	CURS_H_START + 1,	0,
++	CURS_H_PRESET,		0,
++	CURS_V_START,		0,
++	CURS_V_START + 1,	0,
++	CURS_V_PRESET,		0,
++	CURS_CTL,		0,
++	EXT_ATTRIB_CTL,		EXT_ATTRIB_CTL_EXT,
++	EXT_OVERSCAN_RED,	0,
++	EXT_OVERSCAN_GREEN,	0,
++	EXT_OVERSCAN_BLUE,	0,
++};
++
++/* specific register setting for the 2000 series */
++static char igs_2000_regs[] __devinitdata = {
++	/* some of these are questionable when we have a BIOS */
++	EXT_MEM_CTL0,		EXT_MEM_CTL0_7CLK |
++				EXT_MEM_CTL0_RAS_1 |
++				EXT_MEM_CTL0_MULTCAS,
++	EXT_HIDDEN_CTL1,	0x30,
++	EXT_FIFO_CTL,		0x0b,
++	EXT_FIFO_CTL + 1,	0x17,
++	0x76,			0x00,
++	EXT_HIDDEN_CTL4,	0xc8
+ };
+ 
+ /*
+- * We need to wake up the CyberPro, and make sure its in linear memory
+- * mode.  Unfortunately, this is specific to the platform and card that
+- * we are running on.
+- *
+- * On x86 and ARM, should we be initialising the CyberPro first via the
+- * IO registers, and then the MMIO registers to catch all cases?  Can we
+- * end up in the situation where the chip is in MMIO mode, but not awake
+- * on an x86 system?
+- *
+- * Note that on the NetWinder, the firmware automatically detects the
+- * type, width and size, and leaves this in extended registers 0x71 and
+- * 0x72 for us.
++ * Initialise the CyberPro hardware.
+  */
+-static inline void cyberpro_init_hw(struct cfb_info *cfb, int at_boot)
++static void cyberpro_init_hw(struct cfb_info *cfb)
+ {
+ 	int i;
+ 
+-	/*
+-	 * Wake up the CyberPro.
+-	 */
+-#ifdef __sparc__
+-#ifdef __sparc_v9__
+-#error "You loose, consult DaveM."
+-#else
+-	/*
+-	 * SPARC does not have an "outb" instruction, so we generate
+-	 * I/O cycles storing into a reserved memory space at
+-	 * physical address 0x3000000
+-	 */
+-	{
+-		unsigned char *iop;
+-
+-		iop = ioremap(0x3000000, 0x5000);
+-		if (iop == NULL) {
+-			prom_printf("iga5000: cannot map I/O\n");
+-			return -ENOMEM;
+-		}
+-
+-		writeb(0x18, iop + 0x46e8);
+-		writeb(0x01, iop + 0x102);
+-		writeb(0x08, iop + 0x46e8);
+-		writeb(0x33, iop + 0x3ce);
+-		writeb(0x01, iop + 0x3cf);
+-
+-		iounmap((void *)iop);
+-	}
+-#endif
+-
+-	if (at_boot) {
+-		/*
+-		 * Use mclk from BIOS.  Only read this if we're
+-		 * initialising this card for the first time.
+-		 * FIXME: what about hotplug?
+-		 */
+-		cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
+-		cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
+-	}
+-#endif
+-#if defined(__i386__) || defined(__x86_64__) || defined(__mips__)
+-	/*
+-	 * x86 and MIPS are simple, we just do regular
+-	 * outb's instead of cyber2000fb_writeb.
+-	 */
+-	outb(0x18, 0x46e8);
+-	outb(0x01, 0x102);
+-	outb(0x08, 0x46e8);
+-	outb(0x33, 0x3ce);
+-	outb(0x01, 0x3cf);
+-
+-	if (at_boot) {
+-		/*
+-		 * Use mclk from BIOS.  Only read this if we're
+-		 * initialising this card for the first time.
+-		 * FIXME: what about hotplug?
+-		 */
+-		cfb->mclk_mult = cyber2000_grphr(MCLK_MULT, cfb);
+-		cfb->mclk_div  = cyber2000_grphr(MCLK_DIV, cfb);
+-	}
+-#endif
+-#ifdef __arm__
+-	cyber2000fb_writeb(0x18, 0x46e8, cfb);
+-	cyber2000fb_writeb(0x01, 0x102, cfb);
+-	cyber2000fb_writeb(0x08, 0x46e8, cfb);
+-	cyber2000fb_writeb(0x33, 0x3ce, cfb);
+-	cyber2000fb_writeb(0x01, 0x3cf, cfb);
+-
+-	/*
+-	 * MCLK on the NetWinder and the Shark is fixed at 75MHz
+-	 */
+-	cfb->mclk_mult = 0xdb;
+-	cfb->mclk_div  = 0x54;
+-#endif
+-
+-	/*
+-	 * Initialise the CyberPro
+-	 */
+ 	for (i = 0; i < sizeof(igs_regs); i += 2)
+ 		cyber2000_grphw(igs_regs[i], igs_regs[i+1], cfb);
+ 
+-	if (at_boot) {
++	if (cfb->id == ID_CYBERPRO_5000) {
+ 		/*
+-		 * get the video RAM size and width from the VGA register.
+-		 * This should have been already initialised by the BIOS,
+-		 * but if it's garbage, claim default 1MB VRAM (woody)
++		 * On the CyberPro5XXXX, ensure that we're using the correct
++		 * PLL (5XXX's may be programmed to use an additional set of
++		 * PLLs.)
+ 		 */
+-		cfb->mem_ctl1 = cyber2000_grphr(MEM_CTL1, cfb);
+-		cfb->mem_ctl2 = cyber2000_grphr(MEM_CTL2, cfb);
++		unsigned char val;
++		cyber2000fb_writeb(0xba, 0x3ce, cfb);
++		val = cyber2000fb_readb(0x3cf, cfb) & 0x80;
++		cyber2000fb_writeb(val, 0x3cf, cfb);
++		cyber2000fb_ops.fb_pan_display = NULL; /* FIXME: panning broken */
+ 	} else {
+ 		/*
+-		 * Reprogram the MEM_CTL1 and MEM_CTL2 registers
++		 * Other supported chips (2000 series) appear to need
++		 * these registers programming
+ 		 */
+-		cyber2000_grphw(MEM_CTL1, cfb->mem_ctl1, cfb);
+-		cyber2000_grphw(MEM_CTL2, cfb->mem_ctl2, cfb);
++		for (i = 0; i < sizeof(igs_2000_regs); i += 2)
++			cyber2000_grphw(igs_2000_regs[i],
++					igs_2000_regs[i+1],
++					cfb);
+ 	}
+ 
+-	/*
+-	 * Ensure thatwe are using the correct PLL.
+-	 * (CyberPro 5000's may be programmed to use
+-	 * an additional set of PLLs.
+-	 */
+-	cyber2000fb_writeb(0xba, 0x3ce, cfb);
+-	cyber2000fb_writeb(cyber2000fb_readb(0x3cf, cfb) & 0x80, 0x3cf, cfb);
+ }
+ 
+ static struct cfb_info * __devinit
+-cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name)
++cyberpro_alloc_fb_info(unsigned int id, char *name)
+ {
+ 	struct cfb_info *cfb;
+ 
+@@ -1480,10 +1507,9 @@
+ 
+ 	memset(cfb, 0, sizeof(struct cfb_info) + sizeof(struct display));
+ 
+-	cfb->currcon		= -1;
+-	cfb->dev		= dev;
++	cfb->id			= id;
+ 
+-	if (id->driver_data == FB_ACCEL_IGS_CYBER5000)
++	if (id == ID_CYBERPRO_5000)
+ 		cfb->ref_ps	= 40690; // 24.576 MHz
+ 	else
+ 		cfb->ref_ps	= 69842; // 14.31818 MHz (69841?)
+@@ -1492,7 +1518,7 @@
+ 	cfb->divisors[1]	= 2;
+ 	cfb->divisors[2]	= 4;
+ 
+-	if (id->driver_data == FB_ACCEL_IGS_CYBER2000)
++	if (id == ID_CYBERPRO_2000)
+ 		cfb->divisors[3] = 8;
+ 	else
+ 		cfb->divisors[3] = 6;
+@@ -1504,7 +1530,24 @@
+ 	cfb->fb.fix.xpanstep	= 0;
+ 	cfb->fb.fix.ypanstep	= 1;
+ 	cfb->fb.fix.ywrapstep	= 0;
+-	cfb->fb.fix.accel	= id->driver_data;
++
++	switch (id) {
++	case ID_IGA_1682:
++		cfb->fb.fix.accel = 0;
++		break;
++
++	case ID_CYBERPRO_2000:
++		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2000;
++		break;
++
++	case ID_CYBERPRO_2010:
++		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER2010;
++		break;
++
++	case ID_CYBERPRO_5000:
++		cfb->fb.fix.accel = FB_ACCEL_IGS_CYBER5000;
++		break;
++	}
+ 
+ 	cfb->fb.var.nonstd	= 0;
+ 	cfb->fb.var.activate	= FB_ACTIVATE_NOW;
+@@ -1569,55 +1612,46 @@
+ 	return 0;
+ }
+ 
+-static int __devinit
+-cyberpro_probe(struct pci_dev *dev, const struct pci_device_id *id)
++/*
++ * The CyberPro chips can be placed on many different bus types.
++ * This probe function is common to all bus types.  The bus-specific
++ * probe function is expected to have:
++ *  - enabled access to the linear memory region
++ *  - memory mapped access to the registers
++ *  - initialised mem_ctl1 and mem_ctl2 appropriately.
++ */
++static int __devinit cyberpro_common_probe(struct cfb_info *cfb)
+ {
+-	struct cfb_info *cfb;
+-	u_int h_sync, v_sync;
+ 	u_long smem_size;
+-	char name[16];
++	u_int h_sync, v_sync;
+ 	int err;
+ 
+-	sprintf(name, "CyberPro%4X", id->device);
+-
+-	err = pci_enable_device(dev);
+-	if (err)
+-		return err;
+-
+-	err = pci_request_regions(dev, name);
+-	if (err)
+-		return err;
+-
+-	err = -ENOMEM;
+-	cfb = cyberpro_alloc_fb_info(dev, id, name);
+-	if (!cfb)
+-		goto failed_release;
+-
+-	cfb->region = ioremap(pci_resource_start(dev, 0),
+-			      pci_resource_len(dev, 0));
+-	if (!cfb->region)
+-		goto failed_ioremap;
+-
+-	cfb->regs = cfb->region + MMIO_OFFSET;
++	cyberpro_init_hw(cfb);
+ 
+-	cyberpro_init_hw(cfb, 1);
++	/*
++	 * Get the video RAM size and width from the VGA register.
++	 * This should have been already initialised by the BIOS,
++	 * but if it's garbage, claim default 1MB VRAM (woody)
++	 */
++	cfb->mem_ctl0 = cyber2000_grphr(EXT_MEM_CTL0, cfb);
++	cfb->mem_ctl1 = cyber2000_grphr(EXT_MEM_CTL1, cfb);
++	cfb->mem_ctl2 = cyber2000_grphr(EXT_MEM_CTL2, cfb);
+ 
++	/*
++	 * Determine the size of the memory.
++	 */
+ 	switch (cfb->mem_ctl2 & MEM_CTL2_SIZE_MASK) {
+ 	case MEM_CTL2_SIZE_4MB:	smem_size = 0x00400000; break;
+ 	case MEM_CTL2_SIZE_2MB:	smem_size = 0x00200000; break;
++	case MEM_CTL2_SIZE_1MB: smem_size = 0x00100000; break;
+ 	default:		smem_size = 0x00100000; break;
+ 	}
+ 
+-	/*
+-	 * Hmm, we _need_ a portable way of finding the address for
+-	 * the remap stuff, both for mmio and for smem.
+-	 */
+-	cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
+-	cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
+-	cfb->fb.fix.mmio_len   = MMIO_SIZE;
+ 	cfb->fb.fix.smem_len   = smem_size;
++	cfb->fb.fix.mmio_len   = MMIO_SIZE;
+ 	cfb->fb.screen_base    = cfb->region;
+ 
++	err = -EINVAL;
+ 	if (!fb_find_mode(&cfb->fb.var, &cfb->fb, NULL, NULL, 0,
+ 	    		  &cyber2000fb_default_mode, 8)) {
+ 		printk("%s: no valid mode found\n", cfb->fb.fix.id);
+@@ -1644,13 +1678,181 @@
+ 	v_sync = h_sync / (cfb->fb.var.yres + cfb->fb.var.upper_margin +
+ 		 cfb->fb.var.lower_margin + cfb->fb.var.vsync_len);
+ 
+-	printk(KERN_INFO "%s: %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
++	printk(KERN_INFO "%s: %dKiB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+ 		cfb->fb.fix.id, cfb->fb.fix.smem_len >> 10,
+ 		cfb->fb.var.xres, cfb->fb.var.yres,
+ 		h_sync / 1000, h_sync % 1000, v_sync);
+ 
+ 	err = register_framebuffer(&cfb->fb);
+-	if (err < 0)
++
++failed:
++	return err;
++}
++
++static void cyberpro_common_resume(struct cfb_info *cfb)
++{
++	cyberpro_init_hw(cfb);
++
++	/*
++	 * Reprogram the MEM_CTL0, 1 and 2 registers
++	 */
++	cyber2000_grphw(EXT_MEM_CTL0, cfb->mem_ctl0, cfb);
++	cyber2000_grphw(EXT_MEM_CTL1, cfb->mem_ctl1, cfb);
++	cyber2000_grphw(EXT_MEM_CTL2, cfb->mem_ctl2, cfb);
++
++	/*
++	 * Restore the old video mode and the palette.
++	 * We also need to tell fbcon to redraw the console.
++	 */
++	cfb->fb.var.activate = FB_ACTIVATE_NOW;
++	cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
++}
++
++
++
++
++/*
++ * PCI specific support.
++ */
++
++/*
++ * We need to wake up the CyberPro, and make sure its in linear memory
++ * mode.  Unfortunately, this is specific to the platform and card that
++ * we are running on.
++ *
++ * On x86 and ARM, should we be initialising the CyberPro first via the
++ * IO registers, and then the MMIO registers to catch all cases?  Can we
++ * end up in the situation where the chip is in MMIO mode, but not awake
++ * on an x86 system?
++ */
++static int cyberpro_pci_enable_mmio(struct cfb_info *cfb)
++{
++	unsigned char val;
++
++#if defined(__sparc_v9__)
++#error "You loose, consult DaveM."
++#elif defined(__sparc__)
++	/*
++	 * SPARC does not have an "outb" instruction, so we generate
++	 * I/O cycles storing into a reserved memory space at
++	 * physical address 0x3000000
++	 */
++	unsigned char *iop;
++
++	iop = ioremap(0x3000000, 0x5000);
++	if (iop == NULL) {
++		prom_printf("iga5000: cannot map I/O\n");
++		return -ENOMEM;
++	}
++
++	writeb(0x18, iop + 0x46e8);
++	writeb(0x01, iop + 0x102);
++	writeb(0x08, iop + 0x46e8);
++	writeb(EXT_BIU_MISC, iop + 0x3ce);
++	writeb(EXT_BIU_MISC_LIN_ENABLE, iop + 0x3cf);
++
++	iounmap((void *)iop);
++#elif defined(CONFIG_ARCH_SHARK)
++	/*
++	 * Shark probably needs to do it this way rather than use the
++	 * IO method below.  Since the CyberPro on the Shark isn't a
++	 * PCI device, we probably want to move this to a bus-specific
++	 * probe function.  Do we even need to do this?
++	 */
++	cyber2000fb_writeb(0x18, 0x46e8, cfb);
++	cyber2000fb_writeb(0x01, 0x102, cfb);
++	cyber2000fb_writeb(0x08, 0x46e8, cfb);
++	cyber2000fb_writeb(EXT_BIU_MISC, 0x3ce, cfb);
++	cyber2000fb_writeb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf, cfb);
++#else
++	/*
++	 * Most other machine types are "normal", so
++	 * we use the standard IO-based wakeup.
++	 */
++	outb(0x18, 0x46e8);
++	outb(0x01, 0x102);
++	outb(0x08, 0x46e8);
++	outb(EXT_BIU_MISC, 0x3ce);
++	outb(EXT_BIU_MISC_LIN_ENABLE, 0x3cf);
++#endif
++
++	/*
++	 * Allow the CyberPro to accept PCI burst accesses
++	 */
++	val = cyber2000_grphr(EXT_BUS_CTL, cfb);
++	if (!(val & EXT_BUS_CTL_PCIBURST_WRITE)) {
++		printk(KERN_INFO "%s: enabling PCI bursts\n", cfb->fb.fix.id);
++
++		val |= EXT_BUS_CTL_PCIBURST_WRITE;
++
++		if (cfb->id == ID_CYBERPRO_5000)
++			val |= EXT_BUS_CTL_PCIBURST_READ;
++
++		cyber2000_grphw(EXT_BUS_CTL, val, cfb);
++	}
++
++	return 0;
++}
++
++static int __devinit
++cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
++{
++	struct cfb_info *cfb;
++	char name[16];
++	int err;
++
++	sprintf(name, "CyberPro%4X", id->device);
++
++	err = pci_enable_device(dev);
++	if (err)
++		return err;
++
++	err = pci_request_regions(dev, name);
++	if (err)
++		return err;
++
++	err = -ENOMEM;
++	cfb = cyberpro_alloc_fb_info(id->driver_data, name);
++	if (!cfb)
++		goto failed_release;
++
++	cfb->dev = dev;
++	cfb->region = ioremap(pci_resource_start(dev, 0),
++			      pci_resource_len(dev, 0));
++	if (!cfb->region)
++		goto failed_ioremap;
++
++	cfb->regs = cfb->region + MMIO_OFFSET;
++	cfb->fb.fix.mmio_start = pci_resource_start(dev, 0) + MMIO_OFFSET;
++	cfb->fb.fix.smem_start = pci_resource_start(dev, 0);
++
++	/*
++	 * Bring up the hardware.  This is expected to enable access
++	 * to the linear memory region, and allow access to the memory
++	 * mapped registers.  Also, mem_ctl1 and mem_ctl2 must be
++	 * initialised.
++	 */
++	err = cyberpro_pci_enable_mmio(cfb);
++	if (err)
++		goto failed;
++
++	/*
++	 * Use MCLK from BIOS. FIXME: what about hotplug?
++	 */
++	cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb);
++	cfb->mclk_div  = cyber2000_grphr(EXT_MCLK_DIV, cfb);
++#ifdef __arm__
++	if (machine_is_netwinder() || machine_is_shark()) {
++		/*
++		 * MCLK on the NetWinder and the Shark is fixed at 75MHz
++		 */
++		cfb->mclk_mult = 0xdb;
++		cfb->mclk_div  = 0x54;
++	}
++#endif
++
++	err = cyberpro_common_probe(cfb);
++	if (err)
+ 		goto failed;
+ 
+ 	/*
+@@ -1672,7 +1874,7 @@
+ 	return err;
+ }
+ 
+-static void __devexit cyberpro_remove(struct pci_dev *dev)
++static void __devexit cyberpro_pci_remove(struct pci_dev *dev)
+ {
+ 	struct cfb_info *cfb = pci_get_drvdata(dev);
+ 
+@@ -1701,7 +1903,7 @@
+ 	}
+ }
+ 
+-static int cyberpro_suspend(struct pci_dev *dev, u32 state)
++static int cyberpro_pci_suspend(struct pci_dev *dev, u32 state)
+ {
+ 	return 0;
+ }
+@@ -1709,41 +1911,44 @@
+ /*
+  * Re-initialise the CyberPro hardware
+  */
+-static int cyberpro_resume(struct pci_dev *dev)
++static int cyberpro_pci_resume(struct pci_dev *dev)
+ {
+ 	struct cfb_info *cfb = pci_get_drvdata(dev);
+ 
+ 	if (cfb) {
+-		cyberpro_init_hw(cfb, 0);
+-
+-		/*
+-		 * Restore the old video mode and the palette.
+-		 * We also need to tell fbcon to redraw the console.
+-		 */
+-		cfb->fb.var.activate = FB_ACTIVATE_NOW;
+-		cyber2000fb_set_var(&cfb->fb.var, -1, &cfb->fb);
++		cyberpro_pci_enable_mmio(cfb);
++		cyberpro_common_resume(cfb);
+ 	}
+ 
+ 	return 0;
+ }
+ 
+ static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
++//	Not yet
++//	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
++//		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
+ 	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
+-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2000 },
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
+ 	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
+-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER2010 },
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2010 },
+ 	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_5000,
+-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_IGS_CYBER5000 },
++		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_5000 },
+ 	{ 0, }
+ };
+ 
++MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
++
++#ifndef __devexit_p
++#define __devexit_p(x) (x)
++#endif
++
+ static struct pci_driver cyberpro_driver = {
+-	name:		"CyberPro",
+-	probe:		cyberpro_probe,
+-	remove:		__devexit_p(cyberpro_remove),
+-	suspend:	cyberpro_suspend,
+-	resume:		cyberpro_resume,
+-	id_table:	cyberpro_pci_table
++	.name		= "CyberPro",
++	.probe		= cyberpro_pci_probe,
++	.remove		= __devexit_p(cyberpro_pci_remove),
++	.suspend	= cyberpro_pci_suspend,
++	.resume		= cyberpro_pci_resume,
++	.id_table	= cyberpro_pci_table
+ };
+ 
+ /*
+@@ -1768,5 +1973,4 @@
+ 
+ MODULE_AUTHOR("Russell King");
+ MODULE_DESCRIPTION("CyberPro 2000, 2010 and 5000 framebuffer driver");
+-MODULE_DEVICE_TABLE(pci,cyberpro_pci_table);
+ MODULE_LICENSE("GPL");
+--- linux-2.4.25/drivers/video/cyber2000fb.h~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/drivers/video/cyber2000fb.h	2004-03-31 17:15:09.000000000 +0200
+@@ -36,24 +36,55 @@
+ #define debug_printf(x...) do { } while (0)
+ #endif
+ 
+-#define PIXFORMAT_8BPP		0
+-#define PIXFORMAT_16BPP		1
+-#define PIXFORMAT_24BPP		2
+-#define PIXFORMAT_32BPP		3
++#define RAMDAC_RAMPWRDN		0x01
++#define RAMDAC_DAC8BIT		0x02
++#define RAMDAC_VREFEN		0x04
++#define RAMDAC_BYPASS		0x10
++#define RAMDAC_DACPWRDN		0x40
+ 
+-#define VISUALID_256		1
+-#define VISUALID_64K		2
+-#define VISUALID_16M_32		3
+-#define VISUALID_16M		4
+-#define VISUALID_32K		6
++#define EXT_CRT_VRTOFL		0x11
++#define EXT_CRT_VRTOFL_LINECOMP10	0x10
++#define EXT_CRT_VRTOFL_INTERLACE	0x20
+ 
+-#define FUNC_CTL		0x3c
+-#define FUNC_CTL_EXTREGENBL		0x80	/* enable access to 0xbcxxx		*/
++#define EXT_CRT_IRQ		0x12
++#define EXT_CRT_IRQ_ENABLE		0x01
++#define EXT_CRT_IRQ_ACT_HIGH		0x04
+ 
+-#define BIU_BM_CONTROL		0x3e
+-#define BIU_BM_CONTROL_ENABLE		0x01	/* enable bus-master			*/
+-#define BIU_BM_CONTROL_BURST		0x02	/* enable burst				*/
+-#define BIU_BM_CONTROL_BACK2BACK	0x04	/* enable back to back			*/
++#define EXT_CRT_TEST		0x13
++
++#define EXT_SYNC_CTL		0x16
++#define EXT_SYNC_CTL_HS_NORMAL		0x00
++#define EXT_SYNC_CTL_HS_0		0x01
++#define EXT_SYNC_CTL_HS_1		0x02
++#define EXT_SYNC_CTL_HS_HSVS		0x03
++#define EXT_SYNC_CTL_VS_NORMAL		0x00
++#define EXT_SYNC_CTL_VS_0		0x04
++#define EXT_SYNC_CTL_VS_1		0x08
++#define EXT_SYNC_CTL_VS_COMP		0x0c
++
++#define EXT_BUS_CTL		0x30
++#define EXT_BUS_CTL_LIN_1MB		0x00
++#define EXT_BUS_CTL_LIN_2MB		0x01
++#define EXT_BUS_CTL_LIN_4MB		0x02
++#define EXT_BUS_CTL_ZEROWAIT		0x04
++#define EXT_BUS_CTL_PCIBURST_WRITE	0x20
++#define EXT_BUS_CTL_PCIBURST_READ	0x80	/* CyberPro 5000 only */
++
++#define EXT_SEG_WRITE_PTR	0x31
++#define EXT_SEG_READ_PTR	0x32
++#define EXT_BIU_MISC		0x33
++#define EXT_BIU_MISC_LIN_ENABLE		0x01
++#define EXT_BIU_MISC_COP_ENABLE		0x04
++#define EXT_BIU_MISC_COP_BFC		0x08
++
++#define EXT_FUNC_CTL		0x3c
++#define EXT_FUNC_CTL_EXTREGENBL		0x80	/* enable access to 0xbcxxx		*/
++
++#define PCI_BM_CTL		0x3e
++#define PCI_BM_CTL_ENABLE		0x01	/* enable bus-master			*/
++#define PCI_BM_CTL_BURST		0x02	/* enable burst				*/
++#define PCI_BM_CTL_BACK2BACK		0x04	/* enable back to back			*/
++#define PCI_BM_CTL_DUMMY		0x08	/* insert dummy cycle			*/
+ 
+ #define X_V2_VID_MEM_START	0x40
+ #define X_V2_VID_SRC_WIDTH	0x43
+@@ -87,6 +118,19 @@
+ 
+ #define K_CAP_X2_CTL1		0x49
+ 
++#define CURS_H_START		0x50
++#define CURS_H_PRESET		0x52
++#define CURS_V_START		0x53
++#define CURS_V_PRESET		0x55
++#define CURS_CTL		0x56
++
++#define EXT_ATTRIB_CTL		0x57
++#define EXT_ATTRIB_CTL_EXT		0x01
++
++#define EXT_OVERSCAN_RED	0x58
++#define EXT_OVERSCAN_GREEN	0x59
++#define EXT_OVERSCAN_BLUE	0x5a
++
+ #define CAP_X_START		0x60
+ #define CAP_X_END		0x62
+ #define CAP_Y_START		0x64
+@@ -96,46 +140,112 @@
+ #define CAP_DDA_Y_INIT		0x6c
+ #define CAP_DDA_Y_INC		0x6e
+ 
+-#define MEM_CTL1		0x71
++#define EXT_MEM_CTL0		0x70
++#define EXT_MEM_CTL0_7CLK		0x01
++#define EXT_MEM_CTL0_RAS_1		0x02
++#define EXT_MEM_CTL0_RAS2CAS_1		0x04
++#define EXT_MEM_CTL0_MULTCAS		0x08
++#define EXT_MEM_CTL0_ASYM		0x10
++#define EXT_MEM_CTL0_CAS1ON		0x20
++#define EXT_MEM_CTL0_FIFOFLUSH		0x40
++#define EXT_MEM_CTL0_SEQRESET		0x80
+ 
+-#define MEM_CTL2		0x72
++#define EXT_MEM_CTL1		0x71
++#define EXT_MEM_CTL1_PAR		0x00
++#define EXT_MEM_CTL1_SERPAR		0x01
++#define EXT_MEM_CTL1_SER		0x03
++#define EXT_MEM_CTL1_SYNC		0x04
++#define EXT_MEM_CTL1_VRAM		0x08
++#define EXT_MEM_CTL1_4K_REFRESH		0x10
++#define EXT_MEM_CTL1_256Kx4		0x00
++#define EXT_MEM_CTL1_512Kx8		0x40
++#define EXT_MEM_CTL1_1Mx16		0x60
++
++#define EXT_MEM_CTL2		0x72
++#define MEM_CTL2_SIZE_1MB		0x00
+ #define MEM_CTL2_SIZE_2MB		0x01
+ #define MEM_CTL2_SIZE_4MB		0x02
+ #define MEM_CTL2_SIZE_MASK		0x03
+ #define MEM_CTL2_64BIT			0x04
+ 
++#define EXT_HIDDEN_CTL1		0x73
++
+ #define EXT_FIFO_CTL		0x74
+ 
++#define EXT_SEQ_MISC		0x77
++#define EXT_SEQ_MISC_8			0x01
++#define EXT_SEQ_MISC_16_RGB565		0x02
++#define EXT_SEQ_MISC_32			0x03
++#define EXT_SEQ_MISC_24_RGB888		0x04
++#define EXT_SEQ_MISC_16_RGB555		0x06
++#define EXT_SEQ_MISC_8_RGB332		0x09
++#define EXT_SEQ_MISC_16_RGB444		0x0a
++
++#define EXT_HIDDEN_CTL4		0x7a
++
++#define CURS_MEM_START		0x7e		/* bits 23..12 */
++
+ #define CAP_PIP_X_START		0x80
+ #define CAP_PIP_X_END		0x82
+ #define CAP_PIP_Y_START		0x84
+ #define CAP_PIP_Y_END		0x86
+ 
+-#define CAP_NEW_CTL1		0x88
++#define EXT_CAP_CTL1		0x88
+ 
+-#define CAP_NEW_CTL2		0x89
++#define EXT_CAP_CTL2		0x89
++#define EXT_CAP_CTL2_ODDFRAMEIRQ	0x01
++#define EXT_CAP_CTL2_ANYFRAMEIRQ	0x02
+ 
+ #define BM_CTRL0		0x9c
+ #define BM_CTRL1		0x9d
+ 
+-#define CAP_MODE1		0xa4
+-#define CAP_MODE1_8BIT			0x01	/* enable 8bit capture mode		*/
+-#define CAP_MODE1_CCIR656		0x02	/* CCIR656 mode				*/
+-#define CAP_MODE1_IGNOREVGT		0x04	/* ignore VGT				*/
+-#define CAP_MODE1_ALTFIFO		0x10	/* use alternate FIFO for capture	*/
+-#define CAP_MODE1_SWAPUV		0x20	/* swap UV bytes			*/
+-#define CAP_MODE1_MIRRORY		0x40	/* mirror vertically			*/
+-#define CAP_MODE1_MIRRORX		0x80	/* mirror horizontally			*/
++#define EXT_CAP_MODE1		0xa4
++#define EXT_CAP_MODE1_8BIT		0x01	/* enable 8bit capture mode		*/
++#define EXT_CAP_MODE1_CCIR656		0x02	/* CCIR656 mode				*/
++#define EXT_CAP_MODE1_IGNOREVGT		0x04	/* ignore VGT				*/
++#define EXT_CAP_MODE1_ALTFIFO		0x10	/* use alternate FIFO for capture	*/
++#define EXT_CAP_MODE1_SWAPUV		0x20	/* swap UV bytes			*/
++#define EXT_CAP_MODE1_MIRRORY		0x40	/* mirror vertically			*/
++#define EXT_CAP_MODE1_MIRRORX		0x80	/* mirror horizontally			*/
+ 
+-#define DCLK_MULT		0xb0
+-#define DCLK_DIV		0xb1
+-#define DCLK_DIV_VFSEL			0x20
+-#define MCLK_MULT		0xb2
+-#define MCLK_DIV		0xb3
++#define EXT_CAP_MODE2		0xa5
++#define EXT_CAP_MODE2_CCIRINVOE		0x01
++#define EXT_CAP_MODE2_CCIRINVVGT	0x02
++#define EXT_CAP_MODE2_CCIRINVHGT	0x04
++#define EXT_CAP_MODE2_CCIRINVDG		0x08
++#define EXT_CAP_MODE2_DATEND		0x10
++#define EXT_CAP_MODE2_CCIRDGH		0x20
++#define EXT_CAP_MODE2_FIXSONY		0x40
++#define EXT_CAP_MODE2_SYNCFREEZE	0x80
+ 
+-#define CAP_MODE2		0xa5
++#define EXT_TV_CTL		0xae
+ 
+-#define Y_TV_CTL		0xae
++#define EXT_DCLK_MULT		0xb0
++#define EXT_DCLK_DIV		0xb1
++#define EXT_DCLK_DIV_VFSEL		0x20
++#define EXT_MCLK_MULT		0xb2
++#define EXT_MCLK_DIV		0xb3
++
++#define EXT_LATCH1		0xb5
++#define EXT_LATCH1_VAFC_EN		0x01	/* enable VAFC				*/
++
++#define EXT_FEATURE		0xb7
++#define EXT_FEATURE_BUS_MASK		0x07	/* host bus mask			*/
++#define EXT_FEATURE_BUS_PCI		0x00
++#define EXT_FEATURE_BUS_VL_STD		0x04
++#define EXT_FEATURE_BUS_VL_LINEAR	0x05
++#define EXT_FEATURE_1682		0x20	/* IGS 1682 compatibility		*/
++
++#define EXT_LATCH2		0xb6
++#define EXT_LATCH2_I2C_CLKEN		0x10
++#define EXT_LATCH2_I2C_CLK		0x20
++#define EXT_LATCH2_I2C_DATEN		0x40
++#define EXT_LATCH2_I2C_DAT		0x80
++
++#define EXT_XT_CTL		0xbe
++#define EXT_XT_CAP16			0x04
++#define EXT_XT_LINEARFB			0x08
++#define EXT_XT_PAL			0x10
+ 
+ #define EXT_MEM_START		0xc0		/* ext start address 21 bits		*/
+ #define HOR_PHASE_SHIFT		0xc2		/* high 3 bits				*/
+@@ -160,25 +270,37 @@
+ #define EXT_VID_FMT_RGB565		0x02
+ #define EXT_VID_FMT_RGB888_24		0x03
+ #define EXT_VID_FMT_RGB888_32		0x04
++#define EXT_VID_FMT_RGB8		0x05
++#define EXT_VID_FMT_RGB4444		0x06
++#define EXT_VID_FMT_RGB8T		0x07
+ #define EXT_VID_FMT_DUP_PIX_ZOON	0x08	/* duplicate pixel zoom			*/
+ #define EXT_VID_FMT_MOD_3RD_PIX		0x20	/* modify 3rd duplicated pixel		*/
+ #define EXT_VID_FMT_DBL_H_PIX		0x40	/* double horiz pixels			*/
+-#define EXT_VID_FMT_UV128		0x80	/* UV data offset by 128		*/
++#define EXT_VID_FMT_YUV128		0x80	/* YUV data offset by 128		*/
+ 
+ #define EXT_VID_DISP_CTL1	0xdc
+ #define EXT_VID_DISP_CTL1_INTRAM	0x01	/* video pixels go to internal RAM	*/
+ #define EXT_VID_DISP_CTL1_IGNORE_CCOMP	0x02	/* ignore colour compare registers	*/
+ #define EXT_VID_DISP_CTL1_NOCLIP	0x04	/* do not clip to 16235,16240		*/
+ #define EXT_VID_DISP_CTL1_UV_AVG	0x08	/* U/V data is averaged			*/
+-#define EXT_VID_DISP_CTL1_Y128		0x10	/* Y data offset by 128			*/
+-#define EXT_VID_DISP_CTL1_VINTERPOL_OFF	0x20	/* vertical interpolation off		*/
++#define EXT_VID_DISP_CTL1_Y128		0x10	/* Y data offset by 128 (if YUV128 set)	*/
++#define EXT_VID_DISP_CTL1_VINTERPOL_OFF	0x20	/* disable vertical interpolation	*/
+ #define EXT_VID_DISP_CTL1_FULL_WIN	0x40	/* video out window full		*/
+ #define EXT_VID_DISP_CTL1_ENABLE_WINDOW	0x80	/* enable video window			*/
+ 
+ #define EXT_VID_FIFO_CTL1	0xdd
++#define EXT_VID_FIFO_CTL1_OE_HIGH	0x02
++#define EXT_VID_FIFO_CTL1_INTERLEAVE	0x04	/* enable interleaved memory read	*/
++
++#define EXT_ROM_UCB4GH		0xe5
++#define EXT_ROM_UCB4GH_FREEZE		0x02	/* capture frozen			*/
++#define EXT_ROM_UCB4GH_ODDFRAME		0x04	/* 1 = odd frame captured		*/
++#define EXT_ROM_UCB4GH_1HL		0x08	/* first horizonal line after VGT falling edge */
++#define EXT_ROM_UCB4GH_ODD		0x10	/* odd frame indicator			*/
++#define EXT_ROM_UCB4GH_INTSTAT		0x20	/* video interrupt			*/
+ 
+ #define VFAC_CTL1		0xe8
+-#define VFAC_CTL1_CAPTURE		0x01	/* capture enable			*/
++#define VFAC_CTL1_CAPTURE		0x01	/* capture enable (only when VSYNC high)*/
+ #define VFAC_CTL1_VFAC_ENABLE		0x02	/* vfac enable				*/
+ #define VFAC_CTL1_FREEZE_CAPTURE	0x04	/* freeze capture			*/
+ #define VFAC_CTL1_FREEZE_CAPTURE_SYNC	0x08	/* sync freeze capture			*/
+@@ -197,6 +319,13 @@
+ #define VFAC_CTL2_INVERT_OVSYNC		0x80	/* invert other vsync input		*/
+ 
+ #define VFAC_CTL3		0xea
++#define VFAC_CTL3_CAP_LARGE_FIFO	0x01	/* large capture fifo			*/
++#define VFAC_CTL3_CAP_INTERLACE		0x02	/* capture odd and even fields		*/
++#define VFAC_CTL3_CAP_HOLD_4NS		0x00	/* hold capture data for 4ns		*/
++#define VFAC_CTL3_CAP_HOLD_2NS		0x04	/* hold capture data for 2ns		*/
++#define VFAC_CTL3_CAP_HOLD_6NS		0x08	/* hold capture data for 6ns		*/
++#define VFAC_CTL3_CAP_HOLD_0NS		0x0c	/* hold capture data for 0ns		*/
++#define VFAC_CTL3_CHROMAKEY		0x20	/* capture data will be chromakeyed	*/
+ #define VFAC_CTL3_CAP_IRQ		0x40	/* enable capture interrupt		*/
+ 
+ #define CAP_MEM_START		0xeb		/* 18 bits				*/
+@@ -235,26 +364,98 @@
+ #define BM_COUNT		0xbc090		/* read-only				*/
+ 
+ /*
+- * Graphics Co-processor
++ * TV registers
+  */
+-#define CO_CMD_L_PATTERN_FGCOL	0x8000
+-#define CO_CMD_L_INC_LEFT	0x0004
+-#define CO_CMD_L_INC_UP		0x0002
+-
+-#define CO_CMD_H_SRC_PIXMAP	0x2000
+-#define CO_CMD_H_BLITTER	0x0800
++#define TV_VBLANK_EVEN_START	0xbe43c
++#define TV_VBLANK_EVEN_END	0xbe440
++#define TV_VBLANK_ODD_START	0xbe444
++#define TV_VBLANK_ODD_END	0xbe448
++#define TV_SYNC_YGAIN		0xbe44c
++#define TV_UV_GAIN		0xbe450
++#define TV_PED_UVDET		0xbe454
++#define TV_UV_BURST_AMP		0xbe458
++#define TV_HSYNC_START		0xbe45c
++#define TV_HSYNC_END		0xbe460
++#define TV_Y_DELAY1		0xbe464
++#define TV_Y_DELAY2		0xbe468
++#define TV_UV_DELAY1		0xbe46c
++#define TV_BURST_START		0xbe470
++#define TV_BURST_END		0xbe474
++#define TV_HBLANK_START		0xbe478
++#define TV_HBLANK_END		0xbe47c
++#define TV_PED_EVEN_START	0xbe480
++#define TV_PED_EVEN_END		0xbe484
++#define TV_PED_ODD_START	0xbe488
++#define TV_PED_ODD_END		0xbe48c
++#define TV_VSYNC_EVEN_START	0xbe490
++#define TV_VSYNC_EVEN_END	0xbe494
++#define TV_VSYNC_ODD_START	0xbe498
++#define TV_VSYNC_ODD_END	0xbe49c
++#define TV_SCFL			0xbe4a0
++#define TV_SCFH			0xbe4a4
++#define TV_SCP			0xbe4a8
++#define TV_DELAYBYPASS		0xbe4b4
++#define TV_EQL_END		0xbe4bc
++#define TV_SERR_START		0xbe4c0
++#define TV_SERR_END		0xbe4c4
++#define TV_CTL			0xbe4dc	/* reflects a previous register- MVFCLR, MVPCLR etc P241*/
++#define TV_VSYNC_VGA_HS		0xbe4e8
++#define TV_FLICK_XMIN		0xbe514
++#define TV_FLICK_XMAX		0xbe518
++#define TV_FLICK_YMIN		0xbe51c
++#define TV_FLICK_YMAX		0xbe520
+ 
++/*
++ * Graphics Co-processor
++ */
+ #define CO_REG_CONTROL		0xbf011
++#define CO_CTRL_BUSY			0x80
++#define CO_CTRL_CMDFULL			0x04
++#define CO_CTRL_FIFOEMPTY		0x02
++#define CO_CTRL_READY			0x01
++
+ #define CO_REG_SRC_WIDTH	0xbf018
+-#define CO_REG_PIX_FORMAT	0xbf01c
+-#define CO_REG_FORE_MIX		0xbf048
+-#define CO_REG_FOREGROUND	0xbf058
+-#define CO_REG_WIDTH		0xbf060
+-#define CO_REG_HEIGHT		0xbf062
++#define CO_REG_PIXFMT		0xbf01c
++#define CO_PIXFMT_32BPP			0x03
++#define CO_PIXFMT_24BPP			0x02
++#define CO_PIXFMT_16BPP			0x01
++#define CO_PIXFMT_8BPP			0x00
++
++#define CO_REG_FGMIX		0xbf048
++#define CO_FG_MIX_ZERO			0x00
++#define CO_FG_MIX_SRC_AND_DST		0x01
++#define CO_FG_MIX_SRC_AND_NDST		0x02
++#define CO_FG_MIX_SRC			0x03
++#define CO_FG_MIX_NSRC_AND_DST		0x04
++#define CO_FG_MIX_DST			0x05
++#define CO_FG_MIX_SRC_XOR_DST		0x06
++#define CO_FG_MIX_SRC_OR_DST		0x07
++#define CO_FG_MIX_NSRC_AND_NDST		0x08
++#define CO_FG_MIX_SRC_XOR_NDST		0x09
++#define CO_FG_MIX_NDST			0x0a
++#define CO_FG_MIX_SRC_OR_NDST		0x0b
++#define CO_FG_MIX_NSRC			0x0c
++#define CO_FG_MIX_NSRC_OR_DST		0x0d
++#define CO_FG_MIX_NSRC_OR_NDST		0x0e
++#define CO_FG_MIX_ONES			0x0f
++
++#define CO_REG_FGCOLOUR		0xbf058
++#define CO_REG_BGCOLOUR		0xbf05c
++#define CO_REG_PIXWIDTH		0xbf060
++#define CO_REG_PIXHEIGHT	0xbf062
+ #define CO_REG_X_PHASE		0xbf078
+ #define CO_REG_CMD_L		0xbf07c
++#define CO_CMD_L_PATTERN_FGCOL		0x8000
++#define CO_CMD_L_INC_LEFT		0x0004
++#define CO_CMD_L_INC_UP			0x0002
++
+ #define CO_REG_CMD_H		0xbf07e
+-#define CO_REG_SRC_PTR		0xbf170
++#define CO_CMD_H_BGSRCMAP		0x8000	/* otherwise bg colour */
++#define CO_CMD_H_FGSRCMAP		0x2000	/* otherwise fg colour */
++#define CO_CMD_H_BLITTER		0x0800
++
++#define CO_REG_SRC1_PTR		0xbf170
++#define CO_REG_SRC2_PTR		0xbf174
+ #define CO_REG_DEST_PTR		0xbf178
+ #define CO_REG_DEST_WIDTH	0xbf218
+ 
+@@ -269,6 +470,7 @@
+ 	char		*fb;
+ 	char		dev_name[32];
+ 	unsigned int	fb_size;
++	unsigned int	chip_id;
+ 
+ 	/*
+ 	 * The following is a pointer to be passed into the
+@@ -288,10 +490,19 @@
+ 	void (*disable_extregs)(struct cfb_info *);
+ };
+ 
++#define ID_IGA_1682		0
++#define ID_CYBERPRO_2000	1
++#define ID_CYBERPRO_2010	2
++#define ID_CYBERPRO_5000	3
++
++struct fb_var_screeninfo;
++
+ /*
+  * Note! Writing to the Cyber20x0 registers from an interrupt
+  * routine is definitely a bad idea atm.
+  */
+ int cyber2000fb_attach(struct cyberpro_info *info, int idx);
+ void cyber2000fb_detach(int idx);
+-
++void cyber2000fb_enable_extregs(struct cfb_info *cfb);
++void cyber2000fb_disable_extregs(struct cfb_info *cfb);
++void cyber2000fb_get_fb_var(struct cfb_info *cfb, struct fb_var_screeninfo *var);
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/dbmx1fb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,2002 @@
++/******************************************************************************
++	Copyright (C) 2002 Motorola GSG-China
++
++	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.
++*******************************************************************************/
++/*****************************************************************************
++ * File Name:	dbmx1fb.c
++ *
++ * Progammers:	Chen Ning, Zhang Juan
++ *
++ * Date of Creations:	10 DEC,2001
++ *
++ * Synopsis:
++ *
++ * Descirption: DB-MX1 LCD controller Linux frame buffer driver
++ * 		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.
++ *
++ * Modification History:
++ * 10 DEC, 2001, initialization version, frame work for frame buffer driver
++ *
++*******************************************************************************/
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/mm.h>
++#include <linux/tty.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/fb.h>
++#include <linux/delay.h>
++#include <linux/wrapper.h>
++#include <linux/selection.h>
++#include <linux/console.h>
++#include <linux/kd.h>
++#include <linux/vt_kern.h>
++
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/uaccess.h>
++#include <asm/proc/pgtable.h>
++
++#include <video/fbcon.h>
++#include <video/fbcon-mfb.h>
++#include <video/fbcon-cfb4.h>
++#include <video/fbcon-cfb8.h>
++#include <video/fbcon-cfb16.h>
++
++#include "asm/arch/hardware.h"
++#include "asm/arch/platform.h"
++#include "asm/arch/memory.h"
++
++#include "dbmx1fb.h"
++
++#undef SUP_TTY0
++
++#define LCD_PM
++#ifdef LCD_PM
++#include <linux/pm.h>
++struct pm_dev *pm;
++#endif
++
++// PLAM - make sure fbmem.c also has this defined for full screen frame
++// buffer support in SDRAM
++#define FULL_SCREEN
++
++#undef HARDWARE_CURSOR
++// #undef HARDWARE_CURSOR
++#undef DEBUG
++
++
++/********************************************************************************/
++#ifdef DEBUG
++#  define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
++#define FUNC_START	DPRINTK(KERN_ERR"start\n");
++#define FUNC_END	DPRINTK(KERN_ERR"end\n");
++#else
++#  define DPRINTK(fmt, args...)
++#define FUNC_START
++#define FUNC_END
++#endif
++
++#define _IO_ADDRESS(r)		((r)+0xf0000000)
++unsigned int READREG(unsigned int r)
++{
++	volatile unsigned int * reg;
++	reg = (volatile unsigned int*) _IO_ADDRESS(r);
++	return *reg;
++}
++void WRITEREG(unsigned int r, unsigned int val)
++{
++	volatile unsigned int *reg;
++	reg = (volatile unsigned int*) _IO_ADDRESS(r);
++	*reg = val;
++	return;
++}
++
++#define FONT_DATA ((unsigned char *)font->data)
++struct fbcon_font_desc *font;
++
++/* Local LCD controller parameters */
++struct dbmx1fb_par{
++	u_char          *screen_start_address;	/* Screen Start Address */
++	u_char          *v_screen_start_address;/* Virtul Screen Start Address */
++	unsigned long   screen_memory_size;	/* screen memory size */
++	unsigned int    palette_size;
++	unsigned int    max_xres;
++	unsigned int    max_yres;
++	unsigned int    xres;
++	unsigned int    yres;
++	unsigned int    xres_virtual;
++	unsigned int    yres_virtual;
++	unsigned int    max_bpp;
++	unsigned int    bits_per_pixel;
++	unsigned int    currcon;
++	unsigned int    visual;
++	unsigned int 	TFT :1;
++	unsigned int    color :1 ;
++	unsigned int	sharp :1 ;
++
++        unsigned short cfb16[16];
++};
++
++#ifdef HARDWARE_CURSOR
++/* hardware cursor parameters */
++struct dbmx1fb_cursor{
++	//	int	enable;
++		int	startx;
++		int	starty;
++		int	blinkenable;
++		int	blink_rate;
++		int	width;
++		int	height;
++		int	color[3];
++		int	state;
++};
++
++/* Frame buffer of LCD information */
++struct dbmx1fb_info{
++	struct display_switch dispsw;
++	struct dbmx1fb_cursor cursor;
++};
++#endif // HARDWARE_CURSOR
++
++static u_char*	p_framebuffer_memory_address;
++static u_char*	v_framebuffer_memory_address;
++
++/* Fake monspecs to fill in fbinfo structure */
++static struct fb_monspecs monspecs __initdata = {
++	 30000, 70000, 50, 65, 0 	/* Generic */
++};
++
++/* color map initial */
++static unsigned short __attribute__((unused)) color4map[16] = {
++	0x0000, 0x000f,	0x00f0,	0x0f2a,	0x0f00,	0x0f0f,	0x0f88,	0x0ccc,
++	0x0888,	0x00ff,	0x00f8,	0x0f44,	0x0fa6,	0x0f22,	0x0ff0,	0x0fff
++};
++
++static unsigned short gray4map[16] = {
++	0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
++	0x0008, 0x0009, 0x000a, 0x000b, 0x000c,	0x000d,	0x000e,	0x000f
++};
++
++static struct display global_disp;      /* Initial (default) Display Settings */
++static struct fb_info fb_info;
++static struct fb_var_screeninfo init_var = {};
++static struct dbmx1fb_par current_par={ };
++
++/* Frame buffer device API */
++static int  dbmx1fb_get_fix(struct fb_fix_screeninfo *fix, int con,
++		struct fb_info *info);
++static int  dbmx1fb_get_var(struct fb_var_screeninfo *var, int con,
++		struct fb_info *info);
++static int  dbmx1fb_set_var(struct fb_var_screeninfo *var, int con,
++		struct fb_info *info);
++static int  dbmx1fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
++		struct fb_info *info);
++static int  dbmx1fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
++		struct fb_info *info);
++
++/* Interface to the low level driver  */
++static int  dbmx1fb_switch(int con, struct fb_info *info);
++static void dbmx1fb_blank(int blank, struct fb_info *info);
++static int dbmx1fb_updatevar(int con, struct fb_info *info);
++
++/*  Internal routines  */
++static int  _reserve_fb_memory(void);
++static void _install_cmap(int con, struct fb_info *info);
++static void _enable_lcd_controller(void);
++static void _disable_lcd_controller(void);
++static int  _encode_var(struct fb_var_screeninfo *var,
++			struct dbmx1fb_par *par);
++static int  _decode_var(struct fb_var_screeninfo *var,
++                    struct dbmx1fb_par *par);
++
++/* initialization routines */
++static void __init _init_lcd_system(void);
++static int  __init _init_lcd(void);
++static void __init _init_fbinfo(void);
++static int  __init _reserve_fb_memory(void);
++
++/* frame buffer ops */
++static struct fb_ops dbmx1fb_ops = {
++        owner:          THIS_MODULE,
++        fb_get_fix:     dbmx1fb_get_fix,
++        fb_get_var:     dbmx1fb_get_var,
++        fb_set_var:     dbmx1fb_set_var,
++        fb_get_cmap:    dbmx1fb_get_cmap,
++        fb_set_cmap:    dbmx1fb_set_cmap,
++};
++
++#ifdef HARDWARE_CURSOR
++/* Hardware Cursor */
++static void dbmx1fb_cursor(struct display *p, int mode, int x, int y);
++static int dbmx1fb_set_font(struct display *d, int width, int height);
++static UINT8 cursor_color_map[] = {0xf8};
++static void dbmx1fb_set_cursor_state(struct dbmx1fb_info *fb,UINT32 state);
++static void dbmx1fb_set_cursor(struct dbmx1fb_info *fb);
++static void dbmx1fb_set_cursor_blink(struct dbmx1fb_info *fb,int blink);
++
++struct display_switch dbmx1fb_cfb4 = {
++	    setup:              fbcon_cfb4_setup,
++	    bmove:              fbcon_cfb4_bmove,
++	    clear:              fbcon_cfb4_clear,
++	    putc:               fbcon_cfb4_putc,
++	    putcs:              fbcon_cfb4_putcs,
++	    revc:               fbcon_cfb4_revc,
++	    cursor:             dbmx1fb_cursor,
++	    set_font:           dbmx1fb_set_font,
++	    fontwidthmask:      FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(16)
++};
++
++struct display_switch dbmx1fb_cfb8 = {
++	    setup:              fbcon_cfb8_setup,
++	    bmove:              fbcon_cfb8_bmove,
++	    clear:              fbcon_cfb8_clear,
++	    putc:               fbcon_cfb8_putc,
++	    putcs:              fbcon_cfb8_putcs,
++	    revc:               fbcon_cfb8_revc,
++	    cursor:             dbmx1fb_cursor,
++	    set_font:           dbmx1fb_set_font,
++	    fontwidthmask:      FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(16)
++};
++
++struct display_switch dbmx1fb_cfb16 = {
++	    setup:              fbcon_cfb16_setup,
++	    bmove:              fbcon_cfb16_bmove,
++	    clear:              fbcon_cfb16_clear,
++	    putc:               fbcon_cfb16_putc,
++	    putcs:              fbcon_cfb16_putcs,
++	    revc:               fbcon_cfb16_revc,
++	    cursor:             dbmx1fb_cursor,
++	    set_font:           dbmx1fb_set_font,
++	    fontwidthmask:      FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(16)
++};
++#endif // HARDWARE_CURSOR
++
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_getcolreg()
++ *
++ * Input: 	regno	: Color register ID
++ *		red	: Color map red[]
++ *		green	: Color map green[]
++ *		blue	: Color map blue[]
++ *	transparent	: Flag
++ *		info	: Fb_info database
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Description: Transfer to fb_xxx_cmap handlers as parameters to
++ *		control color registers
++ *
++ * Modification History:
++ *	10 DEC,2001, Chen Ning
++******************************************************************************/
++#define RED	0xf00
++#define GREEN	0xf0
++#define BLUE	0x0f
++static int dbmx1fb_getcolreg(u_int regno, u_int *red, u_int *green,
++	u_int *blue, u_int *trans, struct fb_info *info)
++{
++	unsigned int val;
++
++	FUNC_START;
++
++	if(regno >= current_par.palette_size)
++		return 1;
++
++	val = READREG(DBMX1_LCD_MAPRAM+regno);
++
++	if((current_par.bits_per_pixel == 4)&&(!current_par.color))
++	{
++		*red = *green = *blue = (val & BLUE) << 4;//TODO:
++		*trans = 0;
++	}
++	else
++	{
++		*red = (val & RED) << 4;
++		*green = (val & GREEN) << 8;
++		*blue = (val & BLUE) << 12;
++		*trans = 0;
++	}
++
++	FUNC_END;
++	return 0;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_setcolreg()
++ *
++ * Input: 	regno	: Color register ID
++ *		red	: Color map red[]
++ *		green	: Color map green[]
++ *		blue	: Color map blue[]
++ *	transparent	: Flag
++ *		info	: Fb_info database
++ *
++ * Value Returned: int 	: Return status.If no error, return 0.
++ *
++ * Description: Transfer to fb_xxx_cmap handlers as parameters to
++ *		control color registers
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++ *****************************************************************************/
++static int
++dbmx1fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++		u_int trans, struct fb_info *info)
++{
++	unsigned int val=0;
++	FUNC_START
++	if(regno >= current_par.palette_size)
++		return 1;
++
++	if((current_par.bits_per_pixel == 4)&&(!current_par.color))
++		val = (blue & 0x00f) << 12;//TODO:
++	else
++	{
++		val = (blue >> 12 ) & BLUE;
++		val |= (green >> 8) & GREEN;
++		val |= (red >> 4) & RED;
++	}
++
++        if (regno < 16) {
++		current_par.cfb16[regno] =
++			regno | regno << 5 | regno << 10;
++}
++
++	WRITEREG(DBMX1_LCD_MAPRAM+regno, val);
++	FUNC_END;
++	return 0;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_get_cmap()
++ *
++ * Input: 	cmap	: Ouput data pointer
++ *		kspc   	: Kernel space flag
++ *		con    	: Console ID
++ *		info	: Frame buffer information
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Description: Data is copied from hardware or local or system DISPAY,
++ *		and copied to cmap.
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int
++dbmx1fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
++		                 struct fb_info *info)
++{
++        int err = 0;
++
++	FUNC_START;
++        DPRINTK("current_par.visual=%d\n", current_par.visual);
++        if (con == current_par.currcon)
++		err = fb_get_cmap(cmap, kspc, dbmx1fb_getcolreg, info);
++        else if (fb_display[con].cmap.len)
++		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
++        else
++		fb_copy_cmap(fb_default_cmap(current_par.palette_size),
++                             cmap, kspc ? 0 : 2);
++        FUNC_END;
++	return err;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_set_cmap()
++ *
++ * Input: 	cmap	: Ouput data pointer
++ *		kspc   	: Kernel space flag
++ *		con    	: Console ID
++ *		info	: Frame buffer information
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Description: Copy data from cmap and copy to DISPLAY. If DISPLAy has no cmap,
++ * 		allocate memory for it. If DISPLAY is current console and visible,
++ * 		then hardware color map shall be set.
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int
++dbmx1fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
++{
++        int err = 0;
++
++	FUNC_START;
++        DPRINTK("current_par.visual=%d\n", current_par.visual);
++        if (!fb_display[con].cmap.len)
++                err = fb_alloc_cmap(&fb_display[con].cmap,
++                                    current_par.palette_size, 0);
++
++        if (!err) {
++                if (con == current_par.currcon)
++                        err = fb_set_cmap(cmap, kspc, dbmx1fb_setcolreg,
++                                          info);
++                fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
++        }
++	FUNC_END;
++        return err;
++}
++/*****************************************************************************
++ * Function Name: dbmx1fb_get_var()
++ *
++ * Input: 	var	: Iuput data pointer
++ *		con	: Console ID
++ *		info	: Frame buffer information
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Functions Called: 	_encode_var()
++ *
++ * Description: Get color map from current, or global display[console]
++ * 		used by ioctl
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int
++dbmx1fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++        if (con == -1) {
++		_encode_var(var, &current_par);
++        } else
++		*var = fb_display[con].var;
++        return 0;
++}
++
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_updatevar()
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Fill in display switch with LCD information,
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int dbmx1fb_updatevar(int con, struct fb_info *info)
++{
++        DPRINTK("entered\n");
++        return 0;
++}
++
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_set_dispsw()
++ *
++ * Input: 	display		: Iuput data pointer
++ *		dbmx1fb_info   	: Frame buffer of LCD information
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Fill in display switch with LCD information,
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void dbmx1fb_set_dispsw(struct display *disp
++#ifdef HARDWARE_CURSOR
++		,struct dbmx1fb_info *info
++#endif
++		)
++{
++	FUNC_START;
++	switch (disp->var.bits_per_pixel) {
++#ifdef HARDWARE_CURSOR
++#ifdef FBCON_HAS_CFB4
++		case 4:
++                    fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR;
++		    info->dispsw = dbmx1fb_cfb4;
++		    disp->dispsw = &info->dispsw;
++		    disp->dispsw_data = NULL;
++		    break;
++#endif
++#ifdef FBCON_HAS_CFB8
++		case 8:
++                    fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR;
++		    info->dispsw = dbmx1fb_cfb8;
++		    disp->dispsw = &info->dispsw;
++		    disp->dispsw_data = NULL;
++		    break;
++#endif
++#ifdef FBCON_HAS_CFB16
++		case 12:
++		case 16:
++                    fb_info.fix.visual = FB_VISUAL_DIRECTCOLOR;
++		    info->dispsw = dbmx1fb_cfb16;
++		    disp->dispsw = &info->dispsw;
++		    disp->dispsw_data = current_par.cfb16;
++		    break;
++#endif
++#else //!HARDWARE_CURSOR
++		    /* first step disable the hardware cursor */
++#ifdef FBCON_HAS_CFB4
++		case 4:
++                    fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR;
++		    disp->dispsw = &fbcon_cfb4;
++		    disp->dispsw_data = NULL;
++		    break;
++#endif
++#ifdef FBCON_HAS_CFB8
++		case 8:
++                    fb_info.fix.visual = FB_VISUAL_PSEUDOCOLOR;
++		    disp->dispsw = &fbcon_cfb8;
++		    disp->dispsw_data = NULL;
++		    break;
++#endif
++#ifdef FBCON_HAS_CFB16
++		case 12:
++		case 16:
++                    fb_info.fix.visual = FB_VISUAL_DIRECTCOLOR;
++		    disp->dispsw = &fbcon_cfb16;
++		    disp->dispsw_data = current_par.cfb16;
++		    break;
++#endif
++
++#endif // HARDWARE_CURSOR
++		default:
++		    disp->dispsw = &fbcon_dummy;
++		    disp->dispsw_data = NULL;
++	}
++#ifdef HARDWARE_CURSOR
++	if (&info->cursor)
++	{
++		info->dispsw.cursor = dbmx1fb_cursor;
++		info->dispsw.set_font = dbmx1fb_set_font;
++	}
++#endif // HARDWARE_CURSOR
++	FUNC_END;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_set_var()
++ *
++ * Input: 	var	: Iuput data pointer
++ *		con	: Console ID
++ *		info	: Frame buffer information
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Functions Called: 	dbmx1fb_decode_var()
++ * 			dbmx1fb_encode_var()
++ *  			dbmx1fb_set_dispsw()
++ *
++ * Description: set current_par by var, also set display data, specially the console
++ * 		related fileops, then enable the lcd controller, and set cmap to
++ * 		hardware.
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int
++dbmx1fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
++{
++	struct display *display;
++	int err, chgvar = 0;
++	struct dbmx1fb_par par;
++
++	FUNC_START;
++	if (con >= 0)
++		display = &fb_display[con]; /* Display settings for console */
++        else
++                display = &global_disp;     /* Default display settings */
++
++        /* Decode var contents into a par structure, adjusting any */
++        /* out of range values. */
++        if ((err = _decode_var(var, &par))){
++		DPRINTK("decode var error!");
++                return err;
++	}
++
++	// Store adjusted par values into var structure
++	_encode_var(var, &par);
++
++	if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
++		return 0;
++
++	else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) &&
++			((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN))
++		return -EINVAL;
++
++	if (con >= 0) {
++		if ((display->var.xres != var->xres) ||
++			(display->var.yres != var->yres) ||
++			(display->var.xres_virtual != var->xres_virtual) ||
++			(display->var.yres_virtual != var->yres_virtual) ||
++			(display->var.sync != var->sync)                 ||
++			(display->var.bits_per_pixel != var->bits_per_pixel) ||
++			(memcmp(&display->var.red, &var->red, sizeof(var->red))) ||
++			(memcmp(&display->var.green, &var->green, sizeof(var->green)
++				)) ||
++			(memcmp(&display->var.blue, &var->blue, sizeof(var->blue))))
++			chgvar = 1;
++	}
++
++	display->var 		= *var;
++	display->screen_base    = par.v_screen_start_address;
++	display->visual         = par.visual;
++	display->type           = FB_TYPE_PACKED_PIXELS;
++	display->type_aux       = 0;
++	display->ypanstep       = 0;
++	display->ywrapstep      = 0;
++	display->line_length    =
++	display->next_line      = (var->xres * 16) / 8;
++
++	display->can_soft_blank = 1;
++	display->inverse        = 0;
++
++	dbmx1fb_set_dispsw(display
++#ifdef HARDWARE_CURSOR
++			, (struct dbmx1fb_info *)info
++#endif // HARDWARE_CURSOR
++			);
++
++	/* If the console has changed and the console has defined */
++	/* a changevar function, call that function. */
++	if (chgvar && info && info->changevar)
++		info->changevar(con);	// TODO:
++
++	/* If the current console is selected and it's not truecolor,
++	*  update the palette
++	*/
++	if ((con == current_par.currcon) &&
++			(current_par.visual != FB_VISUAL_TRUECOLOR)) {
++		struct fb_cmap *cmap;
++
++		current_par = par;	// TODO ?
++		if (display->cmap.len)
++			cmap = &display->cmap;
++		else
++			cmap = fb_default_cmap(current_par.palette_size);
++
++		fb_set_cmap(cmap, 1, dbmx1fb_setcolreg, info);
++	}
++
++	/* If the current console is selected, activate the new var. */
++	if (con == current_par.currcon){
++		init_var = *var;	// TODO:gcc support structure copy?
++		_enable_lcd_controller();
++	}
++
++	FUNC_END;
++	return 0;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_get_fix()
++ *
++ * Input: 	fix	: Ouput data pointer
++ *		con	: Console ID
++ *		info	: Frame buffer information
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Functions Called: VOID
++ *
++ * Description: get fix from display data, current_par data
++ * 		used by ioctl
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int
++dbmx1fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
++{
++        struct display *display;
++
++	FUNC_START;
++        memset(fix, 0, sizeof(struct fb_fix_screeninfo));
++        strcpy(fix->id, DBMX1_NAME);
++
++        if (con >= 0)
++        {
++                DPRINTK("Using console specific display for con=%d\n",con);
++                display = &fb_display[con];  /* Display settings for console */
++        }
++        else
++                display = &global_disp;      /* Default display settings */
++
++        fix->smem_start  = (unsigned long)current_par.screen_start_address;
++        fix->smem_len    = current_par.screen_memory_size;
++//printk("dbmx1fb_get_fix, pointer fix: 0x%08x, smem_len: 0x%08x\n",fix,fix->smem_len);
++        fix->type        = display->type;
++        fix->type_aux    = display->type_aux;
++        fix->xpanstep    = 0;
++        fix->ypanstep    = display->ypanstep;
++        fix->ywrapstep   = display->ywrapstep;
++        fix->visual      = display->visual;
++        fix->line_length = display->line_length;
++        fix->accel       = FB_ACCEL_NONE;
++
++	FUNC_END;
++        return 0;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_inter_handler()
++ *
++ * Input:
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Interrupt handler
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void dbmx1fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs)
++{
++	unsigned int intsr;
++	FUNC_START;
++	intsr = READREG(DBMX1_LCD_INTSR);		// read to clear status
++	printk(KERN_ERR"lcd interrupt!\n");
++	FUNC_END;
++	// handle
++}
++
++#ifdef LCD_PM
++#define PM_OPT " [pm]"
++#define LCD_PMST_RESUME 0
++#define LCD_PMST_SUSPEND 1
++static unsigned int lcd_pm_status = LCD_PMST_RESUME;
++
++void lcd_pm_resume(void)
++{
++	if(lcd_pm_status == LCD_PMST_RESUME)
++		return;
++	WRITEREG(0x21c21c, 0x10000);	// light on
++	WRITEREG(DBMX1_LCD_REFMCR, 0xf000002);
++	WRITEREG(DBMX1_LCD_PWMR, 0x00a9008a);
++	lcd_pm_status = LCD_PMST_RESUME;
++//	printk(KERN_ERR"lcd resumed\n");
++}
++
++void lcd_pm_suspend(void)
++{
++	unsigned val;
++	if(lcd_pm_status == LCD_PMST_SUSPEND)
++		return;
++	val = READREG(0x20502c);
++	val |= 0x8000;
++	WRITEREG(0x20502c, val);
++	//To produce enough dealy time before trun off the LCDC.
++	for(val=0;val<=600000;val++);
++	val = READREG(0x21c21c);
++	val &= ~0x10000;
++	WRITEREG(0x21c21c, val);	// light off
++	WRITEREG(DBMX1_LCD_REFMCR, 0x0);
++	lcd_pm_status = LCD_PMST_SUSPEND;
++//	printk(KERN_ERR"lcd suspended\n");
++}
++
++int lcd_pm_handler(struct pm_dev *dev, pm_request_t rqst, void *data)
++{
++	switch(rqst){
++		case PM_RESUME:
++			lcd_pm_resume();
++			break;
++		case PM_SUSPEND:
++			lcd_pm_suspend();
++			break;
++		default:
++			break;
++		}
++	return 0;
++}
++#endif // LCD_PM
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_init()
++ *
++ * Input: VOID
++ *
++ * Value Returned: int 		: Return status.If no error, return 0.
++ *
++ * Functions Called: 	_init_fbinfo()
++ *			disable_irq()
++ *	 		enable_irq()
++ *			_init_lcd()
++ *			dbmx1fb_init_cursor()
++ *
++ * Description: initialization module, all of init routine's entry point
++ * 		initialize fb_info, init_var, current_par
++ * 		and setup interrupt, memory, lcd controller
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++int __init dbmx1fb_init(void)
++{
++	int ret;
++#ifdef HARDWARE_CURSOR
++	struct dbmx1fb_info *info;
++#endif // HARDWARE_CURSOR
++
++	_init_lcd_system();
++
++	_init_fbinfo();
++
++	if ((ret = _reserve_fb_memory()) != 0){
++		printk(KERN_ERR"failed for reserved DBMX frame buffer memory\n");
++		return ret;
++	}
++
++#if 0
++	if (request_irq(IRQ_LCD,
++				dbmx1fb_inter_handler,
++				SA_INTERRUPT,
++				DEV_NAME,
++				NULL) != 0) {
++		printk(KERN_ERR "dbmx1fb: failed in request_irq\n");
++		return -EBUSY;
++	}
++
++	disable_irq(IRQ_LCD);
++#endif
++        if (dbmx1fb_set_var(&init_var, -1, &fb_info))
++		; //current_par.allow_modeset = 0;
++
++	_init_lcd();
++	_enable_lcd_controller();
++
++#ifdef HARDWARE_CURSOR
++	info = kmalloc(sizeof(struct dbmx1fb_info), GFP_KERNEL);
++	if(info == NULL){
++		printk(KERN_ERR"can not kmalloc dbmx1fb_info memory\n");
++		return -1;
++	}
++
++	memset(info,0,sizeof(struct dbmx1fb_info));
++
++	info->cursor.blink_rate = DEFAULT_CURSOR_BLINK_RATE;
++	info->cursor.blinkenable = 0;
++	info->cursor.state = LCD_CURSOR_OFF;
++	WRITEREG(DBMX1_LCD_LCXYP,0x90010001);
++	WRITEREG(DBMX1_LCD_CURBLKCR,0x1F1F0000);
++	WRITEREG(DBMX1_LCD_LCHCC,0x0000F800);
++
++	DPRINTK(KERN_ERR"LCXYP = %x\n",READREG(DBMX1_LCD_LCXYP));
++	DPRINTK(KERN_ERR"CURBLICR = %x\n",READREG(DBMX1_LCD_CURBLKCR));
++	DPRINTK(KERN_ERR"LCHCC = %x\n",READREG(DBMX1_LCD_LCHCC));
++
++	//dbmx1fb_set_cursor(info);
++	//info->cursor = dbmx1fb_init_cursor(info);
++#endif // HARDWARE_CURSOR
++
++	register_framebuffer(&fb_info);
++
++#ifdef LCD_PM
++	pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, lcd_pm_handler);
++	printk("register LCD power management successfully.\n");
++#endif
++#if 0
++	enable_irq(IRQ_LCD);	// TODO:
++#endif
++	/* This driver cannot be unloaded at the moment */
++	MOD_INC_USE_COUNT;
++
++	return 0;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_setup()
++ *
++ * Input: info	: VOID
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Functions Called: VOID
++ *
++ * Description: basically, this routine used to parse command line parameters, which
++ * 		is initialization parameters for lcd controller, such as freq, xres,
++ * 		yres, and so on
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++int __init dbmx1fb_setup(char *options)
++{
++	FUNC_START;
++	FUNC_END;
++	return 0;
++}
++
++/*****************************************************************************
++ * Function Name: _init_fbinfo()
++ *
++ * Input: VOID
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: while 16bpp is used to store a 12 bits pixels packet, but
++ * 		it is not a really 16bpp system. maybe in-compatiable with
++ * 		other system or GUI.There are some field in var which specify
++ *		the red/green/blue offset in a 16bit word, just little endian is
++ * 		concerned
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void __init _init_fbinfo(void)
++{
++// Thomas Wong add this for debugging
++//	*((unsigned char *)0xF5000008) = '&';
++
++	FUNC_START;
++        strcpy(fb_info.modename, DBMX1_NAME);
++        strcpy(fb_info.fontname, "Acorn8x8");
++
++        fb_info.node            = -1;
++        fb_info.flags           = FBINFO_FLAG_DEFAULT;	// Low-level driver is not a module
++        fb_info.fbops           = &dbmx1fb_ops;
++        fb_info.monspecs        = monspecs;
++        fb_info.disp            = &global_disp;
++        fb_info.changevar       = NULL;
++        fb_info.switch_con      = dbmx1fb_switch;
++        fb_info.updatevar       = dbmx1fb_updatevar;
++        fb_info.blank           = dbmx1fb_blank;
++
++/*
++ * * setup initial parameters
++ * */
++        memset(&init_var, 0, sizeof(init_var));
++
++        init_var.transp.length  = 0;
++        init_var.nonstd         = 0;
++        init_var.activate       = FB_ACTIVATE_NOW;
++        init_var.xoffset        = 0;
++        init_var.yoffset        = 0;
++        init_var.height         = -1;
++        init_var.width          = -1;
++        init_var.vmode          = FB_VMODE_NONINTERLACED;
++
++        if (1) {
++                current_par.max_xres    = LCD_MAXX;
++                current_par.max_yres    = LCD_MAXY;
++                current_par.max_bpp     = LCD_MAX_BPP;		// 12
++                init_var.red.length     = 5;  // 5;
++                init_var.green.length   = 6;  // 6;
++                init_var.blue.length    = 5;  // 5;
++#ifdef __LITTLE_ENDIAN
++                init_var.red.offset    = 11;
++                init_var.green.offset  = 5;
++                init_var.blue.offset   = 0;
++#endif //__LITTLE_ENDIAN
++		init_var.grayscale      = 16;	// i suppose, TODO
++                init_var.sync           = 0;
++                init_var.pixclock       = 171521;	// TODO
++        }
++
++        current_par.screen_start_address       = NULL;
++        current_par.v_screen_start_address       = NULL;
++        current_par.screen_memory_size         = MAX_PIXEL_MEM_SIZE;
++// Thomas Wong add this for debugging
++//printk("_init_fbinfo, pointer to current_par: 0x%08x, screen_memory_size: 0x%08x\n", &current_par,current_par.screen_memory_size);
++        current_par.currcon             = -1;	// TODO
++
++        init_var.xres                   = current_par.max_xres;
++        init_var.yres                   = current_par.max_yres;
++        init_var.xres_virtual           = init_var.xres;
++        init_var.yres_virtual           = init_var.yres;
++        init_var.bits_per_pixel         = current_par.max_bpp;
++
++	FUNC_END;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_blank()
++ *
++ * Input: 	blank	: Blank flag
++ *		info	: Frame buffer database
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: 	_enable_lcd_controller()
++ * 			_disable_lcd_controller()
++ *
++ * Description: blank the screen, if blank, disable lcd controller, while if no blank
++ * 		set cmap and enable lcd controller
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void
++dbmx1fb_blank(int blank, struct fb_info *info)
++{
++#ifdef SUP_TTY0
++        int i;
++
++	FUNC_START;
++        DPRINTK("blank=%d info->modename=%s\n", blank, info->modename);
++        if (blank) {
++                if (current_par.visual != FB_VISUAL_TRUECOLOR)
++  	              for (i = 0; i < current_par.palette_size; i++)
++			      ; // TODO
++//printk("Disable LCD\n");
++					 _disable_lcd_controller();
++        }
++        else {
++                if (current_par.visual != FB_VISUAL_TRUECOLOR)
++                	dbmx1fb_set_cmap(&fb_display[current_par.currcon].cmap,
++					1,
++					current_par.currcon, info);
++//printk("Enable LCD\n");
++                _enable_lcd_controller();
++        }
++	FUNC_END;
++#endif //SUP_TTY0
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_switch()
++ *
++ * Input:  	info	: Frame buffer database
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called:
++ *
++ * Description: Switch to another console
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int dbmx1fb_switch(int con, struct fb_info *info)
++{
++	FUNC_START;
++	if (current_par.visual != FB_VISUAL_TRUECOLOR) {
++		struct fb_cmap *cmap;
++	        if (current_par.currcon >= 0) {
++	        	// Get the colormap for the selected console
++			cmap = &fb_display[current_par.currcon].cmap;
++
++		if (cmap->len)
++			fb_get_cmap(cmap, 1, dbmx1fb_getcolreg, info);
++		}
++	}
++
++	current_par.currcon = con;
++	fb_display[con].var.activate = FB_ACTIVATE_NOW;
++	dbmx1fb_set_var(&fb_display[con].var, con, info);
++	FUNC_END;
++	return 0;
++}
++
++/*****************************************************************************
++ * Function Name: _encode_par()
++ *
++ * Input:  	var	: Input var data
++ *		par	: LCD controller parameters
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called:
++ *
++ * Description: use current_par to set a var structure
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int _encode_var(struct fb_var_screeninfo *var,
++		struct dbmx1fb_par *par)
++{
++        // Don't know if really want to zero var on entry.
++	// Look at set_var to see.  If so, may need to add extra params to par
++
++	//      memset(var, 0, sizeof(struct fb_var_screeninfo));
++
++	var->xres = par->xres;
++	var->yres = par->yres;
++	var->xres_virtual = par->xres_virtual;
++	var->yres_virtual = par->yres_virtual;
++
++	var->bits_per_pixel = par->bits_per_pixel;
++
++	DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
++	switch(var->bits_per_pixel) {
++	case 2:
++	case 4:
++	case 8:
++		var->red.length    = 4;
++		var->green         = var->red;
++		var->blue          = var->red;
++		var->transp.length = 0;
++		break;
++	case 12:          // This case should differ for Active/Passive mode
++	case 16:
++		if (1) {
++			var->red.length    = 4;
++			var->blue.length   = 4;
++			var->green.length  = 4;
++			var->transp.length = 0;
++#ifdef __LITTLE_ENDIAN
++			var->red.offset    = 8;
++			var->green.offset  = 4;
++			var->blue.offset   = 0;
++			var->transp.offset = 0;
++#endif // __LITTLE_ENDIAN
++		}
++		else
++		{
++			var->red.length    = 5;
++			var->blue.length   = 5;
++			var->green.length  = 6;
++		    	var->transp.length = 0;
++		    	var->red.offset    = 11;
++	        	var->green.offset  = 5;
++		    	var->blue.offset   = 0;
++	       		var->transp.offset = 0;
++	    	}
++	        break;
++	  }
++
++        return 0;
++}
++
++/*****************************************************************************
++ * Function Name: _decode_var
++ *
++ * Input:  	var	: Input var data
++ *		par	: LCD controller parameters
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Get the video params out of 'var'. If a value doesn't fit,
++ * 		round it up,if it's too big, return -EINVAL.
++ *
++ * Cautions: Round up in the following order: bits_per_pixel, xres,
++ * 	yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
++ * 	bitfields, horizontal timing, vertical timing.
++ *
++ * Modification History:
++ *	10 DEC,2001, Chen Ning
++******************************************************************************/
++static int _decode_var(struct fb_var_screeninfo *var,
++                    struct dbmx1fb_par *par)
++{
++	*par = current_par;
++
++	if ((par->xres = var->xres) < MIN_XRES)
++		par->xres = MIN_XRES;
++	if ((par->yres = var->yres) < MIN_YRES)
++		par->yres = MIN_YRES;
++	if (par->xres > current_par.max_xres)
++		par->xres = current_par.max_xres;
++	if (par->yres > current_par.max_yres)
++		par->yres = current_par.max_yres;
++	par->xres_virtual =
++		var->xres_virtual < par->xres ? par->xres : var->xres_virtual;
++        par->yres_virtual =
++		var->yres_virtual < par->yres ? par->yres : var->yres_virtual;
++        par->bits_per_pixel = var->bits_per_pixel;
++
++	switch (par->bits_per_pixel) {
++#ifdef FBCON_HAS_CFB4
++        case 4:
++		par->visual = FB_VISUAL_PSEUDOCOLOR;
++		par->palette_size = 16;
++                break;
++#endif
++#ifdef FBCON_HAS_CFB8
++	case 8:
++		par->visual = FB_VISUAL_PSEUDOCOLOR;
++		par->palette_size = 256;
++		break;
++#endif
++#ifdef FBCON_HAS_CFB16
++	case 12: 	// RGB 444
++	case 16:  	/* RGB 565 */
++		par->visual = FB_VISUAL_TRUECOLOR;
++		par->palette_size = 0;
++		break;
++#endif
++	default:
++		return -EINVAL;
++	}
++
++	par->screen_start_address  =(u_char*)(
++			(u_long)p_framebuffer_memory_address+PAGE_SIZE);
++	par->v_screen_start_address =(u_char*)(
++			(u_long)v_framebuffer_memory_address+PAGE_SIZE);
++
++// Thomas Wong - try to change start address here (map to SRAM, instead of SDRAM)
++#ifndef FULL_SCREEN
++	par->screen_start_address  =(u_char*)(0x00300000);
++	par->v_screen_start_address =(u_char*)(0xF0300000);
++#endif
++
++//	par->screen_start_address  =(u_char*)(0x0BE00000);
++//	par->v_screen_start_address =(u_char*)(0xFBE00000);
++
++//	par->screen_start_address  =(u_char*)(0x12000000);
++//	par->v_screen_start_address =(u_char*)(0xF2000000);
++
++	return 0;
++}
++
++
++/*****************************************************************************
++ * Function Name: _reserve_fb_memory()
++ *
++ * Input: VOID
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called:
++ *
++ * Description: get data out of var structure and set related LCD controller registers
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int __init _reserve_fb_memory(void)
++{
++        u_int  required_pages;
++        u_int  extra_pages;
++        u_int  order;
++        struct page *page;
++        char   *allocated_region;
++
++	DPRINTK("frame buffer memory size = %x\n", (unsigned int)ALLOCATED_FB_MEM_SIZE);
++        if (v_framebuffer_memory_address != NULL)
++                return -EINVAL;
++
++        /* Find order required to allocate enough memory for framebuffer */
++        required_pages = ALLOCATED_FB_MEM_SIZE >> PAGE_SHIFT;
++        for (order = 0 ; required_pages >> order ; order++) {;}
++        extra_pages = (1 << order) - required_pages;
++
++        if ((allocated_region =
++             	(char *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)) == NULL){
++
++		DPRINTK("can not allocated memory\n");
++           	return -ENOMEM;
++	}
++
++
++        v_framebuffer_memory_address = (u_char *)allocated_region +
++		(extra_pages << PAGE_SHIFT);
++        p_framebuffer_memory_address = (u_char *)__virt_to_phys(
++			(u_long)v_framebuffer_memory_address);
++#if 0
++	printk(KERN_ERR"Frame buffer __get_free_pages vd:= %x, pd= %x",
++			(unsigned int)v_framebuffer_memory_address,
++			(unsigned int)p_framebuffer_memory_address);
++#endif
++        /* Free all pages that we don't need but were given to us because */
++        /* __get_free_pages() works on powers of 2. */
++        for (;extra_pages;extra_pages--)
++          free_page((u_int)allocated_region + ((extra_pages-1) << PAGE_SHIFT));
++
++	/* Set reserved flag for fb memory to allow it to be remapped into */
++        /* user space by the common fbmem driver using remap_page_range(). */
++        for(page = virt_to_page(v_framebuffer_memory_address);
++            page < virt_to_page(v_framebuffer_memory_address
++		    + ALLOCATED_FB_MEM_SIZE);
++	    page++)
++		mem_map_reserve(page);
++#if 0
++        /* Remap the fb memory to a non-buffered, non-cached region */
++        v_framebuffer_memory_address = (u_char *)__ioremap(
++			(u_long)p_framebuffer_memory_address,
++			ALLOCATED_FB_MEM_SIZE,
++			L_PTE_PRESENT 	|
++			L_PTE_YOUNG 	|
++			L_PTE_DIRTY 	|
++			L_PTE_WRITE);
++#endif
++	current_par.screen_start_address  =(u_char*)(
++			(u_long)p_framebuffer_memory_address+PAGE_SIZE);
++	current_par.v_screen_start_address =(u_char*)(
++			(u_long)v_framebuffer_memory_address+PAGE_SIZE);
++
++	DPRINTK("physical screen start addres: %x\n",
++			(u_long)p_framebuffer_memory_address+PAGE_SIZE);
++
++#ifndef FULL_SCREEN
++// Thomas Wong - we'll try to change the screen start address here
++//	printk("\n\rMap LCD screen to SDRAM.\n\r");
++
++	printk("\n\rMap LCD screen to embedded SRAM.\n\r");
++	current_par.screen_start_address  =(u_char*)(0x00300000);
++	current_par.v_screen_start_address =(u_char*)(0xF0300000);
++#endif
++
++//	printk("\n\rMap LCD screen to SDRAM 0xFBE00000.\n\r");
++//	current_par.screen_start_address  =(u_char*)(0x0BE00000);
++//	current_par.v_screen_start_address =(u_char*)(0xFBE00000);
++
++//	printk("\n\rMap LCD screen to SRAM 0x12000000.\n\r");
++//	current_par.screen_start_address  =(u_char*)(0x12000000);
++//	current_par.v_screen_start_address =(u_char*)(0xF2000000);
++
++        return (v_framebuffer_memory_address == NULL ? -EINVAL : 0);
++}
++
++/*****************************************************************************
++ * Function Name: _enable_lcd_controller()
++ *
++ * Input: VOID
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called:
++ *
++ * Description: enable Lcd controller, setup registers,
++ *		base on current_par value
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void _enable_lcd_controller(void)
++{
++	unsigned int val;
++#if 0
++	int i;
++	val =0;
++
++	FUNC_START;
++	_decode_var(&init_var, &current_par);
++
++	val = current_par.xres/16;
++	val <<= 20;
++	val += current_par.yres;
++	WRITEREG(DBMX1_LCD_XYMAX, val);
++
++	val=0;
++	val=current_par.xres_virtual /2;
++	WRITEREG(DBMX1_LCD_VPW, val);
++
++	switch(current_par.bits_per_pixel ){
++	case 4:	// for gray only
++		for(i=0; i<16; i++){
++			WRITEREG(DBMX1_LCD_MAPRAM+i, gray4map[i]);
++		}
++		WRITEREG(DBMX1_LCD_PANELCFG, PANELCFG_VAL_4);
++		WRITEREG(DBMX1_LCD_VCFG, VCFG_VAL_4);
++		WRITEREG(DBMX1_LCD_HCFG, HCFG_VAL_4);
++		WRITEREG(DBMX1_LCD_INTCR, INTCR_VAL_4);	// no interrupt
++		WRITEREG(DBMX1_LCD_REFMCR, REFMCR_VAL_4);
++		WRITEREG(DBMX1_LCD_DMACR, DMACR_VAL_4);
++		WRITEREG(DBMX1_LCD_PWMR, PWMR_VAL);
++		break;
++	case 12:
++	case 16:
++		WRITEREG(DBMX1_LCD_PANELCFG, PANELCFG_VAL_12);
++		WRITEREG(DBMX1_LCD_HCFG, HCFG_VAL_12);
++		WRITEREG(DBMX1_LCD_VCFG, VCFG_VAL_12);
++		WRITEREG(DBMX1_LCD_REFMCR, 0x0);
++		WRITEREG(DBMX1_LCD_DMACR, DMACR_VAL_12);
++		WRITEREG(DBMX1_LCD_PWMR, 0x00008200);
++		WRITEREG(DBMX1_LCD_REFMCR, 0x0f000002);
++		WRITEREG(DBMX1_LCD_PWMR, 0x0000008a);
++
++		break;
++	}
++#else
++	val = READREG(0x21c21c);
++	val |= 0x0010000;
++	WRITEREG(0x21c21c, val);
++
++	WRITEREG(DBMX1_LCD_PWMR, 0x8200);
++	WRITEREG(DBMX1_LCD_REFMCR, 0xf000002);
++
++	// Thomas Wong - we want 0x8A not 0x200
++//	WRITEREG(DBMX1_LCD_PWMR, 0x200);
++// PLAM -- for rev2 (endian bit)
++//	WRITEREG(DBMX1_LCD_PWMR, 0x0000008A);
++	WRITEREG(DBMX1_LCD_PWMR, 0x00A9008A);
++// end PLAM
++#endif
++
++	FUNC_END;
++}
++
++/*****************************************************************************
++ * Function Name: _disable_lcd_controller()
++ *
++ * Input: VOID
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: just disable the LCD controller
++ * 		disable lcd interrupt. others, i have no ideas
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void _disable_lcd_controller(void)
++{
++	unsigned int val;
++	val = READREG(0x21c21c);
++	val &= ~0x0010000;
++	WRITEREG(0x21c21c, val);
++
++	WRITEREG(DBMX1_LCD_PWMR, 0x8200);
++//	WRITEREG(DBMX1_LCD_REFMCR, DISABLELCD_VAL);
++	WRITEREG(0x205034, 0x0);
++}
++
++/*****************************************************************************
++ * Function Name: _install_cmap
++ *
++ * Input: VOID
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called:
++ *
++ * Description: set color map to hardware
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void _install_cmap(int con, struct fb_info *info)
++{
++        if (con != current_par.currcon)
++                return ;
++        if (fb_display[con].cmap.len)
++                fb_set_cmap(&fb_display[con].cmap, 1, dbmx1fb_setcolreg, info);
++        else
++                fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
++				1,
++				dbmx1fb_setcolreg,
++				info);
++	return ;
++}
++
++/*****************************************************************************
++ * Function Name: _init_lcd_system
++ *
++ * Input: VOID
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called:
++ *
++ * Description: initialize the gpio port C and port D with DMA enable
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static void __init _init_lcd_system(void)
++{
++unsigned int val;
++
++/* Thomas Wong - we don't need DMA here
++	// dma reset & enable
++	val = READREG(0x209000);
++	val |= 0x02;
++	WRITEREG(0x209000, val);
++	val = READREG(0x209000);
++	val |= 0x01;
++	WRITEREG(0x209000, val);
++*/
++	// gpio
++	//clear port D for LCD signal
++	WRITEREG(0x21c320, 0x0);
++	WRITEREG(0x21c338, 0x0);
++
++	val = READREG(0x21c220);
++	val |= 0x10000;
++	WRITEREG(0x21c220, val);
++	val = READREG(0x21c208);
++	val |= 0x03;
++	WRITEREG(0x21c208, val);
++	val = READREG(0x21c200);
++	val |= 0x10000;
++	WRITEREG(0x21c200, val);
++	val = READREG(0x21c238);
++	val |= 0x10000;
++	WRITEREG(0x21c238, val);
++	val = READREG(0x21c21c);
++	val |= 0x10000;
++	WRITEREG(0x21c21c, val);
++
++}
++
++static void set_pclk(unsigned int fmhz)
++{
++	unsigned int div= 96/fmhz;
++	unsigned int reg;
++	reg = READREG(0x21b020);
++	reg &= ~0xf0;
++	WRITEREG(0x21b020, reg);
++	reg |= ((div-1)<<4) &0xf0;
++	WRITEREG(0x21b020, reg);
++}
++
++/*****************************************************************************
++ * Function Name: _init_lcd
++ *
++ * Input: VOID
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: _decode_var()
++ *
++ * Description: initialize the LCD controller, use current_par for 12bpp
++ *
++ * Modification History:
++ *		10 DEC,2001, Chen Ning
++******************************************************************************/
++static int __init _init_lcd()
++{
++
++	unsigned int val, rate;
++	int i;
++	unsigned char * pscr;
++	//unsigned long pclk,temp,PCLKDIV2;
++	//unsigned long MFI,MFN,PD,MFD,tempReg,MCUPLLCLK;
++
++
++	_decode_var(&init_var, &current_par);
++
++	// gpio	begin
++	val = READREG(0x21c21c);
++	val &= ~0x00010000;
++	WRITEREG(0x21c21c, val);
++	DPRINTK(KERN_ERR"DR=%x\n", READREG(0x21c21c));
++
++	// LCD regs
++	DPRINTK(KERN_ERR"write SSA by %x\n",
++			(unsigned int)current_par.screen_start_address);
++	WRITEREG(DBMX1_LCD_SSA, (unsigned int)current_par.screen_start_address);
++	DPRINTK(KERN_ERR"SSA=%x\n", READREG(DBMX1_LCD_SSA));
++
++	val =0;
++	val = current_par.xres/16;
++	val = val<<20;
++	val += current_par.yres;
++	DPRINTK(KERN_ERR"par.x=%x, y=%x\n",
++			current_par.xres,
++			current_par.yres);
++	WRITEREG(DBMX1_LCD_XYMAX, val);
++	DPRINTK(KERN_ERR"XYMAX=%x\n", READREG(DBMX1_LCD_XYMAX));
++
++	val=0;
++	val=current_par.xres_virtual/2;
++	WRITEREG(DBMX1_LCD_VPW, val);
++	DPRINTK(KERN_ERR"VPW=%x\n", READREG(DBMX1_LCD_VPW));
++
++	set_pclk(4);
++
++	DPRINTK(KERN_ERR"DBMX1_LCD_PANELCFG=%x\n",
++			READREG(DBMX1_LCD_PANELCFG));
++
++	WRITEREG(DBMX1_LCD_HCFG, 0x04000f06);
++	DPRINTK(KERN_ERR"DBMX1_LCD_HCFG=%x\n",
++			READREG(DBMX1_LCD_HCFG));
++
++	WRITEREG(DBMX1_LCD_VCFG, 0x04000907);
++	DPRINTK(KERN_ERR"DBMX1_LCD_VCFG=%x\n",
++			READREG(DBMX1_LCD_VCFG));
++
++	WRITEREG(DBMX1_LCD_REFMCR, 0x0);
++	DPRINTK(KERN_ERR"DBMX1_LCD_REFMCR=%x\n",
++			READREG(DBMX1_LCD_REFMCR));
++
++	WRITEREG(DBMX1_LCD_DMACR, DMACR_VAL_12);
++	DPRINTK(KERN_ERR"DBMX1_LCD_DMACR=%x\n",
++			READREG(DBMX1_LCD_DMACR));
++
++	WRITEREG(DBMX1_LCD_PWMR, 0x00008200);
++	DPRINTK(KERN_ERR"DBMX1_LCD_PWMR=%x\n",
++			READREG(DBMX1_LCD_PWMR));
++
++	// Thomas Wong - we don't want to turn it on here
++	/*
++	WRITEREG(DBMX1_LCD_REFMCR, 0x0f000002)
++	DPRINTK(KERN_ERR"DBMX1_LCD_REFMCR=%x\n",
++			READREG(DBMX1_LCD_REFMCR));
++	*/
++
++	WRITEREG(DBMX1_LCD_PWMR, 0x0000008a);
++	DPRINTK(KERN_ERR"DBMX1_LCD_PWMR=%x\n",
++			READREG(DBMX1_LCD_PWMR));
++
++	// Thomas Wong
++	WRITEREG(0x21B020, 0x000B005B);
++// PLAM -- for rev2 (new register and endian bits)
++	WRITEREG(DBMX1_LCD_PANELCFG, 0xF8008B42);	// little endian
++//	WRITEREG(DBMX1_LCD_PANELCFG, 0xF8048B42);	// big endian
++	WRITEREG(DBMX1_LCD_LGPMR, 0x00090300);
++//	WRITEREG(DBMX1_LCD_PWMR, 0x0000008A);
++	WRITEREG (DBMX1_LCD_PWMR, 0x009A008A);
++// end PLAM
++
++// PLAM -- for rev2 (new DMACR setting)
++//	WRITEREG(DBMX1_LCD_DMACR, 0x800C0002);
++	WRITEREG(DBMX1_LCD_DMACR, 0x00040008);
++//end PLAM
++
++
++#define DMACR_VAL_12	0x800C0002
++
++
++//	WRITEREG(DBMX1_LCD_INTCR, INTCR_VAL_12);
++//	DPRINTK(KERN_ERR"DBMX1_LCD_INTCR=%x\n",
++//			READREG(DBMX1_LCD_INTCR));
++
++	// warm up LCD
++	for(i=0;i<10000000;i++) ;
++
++	// gpio end
++	val = READREG(0x21c21c);
++	val |= 0x00010000;
++	WRITEREG(0x21c21c, val);
++	DPRINTK(KERN_ERR"DR=%x\n",
++			READREG(0x21c21c));
++#if 0
++	// clear screen
++	pscr = current_par.v_screen_start_address;
++	for(i=0; i< (current_par.screen_memory_size - 2*PAGE_SIZE); i++){
++		*pscr++ = 0xff;
++	}
++#endif
++	DPRINTK(KERN_ERR"_init_lcd end \n");
++
++	return 0;
++}
++
++#ifdef HARDWARE_CURSOR
++
++/*
++ * Hardware cursor support
++ */
++ /*****************************************************************************
++ * Function Name: dbmx1fb_set_cursor_color()
++ *
++ * Input:   fb	: frame buffer database
++ *	    red	: red component level in the cursor
++ *	  green	: green component level in the cursor
++ *	   blue	: blue component level in the cursor
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Set color of hardware cursor
++ *
++ * Modification History:
++ *		10 DEC,2001, Zhang Juan
++******************************************************************************/
++static void dbmx1fb_set_cursor_color(struct dbmx1fb_info *fb, UINT8 *red, UINT8 *green, UINT8 *blue)
++{
++	struct dbmx1fb_cursor *c = &fb->cursor;
++	UINT32 color;
++
++	FUNC_START;
++	c->color[0] = *red;
++	c->color[1] = *green;
++	c->color[2] = *blue;
++	color = (UINT32)*red;
++	color |= (UINT32)(*green>>5);
++	color |= (UINT32)(*blue>>11);
++
++	WRITEREG(DBMX1_LCD_LCHCC, color);
++	FUNC_END;
++}
++
++ /*****************************************************************************
++ * Function Name: dbmx1fb_set_cursor()
++ *
++ * Input:   fb	: frame buffer database
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Load information of hardware cursor
++ *
++ * Modification History:
++ *		10 DEC,2001, Zhang Juan
++******************************************************************************/
++static void dbmx1fb_set_cursor(struct dbmx1fb_info *fb)
++{
++	struct dbmx1fb_cursor *c = &fb->cursor;
++	UINT32 temp,tempReg,x,y;
++
++	FUNC_START;
++	//DPRINTK(KERN_ERR"BLINK_RATE=%x\n",c->blink_rate);
++//	DPRINTK(KERN_ERR"width=%x\n",c->width);
++//	DPRINTK(KERN_ERR"height=%x\n",c->height);
++
++	x = c->startx << 16;
++	if (c->state == LCD_CURSOR_ON)
++	x |= CURSOR_ON_MASK;
++
++#ifdef FBCON_HAS_CFB4
++    else if(c->state == LCD_CURSOR_REVERSED)
++		x |= CURSOR_REVERSED_MASK;
++    else if(c->state == LCD_CURSOR_ON_WHITE)
++		x |= CURSOR_WHITE_MASK;
++#elif defined(FBCON_HAS_CFB8)||defined(FBCON_HAS_CFB16)
++    else if(c->state == LCD_CURSOR_INVERT_BGD)
++		x |= CURSOR_INVERT_MASK;
++    else if(c->state == LCD_CURSOR_AND_BGD)
++		x |= CURSOR_AND_BGD_MASK;
++    else if(c->state == LCD_CURSOR_OR_BGD)
++		x |= CURSOR_OR_BGD_MASK;
++    else if(c->state == LCD_CURSOR_XOR_BGD)
++		x |= CURSOR_XOR_BGD_MASK;
++#endif
++    else
++	x = c->startx;
++
++	y = c->starty;
++
++	temp = (UINT32)x | (UINT32)y;
++	WRITEREG(DBMX1_LCD_LCXYP, temp);
++	//DPRINTK(KERN_ERR"lcxyp=%x\n",READREG(DBMX1_LCD_LCXYP));
++
++	temp = (UINT32)((c->width<<8) | (c->height));
++	tempReg = (UINT32)((temp<<16) | c->blink_rate);
++
++	WRITEREG(DBMX1_LCD_CURBLKCR, tempReg);
++
++	//c->blink_rate = 10;
++	if (c->blinkenable)
++		dbmx1fb_set_cursor_blink(fb,c->blink_rate);
++	DPRINTK(KERN_ERR"CURBLKCR=%x\n",READREG(DBMX1_LCD_CURBLKCR));
++	FUNC_END;
++}
++
++ /*****************************************************************************
++ * Function Name: dbmx1fb_set_cursor_blink()
++ *
++ * Input:   fb  : frame buffer database
++ *	 blink	: input blink frequency of cursor
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Set blink frequency of hardware cursor
++ *
++ * Modification History:
++ *		10 DEC,2001, Zhang Juan
++******************************************************************************/
++static void dbmx1fb_set_cursor_blink(struct dbmx1fb_info *fb,int blink)
++{
++	struct dbmx1fb_cursor *c = &fb->cursor;
++
++	unsigned long   temp,tempReg;
++	unsigned long   PCD, XMAX, YMAX, PCLKDIV2;
++	unsigned long   tempMicroPeriod;
++
++	FUNC_START;
++	DPRINTK(KERN_ERR"dbmx1fb_set_cursor_blink\n");
++
++	if(!c){
++		DPRINTK(KERN_ERR"dangerouts, for c == null\n");
++	}
++	c->blink_rate = blink;
++
++	tempReg = READREG(DBMX1_LCD_XYMAX);
++	XMAX = (tempReg & XMAX_MASK) >> 20;
++	YMAX = tempReg & YMAX_MASK;
++	//XMAX = 240;
++	//YMAX = 320;
++	tempReg = READREG(PCDR);
++	PCLKDIV2 = (tempReg & PCLKDIV2_MASK) >> 4;
++	tempReg = READREG(DBMX1_LCD_PANELCFG);
++	PCD = tempReg & PCD_MASK;
++
++	temp = (PCLKDIV2 + 1);
++
++	if (!blink)
++	{
++		/* disable the blinking cursor function when frequency is 0 */
++		tempReg = READREG(DBMX1_LCD_CURBLKCR);
++		tempReg &= CURSORBLINK_DIS_MASK;
++		WRITEREG(DBMX1_LCD_CURBLKCR,tempReg);
++	}
++	else
++	{
++
++		tempMicroPeriod = temp * XMAX * YMAX * (PCD + 1);
++		temp = 96*10000000/(blink * tempMicroPeriod);
++		tempReg = READREG(DBMX1_LCD_CURBLKCR);
++		tempReg |= CURSORBLINK_EN_MASK;
++		tempReg |= temp;
++		WRITEREG(DBMX1_LCD_CURBLKCR,tempReg);
++		DPRINTK(KERN_ERR"Inter_CURBLKCR=%x\n",READREG(DBMX1_LCD_CURBLKCR));
++	}
++
++	FUNC_END;
++}
++
++ /*****************************************************************************
++ * Function Name: dbmx1fb_set_cursor_state()
++ *
++ * Input:   fb  : frame buffer database
++ *	 state	: The status of the cursor to be set. e.g.
++ *            		LCD_CURSOR_OFF
++ *                      LCD_CURSOR_ON
++ *                      LCD_CURSOR_REVERSED
++ *                      LCD_CURSOR_ON_WHITE
++ *                      LCD_CURSOR_OR_BGD
++ *                      LCD_CURSOR_XOR_BGD
++ *                      LCD_CURSOR_AND_BGD
++ *
++ * Value Returned: VOID
++ *
++ * Functions Called: VOID
++ *
++ * Description: Set state of cursor
++ *
++ * Modification History:
++ *		10 DEC,2001, Zhang Juan
++******************************************************************************/
++static void dbmx1fb_set_cursor_state(struct dbmx1fb_info *fb,UINT32 state)
++{
++	struct dbmx1fb_cursor *c = &fb->cursor;
++	UINT32 temp;
++
++	FUNC_START;
++	c->state = state;
++	temp = READREG(DBMX1_LCD_LCXYP);
++    	temp &= CURSOR_OFF_MASK;
++
++    	if (state == LCD_CURSOR_OFF)
++        	temp = temp;
++    	else if (state == LCD_CURSOR_ON)
++        	temp |= CURSOR_ON_MASK;
++#ifdef FBCON_HAS_CFB4
++    	else if (state == LCD_CURSOR_REVERSED)
++        	temp |= CURSOR_REVERSED_MASK;
++    	else if (state == LCD_CURSOR_ON_WHITE)
++		temp |= CURSOR_WHITE_MASK;
++#elif defined(FBCON_HAS_CFB8)||defined(FBCON_HAS_CFB16)
++	else if(state == LCD_CURSOR_INVERT_BGD)
++		temp |= CURSOR_INVERT_MASK;
++    	else if (state == LCD_CURSOR_OR_BGD)
++        	temp |= CURSOR_OR_BGD_MASK;
++    	else if (state == LCD_CURSOR_XOR_BGD)
++        	temp |= CURSOR_XOR_BGD_MASK;
++	else if (state == LCD_CURSOR_AND_BGD)
++        	temp |= CURSOR_AND_BGD_MASK;
++#endif
++	WRITEREG(DBMX1_LCD_LCXYP,temp);
++	DPRINTK(KERN_ERR"LCDXYP=%x\n",READREG(DBMX1_LCD_LCXYP));
++	FUNC_END;
++}
++
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_cursor()
++ *
++ * Input:   fb     		: frame buffer database
++ *
++ * Value Returned: 	cursor : The structure of hardware cursor
++ *
++ * Functions Called: 	dbmx1fb_set_cursor()
++ *			dbmx1fb_set_cursor_state()
++ *
++ * Description: The entry for display switch to operate hardware cursor
++ *
++ * Modification History:
++ *		10 DEC,2001, Zhang Juan
++******************************************************************************/
++static void dbmx1fb_cursor(struct display *p, int mode, int x, int y)
++{
++	struct dbmx1fb_info *fb = (struct dbmx1fb_info *)p->fb_info;
++	struct dbmx1fb_cursor *c = &fb->cursor;
++
++	FUNC_START;
++	if (c==0) return;
++
++
++	x *= fontwidth(p);
++	y *= fontheight(p);
++
++	c->startx = x;
++	c->starty = y;
++
++	switch (mode) {
++	case CM_ERASE:
++		dbmx1fb_set_cursor_state(fb,LCD_CURSOR_OFF);
++		break;
++
++	case CM_DRAW:
++	case CM_MOVE:
++		c->state = LCD_CURSOR_ON;
++		dbmx1fb_set_cursor(fb);
++		dbmx1fb_set_cursor_state(fb, c->state);
++		break;
++	}
++	FUNC_END;
++}
++
++/*****************************************************************************
++ * Function Name: dbmx1fb_set_font()
++ *
++ * Input:   display	: console datebase
++ * 	    width	: The new width of cursor to be set.
++ * 	    height	: The new height of cursor position to be set
++ *
++ * Value Returned: int	: Return status.If no error, return 0.
++ *
++ * Functions Called: dbmx1fb_set_cursor()
++ *		     dbmx1fb_set_cursor_color()
++ *
++ * Description: Set  font for cursor
++ *
++ * Modification History:
++ *		10 DEC,2001, Zhang Juan
++******************************************************************************/
++static int dbmx1fb_set_font(struct display *d, int width, int height)
++{
++	struct dbmx1fb_info *fb=(struct dbmx1fb_info *)d->fb_info;
++	struct dbmx1fb_cursor *c = &fb->cursor;
++
++	FUNC_START;
++	if(!d){
++		printk(KERN_ERR"dbmx1fb_set_font d=null\n");
++		return -1;
++	}
++
++	if (c) {
++		if (!width || !height) {
++			width = 16;
++			height = 16;
++		}
++
++		c->width = width;
++		c->height = height;
++
++		DPRINTK(KERN_ERR"set cursor\n");
++		dbmx1fb_set_cursor(fb);
++		DPRINTK(KERN_ERR"set color cursor\n");
++		dbmx1fb_set_cursor_color(fb, cursor_color_map,
++				cursor_color_map, cursor_color_map);
++	}else{
++		DPRINTK(KERN_ERR"set cursor failed, cursor == null\n");
++	}
++
++	FUNC_END;
++	return 1;
++}
++#endif // HARDWARE_CURSOR
++/* end of file */
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/drivers/video/dbmx1fb.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,213 @@
++/****************************************************************************
++ *
++ * Copyright (C) 2001, Chen Ning All Rights Reserved
++ *
++ * File Name:	dbmx1fb.h
++ *
++ * Progammers:	Chen Ning, Zhang Juan
++ *
++ * Date of Creations:	10 DEC,2001
++ *
++ * Synopsis:
++ *
++ * Descirption:
++ *
++ * Modification History:
++ * 10 DEC, 2001, initialization version, frame work for frame buffer driver
++ *
++*******************************************************************************/
++
++#ifndef LCDFB_H
++#define LCDFB_H
++#include "asm/arch/hardware.h"
++#include "asm/arch/platform.h"
++
++typedef signed char          	BOOLEAN;
++typedef unsigned char        	UINT8;              		/* Unsigned  8 bit quantity 	*/
++typedef signed char          	SINT8;              		/* Signed    8 bit quantity 		*/
++typedef unsigned short       	UINT16;             		/* Unsigned 16 bit quantity 	*/
++typedef signed short         	SINT16;            		/* Signed   16 bit quantity 		*/
++typedef unsigned long        	UINT32;             		/* Unsigned 32 bit quantity 	*/
++typedef signed long          	SINT32;             		/* Signed   32 bit quantity 		*/
++
++typedef volatile BOOLEAN     	VBOOLEAN;
++typedef volatile UINT8       	VUINT8;             		/* Unsigned  8 bit quantity 	*/
++typedef volatile SINT8       	VSINT8;             		/* Signed    8 bit quantity 		*/
++typedef volatile UINT16      	VUINT16;            	/* Unsigned 16 bit quantity 	*/
++typedef volatile SINT16      	VSINT16;            	/* Signed   16 bit quantity 		*/
++typedef volatile UINT32      	VUINT32;            	/* Unsigned 32 bit quantity 	*/
++typedef volatile SINT32      	VSINT32;            	/* Signed   32 bit quantity 		*/
++
++#define LCDBASE		0x00205000
++#define LCD_REGIONSIZE	0xc00
++
++#define DBMX1_LCD_SSA		0x00205000
++#define DBMX1_LCD_XYMAX		0x00205004
++#define DBMX1_LCD_VPW		0x00205008
++#define DBMX1_LCD_LCXYP		0x0020500c
++#define DBMX1_LCD_CURBLKCR	0x00205010
++#define DBMX1_LCD_LCHCC		0x00205014
++#define DBMX1_LCD_PANELCFG	0x00205018
++#define DBMX1_LCD_HCFG		0x0020501c
++#define DBMX1_LCD_VCFG		0x00205020
++#define DBMX1_LCD_POS		0x00205024
++#define DBMX1_LCD_LGPMR		0x00205028
++#define DBMX1_LCD_PWMR		0x0020502c
++#define DBMX1_LCD_DMACR		0x00205030
++#define DBMX1_LCD_REFMCR	0x00205034
++#define DBMX1_LCD_INTCR		0x00205038
++#define DBMX1_LCD_INTSR		0x00205040
++#define DBMX1_LCD_MAPRAM	0x00205800
++
++#define MPCTL0			0x0021B004
++#define PCDR			0X0021B020
++
++#define SSA		DBMX1_LCD_SSA
++#define XYMAX		DBMX1_LCD_XYMAX
++#define VPW		DBMX1_LCD_VPW
++#define LCXYP		DBMX1_LCD_LCXYP
++#define CURBLKCR	DBMX1_LCD_CURBLKCR
++#define LCHCC		DBMX1_LCD_LCHCC
++#define PANELCFG	DBMX1_LCD_PANELCFG
++#define VCFG		DBMX1_LCD_VCFG
++#define HCFG		DBMX1_LCD_HCFG
++#define POS		DBMX1_LCD_POS
++#define LGPMR		DBMX1_LCD_LGPMR
++#define PWMR		DBMX1_LCD_PWMR
++#define DMACR		DBMX1_LCD_DMACR
++#define REFMCR		DBMX1_LCD_REFMCR
++#define INTCR		DBMX1_LCD_INTCR
++#define INTSR		DBMX1_LCD_INTSR
++#define MAPRAM		DBMX1_LCD_MAPRAM
++// default value
++#define SHARP_TFT_240x320
++
++#ifdef SHARP_TFT_240x320
++#define PANELCFG_VAL_12	0xf8008b48
++#define HCFG_VAL_12	0x04000f06
++#define VCFG_VAL_12	0x04000907
++#define PWMR_VAL	0x0000008a
++#define LCD_MAXX	240
++#define LCD_MAXY	320
++#else //SHARP_TFT_240x320
++
++#define PANELCFG_VAL_12	0xf8088c6b
++#define HCFG_VAL_12	0x04000f06
++#define VCFG_VAL_12	0x04010c03
++#define PWMR_VAL	0x00000200
++#define LCD_MAXX	320
++#define LCD_MAXY	240
++#endif // SHARP_TFT_240x320
++
++#define PANELCFG_VAL_4	0x20008c09
++#define PANELCFG_VAL_4C	0x60008c09
++
++#define HCFG_VAL_4	0x04000f07
++
++#define VCFG_VAL_4	0x04010c03
++
++
++#define REFMCR_VAL_4	0x00000003
++#define REFMCR_VAL_12	0x00000003
++#define DISABLELCD_VAL	0x00000000
++
++#define DMACR_VAL_4	0x800c0003	// 12 & 3 TRIGGER
++#define DMACR_VAL_12	0x00020008
++
++#define INTCR_VAL_4	0x00000000
++#define INTCR_VAL_12	0x00000000
++
++#define INTSR_UDRERR	0x00000008
++#define INTSR_ERRRESP	0x00000004
++#define INTSR_EOF	0x00000002
++#define INTSR_BOF	0x00000001
++
++#define MIN_XRES        64
++#define MIN_YRES        64
++
++#define LCD_MAX_BPP	16
++
++#if 0
++#define READREG(r)	\
++	inl(IO_ADDRESS(r))
++
++#define WRITEREG(r, val) \
++	outl(val, IO_ADDRESS(r))
++#else
++#endif // 0
++
++#define MAX_PALETTE_NUM_ENTRIES         256
++#define MAX_PIXEL_MEM_SIZE \
++        ((current_par.max_xres * current_par.max_yres * current_par.max_bpp)/8)
++#define MAX_FRAMEBUFFER_MEM_SIZE \
++	        (MAX_PIXEL_MEM_SIZE + 32)
++#define ALLOCATED_FB_MEM_SIZE \
++	        (PAGE_ALIGN(MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2))
++
++	// TODO:
++#define FBCON_HAS_CFB4
++#define FBCON_HAS_CFB8
++#define FBCON_HAS_CFB16
++
++#define IRQ_LCD			12		// TODO: which irq?
++#define DBMX1_NAME 		"DBMX1FB"
++#define DEV_NAME		DBMX1_NAME
++#define MAX_PALETTE_NUM_ENTRIES 256
++#define DEFAULT_CURSOR_BLINK_RATE (20)
++#define CURSOR_DRAW_DELAY  (2)
++/*cursor status*/
++#define LCD_CURSOR_OFF	            0
++#define LCD_CURSOR_ON               1
++
++#ifdef FBCON_HAS_CFB4
++	#define LCD_CURSOR_REVERSED     2
++   	#define LCD_CURSOR_ON_WHITE     3
++#elif defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB16)
++   	#define LCD_CURSOR_INVERT_BGD	2
++   	#define LCD_CURSOR_AND_BGD	3
++	#define LCD_CURSOR_OR_BGD       4
++	#define LCD_CURSOR_XOR_BGD      5
++#endif //FBCON_HAS_CFB4
++
++/* MASK use for caculating MCDUPLLCLK */
++#define MFI_MASK		0x00003C00
++#define MFN_MASK		0x000003FF
++#define PD_MASK			0x3C000000
++#define MFD_MASK		0x03FF0000
++#define PCLKDIV2_MASK		0x000000F0
++#define PCD_MASK		0x0000003F
++#define XMAX_MASK                   0xF3F00000
++#define YMAX_MASK                   0x000001FF
++#define HWAIT1_MASK                 0x0000FF00
++#define HWAIT2_MASK                 0x000000FF
++#define HWIDTH_MASK                 0xFC000000
++#define PASSDIV_MASK		0x00FF0000
++#define VWAIT1_MASK                 0x0000FF00
++#define VWAIT2_MASK                 0x000000FF
++#define VWIDTH_MASK                 0xFC000000
++#define CURSORBLINK_DIS_MASK	0x80000000
++
++#define DISPLAY_MODE_MASK		0x80000000
++
++#define MCU_FREQUENCE               32768
++#define COLOR_MASK	0x40000000
++
++/*  MASK use for indicating the cursor status  */
++#define CURSOR_ON_MASK              0x40000000
++#define CURSOR_OFF_MASK		   0x0FFFFFFF
++#define MAX_CURSOR_WIDTH            31
++#define MAX_CURSOR_HEIGHT           31
++#define CURSORBLINK_EN_MASK		0x80000000
++
++#ifdef FBCON_HAS_CFB4
++#define CURSOR_REVERSED_MASK        0x80000000
++#define CURSOR_WHITE_MASK           0xC0000000
++#else
++#define CURSOR_INVERT_MASK		0x80000000
++#define CURSOR_AND_BGD_MASK         0xC0000000
++#define CURSOR_OR_BGD_MASK          0x50000000
++#define CURSOR_XOR_BGD_MASK         0x90000000
++#endif // FBCON_HAS_CFB4
++
++#endif //LCDFB_H
++
+--- linux-2.4.25/drivers/video/fbmem.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/drivers/video/fbmem.c	2004-03-31 17:15:09.000000000 +0200
+@@ -61,7 +61,9 @@
+ extern int pm2fb_setup(char*);
+ extern int pm3fb_init(void);
+ extern int pm3fb_setup(char*);
++extern int clps711xfb_init(void);
+ extern int cyber2000fb_init(void);
++extern int cyber2000fb_setup(char*);
+ extern int retz3fb_init(void);
+ extern int retz3fb_setup(char*);
+ extern int clgenfb_init(void);
+@@ -145,6 +147,8 @@
+ extern int sstfb_setup(char*);
+ extern int it8181fb_init(void);
+ extern int it8181fb_setup(char*);
++extern int anakinfb_init(void);
++extern int dbmx1fb_init(void);
+ 
+ static struct {
+ 	const char *name;
+@@ -170,11 +174,14 @@
+ #ifdef CONFIG_FB_AMIGA
+ 	{ "amifb", amifb_init, amifb_setup },
+ #endif
++#ifdef CONFIG_FB_CLPS711X
++	{ "clps711xfb", clps711xfb_init, NULL },
++#endif
+ #ifdef CONFIG_FB_CYBER
+ 	{ "cyber", cyberfb_init, cyberfb_setup },
+ #endif
+ #ifdef CONFIG_FB_CYBER2000
+-	{ "cyber2000", cyber2000fb_init, NULL },
++	{ "cyber2000", cyber2000fb_init, cyber2000fb_setup },
+ #endif
+ #ifdef CONFIG_FB_PM2
+ 	{ "pm2fb", pm2fb_init, pm2fb_setup },
+@@ -226,10 +233,10 @@
+ #endif
+ #ifdef CONFIG_FB_S3TRIO
+ 	{ "s3trio", s3triofb_init, NULL },
+-#endif 
++#endif
+ #ifdef CONFIG_FB_FM2
+ 	{ "fm2fb", fm2fb_init, fm2fb_setup },
+-#endif 
++#endif
+ #ifdef CONFIG_FB_SIS
+ 	{ "sisfb", sisfb_init, sisfb_setup },
+ #endif
+@@ -242,7 +249,7 @@
+ 
+ 	/*
+ 	 * Generic drivers that are used as fallbacks
+-	 * 
++	 *
+ 	 * These depend on resource management and must be initialized
+ 	 * _after_ all other frame buffer devices that use resource
+ 	 * management!
+@@ -253,7 +260,7 @@
+ #endif
+ #ifdef CONFIG_FB_VESA
+ 	{ "vesa", vesafb_init, vesafb_setup },
+-#endif 
++#endif
+ 
+ 	/*
+ 	 * Chipset specific drivers that don't use resource management (yet)
+@@ -276,7 +283,7 @@
+ #endif
+ #ifdef CONFIG_FB_HGA
+ 	{ "hga", hgafb_init, hgafb_setup },
+-#endif 
++#endif
+ #ifdef CONFIG_FB_IGA
+ 	{ "igafb", igafb_init, igafb_setup },
+ #endif
+@@ -291,7 +298,7 @@
+ #endif
+ #ifdef CONFIG_FB_HP300
+ 	{ "hpfb", hpfb_init, NULL },
+-#endif 
++#endif
+ #ifdef CONFIG_FB_G364
+ 	{ "g364", g364fb_init, NULL },
+ #endif
+@@ -307,6 +314,9 @@
+ #ifdef CONFIG_FB_TX3912
+ 	{ "tx3912", tx3912fb_init, NULL },
+ #endif
++#ifdef CONFIG_FB_ANAKIN
++	{ "anakinfb", anakinfb_init, NULL },
++#endif
+ #ifdef CONFIG_FB_E1355
+ 	{ "e1355fb", e1355fb_init, e1355fb_setup },
+ #endif
+@@ -330,10 +340,13 @@
+ #endif
+ #ifdef CONFIG_FB_AU1100
+ 	{ "au1100fb", au1100fb_init, au1100fb_setup },
+-#endif 
++#endif
+ #ifdef CONFIG_FB_IT8181
+ 	{ "it8181fb", it8181fb_init, it8181fb_setup },
+ #endif
++#ifdef CONFIG_FB_DBMX1
++	{ "dbmx1fb", dbmx1fb_init, NULL },
++#endif
+ 
+ 
+ 	/*
+@@ -342,7 +355,7 @@
+ 
+ #ifdef CONFIG_FB_VGA16
+ 	{ "vga16", vga16fb_init, vga16fb_setup },
+-#endif 
++#endif
+ #ifdef CONFIG_FB_STI
+ 	{ "stifb", stifb_init, stifb_setup },
+ #endif
+@@ -371,7 +384,7 @@
+ 
+ struct fb_info *registered_fb[FB_MAX];
+ int num_registered_fb;
+-extern int fbcon_softback_size; 
++extern int fbcon_softback_size;
+ 
+ static int first_fb_vc;
+ static int last_fb_vc = MAX_NR_CONSOLES-1;
+@@ -480,7 +493,7 @@
+ }
+ #endif /* CONFIG_KMOD */
+ 
+-static int 
++static int
+ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ 	 unsigned long arg)
+ {
+@@ -492,7 +505,7 @@
+ 	struct fb_fix_screeninfo fix;
+ 	struct fb_con2fbmap con2fb;
+ 	int i;
+-	
++
+ 	if (! fb)
+ 		return -ENODEV;
+ 	switch (cmd) {
+@@ -576,7 +589,7 @@
+ 	}
+ }
+ 
+-static int 
++static int
+ fb_mmap(struct file *file, struct vm_area_struct * vma)
+ {
+ 	int fbidx = GET_FB_IDX(file->f_dentry->d_inode->i_rdev);
+@@ -667,11 +680,11 @@
+ #elif defined(__sh__)
+ 	pgprot_val(vma->vm_page_prot) &= ~_PAGE_CACHABLE;
+ #elif defined(__hppa__)
+-	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; 
++	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+ #elif defined(__ia64__)
+ 	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ #elif defined(__hppa__)
+-	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE; 
++	pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+ #else
+ #warning What do we have to do here??
+ #endif
+@@ -724,7 +737,7 @@
+ 	return res;
+ }
+ 
+-static int 
++static int
+ fb_release(struct inode *inode, struct file *file)
+ {
+ 	int fbidx = GET_FB_IDX(inode->i_rdev);
+@@ -856,7 +869,7 @@
+  *
+  */
+ 
+-void __init 
++void __init
+ fbmem_init(void)
+ {
+ 	int i;
+@@ -904,7 +917,7 @@
+ 
+     if (!options || !*options)
+ 	    return 0;
+-	    
++
+     if (!strncmp(options, "scrollback:", 11)) {
+ 	    options += 11;
+ 	    if (*options) {
+@@ -930,7 +943,7 @@
+ 		    }
+ 	    return 0;
+     }
+-    
++
+     if (!strncmp(options, "vc:", 3)) {
+ 	    options += 3;
+ 	    if (*options)
+--- linux-2.4.25/drivers/video/font_acorn_8x8.c~2.4.25-vrs2.patch	1998-09-30 05:56:33.000000000 +0200
++++ linux-2.4.25/drivers/video/font_acorn_8x8.c	2004-03-31 17:15:09.000000000 +0200
+@@ -11,33 +11,33 @@
+ /* 03 */  0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^C */
+ /* 04 */  0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, /* ^D */
+ /* 05 */  0x00, 0x18, 0x3c, 0xe7, 0xe7, 0x3c, 0x18, 0x00, /* ^E */
+-/* 06 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 07 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 08 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 09 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 0A */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 0B */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 0C */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 0D */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 0E */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 0F */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* 06 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 07 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 08 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 09 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 0A */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 0B */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 0C */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 0D */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 0E */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 0F */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ /* 10 */  0x00, 0x60, 0x78, 0x7e, 0x7e, 0x78, 0x60, 0x00, /* |> */
+ /* 11 */  0x00, 0x06, 0x1e, 0x7e, 0x7e, 0x1e, 0x06, 0x00, /* <| */
+-/* 12 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 13 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 14 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 15 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 16 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 17 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 18 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 19 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 1A */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 1B */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 1C */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 1D */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* 12 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 13 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 14 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 15 */  0x3c, 0x60, 0x3c, 0x66, 0x3c, 0x06, 0x3c, 0x00,
++/* 16 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 17 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 18 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 19 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 1A */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 1B */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 1C */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 1D */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ /* 1E */  0x00, 0x18, 0x18, 0x3c, 0x3c, 0x7e, 0x7e, 0x00, /* /\ */
+ /* 1F */  0x00, 0x7e, 0x7e, 0x3c, 0x3c, 0x18, 0x18, 0x00, /* \/ */
+-/* 20 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*	 */
++/* 20 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*   */
+ /* 21 */  0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00, /* ! */
+ /* 22 */  0x6C, 0x6C, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, /* " */
+ /* 23 */  0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00, /* # */
+@@ -132,55 +132,55 @@
+ /* 7C */  0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, /* | */
+ /* 7D */  0x30, 0x18, 0x18, 0x0E, 0x18, 0x18, 0x30, 0x00, /* } */
+ /* 7E */  0x31, 0x6B, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, /* ~ */
+-/* 7F */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,  /*  */
+-/* 80 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 81 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 82 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 83 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 84 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 85 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 86 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 87 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 88 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 89 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 8A */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 8B */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 8C */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 8D */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 8E */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 8F */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 90 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 91 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 92 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 93 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 94 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 95 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 96 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 97 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 98 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 99 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 9A */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 9B */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 9C */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 9D */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 9E */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* 9F */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A0 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A1 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A2 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A3 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A4 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A8 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* A9 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* AA */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* AB */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* AC */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* AD */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* AE */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* AF */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* 7F */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /*  */
++/* 80 */  0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x30, 0x60,
++/* 81 */  0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3e, 0x00,
++/* 82 */  0x0c, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
++/* 83 */  0x18, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
++/* 84 */  0x66, 0x00, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
++/* 85 */  0x30, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
++/* 86 */  0x3c, 0x66, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
++/* 87 */  0x00, 0x00, 0x3c, 0x66, 0x60, 0x66, 0x3c, 0x60,
++/* 88 */  0x3c, 0x66, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
++/* 89 */  0x66, 0x00, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
++/* 8A */  0x30, 0x18, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00,
++/* 8B */  0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
++/* 8C */  0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
++/* 8D */  0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
++/* 8E */  0x66, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00,
++/* 8F */  0x18, 0x66, 0x00, 0x3c, 0x66, 0x7e, 0x66, 0x00,
++/* 90 */  0x0c, 0x18, 0x7e, 0x60, 0x7c, 0x60, 0x7e, 0x00,
++/* 91 */  0x00, 0x00, 0x3f, 0x0d, 0x3f, 0x6c, 0x3f, 0x00,
++/* 92 */  0x3f, 0x66, 0x66, 0x7f, 0x66, 0x66, 0x67, 0x00,
++/* 93 */  0x3c, 0x66, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
++/* 94 */  0x66, 0x00, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
++/* 95 */  0x30, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
++/* 96 */  0x3c, 0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
++/* 97 */  0x30, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
++/* 98 */  0x66, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x06, 0x3c,
++/* 99 */  0x66, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x3c, 0x00,
++/* 9A */  0x66, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00,
++/* 9B */  0x08, 0x3e, 0x6b, 0x68, 0x6b, 0x3e, 0x08, 0x00,
++/* 9C */  0x1c, 0x36, 0x30, 0x7c, 0x30, 0x30, 0x7e, 0x00,
++/* 9D */  0x66, 0x3c, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00,
++/* 9E */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* 9F */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* A0 */  0x0c, 0x18, 0x3c, 0x06, 0x3e, 0x66, 0x3e, 0x00,
++/* A1 */  0x0c, 0x18, 0x00, 0x38, 0x18, 0x18, 0x3c, 0x00,
++/* A2 */  0x0c, 0x18, 0x00, 0x3c, 0x66, 0x66, 0x3c, 0x00,
++/* A3 */  0x0c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x3e, 0x00,
++/* A4 */  0x36, 0x6c, 0x00, 0x7c, 0x66, 0x66, 0x66, 0x00,
++/* A5 */  0x36, 0x6c, 0x00, 0x66, 0x76, 0x6e, 0x66, 0x00,
++/* A6 */  0x1c, 0x06, 0x1e, 0x36, 0x1e, 0x00, 0x3e, 0x00,
++/* A7 */  0x1c, 0x36, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00,
++/* A8 */  0x18, 0x00, 0x18, 0x18, 0x30, 0x66, 0x3c, 0x00,
++/* A9 */  0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* AA */  0x7e, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* AB */  0x40, 0xc0, 0x40, 0x4f, 0x41, 0x0f, 0x08, 0x0f,
++/* AC */  0x40, 0xc0, 0x40, 0x48, 0x48, 0x0a, 0x0f, 0x02,
++/* AD */  0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
++/* AE */  0x00, 0x33, 0x66, 0xcc, 0xcc, 0x66, 0x33, 0x00,
++/* AF */  0x00, 0xcc, 0x66, 0x33, 0x33, 0x66, 0xcc, 0x00,
+ /* B0 */  0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88,
+ /* B1 */  0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
+ /* B2 */  0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
+@@ -229,37 +229,37 @@
+ /* DD */  0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ /* DE */  0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ /* DF */  0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+-/* E0 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E1 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E2 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E3 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E4 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E8 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* E9 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* EA */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* EB */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* EC */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* ED */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* EE */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* EF */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F0 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F1 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F2 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F3 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F4 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F5 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F6 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F7 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F8 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* F9 */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* FA */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* FB */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* FC */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* FD */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-/* FE */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* E0 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* E1 */  0x3c, 0x66, 0x66, 0x6c, 0x66, 0x66, 0x6c, 0xc0,
++/* E2 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* E3 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* E4 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* E5 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* E6 */  0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x3e, 0x60,
++/* E7 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* E8 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* E9 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* EA */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* EB */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* EC */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* ED */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* EE */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* EF */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* F0 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* F1 */  0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00,
++/* F2 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* F3 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* F4 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* F5 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* F6 */  0x00, 0x18, 0x00, 0xff, 0x00, 0x18, 0x00, 0x00,
++/* F7 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* F8 */  0x3c, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
++/* F9 */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* FA */  0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
++/* FB */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* FC */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
++/* FD */  0x38, 0x04, 0x18, 0x20, 0x3c, 0x00, 0x00, 0x00,
++/* FE */  0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00,
+ /* FF */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ 
+--- linux-2.4.25/drivers/video/pm3fb.c~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/drivers/video/pm3fb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -5,7 +5,6 @@
+  *  Based on code written by:
+  *           Sven Luther, <luther@dpt-info.u-strasbg.fr>
+  *           Alan Hourihane, <alanh@fairlite.demon.co.uk>
+- *           Russel King, <rmk@arm.linux.org.uk>
+  *  Based on linux/drivers/video/skeletonfb.c:
+  *	Copyright (C) 1997 Geert Uytterhoeven
+  *  Based on linux/driver/video/pm2fb.c:
+@@ -16,13 +15,9 @@
+  *  License. See the file COPYING in the main directory of this archive for
+  *  more details.
+  *
+- *  $Header$
++ *  $Header$
+  *
+  *  CHANGELOG:
+- *  Mon Feb 11 10:35:48 MET 2002, v 1.4.11B: Cosmetic update.
+- *  Wed Jan 23 14:16:59 MET 2002, v 1.4.11: Preliminary 2.5.x support, patch for 2.5.2.
+- *  Wed Nov 28 11:08:29 MET 2001, v 1.4.10: potential bug fix for SDRAM-based board, patch for 2.4.16.
+- *  Thu Sep 20 10:24:42 MET DST 2001, v 1.4.9: sync bug fix, preliminary flatpanel support, better timings.
+  *  Tue Aug 28 10:13:01 MET DST 2001, v 1.4.8: memory timings check, minor bug fixes.
+  *  Wed Jul 18 19:06:14 CEST 2001, v 1.4.7: Mode fix (800x600-100, 1024x768-100 changed), using HW panning + accel bug fix.
+  *  Mon Jun 25 10:33:56 MET DST 2001, v 1.4.6: Depth 12 fix, chip reset ioctl, moved memory erase ioctl to DEBUG.
+@@ -53,8 +48,8 @@
+  */
+ 
+ #include <linux/config.h>
+-#include <linux/module.h>
+ #include <linux/version.h>
++#include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+@@ -80,7 +75,6 @@
+ 
+ #include <asm/io.h>
+ #include <asm/uaccess.h>
+-
+ #ifdef CONFIG_FB_OF
+ #include <asm/prom.h>
+ #endif
+@@ -128,7 +122,6 @@
+ 	unsigned long refresh;
+ 	unsigned long powerdown;
+ };
+-typedef enum pm3fb_timing_result { pm3fb_timing_ok, pm3fb_timing_problem, pm3fb_timing_retry } pm3fb_timing_result;
+ #define PM3FB_UNKNOWN_TIMING_VALUE ((unsigned long)-1)
+ #define PM3FB_UNKNOWN_TIMINGS { PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE, PM3FB_UNKNOWN_TIMING_VALUE }
+ 
+@@ -191,21 +184,13 @@
+ 			    PM3VideoControl_VSYNC_ACTIVE_HIGH
+ 			    | PM3VideoControl_PIXELSIZE_8BIT}}, {
+ 		"1024x768-74-32", {
+-			78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
+-			806, 1024, 0, 32,
+-			PM3VideoControl_ENABLE |
+-			PM3VideoControl_HSYNC_ACTIVE_HIGH
+-			|
+-			PM3VideoControl_VSYNC_ACTIVE_HIGH
+-			| PM3VideoControl_PIXELSIZE_32BIT}},
+-/* Generated mode : "1600x1024", for the SGI 1600SW flat panel*/
+-	{
+-		"SGI1600SW", {
+-			108000, 1600, 1024, 16, 56, 104, 1704, 3, 6, 32,
+-			1056, 1600, 0, 8,
+-			PM3VideoControl_ENABLE|
+-			PM3VideoControl_HSYNC_ACTIVE_LOW|PM3VideoControl_VSYNC_ACTIVE_LOW|
+-			PM3VideoControl_PIXELSIZE_32BIT}}, 
++	78752, 1024, 768, 32, 128, 304, 1328, 1, 4, 38,
++			    806, 1024, 0, 32,
++			    PM3VideoControl_ENABLE |
++			    PM3VideoControl_HSYNC_ACTIVE_HIGH
++			    |
++			    PM3VideoControl_VSYNC_ACTIVE_HIGH
++			    | PM3VideoControl_PIXELSIZE_32BIT}},
+ /* ##### auto-generated mode, by fbtimings2pm3 */
+ /* Generated mode : "640x480-60" */
+ 	{
+@@ -554,11 +539,9 @@
+ short noaccel[PM3_MAX_BOARD];
+ char fontn[PM3_MAX_BOARD][PM3_FONTNAME_SIZE];
+ short depth[PM3_MAX_BOARD];
+-short flatpanel[PM3_MAX_BOARD];
+ static struct display disp[PM3_MAX_BOARD];
+ static char g_options[PM3_OPTIONS_SIZE] __initdata = "pm3fb,dummy";
+ short printtimings = 0;
+-short forcesize[PM3_MAX_BOARD];
+ 
+ /* ********************* */
+ /* ***** prototype ***** */
+@@ -566,8 +549,7 @@
+ /* card-specific */
+ static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info);
+ /* permedia3-specific */
+-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
+-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info);
++static int pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info);
+ static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info);
+ static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
+ 					unsigned long r);
+@@ -683,7 +665,7 @@
+ 	    NULL, NULL
+ };
+ #endif /* KERNEL_2_2 */
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ struct fbgen_hwswitch pm3fb_switch = {
+ 	pm3fb_detect, pm3fb_encode_fix, pm3fb_decode_var, pm3fb_encode_var,
+ 	pm3fb_get_par, pm3fb_set_par, pm3fb_getcolreg, pm3fb_setcolreg,
+@@ -696,7 +678,7 @@
+ 	fbgen_get_fix, fbgen_get_var, fbgen_set_var,
+ 	fbgen_get_cmap, fbgen_set_cmap, fbgen_pan_display, pm3fb_ioctl, NULL, NULL
+ };
+-#endif /* KERNEL_2_4 or KERNEL_2_5 */
++#endif /* KERNEL_2_4 */
+ #ifdef PM3FB_USE_ACCEL
+ #ifdef FBCON_HAS_CFB32
+ static struct display_switch pm3fb_cfb32 = {
+@@ -727,75 +709,52 @@
+ #endif /* FBCON_HAS_CFB8 */
+ #endif /* PM3FB_USE_ACCEL */
+ 
+-/* ****************************** */
+-/* ***** card-specific data ***** */
+-/* ****************************** */
+-struct pm3fb_card_timings {
+-	unsigned long memsize; /* 0 for last value (i.e. default) */
+-	struct pm3fb_timings memt;
+-};
+-
+-static struct pm3fb_card_timings t_FormacProFormance3[] = {
+-	{ 16, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} },
+-	{ 0, { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} } /* from 16 MB PF3 */
+-};
+-
+-static struct pm3fb_card_timings t_AppianJeronimo2000[] = {
+-	{ 32, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} },
+-	{ 0, { 0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} } /* from 32MB J2000 */
+-};
+-
+-static struct pm3fb_card_timings t_3DLabsOxygenVX1[] = {
+-	{ 32, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} },
+-	{ 0, { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000} } /* from 32MB VX1 */
+-};
+-
++/* ********************************** */
++/* ***** card-specific function ***** */
++/* ********************************** */
+ static struct {
+ 		char cardname[32]; /* recognized card name */
+ 		u16 subvendor; /* subvendor of the card */
+ 		u16 subdevice; /* subdevice of the card */
+ 		u8  func; /* function of the card to which the extra init apply */
+ 		void (*specific_setup)(struct pm3fb_info *l_fb_info); /* card/func specific setup, done before _any_ FB access */
+-	struct pm3fb_card_timings *c_memt; /* defauls timings for the boards */
++	struct pm3fb_timings memt; /* default timing for the board WARNING : might be *card* - specific */
+ } cardbase[] = {
+-	{ "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, NULL },
+-	{ "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL,
+-	  t_AppianJeronimo2000
+-	},
++	{ "Unknown Permedia3 board", 0xFFFF, 0xFFFF, 0xFF, NULL, PM3FB_UNKNOWN_TIMINGS },
++	{ "Appian Jeronimo 2000 head 1", 0x1097, 0x3d32, 1, NULL, PM3FB_UNKNOWN_TIMINGS },
+ 	{ "Appian Jeronimo 2000 head 2", 0x1097, 0x3d32, 2, pm3fb_j2000_setup,
+-	  t_AppianJeronimo2000
++	  {0x02e311B8, 0x07424905, 0x0c000003, 0x00000061, 0x00000000} /* also in pm3fb_j2000_setup */
+ 	},
+ 	{ "Formac ProFormance 3", PCI_VENDOR_ID_3DLABS, 0x000a, 0, NULL, /* Formac use 3DLabs ID ?!? */
+-	  t_FormacProFormance3
++	  { 0x02e311b8, 0x06100205, 0x08000002, 0x00000079, 0x00000000} /* from the 16Mb ProFormance 3 */
+ 	},
+-	{ "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, NULL },
++	{ "3DLabs Permedia3 Create!", PCI_VENDOR_ID_3DLABS, 0x0127, 0, NULL, PM3FB_UNKNOWN_TIMINGS },
+ 	{ "3DLabs Oxygen VX1 PCI", PCI_VENDOR_ID_3DLABS, 0x0121, 0, NULL,
+-	  t_3DLabsOxygenVX1
++	  { 0x30e311b8, 0x08501204, 0x08000002, 0x0000006b, 0x00000000 }
+ 	},
+-	{ "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, NULL },
+-	{ "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, NULL },
+-	{ "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, NULL },
+-	{ "\0", 0x0, 0x0, 0, NULL, NULL }
++	{ "3DLabs Oxygen VX1 AGP", PCI_VENDOR_ID_3DLABS, 0x0125, 0, NULL, PM3FB_UNKNOWN_TIMINGS },
++	{ "3DLabs Oxygen VX1-16 AGP", PCI_VENDOR_ID_3DLABS, 0x0140, 0, NULL, PM3FB_UNKNOWN_TIMINGS },
++	{ "3DLabs Oxygen VX1-1600SW PCI", PCI_VENDOR_ID_3DLABS, 0x0800, 0, NULL, PM3FB_UNKNOWN_TIMINGS },
++	{ "\0", 0x0, 0x0, 0, NULL, PM3FB_UNKNOWN_TIMINGS }
+ };
+ 
+-/* ********************************** */
+-/* ***** card-specific function ***** */
+-/* ********************************** */
+ static void pm3fb_j2000_setup(struct pm3fb_info *l_fb_info)
+ {       /* the appian j2000 require more initialization of the second head */
+ 	/* l_fb_info must point to the _second_ head of the J2000 */
+ 	
+ 	DTRACE;
+-
+-	l_fb_info->memt = t_AppianJeronimo2000[0].memt; /* 32 MB, first and only j2000 ? */
++	
++	/* Memory timings for the Appian J2000 board. also in cardbase */
++	l_fb_info->memt.caps = 0x02e311B8;
++	l_fb_info->memt.timings = 0x07424905;
++	l_fb_info->memt.control = 0x0c000003;
++	l_fb_info->memt.refresh = 0x00000061;
++	l_fb_info->memt.powerdown = 0x00000000;
+ 	
+ 	pm3fb_write_memory_timings(l_fb_info);
+ }
+ 
+-/* *************************************** */
+-/* ***** permedia3-specific function ***** */
+-/* *************************************** */
+-static pm3fb_timing_result pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
++static int pm3fb_preserve_memory_timings(struct pm3fb_info *l_fb_info)
+ {
+ 	l_fb_info->memt.caps = PM3_READ_REG(PM3LocalMemCaps);
+ 	l_fb_info->memt.timings = PM3_READ_REG(PM3LocalMemTimings);
+@@ -810,35 +769,20 @@
+ 	    (l_fb_info->memt.powerdown == PM3FB_UNKNOWN_TIMING_VALUE))
+ 	{
+ 		printk(KERN_ERR "pm3fb: invalid memory timings in permedia3 board #%ld\n", l_fb_info->board_num);
+-		return(pm3fb_try_memory_timings(l_fb_info));
+-	}
+-	return(pm3fb_timing_ok);
+-}
+-
+-static pm3fb_timing_result pm3fb_try_memory_timings(struct pm3fb_info *l_fb_info)
+-{
+-	if (cardbase[l_fb_info->board_type].c_memt)
+-	{
+-		int i = 0, done = 0;
+-		while (!done)
++		if ((cardbase[l_fb_info->board_type].memt.caps != PM3FB_UNKNOWN_TIMING_VALUE) &&
++		    (cardbase[l_fb_info->board_type].memt.timings != PM3FB_UNKNOWN_TIMING_VALUE) &&
++		    (cardbase[l_fb_info->board_type].memt.control != PM3FB_UNKNOWN_TIMING_VALUE) &&
++		    (cardbase[l_fb_info->board_type].memt.refresh != PM3FB_UNKNOWN_TIMING_VALUE) &&
++		    (cardbase[l_fb_info->board_type].memt.powerdown != PM3FB_UNKNOWN_TIMING_VALUE))
+ 		{
+-			if ((cardbase[l_fb_info->board_type].c_memt[i].memsize == l_fb_info->fb_size)
+-			    || !(cardbase[l_fb_info->board_type].c_memt[i].memsize))
+-			{ /* will use the 0-sized timings by default */
+-				done = 1;
+-				l_fb_info->memt = cardbase[l_fb_info->board_type].c_memt[i].memt;
+-				printk(KERN_WARNING  "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s, %ld MB)\n",
+-				       l_fb_info->board_num,
+-				       cardbase[l_fb_info->board_type].cardname,
+-				       cardbase[l_fb_info->board_type].c_memt[i].memsize);
+-				pm3fb_write_memory_timings(l_fb_info);
+-				return(pm3fb_timing_retry);
+-			}
+-			i++;
++			l_fb_info->memt = cardbase[l_fb_info->board_type].memt;
++			printk(KERN_WARNING "pm3fb: trying to use predefined memory timings for permedia3 board #%ld (%s)\n", l_fb_info->board_num, cardbase[l_fb_info->board_type].cardname);
++			pm3fb_write_memory_timings(l_fb_info);
+ 		}
+-	} else
+-		return(pm3fb_timing_problem);
+-	return(pm3fb_timing_ok);
++		else
++			return(1);
++	}
++	return(0);
+ }
+ 
+ static void pm3fb_write_memory_timings(struct pm3fb_info *l_fb_info)
+@@ -873,6 +817,10 @@
+ 			  PM3RD_SClkControl_ENABLE);
+ }
+ 
++/* *************************************** */
++/* ***** permedia3-specific function ***** */
++/* *************************************** */
++
+ static unsigned long pm3fb_read_dac_reg(struct pm3fb_info *l_fb_info,
+ 					unsigned long r)
+ {
+@@ -1067,7 +1015,6 @@
+ /* write the mode to registers */
+ static void pm3fb_write_mode(struct pm3fb_info *l_fb_info)
+ {
+-	char tempsync = 0x00, tempmisc = 0x00;
+ 	DTRACE;
+ 
+ 	PM3_SLOW_WRITE_REG(PM3MemBypassWriteMask, 0xffffffff);
+@@ -1197,26 +1144,22 @@
+ 	/*
+ 	   PM3_SLOW_WRITE_REG(PM3RD_IndexControl, 0x00);
+ 	 */
+-	if ((l_fb_info->current_par->video & PM3VideoControl_HSYNC_MASK) ==
+-	    PM3VideoControl_HSYNC_ACTIVE_HIGH)
+-		tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
+-	if ((l_fb_info->current_par->video & PM3VideoControl_VSYNC_MASK) ==
+-	    PM3VideoControl_VSYNC_ACTIVE_HIGH)
+-		tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
+-	
+-	PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
+-	DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
+-	
+-	if (flatpanel[l_fb_info->board_num])
+ 	{
+-		PM3_WRITE_DAC_REG(PM3RD_DACControl, PM3RD_DACControl_BLANK_PEDESTAL_ENABLE);
+-		PM3_WAIT(2);
+-		PM3_WRITE_REG(PM3VSConfiguration, 0x06);
+-		PM3_WRITE_REG(0x5a00, 1 << 14); /* black magic... */
+-		tempmisc = PM3RD_MiscControl_VSB_OUTPUT_ENABLE;
++		char tempsync = 0x00;
++
++		if ((l_fb_info->current_par->
++		     video & PM3VideoControl_HSYNC_MASK) ==
++		    PM3VideoControl_HSYNC_ACTIVE_HIGH)
++			tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
++		if ((l_fb_info->current_par->
++		     video & PM3VideoControl_VSYNC_MASK) ==
++		    PM3VideoControl_VSYNC_ACTIVE_HIGH)
++			tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
++
++		PM3_WRITE_DAC_REG(PM3RD_SyncControl, tempsync);
++		DPRINTK(2, "PM3RD_SyncControl: %d\n", tempsync);
+ 	}
+-	else
+-		PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
++	PM3_WRITE_DAC_REG(PM3RD_DACControl, 0x00);
+ 
+ 	switch (l_fb_info->current_par->depth) {
+ 	case 8:
+@@ -1225,7 +1168,8 @@
+ 		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ 				  PM3RD_ColorFormat_CI8_COLOR |
+ 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
+-		tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
++		PM3_WRITE_DAC_REG(PM3RD_MiscControl,
++				  PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE);
+ 		break;
+ 	case 12:
+ 		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+@@ -1234,8 +1178,9 @@
+ 				  PM3RD_ColorFormat_4444_COLOR |
+ 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+ 				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+-		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+-			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
++		PM3_WRITE_DAC_REG(PM3RD_MiscControl,
++				  PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
++				  PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE);
+ 		break;		
+ 	case 15:
+ 		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+@@ -1244,8 +1189,9 @@
+ 				  PM3RD_ColorFormat_5551_FRONT_COLOR |
+ 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+ 				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+-		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+-			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
++		PM3_WRITE_DAC_REG(PM3RD_MiscControl,
++				  PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
++				  PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE);
+ 		break;		
+ 	case 16:
+ 		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+@@ -1254,8 +1200,9 @@
+ 				  PM3RD_ColorFormat_565_FRONT_COLOR |
+ 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
+ 				  PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
+-		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+-			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
++		PM3_WRITE_DAC_REG(PM3RD_MiscControl,
++				  PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
++				  PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE);
+ 		break;
+ 	case 32:
+ 		PM3_WRITE_DAC_REG(PM3RD_PixelSize,
+@@ -1263,12 +1210,12 @@
+ 		PM3_WRITE_DAC_REG(PM3RD_ColorFormat,
+ 				  PM3RD_ColorFormat_8888_COLOR |
+ 				  PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
+-		tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
+-			PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
++		PM3_WRITE_DAC_REG(PM3RD_MiscControl,
++				  PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
++				  PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE);
+ 		break;
+ 	}
+-	PM3_WRITE_DAC_REG(PM3RD_MiscControl, tempmisc);
+-	
++
+ 	PM3_SHOW_CUR_MODE;
+ }
+ 
+@@ -1390,9 +1337,8 @@
+ 
+ static unsigned long pm3fb_size_memory(struct pm3fb_info *l_fb_info)
+ {
+-	unsigned long memsize = 0, tempBypass, i, temp1, temp2;
++	unsigned long memsize, tempBypass, i, temp1, temp2;
+ 	u16 subvendor, subdevice;
+-	pm3fb_timing_result ptr;
+ 
+ 	DTRACE;
+ 
+@@ -1438,7 +1384,7 @@
+ 	
+ 	/* card-specific setup is done, we preserve the final
+            memory timing for future reference */
+-	if ((ptr = pm3fb_preserve_memory_timings(l_fb_info)) == pm3fb_timing_problem) { /* memory timings were wrong ! oops.... */
++	if (pm3fb_preserve_memory_timings(l_fb_info)) { /* memory timings were wrong ! oops.... */
+ 		return(0);
+ 	}
+ 	
+@@ -1464,12 +1410,12 @@
+ 		temp1 = readl((l_fb_info->v_fb + (i * 1048576)));
+ #endif
+ #endif	/* KERNEL_2_2 */
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ 		fb_writel(i * 0x00345678,
+ 			  (l_fb_info->v_fb + (i * 1048576)));
+ 		mb();
+ 		temp1 = fb_readl((l_fb_info->v_fb + (i * 1048576)));
+-#endif /* KERNEL_2_4 or KERNEL_2_5 */
++#endif	/* KERNEL_2_4 */
+ 		/* Let's check for wrapover, write will fail at 16MB boundary */
+ 		if (temp1 == (i * 0x00345678))
+ 			memsize = i;
+@@ -1512,7 +1458,7 @@
+ 				   ((i - 32) * 1048576)));
+ #endif
+ #endif /* KERNEL_2_2 */
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ 			fb_writel(i * 0x00345678,
+ 				  (l_fb_info->v_fb + (i * 1048576)));
+ 			mb();
+@@ -1521,7 +1467,7 @@
+ 			temp2 =
+ 			    fb_readl((l_fb_info->v_fb +
+ 				      ((i - 32) * 1048576)));
+-#endif /* KERNEL_2_4 or KERNEL_2_5 */
++#endif /* KERNEL_2_4 */
+ 			if ((temp1 == (i * 0x00345678)) && (temp2 == 0))	/* different value, different RAM... */
+ 				memsize = i;
+ 			else
+@@ -1538,21 +1484,8 @@
+ 
+ 	DPRINTK(2, "Returning 0x%08lx bytes\n", memsize);
+ 
+-	if (forcesize[l_fb_info->board_num] && ((forcesize[l_fb_info->board_num] * 1048576) != memsize))
+-	{
+-		printk(KERN_WARNING "pm3fb: mismatch between probed (%ld MB) and specified (%hd MB) memory size, using SPECIFIED !\n", memsize, forcesize[l_fb_info->board_num]);
+-		memsize = 1048576 * forcesize[l_fb_info->board_num];
+-	}
+-	
+ 	l_fb_info->fb_size = memsize;
+-	
+-	if (ptr == pm3fb_timing_retry)
+-	{
+-		printk(KERN_WARNING "pm3fb: retrying memory timings check");
+-		if (pm3fb_try_memory_timings(l_fb_info) == pm3fb_timing_problem)
+-			return(0);
+-	}
+-	
++
+ 	return (memsize);
+ }
+ 
+@@ -1571,7 +1504,7 @@
+ 		writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
+ #endif
+ #endif
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ 		fb_writel(cc, (l_fb_info->v_fb + (i * sizeof(u32))));
+ #endif
+ 	}
+@@ -1600,7 +1533,7 @@
+ 	disp[l_fb_info->board_num].scrollmode = 0;	/* SCROLL_YNOMOVE; *//* 0 means "let fbcon choose" */
+ 	l_fb_info->gen.parsize = sizeof(struct pm3fb_par);
+ 	l_fb_info->gen.info.changevar = NULL;
+-	l_fb_info->gen.info.node = B_FREE;
++	l_fb_info->gen.info.node = -1;
+ 	l_fb_info->gen.info.fbops = &pm3fb_ops;
+ 	l_fb_info->gen.info.disp = &(disp[l_fb_info->board_num]);
+ 	if (fontn[l_fb_info->board_num][0])
+@@ -1765,7 +1698,6 @@
+ 	}
+ 
+ 	PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xffffffff);
+-	PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
+ 	PM3_SLOW_WRITE_REG(PM3FBWriteMode,
+ 			   PM3FBWriteMode_WriteEnable |
+ 			   PM3FBWriteMode_OpaqueSpan |
+@@ -1786,7 +1718,9 @@
+ 			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, 4095);
+ 		else
+ 			PM3_SLOW_WRITE_REG(PM3SizeOfFramebuffer, sofb);
+-		
++
++		PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xffffffff);
++
+ 		switch (l_fb_info->current_par->depth) {
+ 		case 8:
+ 			PM3_SLOW_WRITE_REG(PM3DitherMode,
+@@ -1842,10 +1776,7 @@
+ 	height = height * fontheight(p);
+ 	c = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ 
+-	/* block fills in 32bpp are hard, but in low res (width <= 1600 :-)
+-	   we can use 16bpp operations, but not if NoWriteMask is on (SDRAM)  */
+-	if ((l_fb_info->current_par->width > 1600) ||
+-	    (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)) {
++	if (l_fb_info->current_par->width > 1600) {
+ 		PM3_WAIT(4);
+ 
+ 		PM3_WRITE_REG(PM3Config2D,
+@@ -1867,7 +1798,7 @@
+ 			      PM3Render2D_SpanOperation |
+ 			      (PM3Render2D_Width(width)) |
+ 			      (PM3Render2D_Height(height)));
+-	} else {
++	} else {		/* block fills in 32bpp are hard, but in low res (width <= 1600 :-) we can use 16bpp operations */
+ 		PM3_WAIT(8);
+ 
+ 		PM3_WRITE_REG(PM3FBBlockColor, c);
+@@ -1992,10 +1923,7 @@
+ 
+ 	PM3_WAIT(4);
+ 
+-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-		PM3_WRITE_REG(PM3ForegroundColor, c);
+-	else
+-		PM3_WRITE_REG(PM3FBBlockColor, c);
++	PM3_WRITE_REG(PM3FBBlockColor, c);
+ 
+ 	PM3_WRITE_REG(PM3Config2D,
+ 				  PM3Config2D_UseConstantSource |
+@@ -2006,23 +1934,14 @@
+ 	PM3_WRITE_REG(PM3RectanglePosition,
+ 		      (PM3RectanglePosition_XOffset(sx)) |
+ 		      (PM3RectanglePosition_YOffset(sy)));
+-	
+-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-		PM3_WRITE_REG(PM3Render2D,
+-			      PM3Render2D_XPositive |
+-			      PM3Render2D_YPositive |
+-			      PM3Render2D_Operation_Normal |
+-			      PM3Render2D_SpanOperation |
+-			      (PM3Render2D_Width(width)) |
+-			      (PM3Render2D_Height(height)));
+-	else
+-		PM3_WRITE_REG(PM3Render2D,
+-			      PM3Render2D_XPositive |
+-			      PM3Render2D_YPositive |
+-			      PM3Render2D_Operation_Normal |
+-			      (PM3Render2D_Width(width)) |
+-			      (PM3Render2D_Height(height)));
+-	
++
++	PM3_WRITE_REG(PM3Render2D,
++		      PM3Render2D_XPositive |
++		      PM3Render2D_YPositive |
++		      PM3Render2D_Operation_Normal |
++		      (PM3Render2D_Width(width)) |
++		      (PM3Render2D_Height(height)));
++
+ 	pm3fb_wait_pm3(l_fb_info);
+ }
+ 
+@@ -2048,69 +1967,45 @@
+ 					  PM3Config2D_ForegroundROPEnable |
+ 					  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+ 					  PM3Config2D_FBWriteEnable);
+-		
+-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-			PM3_WRITE_REG(PM3ForegroundColor, c);
+-		else
+-			PM3_WRITE_REG(PM3FBBlockColor, c);
+-		
++
++		PM3_WRITE_REG(PM3FBBlockColor, c);
++
+ 		PM3_WRITE_REG(PM3RectanglePosition,
+ 			      (PM3RectanglePosition_XOffset
+ 			       (p->var.xoffset +
+ 				sx)) | (PM3RectanglePosition_YOffset(p->
+ 								     var.
+ 								     yoffset)));
+-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-			PM3_WRITE_REG(PM3Render2D,
+-				      PM3Render2D_XPositive |
+-				      PM3Render2D_YPositive |
+-				      PM3Render2D_Operation_Normal |
+-				      PM3Render2D_SpanOperation |
+-				      (PM3Render2D_Width(p->var.xres - sx)) |
+-				      (PM3Render2D_Height(p->var.yres)));
+-		else
+-			PM3_WRITE_REG(PM3Render2D,
+-				      PM3Render2D_XPositive |
+-				      PM3Render2D_YPositive |
+-				      PM3Render2D_Operation_Normal |
+-				      (PM3Render2D_Width(p->var.xres - sx)) |
+-				      (PM3Render2D_Height(p->var.yres)));
++
++		PM3_WRITE_REG(PM3Render2D,
++			      PM3Render2D_XPositive |
++			      PM3Render2D_YPositive |
++			      PM3Render2D_Operation_Normal |
++			      (PM3Render2D_Width(p->var.xres - sx)) |
++			      (PM3Render2D_Height(p->var.yres)));
+ 	}
+-	
++
+ 	/* bottom margin left -> right */
+ 	PM3_WAIT(4);
+-	
++
+ 	PM3_WRITE_REG(PM3Config2D,
+-		      PM3Config2D_UseConstantSource |
+-		      PM3Config2D_ForegroundROPEnable |
+-		      (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
+-		      PM3Config2D_FBWriteEnable);
+-	
+-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-		PM3_WRITE_REG(PM3ForegroundColor, c);
+-	else
+-		PM3_WRITE_REG(PM3FBBlockColor, c);
+-	
+-	
++				  PM3Config2D_UseConstantSource |
++				  PM3Config2D_ForegroundROPEnable |
++				  (PM3Config2D_ForegroundROP(0x3)) |	/* Ox3 is GXcopy */
++				  PM3Config2D_FBWriteEnable);
++
++	PM3_WRITE_REG(PM3FBBlockColor, c);
++
+ 	PM3_WRITE_REG(PM3RectanglePosition,
+ 		      (PM3RectanglePosition_XOffset(p->var.xoffset)) |
+ 		      (PM3RectanglePosition_YOffset(p->var.yoffset + sy)));
+-	
+-	if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-		PM3_WRITE_REG(PM3Render2D,
+-			      PM3Render2D_XPositive |
+-			      PM3Render2D_YPositive |
+-			      PM3Render2D_Operation_Normal |
+-			      PM3Render2D_SpanOperation |
+-			      (PM3Render2D_Width(p->var.xres)) |
+-			      (PM3Render2D_Height(p->var.yres - sy)));
+-	else
+-		PM3_WRITE_REG(PM3Render2D,
+-			      PM3Render2D_XPositive |
+-			      PM3Render2D_YPositive |
+-			      PM3Render2D_Operation_Normal |
+-			      (PM3Render2D_Width(p->var.xres)) |
+-			      (PM3Render2D_Height(p->var.yres - sy)));
++
++	PM3_WRITE_REG(PM3Render2D,
++		      PM3Render2D_XPositive |
++		      PM3Render2D_YPositive |
++		      PM3Render2D_Operation_Normal |
++		      (PM3Render2D_Width(p->var.xres)) |
++		      (PM3Render2D_Height(p->var.yres - sy)));
+ 
+ 	pm3fb_wait_pm3(l_fb_info);
+ }
+@@ -2288,7 +2183,7 @@
+ 			    int c, int yy, int xx)
+ {
+ 	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+-	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
++	u8 *cdat, asx = 0, asy = 0, o_x, o_y;
+ 	u32 fgx, bgx, ldat;
+ 	int sx, sy, i;
+ 
+@@ -2398,7 +2293,7 @@
+ 			     int xx)
+ {
+ 	struct pm3fb_info *l_fb_info = (struct pm3fb_info *) p->fb_info;
+-	u8 *cdat, asx = 0, asy = 0, o_x = 0, o_y = 0;
++	u8 *cdat, asx = 0, asy = 0, o_x, o_y;
+ 	u32 fgx, bgx, ldat;
+ 	int sx, sy, i, j;
+ 	u16 sc;
+@@ -2516,12 +2411,7 @@
+ 	yy = yy * fontheight(p);
+ 
+ 	if (l_fb_info->current_par->depth == 8)
+-	{
+-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0x0F0F0F0F);
+-		else
+-			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
+-	}
++		PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0x0F0F0F0F);
+ 
+ 	PM3_WAIT(3);
+ 
+@@ -2547,12 +2437,7 @@
+ 	pm3fb_wait_pm3(l_fb_info);
+ 
+ 	if (l_fb_info->current_par->depth == 8)
+-	{
+-		if (l_fb_info->memt.caps & PM3LocalMemCaps_NoWriteMask)
+-			PM3_SLOW_WRITE_REG(PM3FBSoftwareWriteMask, 0xFFFFFFFF);
+-		else
+-			PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
+-	}
++		PM3_SLOW_WRITE_REG(PM3FBHardwareWriteMask, 0xFFFFFFFF);
+ }
+ 
+ #endif /* FBCON_HAS_CFB8 || FBCON_HAS_CFB16 || FBCON_HAS_CFB32 */
+@@ -2640,25 +2525,12 @@
+ 	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+ 
+ 	if (!(depth_supported(bd))) {
+-		printk(KERN_WARNING "pm3fb: ignoring invalid depth %s for board #%ld\n",
+-		       bds, board_num);
++		DPRINTK(1, "Invalid depth: %s\n", bds);
+ 		return;
+ 	}
+ 	depth[board_num] = bd;
+ }
+ 
+-static void pm3fb_forcesize_setup(char *bds, unsigned long board_num)
+-{
+-	unsigned long bd = simple_strtoul(bds, (char **) NULL, 10);
+-
+-	if (bd > 64) {
+-		printk(KERN_WARNING "pm3fb: ignoring invalid memory size %s for board #%ld\n",
+-		       bds, board_num);
+-		return;
+-	}
+-	forcesize[board_num] = bd;
+-}
+-
+ static char *pm3fb_boardnum_setup(char *options, unsigned long *bn)
+ {
+ 	char *next;
+@@ -2752,12 +2624,6 @@
+ 			pm3fb_bootdepth_setup(options, bn);
+ 		} else if (!strncmp(options, "printtimings", 12)) {
+ 			printtimings = 1;
+-		} else if (!strncmp(options, "flatpanel:", 10)) {
+-			options = pm3fb_boardnum_setup(options + 10, &bn);
+-			flatpanel[bn] = 1;
+-		} else if (!strncmp(options, "forcesize:", 10)) {
+-			options = pm3fb_boardnum_setup(options + 10, &bn);
+-			pm3fb_forcesize_setup(options, bn);
+ 		}
+ 		options = next;
+ 	}
+@@ -3495,7 +3361,7 @@
+ 				    pci_resource_start(l_fb_info->dev, 1);
+ 				l_fb_info->v_fb = (unsigned char *) -1;
+ 
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) 	/* full resource management, new in linux-2.4.x */
++#ifdef KERNEL_2_4		/* full resource management, new in linux-2.4.x */
+ 				if (!request_mem_region
+ 				    ((unsigned long)l_fb_info->p_fb, 64 * 1024 * 1024, /* request full aperture size */
+ 				     "pm3fb")) {
+@@ -3512,10 +3378,8 @@
+ 					     l_fb_info->board_num);
+ 					continue;
+ 				}
+-#endif /* KERNEL_2_4 or KERNEL_2_5 */
+-				if (forcesize[l_fb_info->board_num])
+-					l_fb_info->fb_size = forcesize[l_fb_info->board_num];
+-				
++#endif /* KERNEL_2_4 */
++
+ 				l_fb_info->fb_size =
+ 				    pm3fb_size_memory(l_fb_info);
+ 
+@@ -3611,7 +3475,7 @@
+ /* ***** standard FB API init functions ***** */
+ /* ****************************************** */
+ 
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ int __init pm3fb_setup(char *options)
+ #endif
+ #ifdef KERNEL_2_2
+@@ -3627,12 +3491,12 @@
+ 		PM3_OPTIONS_SIZE) ? PM3_OPTIONS_SIZE : (opsi + 1));
+ 	g_options[PM3_OPTIONS_SIZE - 1] = 0;
+ 
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ 	return (0);
+ #endif
+ }
+ 
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ int __init pm3fb_init(void)
+ #endif
+ #ifdef KERNEL_2_2
+@@ -3641,7 +3505,7 @@
+ {
+ 	DTRACE;
+ 
+-	DPRINTK(2, "This is pm3fb.c, CVS version: $Header$");
++	DPRINTK(2, "This is pm3fb.c, CVS version: $Header$");
+ 
+ 	pm3fb_real_setup(g_options);
+ 
+@@ -3650,7 +3514,7 @@
+ 	if (!fb_info[0].dev) {	/* not even one board ??? */
+ 		DPRINTK(1, "No PCI Permedia3 board detected\n");
+ 	}
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ 	return (0);
+ #endif
+ }
+@@ -3753,9 +3617,7 @@
+ MODULE_PARM(depth,PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+ MODULE_PARM_DESC(depth,"boot-time depth");
+ MODULE_PARM(printtimings, "h");
+-MODULE_PARM_DESC(printtimings, "print the memory timings of the card(s)");
+-MODULE_PARM(forcesize, PM3_MAX_BOARD_MODULE_ARRAY_SHORT);
+-MODULE_PARM_DESC(forcesize, "force specified memory size");
++MODULE_PARM_DESC(printtimings, "print the memory timngs of the card(s)");
+ /*
+ MODULE_SUPPORTED_DEVICE("Permedia3 PCI boards")
+ MODULE_GENERIC_TABLE(gtype,name)
+@@ -3829,14 +3691,14 @@
+ 				if (l_fb_info->vIOBase !=
+ 				    (unsigned char *) -1) {
+ 					pm3fb_unmapIO(l_fb_info);
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5)
++#ifdef KERNEL_2_4
+ 					release_mem_region(l_fb_info->p_fb,
+ 							   l_fb_info->
+ 							   fb_size);
+ 					release_mem_region(l_fb_info->
+ 							   pIOBase,
+ 							   PM3_REGS_SIZE);
+-#endif /* KERNEL_2_4 or KERNEL_2_5 */
++#endif /* KERNEL_2_4 */
+ 				}
+ 				unregister_framebuffer(&l_fb_info->gen.
+ 						       info);
+--- linux-2.4.25/drivers/video/pm3fb.h~2.4.25-vrs2.patch	2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.25/drivers/video/pm3fb.h	2004-03-31 17:15:09.000000000 +0200
+@@ -8,7 +8,7 @@
+  *  License. See the file COPYING in the main directory of this archive for
+  *  more details.
+  *
+- *  $Header$
++ *  $Header$
+  *
+  */
+ 
+@@ -92,7 +92,6 @@
+ #define PM3MemBypassWriteMask					0x1008
+ #define PM3MemScratch						0x1010
+ #define PM3LocalMemCaps						0x1018
+-        #define PM3LocalMemCaps_NoWriteMask                     (1 << 28)
+ #define PM3LocalMemTimings					0x1020
+ #define PM3LocalMemControl					0x1028
+ #define PM3LocalMemRefresh					0x1030
+@@ -1121,10 +1120,6 @@
+ 
+ /* kernel -specific definitions */
+ /* what kernel is this ? */
+-#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)))
+-#define KERNEL_2_5
+-#endif
+-
+ #if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)))
+ #define KERNEL_2_4
+ #endif
+@@ -1138,8 +1133,8 @@
+ #endif
+ #endif
+ 
+-#if (!defined(KERNEL_2_2)) && (!defined(KERNEL_2_4)) && (!defined(KERNEL_2_5))
+-#error "Only kernel 2.2.x, kernel 2.4.y and kernel 2.5.z might work"
++#if (!defined(KERNEL_2_2)) && (!defined(KERNEL_2_4))
++#error "Only kernel 2.2.x and kernel 2.4.y might work"
+ #endif
+ 
+ /* not sure if/why it's needed. doesn't work without on my PowerMac... */
+@@ -1147,11 +1142,6 @@
+ #define MUST_BYTESWAP
+ #endif
+ 
+-/* for compatibility between 2.5, 2.4 and 2.2 */
+-#ifndef B_FREE
+-#define B_FREE   -1
+-#endif
+-
+ /* permedia3 -specific definitions */
+ #define PM3_SCALE_TO_CLOCK(pr, fe, po) ((2 * PM3_REF_CLOCK * fe) / (pr * (1 << (po))))
+ #define PICOS2KHZ(a) (1000000000UL/(a))
+@@ -1219,10 +1209,10 @@
+ #define PM3_READ_REG(r) readl((l_fb_info->vIOBase + r))
+ #endif /* MUST_BYTESWAP */
+ #endif /* KERNEL_2_2 */
+-#if (defined KERNEL_2_4) || (defined KERNEL_2_5) /* native-endian access */
++#ifdef KERNEL_2_4 /* native-endian access */
+ #define PM3_WRITE_REG(r, v) fb_writel(v, (l_fb_info->vIOBase + r))
+ #define PM3_READ_REG(r) fb_readl((l_fb_info->vIOBase + r))
+-#endif /* KERNEL_2_4 or KERNEL_2_5 */
++#endif /* KERNEL_2_4 */
+ 
+ 
+ #define depth2bpp(d) ((d + 7L) & ~7L)
+--- linux-2.4.25/drivers/video/sa1100fb.c~2.4.25-vrs2.patch	2001-11-14 23:52:20.000000000 +0100
++++ linux-2.4.25/drivers/video/sa1100fb.c	2004-03-31 17:15:09.000000000 +0200
+@@ -23,11 +23,11 @@
+  * Thank you.
+  *
+  * Known problems:
+- *  - With the Neponset plugged into an Assabet, LCD powerdown
+- *    doesn't work (LCD stays powered up).  Therefore we shouldn't
+- *    blank the screen.
+- *  - We don't limit the CPU clock rate nor the mode selection
+- *    according to the available SDRAM bandwidth.
++ *	- With the Neponset plugged into an Assabet, LCD powerdown
++ *	  doesn't work (LCD stays powered up).  Therefore we shouldn't
++ *	  blank the screen.
++ *	- We don't limit the CPU clock rate nor the mode selection
++ *	  according to the available SDRAM bandwidth.
+  *
+  * Other notes:
+  *	- Linear grayscale palettes and the kernel.
+@@ -41,6 +41,17 @@
+  *	  David Neuer.  It's around 8 lines of C code, plus another 4 to
+  *	  detect if we are using grayscale.
+  *
++ *	- The following must never be specified in a panel definition:
++ *	     LCCR0_LtlEnd, LCCR3_PixClkDiv, LCCR3_VrtSnchL, LCCR3_HorSnchL
++ *
++ *	- The following should be specified:
++ *	     either LCCR0_Color or LCCR0_Mono
++ *	     either LCCR0_Sngl or LCCR0_Dual
++ *	     either LCCR0_Act or LCCR0_Pas
++ *	     either LCCR3_OutEnH or LCCD3_OutEnL
++ *	     either LCCR3_PixRsEdg or LCCR3_PixFlEdg
++ *	     either LCCR3_ACBsDiv or LCCR3_ACBsCntOff
++ *
+  * Code Status:
+  * 1999/04/01:
+  *	- Driver appears to be working for Brutus 320x200x8bpp mode.  Other
+@@ -147,6 +158,10 @@
+  *
+  * 2001/10/12: <rmk@arm.linux.org.uk>
+  *	- Add patch 681/1 and clean up stork definitions.
++ *
++ * 2002/02/21: <abraham@2d3d.co.za>
++ *  - Added support for ICP LCD-Kit01 on Frodo.
++ *  - Added support for backlight via CPLDs on Frodo.
+  */
+ 
+ #include <linux/config.h>
+@@ -169,6 +184,7 @@
+ #include <asm/mach-types.h>
+ #include <asm/uaccess.h>
+ #include <asm/arch/assabet.h>
++#include <asm/arch/shannon.h>
+ 
+ #include <video/fbcon.h>
+ #include <video/fbcon-mfb.h>
+@@ -177,11 +193,6 @@
+ #include <video/fbcon-cfb16.h>
+ 
+ /*
+- * enable this if your panel appears to have broken
+- */
+-#undef CHECK_COMPAT
+-
+-/*
+  * debugging?
+  */
+ #define DEBUG 0
+@@ -197,243 +208,6 @@
+ void (*sa1100fb_blank_helper)(int blank);
+ EXPORT_SYMBOL(sa1100fb_blank_helper);
+ 
+-
+-#ifdef CHECK_COMPAT
+-static void
+-sa1100fb_check_shadow(struct sa1100fb_lcd_reg *new_regs,
+-			   struct fb_var_screeninfo *var, u_int pcd)
+-{
+-	struct sa1100fb_lcd_reg shadow;
+-	int different = 0;
+-
+-	/*
+-	 * These machines are good machines!
+-	 */
+-	if (machine_is_assabet() || machine_is_h3600())
+-		return;
+-
+-	/*
+-	 * The following ones are bad, bad, bad.
+-	 * Please make yours good!
+-	 */
+-	if (machine_is_pangolin()) {
+-		DPRINTK("Configuring Pangolin LCD\n");
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Color + LCCR0_LDM +
+-		    LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
+-		    LCCR0_LtlEnd + LCCR0_DMADel(0);
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(64) +
+-		    LCCR1_BegLnDel(160) + LCCR1_EndLnDel(24);
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(7) +
+-		    LCCR2_BegFrmDel(7) + LCCR2_EndFrmDel(1);
+-		shadow.lccr3 =
+-		    LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH +
+-		    LCCR3_VrtSnchH + LCCR3_PixFlEdg + LCCR3_OutEnH;
+-
+-		DPRINTK("pcd = %x, PixCldDiv(pcd)=%x\n",
+-			pcd, LCCR3_PixClkDiv(pcd));
+-	}
+-	if (machine_is_freebird()) {
+-		DPRINTK("Configuring  Freebird LCD\n");
+-#if 1
+-		shadow.lccr0 = 0x00000038;
+-		shadow.lccr1 = 0x010108e0;
+-		shadow.lccr2 = 0x0000053f;
+-		shadow.lccr3 = 0x00000c20;
+-#else
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+-		    LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+-		    LCCR0_LtlEnd + LCCR0_DMADel(0);
+-		/* Check ,Chester */
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+-		    LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+-		/* Check ,Chester */
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+-		    LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+-		/* Check ,Chester */
+-		shadow.lccr3 =
+-		    LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
+-		    LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+-		    LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd);
+-#endif
+-	}
+-	if (machine_is_brutus()) {
+-		DPRINTK("Configuring  Brutus LCD\n");
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas +
+-		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+-		    LCCR0_DMADel(0);
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(3) +
+-		    LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+-		    LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+-		shadow.lccr3 =
+-		    LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+-		    LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+-		    LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
+-	}
+-	if (machine_is_huw_webpanel()) {
+-		DPRINTK("Configuring  HuW LCD\n");
+-		shadow.lccr0 = LCCR0_LEN + LCCR0_Dual + LCCR0_LDM;
+-		shadow.lccr1 = LCCR1_DisWdth(var->xres) +
+-		    LCCR1_HorSnchWdth(3) +
+-		    LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+-		shadow.lccr2 = 239 + LCCR2_VrtSnchWdth(1);
+-		shadow.lccr3 = 8 + LCCR3_OutEnH +
+-		    LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+-		    LCCR3_HorSnchH + LCCR3_ACBsCntOff + LCCR3_ACBsDiv(2);
+-	}
+-	if (machine_is_lart()) {
+-		DPRINTK("Configuring LART LCD\n");
+-#if defined LART_GREY_LCD
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
+-		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+-		    LCCR0_DMADel(0);
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(1) +
+-		    LCCR1_BegLnDel(4) + LCCR1_EndLnDel(2);
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+-		    LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+-		shadow.lccr3 =
+-		    LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
+-		    LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH;
+-#endif
+-#if defined LART_COLOR_LCD
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+-		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+-		    LCCR0_DMADel(0);
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(2) +
+-		    LCCR1_BegLnDel(69) + LCCR1_EndLnDel(8);
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(3) +
+-		    LCCR2_BegFrmDel(14) + LCCR2_EndFrmDel(4);
+-		shadow.lccr3 =
+-		    LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
+-		    LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL +
+-		    LCCR3_PixFlEdg;
+-#endif
+-#if defined LART_VIDEO_OUT
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+-		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+-		    LCCR0_DMADel(0);
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(640) + LCCR1_HorSnchWdth(95) +
+-		    LCCR1_BegLnDel(40) + LCCR1_EndLnDel(24);
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(480) + LCCR2_VrtSnchWdth(2) +
+-		    LCCR2_BegFrmDel(32) + LCCR2_EndFrmDel(11);
+-		shadow.lccr3 =
+-		    LCCR3_PixClkDiv(8) + LCCR3_ACBsDiv(512) +
+-		    LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH +
+-		    LCCR3_PixFlEdg + LCCR3_OutEnL;
+-#endif
+-	}
+-	if (machine_is_graphicsclient()) {
+-		DPRINTK("Configuring GraphicsClient LCD\n");
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act;
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(9) +
+-		    LCCR1_EndLnDel(54) + LCCR1_BegLnDel(54);
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(9) +
+-		    LCCR2_EndFrmDel(32) + LCCR2_BegFrmDel(24);
+-		shadow.lccr3 =
+-		    LCCR3_PixClkDiv(10) + LCCR3_ACBsDiv(2) +
+-		    LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL;
+-	}
+-	if (machine_is_omnimeter()) {
+-		DPRINTK("Configuring  OMNI LCD\n");
+-		shadow.lccr0 = LCCR0_LEN | LCCR0_CMS | LCCR0_DPD;
+-		shadow.lccr1 =
+-		    LCCR1_BegLnDel(10) + LCCR1_EndLnDel(10) +
+-		    LCCR1_HorSnchWdth(1) + LCCR1_DisWdth(var->xres);
+-		shadow.lccr2 = LCCR2_DisHght(var->yres);
+-		shadow.lccr3 =
+-		    LCCR3_ACBsDiv(0xFF) + LCCR3_PixClkDiv(44);
+-//jca (GetPCD(25) << LCD3_V_PCD);
+-	}
+-	if (machine_is_xp860()) {
+-		DPRINTK("Configuring XP860 LCD\n");
+-		shadow.lccr0 =
+-		    LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+-		    LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM + LCCR0_DMADel(0);
+-		shadow.lccr1 =
+-		    LCCR1_DisWdth(var->xres) +
+-		    LCCR1_HorSnchWdth(var->hsync_len) +
+-		    LCCR1_BegLnDel(var->left_margin) +
+-		    LCCR1_EndLnDel(var->right_margin);
+-		shadow.lccr2 =
+-		    LCCR2_DisHght(var->yres) +
+-		    LCCR2_VrtSnchWdth(var->vsync_len) +
+-		    LCCR2_BegFrmDel(var->upper_margin) +
+-		    LCCR2_EndFrmDel(var->lower_margin);
+-		shadow.lccr3 =
+-		    LCCR3_PixClkDiv(6) + LCCR3_HorSnchL + LCCR3_VrtSnchL;
+-	}
+-
+-	/*
+-	 * Ok, since we're calculating these values, we want to know
+-	 * if the calculation is correct.  If you see any of these
+-	 * messages _PLEASE_ report the incident to me for diagnosis,
+-	 * including details about what was happening when the
+-	 * messages appeared. --rmk, 30 March 2001
+-	 */
+-	if (shadow.lccr0 != new_regs->lccr0) {
+-		printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n",
+-			shadow.lccr1, new_regs->lccr1);
+-		different = 1;
+-	}
+-	if (shadow.lccr1 != new_regs->lccr1) {
+-		printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n",
+-			shadow.lccr1, new_regs->lccr1);
+-		different = 1;
+-	}
+-	if (shadow.lccr2 != new_regs->lccr2) {
+-		printk(KERN_ERR "LCCR2 mismatch: 0x%08x != 0x%08x\n",
+-			shadow.lccr2, new_regs->lccr2);
+-		different = 1;
+-	}
+-	if (shadow.lccr3 != new_regs->lccr3) {
+-		printk(KERN_ERR "LCCR3 mismatch: 0x%08x != 0x%08x\n",
+-			shadow.lccr3, new_regs->lccr3);
+-		different = 1;
+-	}
+-	if (different) {
+-		printk(KERN_ERR "var: xres=%d hslen=%d lm=%d rm=%d\n",
+-			var->xres, var->hsync_len,
+-			var->left_margin, var->right_margin);
+-		printk(KERN_ERR "var: yres=%d vslen=%d um=%d bm=%d\n",
+-			var->yres, var->vsync_len,
+-			var->upper_margin, var->lower_margin);
+-
+-		printk(KERN_ERR "Please report this to Russell King "
+-			"<rmk@arm.linux.org.uk>\n");
+-	}
+-
+-	DPRINTK("olccr0 = 0x%08x\n", shadow.lccr0);
+-	DPRINTK("olccr1 = 0x%08x\n", shadow.lccr1);
+-	DPRINTK("olccr2 = 0x%08x\n", shadow.lccr2);
+-	DPRINTK("olccr3 = 0x%08x\n", shadow.lccr3);
+-}
+-#else
+-#define sa1100fb_check_shadow(regs,var,pcd)
+-#endif
+-
+-
+-
+ /*
+  * IMHO this looks wrong.  In 8BPP, length should be 8.
+  */
+@@ -488,42 +262,56 @@
+ #endif
+ #endif
+ 
+-#ifdef CONFIG_SA1100_H3600
+-static struct sa1100fb_mach_info h3600_info __initdata = {
+-#ifdef CONFIG_IPAQ_H3100
+-	pixclock:	407766,		bpp:		4,
++#ifdef CONFIG_SA1100_H3XXX
++static struct sa1100fb_mach_info h3800_info __initdata = {
++	pixclock:	174757, 	bpp:		16,
+ 	xres:		320,		yres:		240,
+ 
+-	hsync_len:	26,		vsync_len:	41,
+-	left_margin:	4,		upper_margin:	0,
+-	right_margin:	4,		lower_margin:	0,
++	hsync_len:	3,		vsync_len:	3,
++	left_margin:	12,		upper_margin:	10,
++	right_margin:	17,		lower_margin:	1,
+ 
+-	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+-	cmap_greyscale:	1,		cmap_static:	1,
+-	cmap_inverse:	1,
++	sync:		0,		cmap_static:	1,
+ 
+-	lccr0:		LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+-#else
+-	pixclock:	174757,		bpp:		16,
++	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
++	lccr3:		LCCR3_ACBsCntOff | LCCR3_PixFlEdg | LCCR3_OutEnH,
++};
++
++static struct sa1100fb_mach_info h3600_info __initdata = {
++	pixclock:	174757, 	bpp:		16,
+ 	xres:		320,		yres:		240,
+ 
+ 	hsync_len:	3,		vsync_len:	3,
+ 	left_margin:	12,		upper_margin:	10,
+ 	right_margin:	17,		lower_margin:	1,
+ 
+-	sync:		0,
++	sync:		0,		cmap_static:	1,
+ 
+ 	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+-	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+-#endif
++	lccr3:		LCCR3_ACBsCntOff | LCCR3_OutEnH | LCCR3_PixFlEdg,
+ };
+ 
+ static struct sa1100fb_rgb h3600_rgb_16 = {
+ 	red:	{ offset: 12, length: 4, },
+ 	green:	{ offset: 7,  length: 4, },
+ 	blue:	{ offset: 1,  length: 4, },
+-	transp:	{ offset: 0,  length: 0, },
++	transp: { offset: 0,  length: 0, },
++};
++
++static struct sa1100fb_mach_info h3100_info __initdata = {
++	pixclock:	406977, 	bpp:		4,
++	xres:		320,		yres:		240,
++
++	hsync_len:	26,		vsync_len:	41,
++	left_margin:	4,		upper_margin:	0,
++	right_margin:	4,		lower_margin:	0,
++
++	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++	cmap_greyscale: 1,
++	cmap_inverse:	1,
++
++	lccr0:		LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
++	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+ };
+ #endif
+ 
+@@ -618,6 +406,58 @@
+ 
+ #ifdef CONFIG_SA1100_GRAPHICSCLIENT
+ static struct sa1100fb_mach_info graphicsclient_info __initdata = {
++// for LQ64D343
++	pixclock:	53500,		bpp:		8,
++	xres:		640,		yres:		480,
++
++	hsync_len:	9,		vsync_len:	9,
++	left_margin:	54,		upper_margin:	24,
++	right_margin:	54,		lower_margin:	32,
++
++	sync:		0,
++
++	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
++	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
++};
++#endif
++
++#ifdef CONFIG_SA1100_GRAPHICSMASTER
++static struct sa1100fb_mach_info graphicsmaster_info __initdata = {
++// for LQ64D343
++	pixclock:	53500,		bpp:		8,
++	xres:		640,		yres:		480,
++
++	hsync_len:	9,		vsync_len:	9,
++	left_margin:	54,		upper_margin:	24,
++	right_margin:	54,		lower_margin:	32,
++
++	sync:		0,
++
++	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
++	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
++};
++#endif
++
++#ifdef CONFIG_SA1100_ADSBITSY
++static struct sa1100fb_mach_info adsbitsy_info __initdata = {
++// for LQ64D343
++	pixclock:	53500,		bpp:		8,
++	xres:		640,		yres:		480,
++
++	hsync_len:	9,		vsync_len:	9,
++	left_margin:	54,		upper_margin:	24,
++	right_margin:	54,		lower_margin:	32,
++
++	sync:		0,
++
++	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
++	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
++};
++#endif
++
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++static struct sa1100fb_mach_info adsbitsyplus_info __initdata = {
++// for LQ64D343
+ 	pixclock:	53500,		bpp:		8,
+ 	xres:		640,		yres:		480,
+ 
+@@ -699,7 +539,6 @@
+ 	lccr3:		LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+ };
+ #endif
+-
+ #ifdef LART_KIT01_LCD
+ static struct sa1100fb_mach_info lart_kit01_info __initdata =
+ {
+@@ -707,7 +546,7 @@
+ 	xres:		640,		yres:		480,
+ 
+ 	hsync_len:	64,		vsync_len:	3,
+-	left_margin:	122,		upper_margin:	45,
++	left_margin:	122,	upper_margin:	45,
+ 	right_margin:	10,		lower_margin:	10,
+ 
+ 	sync:		0,
+@@ -717,6 +556,40 @@
+ };
+ #endif
+ 
++#ifdef CONFIG_SA1100_FRODO
++static struct sa1100fb_mach_info frodo_kit01_info __initdata =
++{
++	/* best would be 41731 (25.8mhz), but we can only do 14.743mhz at 191.7mhz clock speed */
++	pixclock:		73030,		bpp:		16,
++	xres:			640,		yres:		480,
++
++	hsync_len:		32,		vsync_len:		19,
++	left_margin:	120,	upper_margin:	33,
++	right_margin:	17,		lower_margin:	12,
++
++	sync:			0,
++
++	lccr0:			LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
++	lccr3:			LCCR3_OutEnH | LCCR3_PixFlEdg
++};
++#endif
++
++#ifdef CONFIG_SA1100_SHANNON
++static struct sa1100fb_mach_info shannon_info __initdata = {
++	pixclock:	152500,		bpp:		8,
++	xres:		640,		yres:		480,
++
++	hsync_len:	4,		vsync_len:	3,
++	left_margin:	2,		upper_margin:	0,
++	right_margin:	1,		lower_margin:	0,
++
++	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, 
++
++	lccr0:		LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
++	lccr3:		LCCR3_ACBsDiv(512),
++};
++#endif
++
+ #ifdef CONFIG_SA1100_OMNIMETER
+ static struct sa1100fb_mach_info omnimeter_info __initdata = {
+ 	pixclock:	0,		bpp:		4,
+@@ -752,7 +625,24 @@
+ 	sync:		FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ 
+ 	lccr0:		LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+-	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg,
++	lccr3:		LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsCntOff,
++};
++#endif
++
++#ifdef CONFIG_SA1100_SIMPUTER
++static struct sa1100fb_mach_info simputer_info __initdata = {
++	pixclock:	70000,		bpp:		4,
++	xres:		320,		yres:		240,
++
++	hsync_len:	9,		vsync_len:	2,
++	left_margin:	9,		upper_margin:	0,
++	right_margin:	2,		lower_margin:	0,
++
++	cmap_greyscale:	1,
++	sync:		FB_SYNC_HOR_HIGH_ACT |  FB_SYNC_VERT_HIGH_ACT ,
++
++	lccr0:		LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
++	lccr3:		LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(202),
+ };
+ #endif
+ 
+@@ -828,7 +718,6 @@
+ #endif
+ 
+ 
+-
+ static struct sa1100fb_mach_info * __init
+ sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
+ {
+@@ -849,11 +738,17 @@
+ #endif
+ 	}
+ #endif
+-#ifdef CONFIG_SA1100_H3600
++#ifdef CONFIG_SA1100_H3XXX
+ 	if (machine_is_h3600()) {
+ 		inf = &h3600_info;
+ 		fbi->rgb[RGB_16] = &h3600_rgb_16;
+ 	}
++	if (machine_is_h3100()) {
++		inf = &h3100_info;
++	}
++	if (machine_is_h3800()) {
++		inf = &h3800_info;
++	}
+ #endif
+ #ifdef CONFIG_SA1100_BRUTUS
+ 	if (machine_is_brutus()) {
+@@ -876,6 +771,22 @@
+ 		inf = &graphicsclient_info;
+ 	}
+ #endif
++#ifdef CONFIG_SA1100_GRAPHICSMASTER
++	if (machine_is_graphicsmaster()) {
++		inf = &graphicsmaster_info;
++	}
++#endif
++#ifdef CONFIG_SA1100_ADSBITSY
++	if (machine_is_adsbitsy()) {
++		inf = &adsbitsy_info;
++	}
++#endif
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++	if (machine_is_adsbitsyplus()) {
++		inf = &adsbitsyplus_info;
++		}
++	}
++#endif
+ #ifdef CONFIG_SA1100_HUW_WEBPANEL
+ 	if (machine_is_huw_webpanel()) {
+ 		inf = &huw_webpanel_info;
+@@ -897,6 +808,21 @@
+ #endif
+ 	}
+ #endif
++#ifdef CONFIG_SA1100_FRODO
++	if (machine_is_frodo()) {
++		inf = &frodo_kit01_info;
++	}
++#endif
++#ifdef CONFIG_SA1100_SHANNON
++	if (machine_is_shannon()) {
++		inf = &shannon_info;
++	}
++#endif
++#ifdef CONFIG_SA1100_SIMPUTER
++	if (machine_is_simputer()) {
++		inf = &simputer_info;
++	}
++#endif
+ #ifdef CONFIG_SA1100_OMNIMETER
+ 	if (machine_is_omnimeter()) {
+ 		inf = &omnimeter_info;
+@@ -1556,7 +1482,8 @@
+ 	unsigned int pcd;
+ 
+ 	if (pixclock) {
+-		pcd = get_cclk_frequency() * pixclock;
++		pcd = cpufreq_get(0) / 100;
++		pcd *= pixclock;
+ 		pcd /= 10000000;
+ 		pcd += 1;	/* make up for integer math truncations */
+ 	} else {
+@@ -1580,6 +1507,7 @@
+ 	return pcd;
+ }
+ 
++
+ /*
+  * sa1100fb_activate_var():
+  *	Configures LCD Controller based on entries in var parameter.  Settings are      
+@@ -1659,8 +1587,6 @@
+ 	if (pcd)
+ 		new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+ 
+-	sa1100fb_check_shadow(&new_regs, var, pcd);
+-
+ 	DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
+ 	DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
+ 	DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
+@@ -1733,6 +1659,10 @@
+ 	if (machine_is_omnimeter())
+ 		LEDBacklightOn();
+ #endif
++#ifdef CONFIG_SA1100_FRODO
++	if (machine_is_frodo())
++		frodo_cpld_set (FRODO_CPLD_GENERAL,FRODO_LCD_BACKLIGHT);
++#endif
+ }
+ 
+ /*
+@@ -1755,6 +1685,10 @@
+ 	if (machine_is_omnimeter())
+ 		LEDBacklightOff();
+ #endif
++#ifdef CONFIG_SA1100_FRODO
++	if (machine_is_frodo())
++		frodo_cpld_clear (FRODO_CPLD_GENERAL,FRODO_LCD_BACKLIGHT);
++#endif
+ }
+ 
+ static void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi)
+@@ -1773,20 +1707,25 @@
+ 	if (machine_is_omnimeter())
+ 		LCDPowerOn();
+ #endif
+-#ifdef CONFIG_SA1100_H3600
+-	if (machine_is_h3600()) {
+-		set_h3600_egpio(EGPIO_H3600_LCD_ON |
+-				EGPIO_H3600_LCD_PCI |
+-				EGPIO_H3600_LCD_5V_ON |
+-				EGPIO_H3600_LVDD_ON);
+-	}
+-#endif
++	if (machine_is_h3xxx())
++		set_h3600_egpio( IPAQ_EGPIO_LCD_ON );     /* Turn on power to the LCD */
+ #ifdef CONFIG_SA1100_STORK
+ 	if (machine_is_stork()) {
+ 		storkSetLCDCPLD(0, 1);
+ 		storkSetLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
+  	}
+ #endif
++#ifdef CONFIG_SA1100_FRODO
++	if (machine_is_frodo())
++		sa1100fb_backlight_on(fbi);
++#endif
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++	if (machine_is_adsbitsyplus()) {
++		ADS_CPLD_PCON &= ~ADS_PCON_PANEL_ON;
++		ADS_CPLD_SUPPC |= ADS_SUPPC_VEE_ON;
++	}
++#endif
++
+ }
+ 
+ static void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
+@@ -1802,20 +1741,24 @@
+ 	if (machine_is_huw_webpanel())
+ 		BCR_set(BCR_TFT_NPWR);
+ #endif
+-#ifdef CONFIG_SA1100_H3600
+-	if (machine_is_h3600()) {
+-		clr_h3600_egpio(EGPIO_H3600_LCD_ON |
+-				EGPIO_H3600_LCD_PCI |
+-				EGPIO_H3600_LCD_5V_ON |
+-				EGPIO_H3600_LVDD_ON);
+-	}
+-#endif
++	if (machine_is_h3xxx())
++		clr_h3600_egpio( IPAQ_EGPIO_LCD_ON );
+ #ifdef CONFIG_SA1100_STORK
+ 	if (machine_is_stork()) {
+ 		storkSetLCDCPLD(0, 0);
+ 		storkClearLatchA(STORK_LCD_BACKLIGHT_INVERTER_ON);
+ 	}
+ #endif
++#ifdef CONFIG_SA1100_FRODO
++	if (machine_is_frodo())
++		sa1100fb_backlight_off(fbi);
++#endif
++#ifdef CONFIG_SA1100_ADSBITSYPLUS
++	if (machine_is_adsbitsyplus()) {
++		ADS_CPLD_PCON |= ADS_PCON_PANEL_ON;
++		ADS_CPLD_SUPPC &= ~ADS_SUPPC_VEE_ON;
++	}
++#endif
+ }
+ 
+ static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
+@@ -1911,15 +1854,29 @@
+ 	LCCR0 |= LCCR0_LEN;
+ 
+ #ifdef CONFIG_SA1100_GRAPHICSCLIENT
+-#error Where is GPIO24 set as an output?  Can we fit this in somewhere else?
+ 	if (machine_is_graphicsclient()) {
+ 		// From ADS doc again...same as disable
+ 		set_current_state(TASK_UNINTERRUPTIBLE);
+ 		schedule_timeout(20 * HZ / 1000);
+-		GPSR |= GPIO_GPIO24;
++		GPDR |= GPIO_GPIO24;
++		GPSR = GPIO_GPIO24;
++	}
++#endif
++#ifdef CONFIG_SA1100_GRAPHICSMASTER
++	if (machine_is_graphicsmaster()) {
++		// From ADS doc again...same as disable
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		schedule_timeout(20 * HZ / 1000);
++		GPDR |= GPIO_GPIO24;
++		GPSR = GPIO_GPIO24;
+ 	}
+ #endif
+ 
++	if (machine_is_shannon()) {
++		GPDR |= SHANNON_GPIO_DISP_EN;
++		GPSR |= SHANNON_GPIO_DISP_EN;
++	}	
++
+ 	DPRINTK("DBAR1 = %p\n", DBAR1);
+ 	DPRINTK("DBAR2 = %p\n", DBAR2);
+ 	DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
+@@ -1935,7 +1892,6 @@
+ 	DPRINTK("Disabling LCD controller\n");
+ 
+ #ifdef CONFIG_SA1100_GRAPHICSCLIENT
+-#error Where is GPIO24 set as an output?  Can we fit this in somewhere else?
+ 	if (machine_is_graphicsclient()) {
+ 		/*
+ 		 * From ADS internal document:
+@@ -1944,6 +1900,22 @@
+ 		 *
+ 		 * We'll wait 20msec.
+ 		 */
++		GPDR |= GPIO_GPIO24;
++		GPCR |= GPIO_GPIO24;
++		set_current_state(TASK_UNINTERRUPTIBLE);
++		schedule_timeout(20 * HZ / 1000);
++	}
++#endif
++#ifdef CONFIG_SA1100_GRAPHICSMASTER
++	if (machine_is_graphicsmaster()) {
++		/*
++		 * From ADS internal document:
++		 *  GPIO24 should be LOW at least 10msec prior to disabling
++		 *  the LCD interface.
++		 *
++		 * We'll wait 20msec.
++		 */
++		GPDR |= GPIO_GPIO24;
+ 		GPCR |= GPIO_GPIO24;
+ 		set_current_state(TASK_UNINTERRUPTIBLE);
+ 		schedule_timeout(20 * HZ / 1000);
+@@ -1958,12 +1930,15 @@
+ 	}
+ #endif
+ 
++	if (machine_is_shannon()) {
++		GPCR |= SHANNON_GPIO_DISP_EN;
++	}	
++
+ 	add_wait_queue(&fbi->ctrlr_wait, &wait);
+ 	set_current_state(TASK_UNINTERRUPTIBLE);
+ 
+ 	LCSR = 0xffffffff;	/* Clear LCD Status Register */
+ 	LCCR0 &= ~LCCR0_LDM;	/* Enable LCD Disable Done Interrupt */
+-	enable_irq(IRQ_LCD);	/* Enable LCD IRQ */
+ 	LCCR0 &= ~LCCR0_LEN;	/* Disable LCD Controller */
+ 
+ 	schedule_timeout(20 * HZ / 1000);
+@@ -2006,12 +1981,13 @@
+ 		 * Disable controller for clock change.  If the
+ 		 * controller is already disabled, then do nothing.
+ 		 */
+-		if (old_state != C_DISABLE) {
++		if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
+ 			fbi->state = state;
+ 			sa1100fb_disable_controller(fbi);
+ 		}
+ 		break;
+ 
++	case C_DISABLE_PM:
+ 	case C_DISABLE:
+ 		/*
+ 		 * Disable controller
+@@ -2050,6 +2026,16 @@
+ 		}
+ 		break;
+ 
++	case C_ENABLE_PM:
++		/*
++		 * Re-enable the controller after PM.  This is not
++		 * perfect - think about the case where we were doing
++		 * a clock change, and we suspended half-way through.
++		 */
++		if (old_state != C_DISABLE_PM)
++			break;
++		/* fall through */
++
+ 	case C_ENABLE:
+ 		/*
+ 		 * Power up the LCD screen, enable controller, and
+@@ -2162,10 +2148,10 @@
+ 
+ 		if (state == 0) {
+ 			/* Enter D0. */
+-			set_ctrlr_state(fbi, C_ENABLE);
++			set_ctrlr_state(fbi, C_ENABLE_PM);
+ 		} else {
+ 			/* Enter D1-D3.  Disable the LCD controller.  */
+-			set_ctrlr_state(fbi, C_DISABLE);
++			set_ctrlr_state(fbi, C_DISABLE_PM);
+ 		}
+ 	}
+ 	DPRINTK("done\n");
+@@ -2304,7 +2290,7 @@
+ 		goto failed;
+ 
+ 	ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT,
+-			  fbi->fb.fix.id, fbi);
++			  "LCD", fbi);
+ 	if (ret) {
+ 		printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
+ 		goto failed;
+--- linux-2.4.25/drivers/video/sa1100fb.h~2.4.25-vrs2.patch	2001-10-25 22:53:52.000000000 +0200
++++ linux-2.4.25/drivers/video/sa1100fb.h	2004-03-31 17:15:09.000000000 +0200
+@@ -127,6 +127,8 @@
+ #define C_DISABLE_CLKCHANGE	(2)
+ #define C_ENABLE_CLKCHANGE	(3)
+ #define C_REENABLE		(4)
++#define C_DISABLE_PM		(5)
++#define C_ENABLE_PM		(6)
+ 
+ #define SA1100_NAME	"SA1100"
+ 
+--- linux-2.4.25/fs/adfs/dir.c~2.4.25-vrs2.patch	2000-09-19 00:14:06.000000000 +0200
++++ linux-2.4.25/fs/adfs/dir.c	2004-03-31 17:15:09.000000000 +0200
+@@ -23,7 +23,7 @@
+ /*
+  * For future.  This should probably be per-directory.
+  */
+-static rwlock_t adfs_dir_lock;
++static rwlock_t adfs_dir_lock = RW_LOCK_UNLOCKED;
+ 
+ static int
+ adfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
+--- linux-2.4.25/fs/adfs/map.c~2.4.25-vrs2.patch	2001-10-25 22:53:53.000000000 +0200
++++ linux-2.4.25/fs/adfs/map.c	2004-03-31 17:15:09.000000000 +0200
+@@ -13,24 +13,27 @@
+ #include <linux/adfs_fs.h>
+ #include <linux/spinlock.h>
+ 
++#include <asm/unaligned.h>
++
+ #include "adfs.h"
+ 
+ /*
+  * For the future...
+  */
+-static rwlock_t adfs_map_lock;
++static rwlock_t adfs_map_lock = RW_LOCK_UNLOCKED;
+ 
++/*
++ * This is fun.  We need to load up to 19 bits from the map at an
++ * arbitary bit alignment.  (We're limited to 19 bits by F+ version
++ * 2).
++ */
+ #define GET_FRAG_ID(_map,_start,_idmask)				\
+ 	({								\
+-		unsigned long _v2, _frag;				\
+-		unsigned int _tmp;					\
+-		_tmp = _start >> 5;					\
+-		_frag = le32_to_cpu(_map[_tmp]);			\
+-		_v2   = le32_to_cpu(_map[_tmp + 1]);			\
+-		_tmp = start & 31;					\
+-		_frag = (_frag >> _tmp) | (_v2 << (32 - _tmp));		\
++		unsigned char *_m = _map + (_start >> 3);		\
++		u32 _frag = get_unaligned((u32 *)_m);			\
++		_frag >>= (_start & 7);					\
+ 		_frag & _idmask;					\
+-	})
++	})	
+ 
+ /*
+  * return the map bit offset of the fragment frag_id in
+@@ -44,14 +47,13 @@
+ 	    const unsigned int frag_id, unsigned int *offset)
+ {
+ 	const unsigned int mapsize = dm->dm_endbit;
+-	const unsigned int idmask = (1 << idlen) - 1;
+-	unsigned long *map = ((unsigned long *)dm->dm_bh->b_data) + 1;
++	const u32 idmask = (1 << idlen) - 1;
++	unsigned char *map = dm->dm_bh->b_data + 4;
+ 	unsigned int start = dm->dm_startbit;
+ 	unsigned int mapptr;
++	u32 frag;
+ 
+ 	do {
+-		unsigned long frag;
+-
+ 		frag = GET_FRAG_ID(map, start, idmask);
+ 		mapptr = start + idlen;
+ 
+@@ -59,15 +61,17 @@
+ 		 * find end of fragment
+ 		 */
+ 		{
+-			unsigned long v2;
++			u32 v, *_map = (u32 *)map;
+ 
+-			while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) {
++			v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
++			while (v == 0) {
+ 				mapptr = (mapptr & ~31) + 32;
+ 				if (mapptr >= mapsize)
+ 					goto error;
++				v = le32_to_cpu(_map[mapptr >> 5]);
+ 			}
+ 
+-			mapptr += 1 + ffz(~v2);
++			mapptr += 1 + ffz(~v);
+ 		}
+ 
+ 		if (frag == frag_id)
+@@ -75,8 +79,11 @@
+ again:
+ 		start = mapptr;
+ 	} while (mapptr < mapsize);
++	return -1;
+ 
+ error:
++	printk(KERN_ERR "adfs: oversized fragment 0x%x at 0x%x-0x%x\n",
++		frag, start, mapptr);
+ 	return -1;
+ 
+ found:
+@@ -102,10 +109,10 @@
+ 	const unsigned int mapsize = dm->dm_endbit + 32;
+ 	const unsigned int idlen  = asb->s_idlen;
+ 	const unsigned int frag_idlen = idlen <= 15 ? idlen : 15;
+-	const unsigned int idmask = (1 << frag_idlen) - 1;
+-	unsigned long *map = (unsigned long *)dm->dm_bh->b_data;
++	const u32 idmask = (1 << frag_idlen) - 1;
++	unsigned char *map = dm->dm_bh->b_data;
+ 	unsigned int start = 8, mapptr;
+-	unsigned long frag;
++	u32 frag;
+ 	unsigned long total = 0;
+ 
+ 	/*
+@@ -133,15 +140,17 @@
+ 		 * find end of fragment
+ 		 */
+ 		{
+-			unsigned long v2;
++			u32 v, *_map = (u32 *)map;
+ 
+-			while ((v2 = map[mapptr >> 5] >> (mapptr & 31)) == 0) {
++			v = le32_to_cpu(_map[mapptr >> 5]) >> (mapptr & 31);
++			while (v == 0) {
+ 				mapptr = (mapptr & ~31) + 32;
+ 				if (mapptr >= mapsize)
+ 					goto error;
++				v = le32_to_cpu(_map[mapptr >> 5]);
+ 			}
+ 
+-			mapptr += 1 + ffz(~v2);
++			mapptr += 1 + ffz(~v);
+ 		}
+ 
+ 		total += mapptr - start;
+--- linux-2.4.25/fs/adfs/super.c~2.4.25-vrs2.patch	2002-02-25 20:38:07.000000000 +0100
++++ linux-2.4.25/fs/adfs/super.c	2004-03-31 17:15:09.000000000 +0200
+@@ -386,6 +386,14 @@
+ 	sb->u.adfs_sb.s_size     = adfs_discsize(dr, sb->s_blocksize_bits);
+ 	sb->u.adfs_sb.s_version  = dr->format_version;
+ 	sb->u.adfs_sb.s_log2sharesize = dr->log2sharesize;
++
++	printk(KERN_DEBUG "ADFS: idlen %d map bit size %d sector size %d\n",
++		dr->idlen, 1 << dr->log2bpmb, 1 << dr->log2secsize);
++	printk(KERN_DEBUG "ADFS: map size %d map2blk %d version %d share size %d\n",
++		sb->u.adfs_sb.s_map_size,
++		sb->u.adfs_sb.s_map2blk,
++		sb->u.adfs_sb.s_version,
++		1 << sb->u.adfs_sb.s_log2sharesize);
+ 	
+ 	sb->u.adfs_sb.s_map = adfs_read_map(sb, dr);
+ 	if (!sb->u.adfs_sb.s_map)
+@@ -393,6 +401,8 @@
+ 
+ 	brelse(bh);
+ 
++	printk(KERN_DEBUG "ADFS: ids per zone %d\n", sb->u.adfs_sb.s_ids_per_zone);
++
+ 	/*
+ 	 * set up enough so that we can read an inode
+ 	 */
+--- linux-2.4.25/fs/binfmt_aout.c~2.4.25-vrs2.patch	2001-11-03 02:39:20.000000000 +0100
++++ linux-2.4.25/fs/binfmt_aout.c	2004-03-31 17:15:09.000000000 +0200
+@@ -422,7 +422,11 @@
+ 	start_thread(regs, ex.a_entry, current->mm->start_stack);
+ 	if (current->ptrace & PT_PTRACED)
+ 		send_sig(SIGTRAP, current, 0);
++#ifndef __arm__
+ 	return 0;
++#else
++	return regs->ARM_r0;
++#endif
+ }
+ 
+ static int load_aout_library(struct file *file)
+@@ -452,8 +456,11 @@
+ 
+ 	/* For  QMAGIC, the starting address is 0x20 into the page.  We mask
+ 	   this off to get the starting address for the page */
+-
+-	start_addr =  ex.a_entry & 0xfffff000;
++#ifndef __arm__
++	start_addr = ex.a_entry & 0xfffff000;
++#else
++	start_addr = ex.a_entry & 0xffff8000;
++#endif
+ 
+ 	if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
+ 		static unsigned long error_time;
+--- linux-2.4.25/fs/binfmt_elf.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/fs/binfmt_elf.c	2004-03-31 17:15:09.000000000 +0200
+@@ -635,7 +635,6 @@
+ 	}
+ 	
+ 	current->mm->start_stack = bprm->p;
+-
+ 	/* Now we do a little grungy work by mmaping the ELF image into
+ 	   the correct location in memory.  At this point, we assume that
+ 	   the image should be loaded at fixed address, not at a variable
+--- linux-2.4.25/fs/exec.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/fs/exec.c	2004-03-31 17:15:09.000000000 +0200
+@@ -315,6 +315,7 @@
+ 	spin_unlock(&tsk->mm->page_table_lock);
+ 
+ 	/* no need for flush_tlb */
++	memc_update_addr(tsk->mm, *pte, address);
+ 	return;
+ out:
+ 	spin_unlock(&tsk->mm->page_table_lock);
+--- linux-2.4.25/fs/jffs/inode-v23.c~2.4.25-vrs2.patch	2001-10-05 00:14:35.000000000 +0200
++++ linux-2.4.25/fs/jffs/inode-v23.c	2004-03-31 17:15:09.000000000 +0200
+@@ -10,7 +10,7 @@
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+- * $Id$
++ * $Id$
+  *
+  * Ported to Linux 2.3.x and MTD:
+  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
+@@ -48,6 +48,7 @@
+ #include <linux/stat.h>
+ #include <linux/blkdev.h>
+ #include <linux/quotaops.h>
++#include <linux/compatmac.h>
+ #include <asm/semaphore.h>
+ #include <asm/byteorder.h>
+ #include <asm/uaccess.h>
+@@ -58,6 +59,11 @@
+ #include "jffs_proc.h"
+ #endif
+ 
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)
++#define minor(x) MINOR(x)
++#define major(x) MAJOR(x)
++#endif
++
+ static int jffs_remove(struct inode *dir, struct dentry *dentry, int type);
+ 
+ static struct super_operations jffs_ops;
+@@ -81,7 +87,7 @@
+ 	D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n",
+ 		  kdevname(dev)));
+ 
+-	if (MAJOR(dev) != MTD_BLOCK_MAJOR) {
++	if (major(dev) != MTD_BLOCK_MAJOR) {
+ 		printk(KERN_WARNING "JFFS: Trying to mount a "
+ 		       "non-mtd device.\n");
+ 		return 0;
+@@ -358,7 +364,7 @@
+ 	inode->i_nlink = raw_inode->nlink;
+ 	inode->i_uid = raw_inode->uid;
+ 	inode->i_gid = raw_inode->gid;
+-	inode->i_rdev = 0;
++	inode->i_rdev = NODEV;
+ 	inode->i_size = raw_inode->dsize;
+ 	inode->i_atime = raw_inode->atime;
+ 	inode->i_mtime = raw_inode->mtime;
+--- linux-2.4.25/fs/jffs/intrep.c~2.4.25-vrs2.patch	2003-06-13 16:51:37.000000000 +0200
++++ linux-2.4.25/fs/jffs/intrep.c	2004-03-31 17:15:09.000000000 +0200
+@@ -10,7 +10,7 @@
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+- * $Id$
++ * $Id$
+  *
+  * Ported to Linux 2.3.x and MTD:
+  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
+@@ -772,6 +772,9 @@
+ 	__u32 free_chunk_size1;
+ 	__u32 free_chunk_size2;
+ 
++	__u32 largest_hole         = 0;
++	__u32 hole_end_offset      = 0;
++	__u32 head_offset;
+ 	
+ #define NUMFREEALLOWED     2        /* 2 chunks of at least erase size space allowed */
+ 	int num_free_space = 0;       /* Flag err if more than TWO
+@@ -884,6 +887,21 @@
+ 							  (unsigned int) start,
+ 							  (unsigned int)(test_start - start)));
+ 
++						D1(printk("Reducing start to 0x%x from 0x%x\n",
++						          test_start, start));
++						if (largest_hole < test_start - start){
++							
++							D3(printk("was hole = %x end_offset = %x\n",
++							          largest_hole, hole_end_offset));
++							if (fmc->head) {
++								largest_hole    = test_start - start;
++								hole_end_offset = test_start;
++							}
++						}
++
++						D3(printk("now = %x end_offset = %x\n",
++					        	largest_hole, hole_end_offset));
++
+ 						/* below, space from "start" to "pos" will be marked dirty. */
+ 						start = test_start; 
+ 						
+@@ -956,6 +974,19 @@
+ 				           num_free_space++;
+ 				           D1(printk("Free space accepted: Starting 0x%x for 0x%x bytes\n",
+ 						     (unsigned int) start, (unsigned int) (pos - start)));
++
++					   if (largest_hole < pos - start) {
++						   
++						   D3(printk("was hole = %x end_offset = %x\n",
++						          largest_hole, hole_end_offset));
++						   if (fmc->head){
++							   largest_hole    = pos - start;
++							   hole_end_offset = pos;
++							}
++
++						   D3(printk("now = %x end_offset = %x\n",
++						          largest_hole, hole_end_offset));
++						}
+ 				 }else{
+ 				         num_free_spc_not_accp++;
+ 					 D1(printk("Free space (#%i) found but *Not* accepted: Starting "
+@@ -968,7 +999,7 @@
+ 						   (unsigned int) start, (unsigned int) (pos - start)));
+ 					 jffs_fmalloced(fmc, (__u32) start,
+ 							(__u32) (pos - start), 0);				           
+-				 }
++				}
+ 				 
+ 			}
+ 			if(num_free_space > NUMFREEALLOWED){
+@@ -1002,9 +1033,11 @@
+ 			   to scan for the magic pattern.  */
+ 			D1(printk("*************** Dirty flash memory or "
+ 				  "bad inode: "
+-				  "hexdump(pos = 0x%lx, len = 128):\n",
+-				  (long)pos));
+-			D1(jffs_hexdump(fmc->mtd, pos, 128));
++				  "hexdump(pos = 0x%lx, len = %d):\n",
++				  (long)pos,
++				  end - pos > 128 ? 128 : end - pos));
++			D1(jffs_hexdump(fmc->mtd, pos,
++			                end - pos > 128 ? 128 : end - pos));
+ 
+ 			for (pos += 4; pos < end; pos += 4) {
+ 				switch (flash_read_u32(fmc->mtd, pos)) {
+@@ -1197,12 +1230,6 @@
+ 
+ 				return -ENOMEM;
+ 			}
+-			if ((err = jffs_insert_node(c, 0, &raw_inode,
+-						    name, node)) < 0) {
+-				printk("JFFS: Failed to handle raw inode. "
+-				       "(err = %d)\n", err);
+-				break;
+-			}
+ 			if (raw_inode.rename) {
+ 				struct jffs_delete_list *dl
+ 				= (struct jffs_delete_list *)
+@@ -1226,6 +1253,12 @@
+ 				c->delete_list = dl;
+ 				node->data_size = 0;
+ 			}
++			if ((err = jffs_insert_node(c, 0, &raw_inode,
++						    name, node)) < 0) {
++				printk("JFFS: Failed to handle raw inode. "
++				       "(err = %d)\n", err);
++				break;
++			}
+ 			D3(jffs_print_node(node));
+ 			node = 0; /* Don't free the node!  */
+ 		}
+@@ -1242,7 +1275,19 @@
+ 		jffs_free_node(node);
+ 		DJM(no_jffs_node--);
+ 	}
+-	jffs_build_end(fmc);
++	if (fmc->head && fmc->tail_extra &&
++	    fmc->head->offset + fmc->flash_size -
++			fmc->tail_extra->offset - fmc->tail_extra->size > largest_hole) {
++		head_offset = fmc->head->offset;
++	}
++	else {
++		head_offset = hole_end_offset;
++	}
++	
++	if (jffs_build_end(fmc, head_offset) < 0) {
++		D(printk("jffs_build_end() failed\n"));
++		return -ENOMEM;
++	}
+ 
+ 	/* Free read buffer */
+ 	kfree (read_buf);
+--- linux-2.4.25/fs/jffs/jffs_fm.c~2.4.25-vrs2.patch	2001-10-05 00:13:18.000000000 +0200
++++ linux-2.4.25/fs/jffs/jffs_fm.c	2004-03-31 17:15:09.000000000 +0200
+@@ -10,7 +10,7 @@
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+- * $Id$
++ * $Id$
+  *
+  * Ported to Linux 2.3.x and MTD:
+  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
+@@ -20,8 +20,14 @@
+ #include <linux/slab.h>
+ #include <linux/blkdev.h>
+ #include <linux/jffs.h>
++#include <linux/compatmac.h>
+ #include "jffs_fm.h"
+ 
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)
++#define minor(x) MINOR(x)
++#define major(x) MAJOR(x)
++#endif
++
+ #if defined(JFFS_MARK_OBSOLETE) && JFFS_MARK_OBSOLETE
+ static int jffs_mark_obsolete(struct jffs_fmcontrol *fmc, __u32 fm_offset);
+ #endif
+@@ -46,7 +52,7 @@
+ 	}
+ 	DJM(no_jffs_fmcontrol++);
+ 
+-	mtd = get_mtd_device(NULL, MINOR(dev));
++	mtd = get_mtd_device(NULL, minor(dev));
+ 
+ 	if (!mtd) {
+ 		kfree(fmc);
+@@ -89,8 +95,8 @@
+ 
+ /* When the flash memory scan has completed, this function should be called
+    before use of the control structure.  */
+-void
+-jffs_build_end(struct jffs_fmcontrol *fmc)
++int
++jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset)
+ {
+ 	D3(printk("jffs_build_end()\n"));
+ 
+@@ -99,13 +105,100 @@
+ 		fmc->tail = fmc->tail_extra;
+ 	}
+ 	else if (fmc->head_extra) {
+-		fmc->tail_extra->next = fmc->head;
+-		fmc->head->prev = fmc->tail_extra;
+-		fmc->head = fmc->head_extra;
++		struct jffs_fm *fm, *cur;
++
++		if (head_offset == fmc->head->offset){
++			fmc->tail->next = fmc->head_extra;
++			fmc->head_extra->prev = fmc->tail;
++			fmc->tail = fmc->tail_extra;
++		}
++		else {
++			fmc->tail_extra->next = fmc->head;
++			fmc->head->prev = fmc->tail_extra;
++			fmc->head = fmc->head_extra;
++			while (fmc->head->offset != head_offset){
++				fmc->tail->next = fmc->head;
++				fmc->head = fmc->head->next;
++				fmc->head->prev = 0;
++				fmc->tail->next->prev = fmc->tail;
++				fmc->tail = fmc->tail->next;
++				fmc->tail->next = 0;
++			}
++		}
++				/* Make sure the only free space we have is between tail and head.
++				 */
++		for (cur = fmc->head; cur && cur != fmc->tail;) {
++			if (cur->offset + cur->size < cur->next->offset) {
++				if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))) {
++					D(printk("jffs_buid_end(): kmalloc failed!\n"));
++					return -ENOMEM;
++				}
++				DJM(no_jffs_fm++);
++				fm->size = cur->next->offset - cur->offset - cur->size;
++				fm->offset = cur->offset + cur->size;
++				fm->nodes = 0;
++				fm->next = cur->next;
++				fm->prev = cur;
++				cur->next->prev = fm;
++				cur->next = fm;
++				cur = fm->next;
++				fmc->free_size -= fm->size;
++				fmc->dirty_size += fm->size;
++			}
++			else if (cur->offset > cur->next->offset) {
++				if (cur->offset + cur->size < fmc->flash_size){
++					if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))){
++						
++						D(printk("jffs_buid_end(): kmalloc failed!\n"));
++						return -ENOMEM;
++					}
++					DJM(no_jffs_fm++);
++					fm->size = fmc->flash_size -
++					           cur->offset - cur->size;
++					fm->nodes = 0;
++					fm->offset = cur->offset + cur->size;
++					fm->next = cur->next;
++					fm->prev = cur;
++					cur->next->prev = fm;
++					cur->next = fm;
++					cur = fm->next;
++					fmc->free_size -= fm->size;
++					fmc->dirty_size += fm->size;
++				}
++				else {
++					cur = cur->next;
++				}
++				if (cur->offset > 0) {
++					
++					if (!(fm = kmalloc(sizeof(struct jffs_fm), GFP_KERNEL))) {
++						D(printk("jffs_buid_end(): kmalloc failed!\n"));
++						return -ENOMEM;
++					}
++					DJM(no_jffs_fm++);
++					fm->size = cur->offset;
++					fm->nodes = 0;
++					fm->offset = 0;
++					fm->next = cur;
++					fm->prev = cur->prev;
++					cur->prev->next = fm;
++					cur->prev = fm;
++					fmc->free_size -= fm->size;
++					fmc->dirty_size += fm->size;
++				}
++			}
++			else if (cur->offset + cur->size != cur->next->offset) {
++				printk("jffs_build_end(): Internal error.\n");
++				return -EINVAL;
++			}
++			else {
++				cur = cur->next;
++			}
++		}
+ 	}
+ 	fmc->head_extra = 0; /* These two instructions should be omitted.  */
+ 	fmc->tail_extra = 0;
+ 	D3(jffs_print_fmcontrol(fmc));
++	return 0;
+ }
+ 
+ 
+--- linux-2.4.25/fs/jffs/jffs_fm.h~2.4.25-vrs2.patch	2001-10-05 00:13:18.000000000 +0200
++++ linux-2.4.25/fs/jffs/jffs_fm.h	2004-03-31 17:15:09.000000000 +0200
+@@ -10,7 +10,7 @@
+  * the Free Software Foundation; either version 2 of the License, or
+  * (at your option) any later version.
+  *
+- * $Id$
++ * $Id$
+  *
+  * Ported to Linux 2.3.x and MTD:
+  * Copyright (C) 2000  Alexander Larsson (alex@cendio.se), Cendio Systems AB
+@@ -123,7 +123,7 @@
+ 
+ 
+ struct jffs_fmcontrol *jffs_build_begin(struct jffs_control *c, kdev_t dev);
+-void jffs_build_end(struct jffs_fmcontrol *fmc);
++int jffs_build_end(struct jffs_fmcontrol *fmc, __u32 head_offset);
+ void jffs_cleanup_fmcontrol(struct jffs_fmcontrol *fmc);
+ 
+ int jffs_fmalloc(struct jffs_fmcontrol *fmc, __u32 size,
+--- linux-2.4.25/fs/partitions/Config.in~2.4.25-vrs2.patch	2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.25/fs/partitions/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -6,6 +6,7 @@
+    bool '  Acorn partition support' CONFIG_ACORN_PARTITION
+    if [ "$CONFIG_ACORN_PARTITION" != "n" ]; then
+ #      bool '    Cumana partition support' CONFIG_ACORN_PARTITION_CUMANA
++      bool '    EESOX partition support' CONFIG_ACORN_PARTITION_EESOX
+       bool '    ICS partition support' CONFIG_ACORN_PARTITION_ICS
+       bool '    Native filecore partition support' CONFIG_ACORN_PARTITION_ADFS
+       bool '    PowerTec partition support' CONFIG_ACORN_PARTITION_POWERTEC
+@@ -52,6 +53,7 @@
+       define_bool CONFIG_ACORN_PARTITION y
+       define_bool CONFIG_ACORN_PARTITION_ADFS y
+ #      define_bool CONFIG_ACORN_PARTITION_CUMANA y
++      define_bool CONFIG_ACORN_PARTITION_EESOX y
+       define_bool CONFIG_ACORN_PARTITION_ICS y
+       define_bool CONFIG_ACORN_PARTITION_POWERTEC y
+       define_bool CONFIG_ACORN_PARTITION_RISCIX y
+--- linux-2.4.25/fs/partitions/acorn.c~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/fs/partitions/acorn.c	2004-03-31 17:15:09.000000000 +0200
+@@ -7,7 +7,10 @@
+  * it under the terms of the GNU General Public License version 2 as
+  * published by the Free Software Foundation.
+  *
+- *  Scan ADFS partitions on hard disk drives.
++ *  Scan ADFS partitions on hard disk drives.  Unfortunately, there
++ *  isn't a standard for partitioning drives on Acorn machines, so
++ *  every single manufacturer of SCSI and IDE cards created their own
++ *  method.
+  */
+ #include <linux/config.h>
+ #include <linux/kernel.h>
+@@ -18,10 +21,18 @@
+ #include <linux/genhd.h>
+ #include <linux/fs.h>
+ #include <linux/pagemap.h>
++#include <linux/adfs_fs.h>
+ 
+ #include "check.h"
+ #include "acorn.h"
+ 
++/*
++ * Partition types. (Oh for reusability)
++ */
++#define PARTITION_RISCIX_MFM	1
++#define PARTITION_RISCIX_SCSI	2
++#define PARTITION_LINUX		9
++
+ static void
+ adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads)
+ {
+@@ -61,6 +72,21 @@
+ }
+ 
+ #ifdef CONFIG_ACORN_PARTITION_RISCIX
++
++struct riscix_part {
++	__u32	start;
++	__u32	length;
++	__u32	one;
++	char	name[16];
++};
++
++struct riscix_record {
++	__u32	magic;
++#define RISCIX_MAGIC	(0x4a657320)
++	__u32	date;
++	struct riscix_part part[8];
++};
++
+ static int
+ riscix_partition(struct gendisk *hd, struct block_device *bdev,
+ 		unsigned long first_sect, int minor, unsigned long nr_sects)
+@@ -102,6 +128,15 @@
+ }
+ #endif
+ 
++#define LINUX_NATIVE_MAGIC 0xdeafa1de
++#define LINUX_SWAP_MAGIC   0xdeafab1e
++
++struct linux_part {
++	__u32 magic;
++	__u32 start_sect;
++	__u32 nr_sects;
++};
++
+ static int
+ linux_partition(struct gendisk *hd, struct block_device *bdev,
+ 		unsigned long first_sect, int minor, unsigned long nr_sects)
+@@ -136,7 +171,7 @@
+ }
+ 
+ #ifdef CONFIG_ACORN_PARTITION_CUMANA
+-static int
++int
+ adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev,
+ 		      unsigned long first_sector, int minor)
+ {
+@@ -147,7 +182,7 @@
+ 	int first = 1;
+ 
+ 	/*
+-	 * Try Cumana style partitions - sector 3 contains ADFS boot block
++	 * Try Cumana style partitions - sector 6 contains ADFS boot block
+ 	 * with pointer to next 'drive'.
+ 	 *
+ 	 * There are unknowns in this code - is the 'cylinder number' of the
+@@ -163,13 +198,13 @@
+ 		struct adfs_discrecord *dr;
+ 		unsigned int nr_sects;
+ 
+-		if (!(minor & mask))
+-			break;
+-
+ 		data = read_dev_sector(bdev, start_blk * 2 + 6, &sect);
+ 		if (!data)
+ 			return -1;
+ 
++		if (!(minor & mask))
++			break;
++
+ 		dr = adfs_partition(hd, name, data, first_sector, minor++);
+ 		if (!dr)
+ 			break;
+@@ -229,7 +264,7 @@
+  *	    hda1 = ADFS partition on first drive.
+  *	    hda2 = non-ADFS partition.
+  */
+-static int
++int
+ adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev,
+ 		   unsigned long first_sector, int minor)
+ {
+@@ -282,11 +317,18 @@
+ 			break;
+ 		}
+ 	}
++	printk("\n");
+ 	return 1;
+ }
+ #endif
+ 
+ #ifdef CONFIG_ACORN_PARTITION_ICS
++
++struct ics_part {
++	__u32 start;
++	__s32 size;
++};
++
+ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long block)
+ {
+ 	Sector sect;
+@@ -303,6 +345,22 @@
+ }
+ 
+ /*
++ * Check for a valid ICS partition using the checksum.
++ */
++static inline int valid_ics_sector(const unsigned char *data)
++{
++	unsigned long sum;
++	int i;
++
++	for (i = 0, sum = 0x50617274; i < 508; i++)
++		sum += data[i];
++
++	sum -= le32_to_cpu(*(__u32 *)(&data[508]));
++
++	return sum == 0;
++}
++
++/*
+  * Purpose: allocate ICS partitions.
+  * Params : hd		- pointer to gendisk structure to store partition info.
+  *	    dev		- device number to access.
+@@ -314,15 +372,14 @@
+  *	    hda2 = ADFS partition 1 on first drive.
+  *		..etc..
+  */
+-static int
++int
+ adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev,
+ 		   unsigned long first_sector, int minor)
+ {
++	const unsigned char *data;
++	const struct ics_part *p;
++	unsigned int mask = (1 << hd->minor_shift) - 1;
+ 	Sector sect;
+-	unsigned char *data;
+-	unsigned long sum;
+-	unsigned int i, mask = (1 << hd->minor_shift) - 1;
+-	struct ics_part *p;
+ 
+ 	/*
+ 	 * Try ICS style partitions - sector 0 contains partition info.
+@@ -331,21 +388,14 @@
+ 	if (!data)
+ 	    	return -1;
+ 
+-	/*
+-	 * check for a valid checksum
+-	 */
+-	for (i = 0, sum = 0x50617274; i < 508; i++)
+-		sum += data[i];
+-
+-	sum -= le32_to_cpu(*(__u32 *)(&data[508]));
+-	if (sum) {
+-	    	put_dev_sector(sect);
+-		return 0; /* not ICS partition table */
++	if (!valid_ics_sector(data)) {
++		put_dev_sector(sect);
++		return 0;
+ 	}
+ 
+ 	printk(" [ICS]");
+ 
+-	for (p = (struct ics_part *)data; p->size; p++) {
++	for (p = (const struct ics_part *)data; p->size; p++) {
+ 		unsigned long start;
+ 		long size;
+ 
+@@ -355,12 +405,19 @@
+ 		start = le32_to_cpu(p->start);
+ 		size  = le32_to_cpu(p->size);
+ 
++		/*
++		 * Negative sizes tell the RISC OS ICS driver to ignore
++		 * this partition - in effect it says that this does not
++		 * contain an ADFS filesystem.
++		 */
+ 		if (size < 0) {
+ 			size = -size;
+ 
+ 			/*
+-			 * We use the first sector to identify what type
+-			 * this partition is...
++			 * Our own extension - We use the first sector
++			 * of the partition to identify what type this
++			 * partition is.  We must not make this visible
++			 * to the filesystem.
+ 			 */
+ 			if (size > 1 && adfspart_check_ICSLinux(bdev, start)) {
+ 				start += 1;
+@@ -375,10 +432,32 @@
+ 	}
+ 
+ 	put_dev_sector(sect);
++	printk("\n");
+ 	return 1;
+ }
+ #endif
+ 
++#ifdef CONFIG_ACORN_PARTITION_POWERTEC
++struct ptec_part {
++	__u32 unused1;
++	__u32 unused2;
++	__u32 start;
++	__u32 size;
++	__u32 unused5;
++	char type[8];
++};
++
++static inline int valid_ptec_sector(const unsigned char *data)
++{
++	unsigned char checksum = 0x2a;
++	int i;
++
++	for (i = 0; i < 511; i++)
++		checksum += data[i];
++
++	return checksum == data[511];
++}
++
+ /*
+  * Purpose: allocate ICS partitions.
+  * Params : hd		- pointer to gendisk structure to store partition info.
+@@ -391,32 +470,27 @@
+  *	    hda2 = ADFS partition 1 on first drive.
+  *		..etc..
+  */
+-#ifdef CONFIG_ACORN_PARTITION_POWERTEC
+-static int
++int
+ adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev,
+ 			unsigned long first_sector, int minor)
+ {
+ 	Sector sect;
+-	unsigned char *data;
+-	struct ptec_partition *p;
+-	unsigned char checksum;
++	const unsigned char *data;
++	const struct ptec_part *p;
+ 	int i;
+ 
+ 	data = read_dev_sector(bdev, 0, &sect);
+ 	if (!data)
+ 		return -1;
+ 
+-	for (checksum = 0x2a, i = 0; i < 511; i++)
+-		checksum += data[i];
+-
+-	if (checksum != data[511]) {
++	if (!valid_ptec_sector(data)) {
+ 		put_dev_sector(sect);
+ 		return 0;
+ 	}
+ 
+ 	printk(" [POWERTEC]");
+ 
+-	for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) {
++	for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) {
+ 		unsigned long start;
+ 		unsigned long size;
+ 
+@@ -430,49 +504,82 @@
+ 	}
+ 
+ 	put_dev_sector(sect);
++	printk("\n");
+ 	return 1;
+ }
+ #endif
+ 
+-static int (*partfn[])(struct gendisk *, struct block_device *, unsigned long, int) = {
+-#ifdef CONFIG_ACORN_PARTITION_ICS
+-	adfspart_check_ICS,
+-#endif
+-#ifdef CONFIG_ACORN_PARTITION_POWERTEC
+-	adfspart_check_POWERTEC,
+-#endif
+-#ifdef CONFIG_ACORN_PARTITION_CUMANA
+-	adfspart_check_CUMANA,
+-#endif
+-#ifdef CONFIG_ACORN_PARTITION_ADFS
+-	adfspart_check_ADFS,
+-#endif
+-	NULL
++#ifdef CONFIG_ACORN_PARTITION_EESOX
++struct eesox_part {
++	char	magic[6];
++	char	name[10];
++	u32	start;
++	u32	unused6;
++	u32	unused7;
++	u32	unused8;
+ };
++
+ /*
+- * Purpose: initialise all the partitions on an ADFS drive.
+- *          These may be other ADFS partitions or a Linux/RiscBSD/RISCiX
+- *	    partition.
++ * Guess who created this format?
++ */
++static const char eesox_name[] = {
++	'N', 'e', 'i', 'l', ' ',
++	'C', 'r', 'i', 't', 'c', 'h', 'e', 'l', 'l', ' ', ' '
++};
++
++/*
++ * EESOX SCSI partition format.
+  *
+- * Params : hd		- pointer to gendisk structure
+- *          dev		- device number to access
+- *	    first_sect  - first available sector on the disk.
+- *	    first_minor	- first available minor on this device.
++ * This is a goddamned awful partition format.  We don't seem to store
++ * the size of the partition in this table, only the start addresses.
+  *
+- * Returns: -1 on error, 0 if not ADFS format, 1 if ok.
++ * There are two possibilities where the size comes from:
++ *  1. The individual ADFS boot block entries that are placed on the disk.
++ *  2. The start address of the next entry.
+  */
+-int acorn_partition(struct gendisk *hd, struct block_device *bdev,
+-		    unsigned long first_sect, int first_minor)
++int
++adfspart_check_EESOX(struct gendisk *hd, struct block_device *bdev,
++		     unsigned long first_sector, int minor)
+ {
++	Sector sect;
++	const unsigned char *data;
++	unsigned char buffer[256];
++	struct eesox_part *p;
++	u32 start = first_sector;
+ 	int i;
+ 
+-	for (i = 0; partfn[i]; i++) {
+-		int r = partfn[i](hd, bdev, first_sect, first_minor);
+-		if (r) {
+-			if (r > 0)
+-				printk("\n");
+-			return r;
+-		}
++	data = read_dev_sector(bdev, 7, &sect);
++	if (!data)
++		return -1;
++
++	/*
++	 * "Decrypt" the partition table.  God knows why...
++	 */
++	for (i = 0; i < 256; i++)
++		buffer[i] = data[i] ^ eesox_name[i & 15];
++
++	put_dev_sector(sect);
++
++	for (i = 0, p = (struct eesox_part *)buffer; i < 8; i++, p++) {
++		u32 next;
++
++		if (memcmp(p->magic, "Eesox", 6))
++			break;
++
++		next = le32_to_cpu(p->start) + first_sector;
++		if (i)
++			add_gd_partition(hd, minor++, start, next - start);
++		start = next;
+ 	}
+-	return 0;
++
++	if (i != 0) {
++		unsigned long size;
++
++		size = hd->part[MINOR(to_kdev_t(bdev->bd_dev))].nr_sects;
++		add_gd_partition(hd, minor++, start, size - start);
++		printk("\n");
++	}
++
++	return i ? 1 : 0;
+ }
++#endif
+--- linux-2.4.25/fs/partitions/acorn.h~2.4.25-vrs2.patch	2001-11-22 20:48:07.000000000 +0100
++++ linux-2.4.25/fs/partitions/acorn.h	2004-03-31 17:15:09.000000000 +0200
+@@ -1,55 +1,28 @@
+ /*
+- * fs/partitions/acorn.h
++ * linux/fs/partitions/acorn.h
+  *
+- * Copyright (C) 1996-1998 Russell King
+- */
+-#include <linux/adfs_fs.h>
+-
+-/*
+- * Partition types. (Oh for reusability)
++ * Copyright (C) 1996-2001 Russell King.
++ *
++ *  I _hate_ this partitioning mess - why can't we have one defined
++ *  format, and everyone stick to it?
+  */
+-#define PARTITION_RISCIX_MFM	1
+-#define PARTITION_RISCIX_SCSI	2
+-#define PARTITION_LINUX		9
+-
+-struct riscix_part {
+-	__u32  start;
+-	__u32  length;
+-	__u32  one;
+-	char name[16];
+-};
+ 
+-struct riscix_record {
+-	__u32  magic;
+-#define RISCIX_MAGIC	(0x4a657320)
+-	__u32  date;
+-	struct riscix_part part[8];
+-};
+-
+-#define LINUX_NATIVE_MAGIC 0xdeafa1de
+-#define LINUX_SWAP_MAGIC   0xdeafab1e
+-
+-struct linux_part {
+-	__u32 magic;
+-	__u32 start_sect;
+-	__u32 nr_sects;
+-};
++int
++adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev,
++		      unsigned long first_sector, int minor);
+ 
+-struct ics_part {
+-	__u32 start;
+-	__s32 size;
+-};
++int
++adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev,
++		   unsigned long first_sector, int minor);
+ 
+-struct ptec_partition {
+-	__u32 unused1;
+-	__u32 unused2;
+-	__u32 start;
+-	__u32 size;
+-	__u32 unused5;
+-	char type[8];
+-};
+-	
++int
++adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev,
++		   unsigned long first_sector, int minor);
+ 
+-int acorn_partition(struct gendisk *hd, struct block_device *bdev,
+-		   unsigned long first_sect, int first_minor);
++int
++adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev,
++			unsigned long first_sector, int minor);
+ 
++int
++adfspart_check_EESOX(struct gendisk *hd, struct block_device *bdev,
++		     unsigned long first_sector, int minor);
+--- linux-2.4.25/fs/partitions/check.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/fs/partitions/check.c	2004-03-31 17:15:09.000000000 +0200
+@@ -40,8 +40,30 @@
+ int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
+ 
+ static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, unsigned long first_sect, int first_minor) = {
+-#ifdef CONFIG_ACORN_PARTITION
+-	acorn_partition,
++	/*
++	 * Probe partition formats with tables at disk address 0
++	 * that also have an ADFS boot block at 0xdc0.
++	 */
++#ifdef CONFIG_ACORN_PARTITION_ICS
++	adfspart_check_ICS,
++#endif
++#ifdef CONFIG_ACORN_PARTITION_POWERTEC
++	adfspart_check_POWERTEC,
++#endif
++#ifdef CONFIG_ACORN_PARTITION_EESOX
++	adfspart_check_EESOX,
++#endif
++
++	/*
++	 * Now move on to formats that only have partition info at
++	 * disk address 0xdc0.  These should come before MSDOS
++	 * partition tables.
++	 */
++#ifdef CONFIG_ACORN_PARTITION_CUMANA
++	adfspart_check_CUMANA,
++#endif
++#ifdef CONFIG_ACORN_PARTITION_ADFS
++	adfspart_check_ADFS,
+ #endif
+ #ifdef CONFIG_SGI_PARTITION
+ 	sgi_partition,
+@@ -79,13 +101,25 @@
+ 	NULL
+ };
+ 
++static char *raid_name (struct gendisk *hd, unsigned int unit, unsigned int part,
++			int major_base, char *buf)
++{
++	int ctlr = hd->major - major_base;
++	if (part == 0)
++		sprintf(buf, "%s/c%dd%d", hd->major_name, ctlr, unit);
++	else
++		sprintf(buf, "%s/c%dd%dp%d", hd->major_name, ctlr, unit,
++			part);
++	return buf;
++}
++
+ /*
+  *	This is ucking fugly but its probably the best thing for 2.4.x
+  *	Take it as a clear reminder that: 1) we should put the device name
+  *	generation in the object kdev_t points to in 2.5.
+  *	and 2) ioctls better work on half-opened devices.
+  */
+- 
++
+ #ifdef CONFIG_ARCH_S390
+ int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+ int (*genhd_dasd_ioctl)(struct inode *inp, struct file *filp,
+@@ -104,10 +138,11 @@
+ char *disk_name (struct gendisk *hd, int minor, char *buf)
+ {
+ 	const char *maj = hd->major_name;
+-	unsigned int unit = (minor >> hd->minor_shift);
+-	unsigned int part = (minor & ((1 << hd->minor_shift) -1 ));
++	unsigned int unit = minor >> hd->minor_shift;
++	unsigned int part = minor & (( 1 << hd->minor_shift) - 1);
++	char *p;
+ 
+-	if ((unit < hd->nr_real) && hd->part[minor].de) {
++	if (unit < hd->nr_real && hd->part[minor].de) {
+ 		int pos;
+ 
+ 		pos = devfs_generate_path (hd->part[minor].de, buf, 64);
+@@ -153,51 +188,32 @@
+ 	}
+ 	if (hd->major >= SCSI_DISK1_MAJOR && hd->major <= SCSI_DISK7_MAJOR) {
+ 		unit = unit + (hd->major - SCSI_DISK1_MAJOR + 1) * 16;
+-		if (unit+'a' > 'z') {
+-			unit -= 26;
+-			sprintf(buf, "sd%c%c", 'a' + unit / 26, 'a' + unit % 26);
+-			if (part)
+-				sprintf(buf + 4, "%d", part);
+-			return buf;
+-		}
+ 	}
+ 	if (hd->major >= COMPAQ_SMART2_MAJOR && hd->major <= COMPAQ_SMART2_MAJOR+7) {
+-		int ctlr = hd->major - COMPAQ_SMART2_MAJOR;
+- 		if (part == 0)
+- 			sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
+- 		else
+- 			sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
+- 		return buf;
+- 	}
++		return raid_name(hd, unit, part, COMPAQ_SMART2_MAJOR, buf);
++	}
+ 	if (hd->major >= COMPAQ_CISS_MAJOR && hd->major <= COMPAQ_CISS_MAJOR+7) {
+-                int ctlr = hd->major - COMPAQ_CISS_MAJOR;
+-                if (part == 0)
+-                        sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
+-                else
+-                        sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
+-                return buf;
++		return raid_name(hd, unit, part, COMPAQ_CISS_MAJOR, buf);
+ 	}
+ 	if (hd->major >= DAC960_MAJOR && hd->major <= DAC960_MAJOR+7) {
+-		int ctlr = hd->major - DAC960_MAJOR;
++		return raid_name(hd, unit, part, DAC960_MAJOR, buf);
++	}
++	if (hd->major == ATARAID_MAJOR) {
++ 		int disk = minor >> hd->minor_shift;
++ 		int part = minor & (( 1 << hd->minor_shift) - 1);
+  		if (part == 0)
+- 			sprintf(buf, "%s/c%dd%d", maj, ctlr, unit);
++ 			sprintf(buf, "%s/d%d", maj, disk);
+  		else
+- 			sprintf(buf, "%s/c%dd%dp%d", maj, ctlr, unit, part);
++ 			sprintf(buf, "%s/d%dp%d", maj, disk, part);
+  		return buf;
+  	}
+-	if (hd->major == ATARAID_MAJOR) {
+-		int disk = minor >> hd->minor_shift;
+-		int part = minor & (( 1 << hd->minor_shift) - 1);
+-		if (part == 0)
+-			sprintf(buf, "%s/d%d", maj, disk);
+-		else
+-			sprintf(buf, "%s/d%dp%d", maj, disk, part);
+-		return buf;
+-	}
+-	if (part)
+-		sprintf(buf, "%s%c%d", maj, unit+'a', part);
++	p = buf;
++	if (unit <= 26)
++		p += sprintf(buf, "%s%c", maj, 'a' + unit);
+ 	else
+-		sprintf(buf, "%s%c", maj, unit+'a');
++		p += sprintf(buf, "%s%c%c", maj, 'a' + unit / 26, 'a' + unit % 26);
++	if (part)
++		sprintf(p, "%d", part);
+ 	return buf;
+ }
+ 
+@@ -207,7 +223,7 @@
+ void add_gd_partition(struct gendisk *hd, int minor, int start, int size)
+ {
+ #ifndef CONFIG_DEVFS_FS
+-	char buf[40];
++	char buf[MAX_DISKNAME_LEN];
+ #endif
+ 
+ 	hd->part[minor].start_sect = start;
+@@ -229,7 +245,7 @@
+ 	static int first_time = 1;
+ 	unsigned long first_sector;
+ 	struct block_device *bdev;
+-	char buf[64];
++	char buf[MAX_DISKNAME_LEN];
+ 	int i;
+ 
+ 	if (first_time)
+--- linux-2.4.25/fs/proc/array.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/fs/proc/array.c	2004-03-31 17:15:09.000000000 +0200
+@@ -362,15 +362,15 @@
+ 		task->cmin_flt,
+ 		task->maj_flt,
+ 		task->cmaj_flt,
+-		task->times.tms_utime,
+-		task->times.tms_stime,
+-		task->times.tms_cutime,
+-		task->times.tms_cstime,
++		hz_to_std(task->times.tms_utime),
++		hz_to_std(task->times.tms_stime),
++		hz_to_std(task->times.tms_cutime),
++		hz_to_std(task->times.tms_cstime),
+ 		priority,
+ 		nice,
+ 		0UL /* removed */,
+ 		task->it_real_value,
+-		task->start_time,
++		hz_to_std(task->start_time),
+ 		vsize,
+ 		mm ? mm->rss : 0, /* you might want to shift this left 3 */
+ 		task->rlim[RLIMIT_RSS].rlim_cur,
+@@ -417,6 +417,7 @@
+ 		end = PMD_SIZE;
+ 	do {
+ 		pte_t page = *pte;
++		unsigned long pfn;
+ 		struct page *ptpage;
+ 
+ 		address += PAGE_SIZE;
+@@ -426,8 +427,11 @@
+ 		++*total;
+ 		if (!pte_present(page))
+ 			continue;
+-		ptpage = pte_page(page);
+-		if ((!VALID_PAGE(ptpage)) || PageReserved(ptpage))
++		pfn = pte_pfn(page);
++		if (!pfn_valid(pfn))
++			continue;
++		ptpage = pfn_to_page(pfn);
++		if (PageReserved(ptpage))
+ 			continue;
+ 		++*pages;
+ 		if (pte_dirty(page))
+@@ -609,14 +613,14 @@
+ 
+ 	len = sprintf(buffer,
+ 		"cpu  %lu %lu\n",
+-		task->times.tms_utime,
+-		task->times.tms_stime);
++		hz_to_std(task->times.tms_utime),
++		hz_to_std(task->times.tms_stime));
+ 		
+ 	for (i = 0 ; i < smp_num_cpus; i++)
+ 		len += sprintf(buffer + len, "cpu%d %lu %lu\n",
+ 			i,
+-			task->per_cpu_utime[cpu_logical_map(i)],
+-			task->per_cpu_stime[cpu_logical_map(i)]);
++			hz_to_std(task->per_cpu_utime[cpu_logical_map(i)]),
++			hz_to_std(task->per_cpu_stime[cpu_logical_map(i)]));
+ 
+ 	return len;
+ }
+--- linux-2.4.25/fs/proc/proc_misc.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/fs/proc/proc_misc.c	2004-03-31 17:15:09.000000000 +0200
+@@ -308,16 +308,16 @@
+ {
+ 	int i, len = 0;
+ 	extern unsigned long total_forks;
+-	unsigned long jif = jiffies;
++	unsigned long jif = hz_to_std(jiffies);
+ 	unsigned int sum = 0, user = 0, nice = 0, system = 0;
+ 	int major, disk;
+ 
+ 	for (i = 0 ; i < smp_num_cpus; i++) {
+ 		int cpu = cpu_logical_map(i), j;
+ 
+-		user += kstat.per_cpu_user[cpu];
+-		nice += kstat.per_cpu_nice[cpu];
+-		system += kstat.per_cpu_system[cpu];
++		user += hz_to_std(kstat.per_cpu_user[cpu]);
++		nice += hz_to_std(kstat.per_cpu_nice[cpu]);
++		system += hz_to_std(kstat.per_cpu_system[cpu]);
+ #if !defined(CONFIG_ARCH_S390)
+ 		for (j = 0 ; j < NR_IRQS ; j++)
+ 			sum += kstat.irqs[cpu][j];
+@@ -331,10 +331,10 @@
+ 		proc_sprintf(page, &off, &len,
+ 			"cpu%d %u %u %u %lu\n",
+ 			i,
+-			kstat.per_cpu_user[cpu_logical_map(i)],
+-			kstat.per_cpu_nice[cpu_logical_map(i)],
+-			kstat.per_cpu_system[cpu_logical_map(i)],
+-			jif - (  kstat.per_cpu_user[cpu_logical_map(i)] \
++			hz_to_std(kstat.per_cpu_user[cpu_logical_map(i)]),
++			hz_to_std(kstat.per_cpu_nice[cpu_logical_map(i)]),
++			hz_to_std(kstat.per_cpu_system[cpu_logical_map(i)]),
++			jif - hz_to_std(  kstat.per_cpu_user[cpu_logical_map(i)] \
+ 				   + kstat.per_cpu_nice[cpu_logical_map(i)] \
+ 				   + kstat.per_cpu_system[cpu_logical_map(i)]));
+ 	proc_sprintf(page, &off, &len,
+@@ -440,12 +440,14 @@
+ 	return proc_calc_metrics(page, start, off, count, eof, len);
+ }
+ 
++#ifdef CONFIG_GENERIC_ISA_DMA
+ static int dma_read_proc(char *page, char **start, off_t off,
+ 				 int count, int *eof, void *data)
+ {
+ 	int len = get_dma_list(page);
+ 	return proc_calc_metrics(page, start, off, count, eof, len);
+ }
++#endif
+ 
+ static int cmdline_read_proc(char *page, char **start, off_t off,
+ 				 int count, int *eof, void *data)
+@@ -613,7 +615,9 @@
+ 		{"interrupts",	interrupts_read_proc},
+ #endif
+ 		{"filesystems",	filesystems_read_proc},
++#ifdef CONFIG_GENERIC_ISA_DMA
+ 		{"dma",		dma_read_proc},
++#endif
+ 		{"cmdline",	cmdline_read_proc},
+ #ifdef CONFIG_SGI_DS1286
+ 		{"rtc",		ds1286_read_proc},
+--- linux-2.4.25/fs/stat.c~2.4.25-vrs2.patch	2004-02-18 14:36:31.000000000 +0100
++++ linux-2.4.25/fs/stat.c	2004-03-31 17:15:09.000000000 +0200
+@@ -26,7 +26,9 @@
+ }
+ 
+ 
+-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \
++    !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \
++    !defined(__x86_64__) && !defined(__mips__)
+ 
+ /*
+  * For backward compatibility?  Maybe this should be moved
+@@ -38,7 +40,7 @@
+ 	struct __old_kernel_stat tmp;
+ 
+ 	memset(&tmp, 0, sizeof(struct __old_kernel_stat));
+-	
++
+ 	if (warncount > 0) {
+ 		warncount--;
+ 		printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n",
+@@ -58,7 +60,7 @@
+ #if BITS_PER_LONG == 32
+ 	if (inode->i_size > MAX_NON_LFS)
+ 		return -EOVERFLOW;
+-#endif	
++#endif
+ 	tmp.st_size = inode->i_size;
+ 	tmp.st_atime = inode->i_atime;
+ 	tmp.st_mtime = inode->i_mtime;
+@@ -84,7 +86,7 @@
+ #if BITS_PER_LONG == 32
+ 	if (inode->i_size > MAX_NON_LFS)
+ 		return -EOVERFLOW;
+-#endif	
++#endif
+ 	tmp.st_size = inode->i_size;
+ 	tmp.st_atime = inode->i_atime;
+ 	tmp.st_mtime = inode->i_mtime;
+@@ -129,7 +131,9 @@
+ }
+ 
+ 
+-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \
++    !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \
++    !defined(__x86_64__) && !defined(__mips__)
+ /*
+  * For backward compatibility?  Maybe this should be moved
+  * into arch/i386 instead?
+@@ -165,7 +169,9 @@
+ 	return error;
+ }
+ 
+-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \
++    !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \
++    !defined(__x86_64__) && !defined(__mips__)
+ 
+ /*
+  * For backward compatibility?  Maybe this should be moved
+@@ -203,7 +209,9 @@
+ 	return error;
+ }
+ 
+-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) && !defined(__mips__)
++#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && \
++    !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__arm__) && \
++    !defined(__x86_64__) && !defined(__mips__)
+ 
+ /*
+  * For backward compatibility?  Maybe this should be moved
+--- linux-2.4.25/include/asm-alpha/ide.h~2.4.25-vrs2.patch	2003-06-13 16:51:38.000000000 +0200
++++ linux-2.4.25/include/asm-alpha/ide.h	2004-03-31 17:15:09.000000000 +0200
+@@ -19,35 +19,15 @@
+ #define MAX_HWIFS	4
+ #endif
+ 
+-static __inline__ int ide_default_irq(ide_ioreg_t base)
+-{
+-	switch (base) {
+-		case 0x1f0: return 14;
+-		case 0x170: return 15;
+-		case 0x1e8: return 11;
+-		case 0x168: return 10;
+-		default:
+-			return 0;
+-	}
+-}
+-
+-static __inline__ ide_ioreg_t ide_default_io_base(int index)
+-{
+-	switch (index) {
+-		case 0:	return 0x1f0;
+-		case 1:	return 0x170;
+-		case 2: return 0x1e8;
+-		case 3: return 0x168;
+-		default:
+-			return 0;
+-	}
+-}
++#define ide_default_io_base(i)	((ide_ioreg_t)0)
++#define ide_default_irq(b)	(0)
+ 
+ static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+ {
+ 	ide_ioreg_t reg = data_port;
+ 	int i;
+ 
++	memset(hw, 0, sizeof(*hw));
+ 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ 		hw->io_ports[i] = reg;
+ 		reg += 1;
+@@ -55,7 +35,7 @@
+ 	if (ctrl_port) {
+ 		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ 	} else {
+-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
++		hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0x206;
+ 	}
+ 	if (irq != NULL)
+ 		*irq = 0;
+@@ -70,13 +50,19 @@
+ {
+ #ifndef CONFIG_BLK_DEV_IDEPCI
+ 	hw_regs_t hw;
+-	int index;
+ 
+-	for (index = 0; index < MAX_HWIFS; index++) {
+-		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+-		hw.irq = ide_default_irq(ide_default_io_base(index));
+-		ide_register_hw(&hw, NULL);
+-	}
++	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
++	hw.irq = 14;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x170, 0x376, NULL);
++	hw.irq = 15;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x1e8, 0x3ee, NULL);
++	hw.irq = 11;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x168, 0x36e, NULL);
++	hw.irq = 10;
++	ide_register_hw(&hw, NULL);
+ #endif /* CONFIG_BLK_DEV_IDEPCI */
+ }
+ 
+--- linux-2.4.25/include/asm-alpha/param.h~2.4.25-vrs2.patch	2000-11-08 08:37:31.000000000 +0100
++++ linux-2.4.25/include/asm-alpha/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -13,6 +13,9 @@
+ # else
+ #  define HZ	1200
+ # endif
++#ifdef __KERNEL__
++# define hz_to_std(a) (a)
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	8192
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/AT91RM9200_MCI.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,127 @@
++// ----------------------------------------------------------------------------
++//          ATMEL Microcontroller Software Support  -  ROUSSET  -
++// ----------------------------------------------------------------------------
++//  The software is delivered "AS IS" without warranty or condition of any
++//  kind, either express, implied or statutory. This includes without
++//  limitation any warranty or condition with respect to merchantability or
++//  fitness for any particular purpose, or against the infringements of
++//  intellectual property rights of others.
++// ----------------------------------------------------------------------------
++// File Name           : AT91RM9200.h
++// Object              : AT91RM9200 / MCI definitions
++// Generated           : AT91 SW Application Group  12/03/2002 (10:48:02)
++// 
++// ----------------------------------------------------------------------------
++
++#ifndef AT91RM9200_MCI_H
++#define AT91RM9200_MCI_H
++
++// *****************************************************************************
++//              SOFTWARE API DEFINITION  FOR Multimedia Card Interface
++// *****************************************************************************
++#ifndef __ASSEMBLY__
++
++typedef struct _AT91S_MCI {
++	AT91_REG	 MCI_CR; 	// MCI Control Register
++	AT91_REG	 MCI_MR; 	// MCI Mode Register
++	AT91_REG	 MCI_DTOR; 	// MCI Data Timeout Register
++	AT91_REG	 MCI_SDCR; 	// MCI SD Card Register
++	AT91_REG	 MCI_ARGR; 	// MCI Argument Register
++	AT91_REG	 MCI_CMDR; 	// MCI Command Register
++	AT91_REG	 Reserved0[2]; 	// 
++	AT91_REG	 MCI_RSPR[4]; 	// MCI Response Register
++	AT91_REG	 MCI_RDR; 	// MCI Receive Data Register
++	AT91_REG	 MCI_TDR; 	// MCI Transmit Data Register
++	AT91_REG	 Reserved1[2]; 	// 
++	AT91_REG	 MCI_SR; 	// MCI Status Register
++	AT91_REG	 MCI_IER; 	// MCI Interrupt Enable Register
++	AT91_REG	 MCI_IDR; 	// MCI Interrupt Disable Register
++	AT91_REG	 MCI_IMR; 	// MCI Interrupt Mask Register
++	AT91_REG	 Reserved2[44]; 	// 
++	AT91_REG	 MCI_RPR; 	// Receive Pointer Register
++	AT91_REG	 MCI_RCR; 	// Receive Counter Register
++	AT91_REG	 MCI_TPR; 	// Transmit Pointer Register
++	AT91_REG	 MCI_TCR; 	// Transmit Counter Register
++	AT91_REG	 MCI_RNPR; 	// Receive Next Pointer Register
++	AT91_REG	 MCI_RNCR; 	// Receive Next Counter Register
++	AT91_REG	 MCI_TNPR; 	// Transmit Next Pointer Register
++	AT91_REG	 MCI_TNCR; 	// Transmit Next Counter Register
++	AT91_REG	 MCI_PTCR; 	// PDC Transfer Control Register
++	AT91_REG	 MCI_PTSR; 	// PDC Transfer Status Register
++} AT91S_MCI, *AT91PS_MCI;
++
++#endif
++
++// -------- MCI_CR : (MCI Offset: 0x0) MCI Control Register -------- 
++#define AT91C_MCI_MCIEN       ((unsigned int) 0x1 <<  0) // (MCI) Multimedia Interface Enable
++#define AT91C_MCI_MCIDIS      ((unsigned int) 0x1 <<  1) // (MCI) Multimedia Interface Disable
++#define AT91C_MCI_PWSEN       ((unsigned int) 0x1 <<  2) // (MCI) Power Save Mode Enable
++#define AT91C_MCI_PWSDIS      ((unsigned int) 0x1 <<  3) // (MCI) Power Save Mode Disable
++// -------- MCI_MR : (MCI Offset: 0x4) MCI Mode Register -------- 
++#define AT91C_MCI_CLKDIV      ((unsigned int) 0x1 <<  0) // (MCI) Clock Divider
++#define AT91C_MCI_PWSDIV      ((unsigned int) 0x1 <<  8) // (MCI) Power Saving Divider
++#define AT91C_MCI_PDCPADV     ((unsigned int) 0x1 << 14) // (MCI) PDC Padding Value
++#define AT91C_MCI_PDCMODE     ((unsigned int) 0x1 << 15) // (MCI) PDC Oriented Mode
++#define AT91C_MCI_BLKLEN      ((unsigned int) 0x1 << 18) // (MCI) Data Block Length
++// -------- MCI_DTOR : (MCI Offset: 0x8) MCI Data Timeout Register -------- 
++#define AT91C_MCI_DTOCYC      ((unsigned int) 0x1 <<  0) // (MCI) Data Timeout Cycle Number
++#define AT91C_MCI_DTOMUL      ((unsigned int) 0x7 <<  4) // (MCI) Data Timeout Multiplier
++#define 	AT91C_MCI_DTOMUL_1                    ((unsigned int) 0x0 <<  4) // (MCI) DTOCYC x 1
++#define 	AT91C_MCI_DTOMUL_16                   ((unsigned int) 0x1 <<  4) // (MCI) DTOCYC x 16
++#define 	AT91C_MCI_DTOMUL_128                  ((unsigned int) 0x2 <<  4) // (MCI) DTOCYC x 128
++#define 	AT91C_MCI_DTOMUL_256                  ((unsigned int) 0x3 <<  4) // (MCI) DTOCYC x 256
++#define 	AT91C_MCI_DTOMUL_1024                 ((unsigned int) 0x4 <<  4) // (MCI) DTOCYC x 1024
++#define 	AT91C_MCI_DTOMUL_4096                 ((unsigned int) 0x5 <<  4) // (MCI) DTOCYC x 4096
++#define 	AT91C_MCI_DTOMUL_65536                ((unsigned int) 0x6 <<  4) // (MCI) DTOCYC x 65536
++#define 	AT91C_MCI_DTOMUL_1048576              ((unsigned int) 0x7 <<  4) // (MCI) DTOCYC x 1048576
++// -------- MCI_SDCR : (MCI Offset: 0xc) MCI SD Card Register -------- 
++#define AT91C_MCI_SCDSEL      ((unsigned int) 0x1 <<  0) // (MCI) SD Card Selector
++#define AT91C_MCI_SCDBUS      ((unsigned int) 0x1 <<  7) // (MCI) SD Card Bus Width
++// -------- MCI_CMDR : (MCI Offset: 0x14) MCI Command Register -------- 
++#define AT91C_MCI_CMDNB       ((unsigned int) 0x1F <<  0) // (MCI) Command Number
++#define AT91C_MCI_RSPTYP      ((unsigned int) 0x3 <<  6) // (MCI) Response Type
++#define 	AT91C_MCI_RSPTYP_NO                   ((unsigned int) 0x0 <<  6) // (MCI) No response
++#define 	AT91C_MCI_RSPTYP_48                   ((unsigned int) 0x1 <<  6) // (MCI) 48-bit response
++#define 	AT91C_MCI_RSPTYP_136                  ((unsigned int) 0x2 <<  6) // (MCI) 136-bit response
++#define AT91C_MCI_SPCMD       ((unsigned int) 0x7 <<  8) // (MCI) Special CMD
++#define 	AT91C_MCI_SPCMD_NONE                 ((unsigned int) 0x0 <<  8) // (MCI) Not a special CMD
++#define 	AT91C_MCI_SPCMD_INIT                 ((unsigned int) 0x1 <<  8) // (MCI) Initialization CMD
++#define 	AT91C_MCI_SPCMD_SYNC                 ((unsigned int) 0x2 <<  8) // (MCI) Synchronized CMD
++#define 	AT91C_MCI_SPCMD_IT_CMD               ((unsigned int) 0x4 <<  8) // (MCI) Interrupt command
++#define 	AT91C_MCI_SPCMD_IT_REP               ((unsigned int) 0x5 <<  8) // (MCI) Interrupt response
++#define AT91C_MCI_OPDCMD      ((unsigned int) 0x1 << 11) // (MCI) Open Drain Command
++#define AT91C_MCI_MAXLAT      ((unsigned int) 0x1 << 12) // (MCI) Maximum Latency for Command to respond
++#define AT91C_MCI_TRCMD       ((unsigned int) 0x3 << 16) // (MCI) Transfer CMD
++#define 	AT91C_MCI_TRCMD_NO                   ((unsigned int) 0x0 << 16) // (MCI) No transfer
++#define 	AT91C_MCI_TRCMD_START                ((unsigned int) 0x1 << 16) // (MCI) Start transfer
++#define 	AT91C_MCI_TRCMD_STOP                 ((unsigned int) 0x2 << 16) // (MCI) Stop transfer
++#define AT91C_MCI_TRDIR       ((unsigned int) 0x1 << 18) // (MCI) Transfer Direction
++#define AT91C_MCI_TRTYP       ((unsigned int) 0x3 << 19) // (MCI) Transfer Type
++#define 	AT91C_MCI_TRTYP_BLOCK                ((unsigned int) 0x0 << 19) // (MCI) Block Transfer type
++#define 	AT91C_MCI_TRTYP_MULTIPLE             ((unsigned int) 0x1 << 19) // (MCI) Multiple Block transfer type
++#define 	AT91C_MCI_TRTYP_STREAM               ((unsigned int) 0x2 << 19) // (MCI) Stream transfer type
++// -------- MCI_SR : (MCI Offset: 0x40) MCI Status Register -------- 
++#define AT91C_MCI_CMDRDY      ((unsigned int) 0x1 <<  0) // (MCI) Command Ready flag
++#define AT91C_MCI_RXRDY       ((unsigned int) 0x1 <<  1) // (MCI) RX Ready flag
++#define AT91C_MCI_TXRDY       ((unsigned int) 0x1 <<  2) // (MCI) TX Ready flag
++#define AT91C_MCI_BLKE        ((unsigned int) 0x1 <<  3) // (MCI) Data Block Transfer Ended flag
++#define AT91C_MCI_DTIP        ((unsigned int) 0x1 <<  4) // (MCI) Data Transfer in Progress flag
++#define AT91C_MCI_NOTBUSY     ((unsigned int) 0x1 <<  5) // (MCI) Data Line Not Busy flag
++#define AT91C_MCI_ENDRX       ((unsigned int) 0x1 <<  6) // (MCI) End of RX Buffer flag
++#define AT91C_MCI_ENDTX       ((unsigned int) 0x1 <<  7) // (MCI) End of TX Buffer flag
++#define AT91C_MCI_RXBUFF      ((unsigned int) 0x1 << 14) // (MCI) RX Buffer Full flag
++#define AT91C_MCI_TXBUFE      ((unsigned int) 0x1 << 15) // (MCI) TX Buffer Empty flag
++#define AT91C_MCI_RINDE       ((unsigned int) 0x1 << 16) // (MCI) Response Index Error flag
++#define AT91C_MCI_RDIRE       ((unsigned int) 0x1 << 17) // (MCI) Response Direction Error flag
++#define AT91C_MCI_RCRCE       ((unsigned int) 0x1 << 18) // (MCI) Response CRC Error flag
++#define AT91C_MCI_RENDE       ((unsigned int) 0x1 << 19) // (MCI) Response End Bit Error flag
++#define AT91C_MCI_RTOE        ((unsigned int) 0x1 << 20) // (MCI) Response Time-out Error flag
++#define AT91C_MCI_DCRCE       ((unsigned int) 0x1 << 21) // (MCI) data CRC Error flag
++#define AT91C_MCI_DTOE        ((unsigned int) 0x1 << 22) // (MCI) Data timeout Error flag
++#define AT91C_MCI_OVRE        ((unsigned int) 0x1 << 30) // (MCI) Overrun flag
++#define AT91C_MCI_UNRE        ((unsigned int) 0x1 << 31) // (MCI) Underrun flag
++// -------- MCI_IER : (MCI Offset: 0x44) MCI Interrupt Enable Register -------- 
++// -------- MCI_IDR : (MCI Offset: 0x48) MCI Interrupt Disable Register -------- 
++// -------- MCI_IMR : (MCI Offset: 0x4c) MCI Interrupt Mask Register -------- 
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/AT91RM9200_SSC.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,129 @@
++// ----------------------------------------------------------------------------
++//          ATMEL Microcontroller Software Support  -  ROUSSET  -
++// ----------------------------------------------------------------------------
++//  The software is delivered "AS IS" without warranty or condition of any
++//  kind, either express, implied or statutory. This includes without
++//  limitation any warranty or condition with respect to merchantability or
++//  fitness for any particular purpose, or against the infringements of
++//  intellectual property rights of others.
++// ----------------------------------------------------------------------------
++// File Name           : AT91RM9200.h
++// Object              : AT91RM9200 / SSC definitions
++// Generated           : AT91 SW Application Group  12/03/2002 (10:48:02)
++// 
++// ----------------------------------------------------------------------------
++
++#ifndef AT91RM9200_SSC_H
++#define AT91RM9200_SSC_H
++
++// *****************************************************************************
++//              SOFTWARE API DEFINITION  FOR Synchronous Serial Controller Interface
++// *****************************************************************************
++#ifndef __ASSEMBLY__
++
++typedef struct _AT91S_SSC {
++	AT91_REG	 SSC_CR; 	// Control Register
++	AT91_REG	 SSC_CMR; 	// Clock Mode Register
++	AT91_REG	 Reserved0[2]; 	// 
++	AT91_REG	 SSC_RCMR; 	// Receive Clock ModeRegister
++	AT91_REG	 SSC_RFMR; 	// Receive Frame Mode Register
++	AT91_REG	 SSC_TCMR; 	// Transmit Clock Mode Register
++	AT91_REG	 SSC_TFMR; 	// Transmit Frame Mode Register
++	AT91_REG	 SSC_RHR; 	// Receive Holding Register
++	AT91_REG	 SSC_THR; 	// Transmit Holding Register
++	AT91_REG	 Reserved1[2]; 	// 
++	AT91_REG	 SSC_RSHR; 	// Receive Sync Holding Register
++	AT91_REG	 SSC_TSHR; 	// Transmit Sync Holding Register
++	AT91_REG	 SSC_RC0R; 	// Receive Compare 0 Register
++	AT91_REG	 SSC_RC1R; 	// Receive Compare 1 Register
++	AT91_REG	 SSC_SR; 	// Status Register
++	AT91_REG	 SSC_IER; 	// Interrupt Enable Register
++	AT91_REG	 SSC_IDR; 	// Interrupt Disable Register
++	AT91_REG	 SSC_IMR; 	// Interrupt Mask Register
++	AT91_REG	 Reserved2[44]; 	// 
++	AT91_REG	 SSC_RPR; 	// Receive Pointer Register
++	AT91_REG	 SSC_RCR; 	// Receive Counter Register
++	AT91_REG	 SSC_TPR; 	// Transmit Pointer Register
++	AT91_REG	 SSC_TCR; 	// Transmit Counter Register
++	AT91_REG	 SSC_RNPR; 	// Receive Next Pointer Register
++	AT91_REG	 SSC_RNCR; 	// Receive Next Counter Register
++	AT91_REG	 SSC_TNPR; 	// Transmit Next Pointer Register
++	AT91_REG	 SSC_TNCR; 	// Transmit Next Counter Register
++	AT91_REG	 SSC_PTCR; 	// PDC Transfer Control Register
++	AT91_REG	 SSC_PTSR; 	// PDC Transfer Status Register
++} AT91S_SSC, *AT91PS_SSC;
++
++#endif
++
++// -------- SSC_CR : (SSC Offset: 0x0) SSC Control Register -------- 
++#define AT91C_SSC_RXEN        ( 0x1 <<  0) // (SSC) Receive Enable
++#define AT91C_SSC_RXDIS       ( 0x1 <<  1) // (SSC) Receive Disable
++#define AT91C_SSC_TXEN        ( 0x1 <<  8) // (SSC) Transmit Enable
++#define AT91C_SSC_TXDIS       ( 0x1 <<  9) // (SSC) Transmit Disable
++#define AT91C_SSC_SWRST       ( 0x1 << 15) // (SSC) Software Reset
++// -------- SSC_RCMR : (SSC Offset: 0x10) SSC Receive Clock Mode Register -------- 
++#define AT91C_SSC_CKS         ( 0x3 <<  0) // (SSC) Receive/Transmit Clock Selection
++#define 	AT91C_SSC_CKS_DIV                  ( 0x0) // (SSC) Divided Clock
++#define 	AT91C_SSC_CKS_TK                   ( 0x1) // (SSC) TK Clock signal
++#define 	AT91C_SSC_CKS_RK                   ( 0x2) // (SSC) RK pin
++#define AT91C_SSC_CKO         ( 0x7 <<  2) // (SSC) Receive/Transmit Clock Output Mode Selection
++#define 	AT91C_SSC_CKO_NONE                 ( 0x0 <<  2) // (SSC) Receive/Transmit Clock Output Mode: None RK pin: Input-only
++#define 	AT91C_SSC_CKO_CONTINOUS            ( 0x1 <<  2) // (SSC) Continuous Receive/Transmit Clock RK pin: Output
++#define 	AT91C_SSC_CKO_DATA_TX              ( 0x2 <<  2) // (SSC) Receive/Transmit Clock only during data transfers RK pin: Output
++#define AT91C_SSC_CKI         ( 0x1 <<  5) // (SSC) Receive/Transmit Clock Inversion
++#define AT91C_SSC_CKG         ( 0x3 <<  6) // (SSC) Receive/Transmit Clock Gating Selection
++#define 	AT91C_SSC_CKG_NONE                 ( 0x0 <<  6) // (SSC) Receive/Transmit Clock Gating: None, continuous clock
++#define 	AT91C_SSC_CKG_LOW                  ( 0x1 <<  6) // (SSC) Receive/Transmit Clock enabled only if RF Low
++#define 	AT91C_SSC_CKG_HIGH                 ( 0x2 <<  6) // (SSC) Receive/Transmit Clock enabled only if RF High
++#define AT91C_SSC_START       ( 0xF <<  8) // (SSC) Receive/Transmit Start Selection
++#define 	AT91C_SSC_START_CONTINOUS            ( 0x0 <<  8) // (SSC) Continuous, as soon as the receiver is enabled, and immediately after the end of transfer of the previous data.
++#define 	AT91C_SSC_START_TX                   ( 0x1 <<  8) // (SSC) Transmit/Receive start
++#define 	AT91C_SSC_START_LOW_RF               ( 0x2 <<  8) // (SSC) Detection of a low level on RF input
++#define 	AT91C_SSC_START_HIGH_RF              ( 0x3 <<  8) // (SSC) Detection of a high level on RF input
++#define 	AT91C_SSC_START_FALL_RF              ( 0x4 <<  8) // (SSC) Detection of a falling edge on RF input
++#define 	AT91C_SSC_START_RISE_RF              ( 0x5 <<  8) // (SSC) Detection of a rising edge on RF input
++#define 	AT91C_SSC_START_LEVEL_RF             ( 0x6 <<  8) // (SSC) Detection of any level change on RF input
++#define 	AT91C_SSC_START_EDGE_RF              ( 0x7 <<  8) // (SSC) Detection of any edge on RF input
++#define 	AT91C_SSC_START_0                    ( 0x8 <<  8) // (SSC) Compare 0
++#define AT91C_SSC_STOP        ( 0x1 << 12) // (SSC) Receive Stop Selection
++#define AT91C_SSC_STTOUT      ( 0x1 << 15) // (SSC) Receive/Transmit Start Output Selection
++#define AT91C_SSC_STTDLY      ( 0xFF << 16) // (SSC) Receive/Transmit Start Delay
++#define AT91C_SSC_PERIOD      ( 0xFF << 24) // (SSC) Receive/Transmit Period Divider Selection
++// -------- SSC_RFMR : (SSC Offset: 0x14) SSC Receive Frame Mode Register -------- 
++#define AT91C_SSC_DATLEN      ( 0x1F <<  0) // (SSC) Data Length
++#define AT91C_SSC_LOOP        ( 0x1 <<  5) // (SSC) Loop Mode
++#define AT91C_SSC_MSBF        ( 0x1 <<  7) // (SSC) Most Significant Bit First
++#define AT91C_SSC_DATNB       ( 0xF <<  8) // (SSC) Data Number per Frame
++#define AT91C_SSC_FSLEN       ( 0xF << 16) // (SSC) Receive/Transmit Frame Sync length
++#define AT91C_SSC_FSOS        ( 0x7 << 20) // (SSC) Receive/Transmit Frame Sync Output Selection
++#define 	AT91C_SSC_FSOS_NONE                 ( 0x0 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: None RK pin Input-only
++#define 	AT91C_SSC_FSOS_NEGATIVE             ( 0x1 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Negative Pulse
++#define 	AT91C_SSC_FSOS_POSITIVE             ( 0x2 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Positive Pulse
++#define 	AT91C_SSC_FSOS_LOW                  ( 0x3 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Driver Low during data transfer
++#define 	AT91C_SSC_FSOS_HIGH                 ( 0x4 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Driver High during data transfer
++#define 	AT91C_SSC_FSOS_TOGGLE               ( 0x5 << 20) // (SSC) Selected Receive/Transmit Frame Sync Signal: Toggling at each start of data transfer
++#define AT91C_SSC_FSEDGE      ( 0x1 << 24) // (SSC) Frame Sync Edge Detection
++// -------- SSC_TCMR : (SSC Offset: 0x18) SSC Transmit Clock Mode Register -------- 
++// -------- SSC_TFMR : (SSC Offset: 0x1c) SSC Transmit Frame Mode Register -------- 
++#define AT91C_SSC_DATDEF      ( 0x1 <<  5) // (SSC) Data Default Value
++#define AT91C_SSC_FSDEN       ( 0x1 << 23) // (SSC) Frame Sync Data Enable
++// -------- SSC_SR : (SSC Offset: 0x40) SSC Status Register -------- 
++#define AT91C_SSC_TXRDY       ( 0x1 <<  0) // (SSC) Transmit Ready
++#define AT91C_SSC_TXEMPTY     ( 0x1 <<  1) // (SSC) Transmit Empty
++#define AT91C_SSC_ENDTX       ( 0x1 <<  2) // (SSC) End Of Transmission
++#define AT91C_SSC_TXBUFE      ( 0x1 <<  3) // (SSC) Transmit Buffer Empty
++#define AT91C_SSC_RXRDY       ( 0x1 <<  4) // (SSC) Receive Ready
++#define AT91C_SSC_OVRUN       ( 0x1 <<  5) // (SSC) Receive Overrun
++#define AT91C_SSC_ENDRX       ( 0x1 <<  6) // (SSC) End of Reception
++#define AT91C_SSC_RXBUFF      ( 0x1 <<  7) // (SSC) Receive Buffer Full
++#define AT91C_SSC_CP0         ( 0x1 <<  8) // (SSC) Compare 0
++#define AT91C_SSC_CP1         ( 0x1 <<  9) // (SSC) Compare 1
++#define AT91C_SSC_TXSYN       ( 0x1 << 10) // (SSC) Transmit Sync
++#define AT91C_SSC_RXSYN       ( 0x1 << 11) // (SSC) Receive Sync
++#define AT91C_SSC_TXENA       ( 0x1 << 16) // (SSC) Transmit Enable
++#define AT91C_SSC_RXENA       ( 0x1 << 17) // (SSC) Receive Enable
++// -------- SSC_IER : (SSC Offset: 0x44) SSC Interrupt Enable Register -------- 
++// -------- SSC_IDR : (SSC Offset: 0x48) SSC Interrupt Disable Register -------- 
++// -------- SSC_IMR : (SSC Offset: 0x4c) SSC Interrupt Mask Register -------- 
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/AT91RM9200_TC.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,165 @@
++// ----------------------------------------------------------------------------
++//          ATMEL Microcontroller Software Support  -  ROUSSET  -
++// ----------------------------------------------------------------------------
++//  The software is delivered "AS IS" without warranty or condition of any
++//  kind, either express, implied or statutory. This includes without
++//  limitation any warranty or condition with respect to merchantability or
++//  fitness for any particular purpose, or against the infringements of
++//  intellectual property rights of others.
++// ----------------------------------------------------------------------------
++// File Name           : AT91RM9200.h
++// Object              : AT91RM9200 definitions
++// Generated           : AT91 SW Application Group  12/03/2002 (10:48:02)
++// 
++// ----------------------------------------------------------------------------
++
++#ifndef AT91RM9200_TC_H
++#define AT91RM9200_TC_H
++
++// *****************************************************************************
++//              SOFTWARE API DEFINITION  FOR Timer Counter Channel Interface
++// *****************************************************************************
++#ifndef __ASSEMBLY__
++
++typedef struct _AT91S_TC {
++	AT91_REG	 TC_CCR; 	// Channel Control Register
++	AT91_REG	 TC_CMR; 	// Channel Mode Register
++	AT91_REG	 Reserved0[2]; 	// 
++	AT91_REG	 TC_CV; 	// Counter Value
++	AT91_REG	 TC_RA; 	// Register A
++	AT91_REG	 TC_RB; 	// Register B
++	AT91_REG	 TC_RC; 	// Register C
++	AT91_REG	 TC_SR; 	// Status Register
++	AT91_REG	 TC_IER; 	// Interrupt Enable Register
++	AT91_REG	 TC_IDR; 	// Interrupt Disable Register
++	AT91_REG	 TC_IMR; 	// Interrupt Mask Register
++} AT91S_TC, *AT91PS_TC;
++
++typedef struct _AT91S_TCB {
++	AT91S_TC	 TCB_TC0; 	// TC Channel 0
++	AT91_REG	 Reserved0[4]; 	// 
++	AT91S_TC	 TCB_TC1; 	// TC Channel 1
++	AT91_REG	 Reserved1[4]; 	// 
++	AT91S_TC	 TCB_TC2; 	// TC Channel 2
++	AT91_REG	 Reserved2[4]; 	// 
++	AT91_REG	 TCB_BCR; 	// TC Block Control Register
++	AT91_REG	 TCB_BMR; 	// TC Block Mode Register
++} AT91S_TCB, *AT91PS_TCB;
++
++#endif
++
++// -------- TC_CCR : (TC Offset: 0x0) TC Channel Control Register -------- 
++#define AT91C_TC_CLKEN        ( 0x1 <<  0) // (TC) Counter Clock Enable Command
++#define AT91C_TC_CLKDIS       ( 0x1 <<  1) // (TC) Counter Clock Disable Command
++#define AT91C_TC_SWTRG        ( 0x1 <<  2) // (TC) Software Trigger Command
++// -------- TC_CMR : (TC Offset: 0x4) TC Channel Mode Register: Capture Mode / Waveform Mode -------- 
++#define AT91C_TC_TCCLKS       ( 0x7 <<  0) // (TC) Clock Selection
++#define		AT91C_TC_TIMER_DIV1_CLOCK             ( 0x0 <<  0) // (TC) MCK/2
++#define		AT91C_TC_TIMER_DIV2_CLOCK             ( 0x1 <<  0) // (TC) MCK/8
++#define		AT91C_TC_TIMER_DIV3_CLOCK             ( 0x2 <<  0) // (TC) MCK/32
++#define		AT91C_TC_TIMER_DIV4_CLOCK             ( 0x3 <<  0) // (TC) MCK/128
++#define		AT91C_TC_TIMER_DIV5_CLOCK             ( 0x4 <<  0) // (TC) MCK/256 = SLOW CLOCK
++#define		AT91C_TC_TIMER_XC0                    ( 0x5 <<  0) // (TC) XC0
++#define		AT91C_TC_TIMER_XC1                    ( 0x6 <<  0) // (TC) XC1
++#define		AT91C_TC_TIMER_XC2                    ( 0x7 <<  0) // (TC) XC2
++#define	AT91C_TC_CLKI         ( 0x1 <<  3) // (TC) Clock Invert
++#define AT91C_TC_BURST        ( 0x3 <<  4) // (TC) Burst Signal Selection
++#define AT91C_TC_CPCSTOP      ( 0x1 <<  6) // (TC) Counter Clock Stopped with RC Compare
++#define AT91C_TC_CPCDIS       ( 0x1 <<  7) // (TC) Counter Clock Disable with RC Compare
++#define AT91C_TC_EEVTEDG      ( 0x3 <<  8) // (TC) External Event Edge Selection
++#define 	AT91C_TC_EEVTEDG_NONE                 ( 0x0 <<  8) // (TC) Edge: None
++#define 	AT91C_TC_EEVTEDG_RISING               ( 0x1 <<  8) // (TC) Edge: rising edge
++#define 	AT91C_TC_EEVTEDG_FALLING              ( 0x2 <<  8) // (TC) Edge: falling edge
++#define 	AT91C_TC_EEVTEDG_BOTH                 ( 0x3 <<  8) // (TC) Edge: each edge
++#define AT91C_TC_EEVT         ( 0x3 << 10) // (TC) External Event  Selection
++#define 	AT91C_TC_EEVT_NONE                 ( 0x0 << 10) // (TC) Signal selected as external event: TIOB TIOB direction: input
++#define 	AT91C_TC_EEVT_RISING               ( 0x1 << 10) // (TC) Signal selected as external event: XC0 TIOB direction: output
++#define 	AT91C_TC_EEVT_FALLING              ( 0x2 << 10) // (TC) Signal selected as external event: XC1 TIOB direction: output
++#define 	AT91C_TC_EEVT_BOTH                 ( 0x3 << 10) // (TC) Signal selected as external event: XC2 TIOB direction: output
++#define AT91C_TC_ENETRG       ( 0x1 << 12) // (TC) External Event Trigger enable
++#define AT91C_TC_WAVESEL      ( 0x3 << 13) // (TC) Waveform  Selection
++#define 	AT91C_TC_WAVESEL_UP                   ( 0x0 << 13) // (TC) UP mode without atomatic trigger on RC Compare
++#define 	AT91C_TC_WAVESEL_UP_AUTO              ( 0x1 << 13) // (TC) UP mode with automatic trigger on RC Compare
++#define 	AT91C_TC_WAVESEL_UPDOWN               ( 0x2 << 13) // (TC) UPDOWN mode without automatic trigger on RC Compare
++#define 	AT91C_TC_WAVESEL_UPDOWN_AUTO          ( 0x3 << 13) // (TC) UPDOWN mode with automatic trigger on RC Compare
++#define AT91C_TC_CPCTRG       ( 0x1 << 14) // (TC) RC Compare Trigger Enable
++#define AT91C_TC_WAVE         ( 0x1 << 15) // (TC) 
++#define AT91C_TC_ACPA         ( 0x3 << 16) // (TC) RA Compare Effect on TIOA
++#define 	AT91C_TC_ACPA_NONE                 ( 0x0 << 16) // (TC) Effect: none
++#define 	AT91C_TC_ACPA_SET                  ( 0x1 << 16) // (TC) Effect: set
++#define 	AT91C_TC_ACPA_CLEAR                ( 0x2 << 16) // (TC) Effect: clear
++#define 	AT91C_TC_ACPA_TOGGLE               ( 0x3 << 16) // (TC) Effect: toggle
++#define AT91C_TC_ACPC         ( 0x3 << 18) // (TC) RC Compare Effect on TIOA
++#define 	AT91C_TC_ACPC_NONE                 ( 0x0 << 18) // (TC) Effect: none
++#define 	AT91C_TC_ACPC_SET                  ( 0x1 << 18) // (TC) Effect: set
++#define 	AT91C_TC_ACPC_CLEAR                ( 0x2 << 18) // (TC) Effect: clear
++#define 	AT91C_TC_ACPC_TOGGLE               ( 0x3 << 18) // (TC) Effect: toggle
++#define AT91C_TC_AEEVT        ( 0x3 << 20) // (TC) External Event Effect on TIOA
++#define 	AT91C_TC_AEEVT_NONE                 ( 0x0 << 20) // (TC) Effect: none
++#define 	AT91C_TC_AEEVT_SET                  ( 0x1 << 20) // (TC) Effect: set
++#define 	AT91C_TC_AEEVT_CLEAR                ( 0x2 << 20) // (TC) Effect: clear
++#define 	AT91C_TC_AEEVT_TOGGLE               ( 0x3 << 20) // (TC) Effect: toggle
++#define AT91C_TC_ASWTRG       ( 0x3 << 22) // (TC) Software Trigger Effect on TIOA
++#define 	AT91C_TC_ASWTRG_NONE                 ( 0x0 << 22) // (TC) Effect: none
++#define 	AT91C_TC_ASWTRG_SET                  ( 0x1 << 22) // (TC) Effect: set
++#define 	AT91C_TC_ASWTRG_CLEAR                ( 0x2 << 22) // (TC) Effect: clear
++#define 	AT91C_TC_ASWTRG_TOGGLE               ( 0x3 << 22) // (TC) Effect: toggle
++#define AT91C_TC_BCPB         ( 0x3 << 24) // (TC) RB Compare Effect on TIOB
++#define 	AT91C_TC_BCPB_NONE                 ( 0x0 << 24) // (TC) Effect: none
++#define 	AT91C_TC_BCPB_SET                  ( 0x1 << 24) // (TC) Effect: set
++#define 	AT91C_TC_BCPB_CLEAR                ( 0x2 << 24) // (TC) Effect: clear
++#define 	AT91C_TC_BCPB_TOGGLE               ( 0x3 << 24) // (TC) Effect: toggle
++#define AT91C_TC_BCPC         ( 0x3 << 26) // (TC) RC Compare Effect on TIOB
++#define 	AT91C_TC_BCPC_NONE                 ( 0x0 << 26) // (TC) Effect: none
++#define 	AT91C_TC_BCPC_SET                  ( 0x1 << 26) // (TC) Effect: set
++#define 	AT91C_TC_BCPC_CLEAR                ( 0x2 << 26) // (TC) Effect: clear
++#define 	AT91C_TC_BCPC_TOGGLE               ( 0x3 << 26) // (TC) Effect: toggle
++#define AT91C_TC_BEEVT        ( 0x3 << 28) // (TC) External Event Effect on TIOB
++#define 	AT91C_TC_BEEVT_NONE                 ( 0x0 << 28) // (TC) Effect: none
++#define 	AT91C_TC_BEEVT_SET                  ( 0x1 << 28) // (TC) Effect: set
++#define 	AT91C_TC_BEEVT_CLEAR                ( 0x2 << 28) // (TC) Effect: clear
++#define 	AT91C_TC_BEEVT_TOGGLE               ( 0x3 << 28) // (TC) Effect: toggle
++#define AT91C_TC_BSWTRG       ( 0x3 << 30) // (TC) Software Trigger Effect on TIOB
++#define 	AT91C_TC_BSWTRG_NONE                 ( 0x0 << 30) // (TC) Effect: none
++#define 	AT91C_TC_BSWTRG_SET                  ( 0x1 << 30) // (TC) Effect: set
++#define 	AT91C_TC_BSWTRG_CLEAR                ( 0x2 << 30) // (TC) Effect: clear
++#define 	AT91C_TC_BSWTRG_TOGGLE               ( 0x3 << 30) // (TC) Effect: toggle
++// -------- TC_SR : (TC Offset: 0x20) TC Channel Status Register -------- 
++#define AT91C_TC_COVFS        ( 0x1 <<  0) // (TC) Counter Overflow
++#define AT91C_TC_LOVRS        ( 0x1 <<  1) // (TC) Load Overrun
++#define AT91C_TC_CPAS         ( 0x1 <<  2) // (TC) RA Compare
++#define AT91C_TC_CPBS         ( 0x1 <<  3) // (TC) RB Compare
++#define AT91C_TC_CPCS         ( 0x1 <<  4) // (TC) RC Compare
++#define AT91C_TC_LDRAS        ( 0x1 <<  5) // (TC) RA Loading
++#define AT91C_TC_LDRBS        ( 0x1 <<  6) // (TC) RB Loading
++#define AT91C_TC_ETRCS        ( 0x1 <<  7) // (TC) External Trigger
++#define AT91C_TC_ETRGS        ( 0x1 << 16) // (TC) Clock Enabling
++#define AT91C_TC_MTIOA        ( 0x1 << 17) // (TC) TIOA Mirror
++#define AT91C_TC_MTIOB        ( 0x1 << 18) // (TC) TIOA Mirror
++// -------- TC_IER : (TC Offset: 0x24) TC Channel Interrupt Enable Register -------- 
++// -------- TC_IDR : (TC Offset: 0x28) TC Channel Interrupt Disable Register -------- 
++// -------- TC_IMR : (TC Offset: 0x2c) TC Channel Interrupt Mask Register -------- 
++
++// *****************************************************************************
++//              SOFTWARE API DEFINITION  FOR Timer Counter Interface
++// *****************************************************************************
++// -------- TCB_BCR : (TCB Offset: 0xc0) TC Block Control Register -------- 
++#define AT91C_TCB_SYNC        ( 0x1 <<  0) // (TCB) Synchro Command
++// -------- TCB_BMR : (TCB Offset: 0xc4) TC Block Mode Register -------- 
++#define AT91C_TCB_TC0XC0S     ( 0x1 <<  0) // (TCB) External Clock Signal 0 Selection
++#define 	AT91C_TCB_TC0XC0S_TCLK0                ( 0x0) // (TCB) TCLK0 connected to XC0
++#define 	AT91C_TCB_TC0XC0S_NONE                 ( 0x1) // (TCB) None signal connected to XC0
++#define 	AT91C_TCB_TC0XC0S_TIOA1                ( 0x2) // (TCB) TIOA1 connected to XC0
++#define 	AT91C_TCB_TC0XC0S_TIOA2                ( 0x3) // (TCB) TIOA2 connected to XC0
++#define AT91C_TCB_TC1XC1S     ( 0x1 <<  2) // (TCB) External Clock Signal 1 Selection
++#define 	AT91C_TCB_TC1XC1S_TCLK1                ( 0x0 <<  2) // (TCB) TCLK1 connected to XC1
++#define 	AT91C_TCB_TC1XC1S_NONE                 ( 0x1 <<  2) // (TCB) None signal connected to XC1
++#define 	AT91C_TCB_TC1XC1S_TIOA0                ( 0x2 <<  2) // (TCB) TIOA0 connected to XC1
++#define 	AT91C_TCB_TC1XC1S_TIOA2                ( 0x3 <<  2) // (TCB) TIOA2 connected to XC1
++#define AT91C_TCB_TC2XC2S     ( 0x1 <<  4) // (TCB) External Clock Signal 2 Selection
++#define 	AT91C_TCB_TC2XC2S_TCLK2                ( 0x0 <<  4) // (TCB) TCLK2 connected to XC2
++#define 	AT91C_TCB_TC2XC2S_NONE                 ( 0x1 <<  4) // (TCB) None signal connected to XC2
++#define 	AT91C_TCB_TC2XC2S_TIOA0                ( 0x2 <<  4) // (TCB) TIOA0 connected to XC2
++#define 	AT91C_TCB_TC2XC2S_TIOA2                ( 0x3 <<  4) // (TCB) TIOA2 connected to XC2
++
++#endif
+--- linux-2.4.25/include/asm-arm/arch-at91rm9200/at91rm9200dk.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/at91rm9200dk.h	2004-03-31 17:15:09.000000000 +0200
+@@ -68,6 +68,7 @@
+ #define AT91_SMR_IRQ5	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ5)
+ #define AT91_SMR_IRQ6	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ6)
+ 
++#define AT91C_CONSOLE_DEFAULT_BAUDRATE 115200	/* default serial console baud-rate */
+ 
+ /*
+  * Serial port configuration.
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/csb337.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,82 @@
++/*
++ * linux/include/asm-arm/arch-at91rm9200/csb337.h
++ *
++ *  Copyright (c) 2003 Christopher Bahns & David Knickerbocker
++ *                     Polaroid 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.
++ *
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_CSB337_H
++#define __ASM_ARCH_HARDWARE_CSB337_H
++
++
++/* AT91RM92000 clocks on CSB337 */
++#define AT91C_MAIN_CLOCK	184320000
++#define AT91C_MASTER_CLOCK	46080000	/* peripheral clock (AT91C_MAIN_CLOCK / 4) */
++#define AT91C_SLOW_CLOCK	32768		/* slow clock */
++
++
++/* FLASH */
++#define AT91_FLASH_BASE		0x10000000	// NCS0: Flash physical base address
++
++/* SDRAM */
++#define AT91_SDRAM_BASE		0x20000000	// NCS1: SDRAM physical base address
++
++/* SmartMedia */
++#define AT91_SMARTMEDIA_BASE	0x40000000	// NCS3: Smartmedia physical base address
++
++/* Multi-Master Memory controller */
++#define AT91_UHP_BASE		0x00300000	// USB Host controller
++
++
++/* Peripheral interrupt configuration */
++#define AT91_SMR_FIQ	(AT91C_AIC_PRIOR_HIGHEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (FIQ)
++#define AT91_SMR_SYS	(AT91C_AIC_PRIOR_HIGHEST | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// System Peripheral
++#define AT91_SMR_PIOA	(AT91C_AIC_PRIOR_LOWEST	 | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Parallel IO Controller A
++#define AT91_SMR_PIOB	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Parallel IO Controller B
++#define AT91_SMR_PIOC	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Parallel IO Controller C
++#define AT91_SMR_PIOD	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Parallel IO Controller D
++#define AT91_SMR_US0	(AT91C_AIC_PRIOR_6       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// USART 0
++#define AT91_SMR_US1	(AT91C_AIC_PRIOR_6       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// USART 1
++#define AT91_SMR_US2	(AT91C_AIC_PRIOR_6       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// USART 2
++#define AT91_SMR_US3	(AT91C_AIC_PRIOR_6       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// USART 3
++#define AT91_SMR_MCI	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Multimedia Card Interface
++#define AT91_SMR_UDP	(AT91C_AIC_PRIOR_4       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// USB Device Port
++#define AT91_SMR_TWI	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Two-Wire Interface
++#define AT91_SMR_SPI	(AT91C_AIC_PRIOR_6       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Serial Peripheral Interface
++#define AT91_SMR_SSC0	(AT91C_AIC_PRIOR_5       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Serial Synchronous Controller 0
++#define AT91_SMR_SSC1	(AT91C_AIC_PRIOR_5       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Serial Synchronous Controller 1
++#define AT91_SMR_SSC2	(AT91C_AIC_PRIOR_5       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Serial Synchronous Controller 2
++#define AT91_SMR_TC0	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Timer Counter 0
++#define AT91_SMR_TC1	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Timer Counter 1
++#define AT91_SMR_TC2	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Timer Counter 2
++#define AT91_SMR_TC3	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Timer Counter 3
++#define AT91_SMR_TC4	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Timer Counter 4
++#define AT91_SMR_TC5	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Timer Counter 5
++#define AT91_SMR_UHP	(AT91C_AIC_PRIOR_3       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// USB Host port
++#define AT91_SMR_EMAC	(AT91C_AIC_PRIOR_3       | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Ethernet MAC
++#define AT91_SMR_IRQ0	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ0)
++#define AT91_SMR_IRQ1	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ1)
++#define AT91_SMR_IRQ2	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ2)
++#define AT91_SMR_IRQ3	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ3)
++#define AT91_SMR_IRQ4	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ4)
++#define AT91_SMR_IRQ5	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ5)
++#define AT91_SMR_IRQ6	(AT91C_AIC_PRIOR_LOWEST  | AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE)	// Advanced Interrupt Controller (IRQ6)
++
++
++#define AT91C_CONSOLE_DEFAULT_BAUDRATE 38400
++
++/*
++ * Serial port configuration.
++ *    0 .. 3 = USART0 .. USART3
++ *    4      = DBGU
++ */
++#define AT91C_UART_MAP		{ 4, 1, -1, -1, -1 }	/* ttyS0, ..., ttyS4 */
++#define AT91C_CONSOLE		0			/* ttyS0 */
++
++#endif
+--- linux-2.4.25/include/asm-arm/arch-at91rm9200/hardware.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/hardware.h	2004-03-31 17:15:09.000000000 +0200
+@@ -82,5 +82,8 @@
+ #include <asm/arch/at91rm9200dk.h>
+ #endif
+ 
++#ifdef CONFIG_MACH_CSB337
++#include <asm/arch/csb337.h>
++#endif
+ 
+ #endif
+--- linux-2.4.25/include/asm-arm/arch-at91rm9200/pio.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/pio.h	2004-03-31 17:15:09.000000000 +0200
+@@ -66,6 +66,18 @@
+ }
+ 
+ /*
++ * Configure interrupt from Ethernet PHY.
++ */
++static inline void AT91_CfgPIO_EMAC_PHY(void) {
++	AT91_SYS->PMC_PCER = 1 << AT91C_ID_PIOC;	/* enable peripheral clock */
++#ifdef CONFIG_MACH_CSB337
++	AT91_SYS->PIOC_ODR = AT91C_PIO_PC2;
++#else
++	AT91_SYS->PIOC_ODR = AT91C_PIO_PC4;
++#endif
++}
++
++/*
+  * Enable the Two-Wire interface.
+  */
+ static inline void AT91_CfgPIO_TWI(void) {
+--- linux-2.4.25/include/asm-arm/arch-at91rm9200/time.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-at91rm9200/time.h	2004-03-31 17:15:09.000000000 +0200
+@@ -27,6 +27,21 @@
+ extern unsigned long (*gettimeoffset)(void);
+ 
+ /*
++ * The ST_CRTR is updated asynchronously to the master clock.  It is therefore
++ *  necessary to read it twice (with the same value) to ensure accuracy.
++ */ 
++static inline unsigned long read_CRTR(void) {
++	unsigned long x1, x2;
++
++	do {
++		x1 = AT91_SYS->ST_CRTR;
++		x2 = AT91_SYS->ST_CRTR;
++	} while (x1 != x2);
++
++	return x1;
++}
++
++/*
+  * Returns number of microseconds since last timer interrupt.  Note that interrupts
+  * will have been disabled by do_gettimeofday()
+  *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
+@@ -36,7 +51,7 @@
+ {
+ 	unsigned long elapsed;
+ 
+-	elapsed = (AT91_SYS->ST_CRTR - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV;
++	elapsed = (read_CRTR() - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV;
+ 
+ 	return (unsigned long)(elapsed * tick) / LATCH;
+ }
+@@ -52,7 +67,7 @@
+ 
+ 			AT91_SYS->ST_RTAR = (AT91_SYS->ST_RTAR + LATCH) & AT91C_ST_ALMV;
+ 
+-		} while (((AT91_SYS->ST_CRTR - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV) >= LATCH);
++		} while (((read_CRTR() - AT91_SYS->ST_RTAR) & AT91C_ST_ALMV) >= LATCH);
+ 
+ 		do_profile(regs);
+ 	}
+--- linux-2.4.25/include/asm-arm/arch-clps711x/system.h~2.4.25-vrs2.patch	2003-06-13 16:51:38.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-clps711x/system.h	2004-03-31 17:15:09.000000000 +0200
+@@ -28,8 +28,8 @@
+ {
+ 	clps_writel(1, HALT);
+ 	__asm__ __volatile__(
+-	"mov	r0, r0
+-	mov	r0, r0");
++	"mov	r0, r0\n\t"
++	"mov	r0, r0");
+ }
+ 
+ static inline void arch_reset(char mode)
+--- linux-2.4.25/include/asm-arm/arch-integrator/uncompress.h~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-integrator/uncompress.h	2004-03-31 17:15:09.000000000 +0200
+@@ -18,6 +18,8 @@
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+ 
++#include <asm/hardware/serial_amba.h>
++
+ #define AMBA_UART_DR	(*(volatile unsigned char *)0x16000000)
+ #define AMBA_UART_LCRH	(*(volatile unsigned char *)0x16000008)
+ #define AMBA_UART_LCRM	(*(volatile unsigned char *)0x1600000c)
+@@ -30,21 +32,25 @@
+  */
+ static void puts(const char *s)
+ {
++	/* Do nothing if the UART is not enabled. */
++	if (!(AMBA_UART_CR & AMBA_UARTCR_UARTEN))
++		return;
++
+ 	while (*s) {
+-		while (AMBA_UART_FR & (1 << 5))
++		while (AMBA_UART_FR & AMBA_UARTFR_TXFF)
+ 			barrier();
+ 
+ 		AMBA_UART_DR = *s;
+ 
+ 		if (*s == '\n') {
+-			while (AMBA_UART_FR & (1 << 5))
++			while (AMBA_UART_FR & AMBA_UARTFR_TXFF)
+ 				barrier();
+ 
+ 			AMBA_UART_DR = '\r';
+ 		}
+ 		s++;
+ 	}
+-	while (AMBA_UART_FR & (1 << 3));
++	while (AMBA_UART_FR & AMBA_UARTFR_BUSY);
+ }
+ 
+ /*
+--- linux-2.4.25/include/asm-arm/arch-riscstation/system.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-riscstation/system.h	2004-03-31 17:15:09.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*
+- *  linux/include/asm-arm/arch-rpc/system.h
++ *  linux/include/asm-arm/arch-riscstation/system.h
+  *
+  *  Copyright (C) 1996-1999 Russell King.
+  *
+@@ -18,7 +18,7 @@
+ 
+ static inline void arch_reset(char mode)
+ {
+-	iomd_writeb(0, IOMD_ROMCR0);
++	iomd_writeb(0x40, IOMD_ROMCR0);
+ 
+ 	/*
+ 	 * Jump into the ROM
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-clock.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,76 @@
++/* linux/include/asm-arm/arch-s3c2410/S3C2410-clock.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * S3C2410 clock register definitions
++ *
++ *  Changelog:
++ *    19-06-2003     BJD     Created file
++ */
++
++#ifndef ASMARM_ARCH_S3C2410_CLOCK_H
++#define ASMARM_ARCH_S3C2410_CLOCK_H
++
++#define S3C2410_CLKREG(x) ((x) + S3C2410_VA_CLKPWR)
++
++#define S3C2410_PLLVAL(_m,_p,_s) ((_m) << 12 | ((_p) << 4) | ((_s)))
++
++#define S3C2410_LOCKTIME    S3C2410_CLKREG(0x00)
++#define S3C2410_MPLLCON     S3C2410_CLKREG(0x04)
++#define S3C2410_UPLLCON     S3C2410_CLKREG(0x08)
++#define S3C2410_CLKCON      S3C2410_CLKREG(0x0C)
++#define S3C2410_CLKSLOW     S3C2410_CLKREG(0x10)
++#define S3C2410_CLKDIVN     S3C2410_CLKREG(0x14)
++
++#define S3C2410_PLLCON_MDIVSHIFT     12
++#define S3C2410_PLLCON_PDIVSHIFT     4
++#define S3C2410_PLLCON_SDIVSHIFT     0
++#define S3C2410_PLLCON_MDIVMASK      ((1<<(1+(19-12)))-1)
++#define S3C2410_PLLCON_PDIVMASK      ((1<<5)-1)
++#define S3C2410_PLLCON_SDIVMASK      3
++
++/* DCLKCON register addresses in gpio.h */
++
++#define S3C2410_DCLKCON_DCLK0EN      (1<<0)
++#define S3C2410_DCLKCON_DCLK0_PCLK   (0<<1)
++#define S3C2410_DCLKCON_DCLK0_UCLK   (1<<1)
++#define S3C2410_DCLKCON_DCLK0_DIV(x) (((x) - 1 )<<4)
++#define S3C2410_DCLKCON_DCLK0_CMP(x) (((x) - 1 )<<8)
++
++#define S3C2410_DCLKCON_DCLK1EN      (1<<16)
++#define S3C2410_DCLKCON_DCLK1_PCLK   (0<<17)
++#define S3C2410_DCLKCON_DCLK1_UCLK   (1<<17)
++#define S3C2410_DCLKCON_DCLK1_DIV(x) (((x) - 1) <<20)
++
++#define S3C2410_CLKDIVN_PDIVN        (1<<0)
++#define S3C2410_CLKDIVN_HDIVN        (1<<1)
++
++static inline unsigned int
++s3c2410_get_pll(int pllval, int baseclk)
++{
++  int mdiv, pdiv, sdiv;
++
++  mdiv = pllval >> S3C2410_PLLCON_MDIVSHIFT;
++  pdiv = pllval >> S3C2410_PLLCON_PDIVSHIFT;
++  sdiv = pllval >> S3C2410_PLLCON_SDIVSHIFT;
++
++  mdiv &= S3C2410_PLLCON_MDIVMASK;
++  pdiv &= S3C2410_PLLCON_PDIVMASK;
++  sdiv &= S3C2410_PLLCON_SDIVMASK;
++
++  return (baseclk * (mdiv + 8)) / ((pdiv + 2) << sdiv);
++}
++
++#endif /* ASMARM_ARCH_S3C2410_CLOCK_H */
++
++
++
++
++
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-gpio.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,602 @@
++/* linux/include/asm-arm/arch-s3c2410/S3C2410-gpio.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * S3C2410 GPIO register definitions
++ *
++ *  Changelog:
++ *    19-06-2003     BJD     Created file
++ *    23-06-2003     BJD     Updated GSTATUS registers
++ */
++
++#ifndef ASMARM_ARCH_S3C2410_GPIO_H
++#define ASMARM_ARCH_S3C2410_GPIO_H
++
++/* configure GPIO ports A..G */
++
++#define S3C2410_GPIOREG(x) ((x) + S3C2410_VA_GPIO)
++
++/* port A - 22bits, zero in bit X makes pin X output
++ * 1 makes port special function, this is default
++*/
++#define S3C2410_GPACON     S3C2410_GPIOREG(0x00)
++#define S3C2410_GPADAT     S3C2410_GPIOREG(0x04)
++
++/* 0x08 and 0x0c are reserved */
++
++/* GPB is 10 IO pins, each configured by 2 bits each in GPBCON.
++ *   00 = input, 01 = output, 10=special function, 11=reserved
++ * bit 0,1 = pin 0, 2,3= pin 1...
++ *
++ * CPBUP = pull up resistor control, 1=disabled, 0=enabled
++*/
++
++#define S3C2410_GPBCON     S3C2410_GPIOREG(0x10)
++#define S3C2410_GPBDAT     S3C2410_GPIOREG(0x14)
++#define S3C2410_GPBUP      S3C2410_GPIOREG(0x18)
++
++/* no i/o pin in port b can have value 3! */
++
++#define S3C2410_GPB0_INP     (0x00 << 0)
++#define S3C2410_GPB0_OUTP    (0x01 << 0)
++#define S3C2410_GPB0_TOUT0   (0x02 << 0)
++
++#define S3C2410_GPB1_INP     (0x00 << 2)
++#define S3C2410_GPB1_OUTP    (0x01 << 2)
++#define S3C2410_GPB1_TOUT1   (0x02 << 2)
++
++#define S3C2410_GPB2_INP     (0x00 << 4)
++#define S3C2410_GPB2_OUTP    (0x01 << 4)
++#define S3C2410_GPB2_TOUT2   (0x02 << 4)
++
++#define S3C2410_GPB3_INP     (0x00 << 6)
++#define S3C2410_GPB3_OUTP    (0x01 << 6)
++#define S3C2410_GPB3_TOUT3   (0x02 << 6)
++
++#define S3C2410_GPB4_INP     (0x00 << 8)
++#define S3C2410_GPB4_OUTP    (0x01 << 8)
++#define S3C2410_GPB4_TCLK0   (0x02 << 8)
++#define S3C2410_GPB4_MASK    (0x03 << 8)
++
++#define S3C2410_GPB5_INP     (0x00 << 10)
++#define S3C2410_GPB5_OUTP    (0x01 << 10)
++#define S3C2410_GPB5_nXBACK  (0x02 << 10)
++
++#define S3C2410_GPB6_INP     (0x00 << 12)
++#define S3C2410_GPB6_OUTP    (0x01 << 12)
++#define S3C2410_GPB6_nXBREQ  (0x02 << 12)
++
++#define S3C2410_GPB7_INP     (0x00 << 14)
++#define S3C2410_GPB7_OUTP    (0x01 << 14)
++#define S3C2410_GPB7_nXDACK1 (0x02 << 14)
++
++#define S3C2410_GPB8_INP     (0x00 << 16)
++#define S3C2410_GPB8_OUTP    (0x01 << 16)
++#define S3C2410_GPB8_nXDREQ1 (0x02 << 16)
++
++#define S3C2410_GPB9_INP     (0x00 << 18)
++#define S3C2410_GPB9_OUTP    (0x01 << 18)
++#define S3C2410_GPB9_nXDACK0 (0x02 << 18)
++
++#define S3C2410_GPB10_INP     (0x00 << 18)
++#define S3C2410_GPB10_OUTP    (0x01 << 18)
++#define S3C2410_GPB10_nXDRE0 (0x02 << 18)
++
++/* Port C consits of 16 GPIO/Special function
++ *
++ * almost identical setup to port b, but the special functions are mostly
++ * to do with the video system's sync/etc.
++*/
++
++#define S3C2410_GPCCON     S3C2410_GPIOREG(0x20)
++#define S3C2410_GPCDAT     S3C2410_GPIOREG(0x24)
++#define S3C2410_GPCUP      S3C2410_GPIOREG(0x28)
++
++#define S3C2410_GPC0_INP        (0x00 << 0)
++#define S3C2410_GPC0_OUTP       (0x01 << 0)
++#define S3C2410_GPC0_LEND       (0x02 << 0)
++
++#define S3C2410_GPC1_INP        (0x00 << 2)
++#define S3C2410_GPC1_OUTP       (0x01 << 2)
++#define S3C2410_GPC1_VCLK       (0x02 << 2)
++
++#define S3C2410_GPC2_INP        (0x00 << 4)
++#define S3C2410_GPC2_OUTP       (0x01 << 4)
++#define S3C2410_GPC2_VLINE      (0x02 << 4)
++
++#define S3C2410_GPC3_INP        (0x00 << 6)
++#define S3C2410_GPC3_OUTP       (0x01 << 6)
++#define S3C2410_GPC3_VFRAME     (0x02 << 6)
++
++#define S3C2410_GPC4_INP        (0x00 << 8)
++#define S3C2410_GPC4_OUTP       (0x01 << 8)
++#define S3C2410_GPC4_VM         (0x02 << 8)
++
++#define S3C2410_GPC5_INP        (0x00 << 10)
++#define S3C2410_GPC5_OUTP       (0x01 << 10)
++#define S3C2410_GPC5_LCDVF0     (0x02 << 10)
++
++#define S3C2410_GPC6_INP        (0x00 << 12)
++#define S3C2410_GPC6_OUTP       (0x01 << 12)
++#define S3C2410_GPC6_LCDVF1     (0x02 << 12)
++
++#define S3C2410_GPC7_INP        (0x00 << 14)
++#define S3C2410_GPC7_OUTP       (0x01 << 14)
++#define S3C2410_GPC7_LCDVF2     (0x02 << 14)
++
++#define S3C2410_GPC8_INP        (0x00 << 16)
++#define S3C2410_GPC8_OUTP       (0x01 << 16)
++#define S3C2410_GPC8_VD0        (0x02 << 16)
++
++#define S3C2410_GPC9_INP        (0x00 << 18)
++#define S3C2410_GPC9_OUTP       (0x01 << 18)
++#define S3C2410_GPC9_VD1        (0x02 << 18)
++
++#define S3C2410_GPC10_INP       (0x00 << 20)
++#define S3C2410_GPC10_OUTP      (0x01 << 20)
++#define S3C2410_GPC10_VD2       (0x02 << 20)
++
++#define S3C2410_GPC11_INP       (0x00 << 22)
++#define S3C2410_GPC11_OUTP      (0x01 << 22)
++#define S3C2410_GPC11_VD3       (0x02 << 22)
++
++#define S3C2410_GPC12_INP       (0x00 << 24)
++#define S3C2410_GPC12_OUTP      (0x01 << 24)
++#define S3C2410_GPC12_VD4       (0x02 << 24)
++
++#define S3C2410_GPC13_INP       (0x00 << 26)
++#define S3C2410_GPC13_OUTP      (0x01 << 26)
++#define S3C2410_GPC13_VD5       (0x02 << 26)
++
++#define S3C2410_GPC14_INP       (0x00 << 28)
++#define S3C2410_GPC14_OUTP      (0x01 << 28)
++#define S3C2410_GPC14_VD6       (0x02 << 28)
++
++#define S3C2410_GPC15_INP       (0x00 << 30)
++#define S3C2410_GPC15_OUTP      (0x01 << 30)
++#define S3C2410_GPC15_VD7       (0x02 << 30)
++
++/* Port D consists of 16 GPIO/Special function
++ *
++ * almost identical setup to port b, but the special functions are mostly
++ * to do with the video system's data.
++*/
++
++#define S3C2410_GPDCON     S3C2410_GPIOREG(0x30)
++#define S3C2410_GPDDAT     S3C2410_GPIOREG(0x34)
++#define S3C2410_GPDUP      S3C2410_GPIOREG(0x38)
++
++#define S3C2410_GPD0_INP        (0x00 << 0)
++#define S3C2410_GPD0_OUTP       (0x01 << 0)
++#define S3C2410_GPD0_VD8        (0x02 << 0)
++
++#define S3C2410_GPD1_INP        (0x00 << 2)
++#define S3C2410_GPD1_OUTP       (0x01 << 2)
++#define S3C2410_GPD1_VD9        (0x02 << 2)
++
++#define S3C2410_GPD2_INP        (0x00 << 4)
++#define S3C2410_GPD2_OUTP       (0x01 << 4)
++#define S3C2410_GPD2_VD10       (0x02 << 4)
++
++#define S3C2410_GPD3_INP        (0x00 << 6)
++#define S3C2410_GPD3_OUTP       (0x01 << 6)
++#define S3C2410_GPD3_VD11       (0x02 << 6)
++
++#define S3C2410_GPD4_INP        (0x00 << 8)
++#define S3C2410_GPD4_OUTP       (0x01 << 8)
++#define S3C2410_GPD4_VD12       (0x02 << 8)
++
++#define S3C2410_GPD5_INP        (0x00 << 10)
++#define S3C2410_GPD5_OUTP       (0x01 << 10)
++#define S3C2410_GPD5_VD13       (0x02 << 10)
++
++#define S3C2410_GPD6_INP        (0x00 << 12)
++#define S3C2410_GPD6_OUTP       (0x01 << 12)
++#define S3C2410_GPD6_VD14       (0x02 << 12)
++
++#define S3C2410_GPD7_INP        (0x00 << 14)
++#define S3C2410_GPD7_OUTP       (0x01 << 14)
++#define S3C2410_GPD7_VD15       (0x02 << 14)
++
++#define S3C2410_GPD8_INP        (0x00 << 16)
++#define S3C2410_GPD8_OUTP       (0x01 << 16)
++#define S3C2410_GPD8_VD16       (0x02 << 16)
++
++#define S3C2410_GPD9_INP        (0x00 << 18)
++#define S3C2410_GPD9_OUTP       (0x01 << 18)
++#define S3C2410_GPD9_VD17       (0x02 << 18)
++
++#define S3C2410_GPD10_INP       (0x00 << 20)
++#define S3C2410_GPD10_OUTP      (0x01 << 20)
++#define S3C2410_GPD10_VD18      (0x02 << 20)
++
++#define S3C2410_GPD11_INP       (0x00 << 22)
++#define S3C2410_GPD11_OUTP      (0x01 << 22)
++#define S3C2410_GPD11_VD19      (0x02 << 22)
++
++#define S3C2410_GPD12_INP       (0x00 << 24)
++#define S3C2410_GPD12_OUTP      (0x01 << 24)
++#define S3C2410_GPD12_VD20      (0x02 << 24)
++
++#define S3C2410_GPD13_INP       (0x00 << 26)
++#define S3C2410_GPD13_OUTP      (0x01 << 26)
++#define S3C2410_GPD13_VD21      (0x02 << 26)
++
++#define S3C2410_GPD14_INP       (0x00 << 28)
++#define S3C2410_GPD14_OUTP      (0x01 << 28)
++#define S3C2410_GPD14_VD22      (0x02 << 28)
++
++#define S3C2410_GPD15_INP       (0x00 << 30)
++#define S3C2410_GPD15_OUTP      (0x01 << 30)
++#define S3C2410_GPD15_VD23      (0x02 << 30)
++
++/* Port E consists of 16 GPIO/Special function
++ *
++ * again, the same as port B, but dealing with I2S, SDI, and
++ * more miscellaneous functions
++*/
++
++#define S3C2410_GPECON     S3C2410_GPIOREG(0x40)
++#define S3C2410_GPEDAT     S3C2410_GPIOREG(0x44)
++#define S3C2410_GPEUP      S3C2410_GPIOREG(0x48)
++
++#define S3C2410_GPE0_INP       (0x00 << 0)
++#define S3C2410_GPE0_OUTP      (0x01 << 0)
++#define S3C2410_GPE0_I2SLRCK   (0x02 << 0)
++#define S3C2410_GPE0_MASK      (0x03 << 0)
++
++#define S3C2410_GPE1_INP       (0x00 << 2)
++#define S3C2410_GPE1_OUTP      (0x01 << 2)
++#define S3C2410_GPE1_I2SSCLK   (0x02 << 2)
++#define S3C2410_GPE1_MASK      (0x03 << 2)
++
++#define S3C2410_GPE2_INP       (0x00 << 4)
++#define S3C2410_GPE2_OUTP      (0x01 << 4)
++#define S3C2410_GPE2_CDCLK     (0x02 << 4)
++
++#define S3C2410_GPE3_INP       (0x00 << 6)
++#define S3C2410_GPE3_OUTP      (0x01 << 6)
++#define S3C2410_GPE3_I2SSDI    (0x02 << 6)
++#define S3C2410_GPE3_MASK      (0x03 << 6)
++
++#define S3C2410_GPE4_INP       (0x00 << 8)
++#define S3C2410_GPE4_OUTP      (0x01 << 8)
++#define S3C2410_GPE4_I2SSDO    (0x02 << 8)
++#define S3C2410_GPE4_MASK      (0x03 << 8)
++
++#define S3C2410_GPE5_INP       (0x00 << 10)
++#define S3C2410_GPE5_OUTP      (0x01 << 10)
++#define S3C2410_GPE5_SDCLK     (0x02 << 10)
++
++#define S3C2410_GPE6_INP       (0x00 << 12)
++#define S3C2410_GPE6_OUTP      (0x01 << 12)
++#define S3C2410_GPE6_SDCLK     (0x02 << 12)
++
++#define S3C2410_GPE7_INP       (0x00 << 14)
++#define S3C2410_GPE7_OUTP      (0x01 << 14)
++#define S3C2410_GPE7_SDCMD     (0x02 << 14)
++
++#define S3C2410_GPE8_INP       (0x00 << 16)
++#define S3C2410_GPE8_OUTP      (0x01 << 16)
++#define S3C2410_GPE8_SDDAT1    (0x02 << 16)
++
++#define S3C2410_GPE9_INP       (0x00 << 18)
++#define S3C2410_GPE9_OUTP      (0x01 << 18)
++#define S3C2410_GPE9_SDDAT2    (0x02 << 18)
++
++#define S3C2410_GPE10_INP      (0x00 << 20)
++#define S3C2410_GPE10_OUTP     (0x01 << 20)
++#define S3C2410_GPE10_SDDAT3   (0x02 << 20)
++
++#define S3C2410_GPE11_INP      (0x00 << 22)
++#define S3C2410_GPE11_OUTP     (0x01 << 22)
++#define S3C2410_GPE11_SPIMISO0 (0x02 << 22)
++
++#define S3C2410_GPE12_INP      (0x00 << 24)
++#define S3C2410_GPE12_OUTP     (0x01 << 24)
++#define S3C2410_GPE12_SPIMOSI0 (0x02 << 24)
++
++#define S3C2410_GPE13_INP      (0x00 << 26)
++#define S3C2410_GPE13_OUTP     (0x01 << 26)
++#define S3C2410_GPE13_SPICLK0  (0x02 << 26)
++
++#define S3C2410_GPE14_INP      (0x00 << 28)
++#define S3C2410_GPE14_OUTP     (0x01 << 28)
++#define S3C2410_GPE14_IICSCL   (0x02 << 28)
++#define S3C2410_GPE14_MASK     (0x03 << 28)
++
++#define S3C2410_GPE15_INP      (0x00 << 30)
++#define S3C2410_GPE15_OUTP     (0x01 << 30)
++#define S3C2410_GPE15_IICSDA   (0x02 << 30)
++#define S3C2410_GPE15_MASK     (0x03 << 30)
++
++#define S3C2410_GPE_PUPDIS(x)  (1<<(x))
++
++/* Port F consists of 8 GPIO/Special function
++ *
++ * GPIO / interrupt inputs
++ *
++ * GPFCON has 2 bits for each of the input pins on port F
++ *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 undefined
++ *
++ * pull up works like all other ports.
++*/
++
++#define S3C2410_GPFCON     S3C2410_GPIOREG(0x50)
++#define S3C2410_GPFDAT     S3C2410_GPIOREG(0x54)
++#define S3C2410_GPFUP      S3C2410_GPIOREG(0x58)
++
++
++#define S3C2410_GPF0_INP    (0x00 << 0)
++#define S3C2410_GPF0_OUTP   (0x01 << 0)
++#define S3C2410_GPF0_EINT0  (0x02 << 0)
++
++#define S3C2410_GPF1_INP    (0x00 << 2)
++#define S3C2410_GPF1_OUTP   (0x01 << 2)
++#define S3C2410_GPF1_EINT1  (0x02 << 2)
++
++#define S3C2410_GPF2_INP    (0x00 << 4)
++#define S3C2410_GPF2_OUTP   (0x01 << 4)
++#define S3C2410_GPF2_EINT2  (0x02 << 4)
++
++#define S3C2410_GPF3_INP    (0x00 << 6)
++#define S3C2410_GPF3_OUTP   (0x01 << 6)
++#define S3C2410_GPF3_EINT3  (0x02 << 6)
++
++#define S3C2410_GPF4_INP    (0x00 << 8)
++#define S3C2410_GPF4_OUTP   (0x01 << 8)
++#define S3C2410_GPF4_EINT4  (0x02 << 8)
++
++#define S3C2410_GPF5_INP    (0x00 << 10)
++#define S3C2410_GPF5_OUTP   (0x01 << 10)
++#define S3C2410_GPF5_EINT5  (0x02 << 10)
++
++#define S3C2410_GPF6_INP    (0x00 << 12)
++#define S3C2410_GPF6_OUTP   (0x01 << 12)
++#define S3C2410_GPF6_EINT6  (0x02 << 12)
++
++#define S3C2410_GPF7_INP    (0x00 << 14)
++#define S3C2410_GPF7_OUTP   (0x01 << 14)
++#define S3C2410_GPF7_EINT7  (0x02 << 14)
++
++/* Port G consists of 8 GPIO/IRQ/Special function
++ *
++ * GPGCON has 2 bits for each of the input pins on port F
++ *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
++ *
++ * pull up works like all other ports.
++*/
++
++#define S3C2410_GPGCON     S3C2410_GPIOREG(0x60)
++#define S3C2410_GPGDAT     S3C2410_GPIOREG(0x64)
++#define S3C2410_GPGUP      S3C2410_GPIOREG(0x68)
++
++#define S3C2410_GPG0_INP      (0x00 << 0)
++#define S3C2410_GPG0_OUTP     (0x01 << 0)
++#define S3C2410_GPG0_EINT8    (0x02 << 0)
++
++#define S3C2410_GPG1_INP      (0x00 << 2)
++#define S3C2410_GPG1_OUTP     (0x01 << 2)
++#define S3C2410_GPG1_EINT9    (0x02 << 2)
++
++#define S3C2410_GPG2_INP      (0x00 << 4)
++#define S3C2410_GPG2_OUTP     (0x01 << 4)
++#define S3C2410_GPG2_EINT10   (0x02 << 4)
++
++#define S3C2410_GPG3_INP      (0x00 << 6)
++#define S3C2410_GPG3_OUTP     (0x01 << 6)
++#define S3C2410_GPG3_EINT11   (0x02 << 6)
++
++#define S3C2410_GPG4_INP      (0x00 << 8)
++#define S3C2410_GPG4_OUTP     (0x01 << 8)
++#define S3C2410_GPG4_EINT12   (0x02 << 8)
++#define S3C2410_GPG4_LCDPWREN (0x03 << 8)
++
++#define S3C2410_GPG5_INP      (0x00 << 10)
++#define S3C2410_GPG5_OUTP     (0x01 << 10)
++#define S3C2410_GPG5_EINT13   (0x02 << 10)
++#define S3C2410_GPG5_SPIMISO1 (0x03 << 10)
++
++#define S3C2410_GPG6_INP      (0x00 << 12)
++#define S3C2410_GPG6_OUTP     (0x01 << 12)
++#define S3C2410_GPG6_EINT14   (0x02 << 12)
++#define S3C2410_GPG6_SPIMOSI1 (0x03 << 12)
++
++#define S3C2410_GPG7_INP      (0x00 << 14)
++#define S3C2410_GPG7_OUTP     (0x01 << 14)
++#define S3C2410_GPG7_EINT15   (0x02 << 14)
++#define S3C2410_GPG7_SPICLK1  (0x03 << 14)
++
++#define S3C2410_GPG8_INP      (0x00 << 16)
++#define S3C2410_GPG8_OUTP     (0x01 << 16)
++#define S3C2410_GPG8_EINT16   (0x02 << 16)
++
++#define S3C2410_GPG9_INP      (0x00 << 18)
++#define S3C2410_GPG9_OUTP     (0x01 << 18)
++#define S3C2410_GPG9_EINT17   (0x02 << 18)
++
++#define S3C2410_GPG10_INP     (0x00 << 20)
++#define S3C2410_GPG10_OUTP    (0x01 << 20)
++#define S3C2410_GPG10_EINT18  (0x02 << 20)
++
++#define S3C2410_GPG11_INP     (0x00 << 22)
++#define S3C2410_GPG11_OUTP    (0x01 << 22)
++#define S3C2410_GPG11_EINT19  (0x02 << 22)
++#define S3C2410_GPG11_TCLK1   (0x03 << 22)
++
++#define S3C2410_GPG12_INP     (0x00 << 24)
++#define S3C2410_GPG12_OUTP    (0x01 << 24)
++#define S3C2410_GPG12_EINT18  (0x02 << 24)
++#define S3C2410_GPG12_XMON    (0x03 << 24)
++
++#define S3C2410_GPG13_INP     (0x00 << 26)
++#define S3C2410_GPG13_OUTP    (0x01 << 26)
++#define S3C2410_GPG13_EINT18  (0x02 << 26)
++#define S3C2410_GPG13_nXPON   (0x03 << 26)
++
++#define S3C2410_GPG14_INP     (0x00 << 28)
++#define S3C2410_GPG14_OUTP    (0x01 << 28)
++#define S3C2410_GPG14_EINT18  (0x02 << 28)
++#define S3C2410_GPG14_YMON    (0x03 << 28)
++
++#define S3C2410_GPG15_INP     (0x00 << 30)
++#define S3C2410_GPG15_OUTP    (0x01 << 30)
++#define S3C2410_GPG15_EINT18  (0x02 << 30)
++#define S3C2410_GPG15_nYPON   (0x03 << 30)
++
++
++#define S3C2410_GPG_PUPDIS(x)  (1<<(x))
++
++/* Port H consists of11 GPIO/serial/Misc pins
++ *
++ * GPGCON has 2 bits for each of the input pins on port F
++ *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func
++ *
++ * pull up works like all other ports.
++*/
++
++#define S3C2410_GPHCON     S3C2410_GPIOREG(0x70)
++#define S3C2410_GPHDAT     S3C2410_GPIOREG(0x74)
++#define S3C2410_GPHUP      S3C2410_GPIOREG(0x78)
++
++#define S3C2410_GPH0_INP    (0x00 << 0)
++#define S3C2410_GPH0_OUTP   (0x01 << 0)
++#define S3C2410_GPH0_nCTS0  (0x02 << 0)
++
++#define S3C2410_GPH1_INP    (0x00 << 2)
++#define S3C2410_GPH1_OUTP   (0x01 << 2)
++#define S3C2410_GPH1_nRTS0  (0x02 << 2)
++
++#define S3C2410_GPH2_INP    (0x00 << 4)
++#define S3C2410_GPH2_OUTP   (0x01 << 4)
++#define S3C2410_GPH2_TXD0   (0x02 << 4)
++
++#define S3C2410_GPH3_INP    (0x00 << 6)
++#define S3C2410_GPH3_OUTP   (0x01 << 6)
++#define S3C2410_GPH3_RXD0   (0x02 << 6)
++
++#define S3C2410_GPH4_INP    (0x00 << 8)
++#define S3C2410_GPH4_OUTP   (0x01 << 8)
++#define S3C2410_GPH4_TXD1   (0x02 << 8)
++
++#define S3C2410_GPH5_INP    (0x00 << 10)
++#define S3C2410_GPH5_OUTP   (0x01 << 10)
++#define S3C2410_GPH5_RXD1   (0x02 << 10)
++
++#define S3C2410_GPH6_INP    (0x00 << 12)
++#define S3C2410_GPH6_OUTP   (0x01 << 12)
++#define S3C2410_GPH6_TXD2   (0x02 << 12)
++#define S3C2410_GPH6_nRTS1  (0x03 << 12)
++
++#define S3C2410_GPH7_INP    (0x00 << 14)
++#define S3C2410_GPH7_OUTP   (0x01 << 14)
++#define S3C2410_GPH7_RXD2   (0x02 << 14)
++#define S3C2410_GPH7_nCTS1  (0x03 << 14)
++
++#define S3C2410_GPH8_INP    (0x00 << 16)
++#define S3C2410_GPH8_OUTP   (0x01 << 16)
++#define S3C2410_GPH8_UCLK   (0x02 << 16)
++
++#define S3C2410_GPH9_INP     (0x00 << 18)
++#define S3C2410_GPH9_OUTP    (0x01 << 18)
++#define S3C2410_GPH9_CLKOUT0 (0x02 << 18)
++
++#define S3C2410_GPH10_INP   (0x00 << 20)
++#define S3C2410_GPH10_OUTP  (0x01 << 20)
++#define S3C2410_GPH10_CLKOUT1  (0x02 << 20)
++
++/* miscellaneous control */
++
++#define S3C2410_MISCCR     S3C2410_GPIOREG(0x80)
++#define S3C2410_DCLKCON    S3C2410_GPIOREG(0x84)
++
++/* see clock.h for dclk definitions */
++
++/* pullup control on databus */
++#define S3C2410_MISCCR_SPUCR_HEN    (0)
++#define S3C2410_MISCCR_SPUCR_HDIS   (1<<0)
++#define S3C2410_MISCCR_SPUCR_LEN    (0)
++#define S3C2410_MISCCR_SPUCR_LDIS   (1<<1)
++
++#define S3C2410_MISCCR_USBDEV       (0)
++#define S3C2410_MISCCR_USBHOST      (1<<3)
++
++#define S3C2410_MISCCR_CLK0_MPLL    (0<<4)
++#define S3C2410_MISCCR_CLK0_UPLL    (1<<4)
++#define S3C2410_MISCCR_CLK0_FCLK    (2<<4)
++#define S3C2410_MISCCR_CLK0_HCLK    (3<<4)
++#define S3C2410_MISCCR_CLK0_PCLK    (4<<4)
++#define S3C2410_MISCCR_CLK0_DCLK0   (5<<4)
++
++#define S3C2410_MISCCR_CLK1_MPLL    (0<<8)
++#define S3C2410_MISCCR_CLK1_UPLL    (1<<8)
++#define S3C2410_MISCCR_CLK1_FCLK    (2<<8)
++#define S3C2410_MISCCR_CLK1_HCLK    (3<<8)
++#define S3C2410_MISCCR_CLK1_PCLK    (4<<8)
++#define S3C2410_MISCCR_CLK1_DCLK1   (5<<8)
++
++#define S3C2410_MISCCR_USBSUSPND0   (1<<12)
++#define S3C2410_MISCCR_USBSUSPND1   (1<<13)
++
++#define S3C2410_MISCCR_nRSTCON      (1<<16)
++
++/* external interrupt control... */
++/* S3C2410_EXTINT0 -> irq sense control for EINT0..EINT7
++ * S3C2410_EXTINT1 -> irq sense control for EINT8..EINT15
++ * S3C2410_EXTINT2 -> irq sense control for EINT16..EINT23
++ *
++ * note S3C2410_EXTINT2 has filtering options for EINT16..EINT23
++ *
++ * Samsung datasheet p9-25
++*/
++
++#define S3C2410_EXTINT0    S3C2410_GPIOREG(0x88)
++#define S3C2410_EXTINT1    S3C2410_GPIOREG(0x8C)
++#define S3C2410_EXTINT2    S3C2410_GPIOREG(0x90)
++
++/* values for S3C2410_EXTINT0/1/2 */
++#define S3C2410_EXTINT_LOWLEV    (0x00)
++#define S3C2410_EXTINT_HILEV     (0x01)
++#define S3C2410_EXTINT_FALLEDGE  (0x02)
++#define S3C2410_EXTINT_RISEEDGE  (0x04)
++#define S3C2410_EXTINT_BOTHEDGE  (0x06)
++
++/* interrupt filtering conrrol for EINT16..EINT23 */
++#define S3C2410_EINFLT0    S3C2410_GPIOREG(0x94)
++#define S3C2410_EINFLT1    S3C2410_GPIOREG(0x98)
++#define S3C2410_EINFLT2    S3C2410_GPIOREG(0x9C)
++#define S3C2410_EINFLT3    S3C2410_GPIOREG(0xA0)
++
++/* mask: 0=enable, 1=disable
++ * 1 bit EINT, 4=EINT4, 23=EINT23
++ * EINT0,1,2,3 are not handled here.
++*/
++#define S3C2410_EINTMASK   S3C2410_GPIOREG(0xA4)
++#define S3C2410_EINTPEND   S3C2410_GPIOREG(0xA8)
++
++/* GSTATUS have miscellaneous information in them
++ *
++ */
++
++#define S3C2410_GSTATUS0   S3C2410_GPIOREG(0x0AC)
++#define S3C2410_GSTATUS1   S3C2410_GPIOREG(0x0B0)
++#define S3C2410_GSTATUS2   S3C2410_GPIOREG(0x0B4)
++#define S3C2410_GSTATUS3   S3C2410_GPIOREG(0x0B8)
++#define S3C2410_GSTATUS4   S3C2410_GPIOREG(0x0BC)
++
++#define S3C2410_GSTATUS0_nWAIT     (1<<3)
++#define S3C2410_GSTATUS0_NCON      (1<<2)
++#define S3C2410_GSTATUS0_RnB       (1<<1)
++#define S3C2410_GSTATUS0_nBATTFLT  (1<<0)
++
++#define S3C2410_GSTATUS2_WTRESET   (1<<2)
++#define S3C2410_GSTATUs2_OFFRESET  (1<<1)
++#define S3C2410_GSTATUS2_PONRESET  (1<<0)
++
++#endif  /* ASMARM_ARCH_S3C2410_GPIO_H */
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-iis.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,61 @@
++/* linux/include/asm/hardware/s3c2410/iis.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * S3C2410 IIS register definition
++ *
++ *  Changelog:
++ *    19-06-2003     BJD     Created file
++ *    26-06-2003     BJD     Finished off definitions for register addresses
++ */
++
++#ifndef ASMARM_ARCH_S3C2410_IIS_H
++#define ASMARM_ARCH_S3C2410_IIS_H
++
++#define S3C2410_IISCON   (S3C2410_VA_IIS + 0x00)
++
++#define S3C2410_IISCON_LRINDEX    (1<<8)
++#define S3C2410_IISCON_TXFIFORDY  (1<<7)
++#define S3C2410_IISCON_RXFIFORDY  (1<<6)
++#define S3C2410_IISCON_TXDMAEN    (1<<5)
++#define S3C2410_IISCON_RXDMAEN    (1<<4)
++#define S3C2410_IISCON_TXIDLE     (1<<3)
++#define S3C2410_IISCON_RXIDLE     (1<<2)
++#define S3C2410_IISCON_IISEN      (1<<0)
++
++#define S3C2410_IISMOD   (S3C2410_VA_IIS + 0x04)
++
++#define S3C2410_IISMOD_SLAVE      (1<<8)
++#define S3C2410_IISMOD_NOXFER     (0<<6)
++#define S3C2410_IISMOD_RXMODE     (1<<6)
++#define S3C2410_IISMOD_TXMODE     (2<<6)
++#define S3C2410_IISMOD_TXRXMODE   (3<<6)
++#define S3C2410_IISMOD_LR_LLOW    (0<<5)
++#define S3C2410_IISMOD_LR_RLOW    (1<<5)
++#define S3C2410_IISMOD_IIS        (0<<4)
++#define S3C2410_IISMOD_MSB        (1<<4)
++#define S3C2410_IISMOD_8BIT       (0<<3)
++#define S3C2410_IISMOD_16BIT      (1<<3)
++#define S3C2410_IISMOD_256FS      (0<<1)
++#define S3C2410_IISMOD_384FS      (1<<1)
++#define S3C2410_IISMOD_16FS       (0<<0)
++#define S3C2410_IISMOD_32FS       (1<<0)
++#define S3C2410_IISMOD_48FS       (2<<0)
++
++#define S3C2410_IISPSR   (S3C2410_VA_IIS + 0x08)
++
++#define S3C2410_IISFCON  (S3C2410_VA_IIS + 0x0c)
++
++#define S3C2410_IISFCON_TXDMA     (1<<15)
++#define S3C2410_IISFCON_RXDMA     (1<<14)
++#define S3C2410_IISFCON_TXENABLE  (1<<13)
++#define S3C2410_IISFCON_RXENABLE  (1<<12)
++
++#define S3C2410_IISFIFO  (S3C2410_VA_IIS + 0x10)
++
++#endif /* ASMARM_ARCH_S3C2410_IIS_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-irq.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,34 @@
++/* linux/include/asm-arm/arch-s3c2410/S3C2410-irq.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Changelog:
++ *    19-06-2003     BJD     Created file
++ */
++
++#ifndef ASMARM_ARCH_S3C2410_IRQ_H
++#define ASMARM_ARCH_S3C2410_IRQ_H
++
++/* interrupt controller */
++
++#define S3C2410_IRQREG(x)   ((x) + S3C2410_VA_IRQ)
++#define S3C2410_EINTREG(x)  ((x) + S3C2410_VA_GPIO)
++
++#define S3C2410_SRCPND         S3C2410_IRQREG(0x000)
++#define S3C2410_INTMOD         S3C2410_IRQREG(0x004)
++#define S3C2410_INTMSK         S3C2410_IRQREG(0x008)
++#define S3C2410_PRIORITY       S3C2410_IRQREG(0x00C)
++#define S3C2410_INTPND         S3C2410_IRQREG(0x010)
++#define S3C2410_INTOFFSET      S3C2410_IRQREG(0x014)
++#define S3C2410_SUBSRCPND      S3C2410_IRQREG(0x018)
++#define S3C2410_INTSUBMSK      S3C2410_IRQREG(0x01C)
++
++#define S3C2410_EINTMASK       S3C2410_EINTREG(0x0A4)
++#define S3C2410_EINTPEND       S3C2410_EINTREG(0X0A8)
++
++#endif /* ASMARM_ARCH_S3C2410_IRQ_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-lcd.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,107 @@
++/* linux/include/asm-arm/arch-s3c2410/S3C2410-lcd.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *
++ *
++ *  Changelog:
++ *    12-06-2003     BJD     Created file
++ *    26-06-2003     BJD     Updated LCDCON register definitions
++*/
++
++#ifndef ASMARM_ARCH_S3C2410_LCD_H
++#define ASMARM_ARCH_S3C2410_LCD_H
++
++#define S3C2410_LCDREG(x) ((x) + S3C2410_VA_LCD)
++
++/* LCD control registers */
++#define S3C2410_LCDCON1     S3C2410_LCDREG(0x00)
++#define S3C2410_LCDCON2     S3C2410_LCDREG(0x04)
++#define S3C2410_LCDCON3     S3C2410_LCDREG(0x08)
++#define S3C2410_LCDCON4     S3C2410_LCDREG(0x0C)
++#define S3C2410_LCDCON5     S3C2410_LCDREG(0x10)
++
++#define S3C2410_LCDCON1_CLKVAL(x)  ((x) << 8)
++#define S3C2410_LCDCON1_MMODE      (1<<7)
++#define S3C2410_LCDCON1_DSCAN4     (0<<5)
++#define S3C2410_LCDCON1_STN4       (1<<5)
++#define S3C2410_LCDCON1_STN8       (2<<5)
++#define S3C2410_LCDCON1_TFT        (3<<5)
++
++#define S3C2410_LCDCON1_STN1BPP    (0<<1)
++#define S3C2410_LCDCON1_STN2GREY   (1<<1)
++#define S3C2410_LCDCON1_STN4GREY   (2<<1)
++#define S3C2410_LCDCON1_STN8BPP    (3<<1)
++#define S3C2410_LCDCON1_STN12BPP   (4<<1)
++
++#define S3C2410_LCDCON1_TFT1BPP    (8<<1)
++#define S3C2410_LCDCON1_TFT2BPP    (9<<1)
++#define S3C2410_LCDCON1_TFT4BPP    (10<<1)
++#define S3C2410_LCDCON1_TFT8BPP    (11<<1)
++#define S3C2410_LCDCON1_TFT16BPP   (12<<1)
++#define S3C2410_LCDCON1_TFT24BPP   (13<<1)
++
++#define S3C2410_LCDCON1_ENVDI      (1)
++
++#define S3C2410_LCDCON2_VBPD(x)     ((x) << 24)
++#define S3C2410_LCDCON2_LINEVAL(x)  ((x) << 14)
++#define S3C2410_LCDCON2_VFPD(x)     ((x) << 6)
++#define S3C2410_LCDCON2_VSPW(x)     ((x) << 0)
++
++#define S3C2410_LCDCON3_HBPD(x)     ((x) << 19)
++#define S3C2410_LCDCON3_WDLY(x)     ((x) << 19)
++#define S3C2410_LCDCON3_HOZVAL(x)   ((x) << 8)
++#define S3C2410_LCDCON3_HFPD(x)     ((x) << 0)
++#define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0)
++
++#define S3C2410_LCDCON4_MVAL(x)     ((x) << 8)
++#define S3C2410_LCDCON4_HSPW(x)     ((x) << 0)
++#define S3C2410_LCDCON4_WLH(x)      ((x) << 0)
++
++#define S3C2410_LCDCON5_BPP24BL     (1<<12)
++#define S3C2410_LCDCON5_FRM565      (1<<11)
++#define S3C2410_LCDCON5_INVVCLK     (1<<10)
++#define S3C2410_LCDCON5_INVVLINE    (1<<9)
++#define S3C2410_LCDCON5_INVVFRAME   (1<<8)
++#define S3C2410_LCDCON5_INVVD       (1<<7)
++#define S3C2410_LCDCON5_INVVSYNC    (1<<8)
++#define S3C2410_LCDCON5_INVHSYNC    (1<<9)
++#define S3C2410_LCDCON5_INVVDEN     (1<<6)
++#define S3C2410_LCDCON5_INVPWREN    (1<<5)
++#define S3C2410_LCDCON5_INVLEND     (1<<4)
++#define S3C2410_LCDCON5_PWREN       (1<<3)
++#define S3C2410_LCDCON5_ENLEND      (1<<2)
++#define S3C2410_LCDCON5_BSWP        (1<<1)
++#define S3C2410_LCDCON5_HWSWP       (1<<0)
++
++/* framebuffer start addressed */
++#define S3C2410_LCDSADDR1   S3C2410_LCDREG(0x14)
++#define S3C2410_LCDSADDR2   S3C2410_LCDREG(0x18)
++#define S3C2410_LCDSADDR3   S3C2410_LCDREG(0x1C)
++
++/* colour lookup and miscellaneous controls */
++
++#define S3C2410_REDLUT     S3C2410_LCDREG(0x20)
++#define S3C2410_GREENLUT   S3C2410_LCDREG(0x24)
++#define S3C2410_BLUELUT    S3C2410_LCDREG(0x28)
++
++#define S3C2410_DITHMODE   S3C2410_LCDREG(0x4C)
++#define S3C2410_TPAL       S3C2410_LCDREG(0x50)
++
++/* interrupt info */
++#define S3C2410_LCDINTPND  S3C2410_LCDREG(0x54)
++#define S3C2410_LCDSRCPND  S3C2410_LCDREG(0x58)
++#define S3C2410_LCDINTMSK  S3C2410_LCDREG(0x5C)
++#define S3C2410_LPCSEL     S3C2410_LCDREG(0x60)
++
++#define S3C2410_TFTPAL(x)  S3C2410_LCDREG((0x400 + (x)*4))
++
++#endif /* ASMARM_ARCH_S3C2410_LCD_H */
++
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-rtc.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,61 @@
++/* linux/include/asm-arm/arch-s3c2410/S3C2410-rtc.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * S3C2410 Timer configuration
++ *
++ *  Changelog:
++ *    05-06-2003     BJD     Created file
++ */
++
++#ifndef ASMARM_ARCH_S3C2410_RTC_H
++#define ASMARM_ARCH_S3C2410_RTC_H
++
++#define S3C2410_RTCREG(x) ((x) + S3C2410_VA_RTC)
++
++#define S3C2410_RTCCON        S3C2410_RTCREG(0x40)
++#define S3C2410_RTCCON_RTCEN  (1<<0)
++#define S3C2410_RTCCON_CLKRST (1<<3)
++
++#define S3C2410_TICNT         S3C2410_RTCREG(0x44)
++#define S3C2410_TICNT_ENABLE  (1<<7)
++
++#define S3C2410_RTCALM        S3C2410_RTCREG(0x50)
++#define S3C2410_RTCALM_ALMEN  (1<<6)
++#define S3C2410_RTCALM_YEAREN (1<<5)
++#define S3C2410_RTCALM_MONEN  (1<<4)
++#define S3C2410_RTCALM_DAYEN  (1<<3)
++#define S3C2410_RTCALM_HOUREN (1<<2)
++#define S3C2410_RTCALM_MINEN  (1<<1)
++#define S3C2410_RTCALM_SECEN  (1<<0)
++
++#define S3C2410_RTCALM_ALL \
++  S3C2410_RTCALM_ALMEN | S3C2410_RTCALM_YEAREN | S3C2410_RTCALM_MONEN |\
++  S3C2410_RTCALM_DAYEN | S3C2410_RTCALM_HOUREN | S3C2410_RTCALM_MINEN |\
++  S3C2410_RTCALM_SECEN
++
++
++#define S3C2410_ALMSEC        S3C2410_RTCREG(0x54)
++#define S3C2410_ALMMIN        S3C2410_RTCREG(0x58)
++#define S3C2410_ALMHOUR       S3C2410_RTCREG(0x5c)
++
++#define S3C2410_ALMDATE       S3C2410_RTCREG(0x60)
++#define S3C2410_ALMMON        S3C2410_RTCREG(0x64)
++#define S3C2410_ALMYEAR       S3C2410_RTCREG(0x68)
++
++#define S3C2410_RTCRST        S3C2410_RTCREG(0x6c)
++
++#define S3C2410_RTCSEC        S3C2410_RTCREG(0x70)
++#define S3C2410_RTCMIN        S3C2410_RTCREG(0x74)
++#define S3C2410_RTCHOUR       S3C2410_RTCREG(0x78)
++#define S3C2410_RTCDATE       S3C2410_RTCREG(0x7c)
++#define S3C2410_RTCDAY        S3C2410_RTCREG(0x80)
++#define S3C2410_RTCMON        S3C2410_RTCREG(0x84)
++#define S3C2410_RTCYEAR       S3C2410_RTCREG(0x88)
++
++#endif /* ASMARM_ARCH_S3C2410_RTC_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-serial.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,98 @@
++/*
++ *  linux/include/asm-arm/arch-s3c2410/S3C2410-serial.h
++ *
++ *  Internal header file for Samsung S3C2410 serial ports (UART0-2)
++ *
++ *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
++ *
++ *  Additional defines, (c) 2003 Simtec Electronics (linux@simtec.co.uk)
++ *
++ *  Adapted from:
++ *
++ *  Internal header file for MX1ADS serial ports (UART1 & 2)
++ *
++ *  Copyright (C) 2002 Shane Nay (shane@minirl.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
++ */
++
++#ifndef ASMARM_ARCH_S3C2410_SERIAL_H
++#define ASMARM_ARCH_S3C2410_SERIAL_H
++
++#define S3C2410_UARTRXH0_OFF      (0x24)
++#define S3C2410_UARTTXH0_OFF      (0x20)
++#define S3C2410_UARTLCON_OFF      (0x00)
++#define S3C2410_UARTCON_OFF       (0x04)
++#define S3C2410_UARTFCON_OFF      (0x08)
++#define S3C2410_UARTMCON_OFF      (0x0C)
++#define S3C2410_UARTBRDIV_OFF     (0x28)
++#define S3C2410_UARTTRSTAT_OFF    (0x10)
++#define S3C2410_UARTERSTAT_OFF    (0x14)
++#define S3C2410_UARTFSTAT_OFF     (0x18)
++#define S3C2410_UARTMSTAT_OFF     (0x1C)
++
++
++#define S3C2410_UART1_OFF         (0x4000)
++#define S3C2410_UART2_OFF         (0x8000)
++
++#define S3C2410_LCON_CFGMASK      ((0xF<<3)|(0x3))
++
++#define S3C2410_LCON_CS5          (0x0)
++#define S3C2410_LCON_CS6          (0x1)
++#define S3C2410_LCON_CS7          (0x2)
++#define S3C2410_LCON_CS8          (0x3)
++
++#define S3C2410_LCON_PNONE        (0x0)
++#define S3C2410_LCON_PEVEN        ((0x5)<<3)
++#define S3C2410_LCON_PODD         ((0x4)<<3)
++
++#define S3C2410_UMCON_AFC         (0x10)
++#define S3C2410_UMCON_RTS         (0x1)
++
++#define S3C2410_UMSTAT_CTS        (0x1)
++
++#define S3C2410_UCON_SBREAK       (1<<4)
++
++#define S3C2410_UCON_TXILEVEL     (1<<9)
++#define S3C2410_UCON_RXILEVEL     (1<<8)
++#define S3C2410_UCON_TXIRQMODE    (1<<2)
++#define S3C2410_UCON_RXIRQMODE    (1<<0)
++#define S3C2410_UCON_RXFIFO_TOI   (1<<7)
++
++#define S3C2410_UCON_DEFAULT      (S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL \
++                                   | S3C2410_UCON_TXIRQMODE | S3C2410_UCON_RXIRQMODE \
++				   | S3C2410_UCON_RXFIFO_TOI)
++
++#define S3C2410_UFCON_FIFOMODE    (1<<0)
++#define S3C2410_UFCON_TXTRIG0     (0<<6)
++#define S3C2410_UFCON_RXTRIG8     (1<<4)
++#define S3C2410_UFCON_RXTRIG12    (2<<4)
++
++#define S3C2410_UFCON_RESETBOTH   (3<<1)
++
++#define S3C2410_UFCON_DEFAULT     (S3C2410_UFCON_FIFOMODE | S3C2410_UFCON_TXTRIG0 \
++                                  | S3C2410_UFCON_RXTRIG8 )
++
++#define S3C2410_UFSTAT_TXFULL     (1<<9)
++#define S3C2410_UFSTAT_RXFULL     (1<<8)
++#define S3C2410_UFSTAT_TXMASK     (15<<4)
++#define S3C2410_UFSTAT_TXSHIFT    (4)
++#define S3C2410_UFSTAT_RXMASK     (15<<0)
++#define S3C2410_UFSTAT_RXSHIFT    (0)
++
++#define S3C2410_UTRSTAT_TXFE      (1<<1)
++#define S3C2410_UTRSTAT_RXDR      (1<<0)
++
++#endif /* ASMARM_ARCH_S3C2410_SERIAL_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-timer.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,81 @@
++/* linux/include/asm-arm/arch-s3c2410/S3C2410-timer.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * S3C2410 Timer configuration
++ *
++ *  Changelog:
++ *    05-06-2003     BJD     Created file
++ *    26-06-2003     BJD     Added more timer definitions to mux / control
++ */
++
++#ifndef ASMARM_ARCH_S3C2410_TIMER_H
++#define ASMARM_ARCH_S3C2410_TIMER_H
++
++#define S3C2410_TIMERREG(x) (S3C2410_VA_TIMER + (x))
++#define S3C2410_TIMERREG2(tmr,reg) S3C2410_TIMERREG((reg)+0x0c+((tmr)*0x0c))
++
++#define S3C2410_TCFG0         S3C2410_TIMERREG(0x00)
++#define S3C2410_TCFG1         S3C2410_TIMERREG(0x04)
++#define S3C2410_TCON          S3C2410_TIMERREG(0x08)
++
++
++#define S3C2410_TCFG1_MUX4_TCLK1  (4<<16)
++#define S3C2410_TCFG1_MUX4_MASK   (15<<16)
++
++#define S3C2410_TCFG1_MUX3_TCLK1  (4<<12)
++#define S3C2410_TCFG1_MUX3_MASK   (15<<12)
++
++#define S3C2410_TCFG1_MUX2_TCLK1  (4<<8)
++#define S3C2410_TCFG1_MUX2_MASK   (15<<8)
++
++#define S3C2410_TCFG1_MUX1_TCLK0  (4<<4)
++#define S3C2410_TCFG1_MUX1_MASK   (15<<4)
++
++#define S3C2410_TCFG1_MUX0_TCLK0  (4<<0)
++#define S3C2410_TCFG1_MUX0_MASK   (15<<0)
++
++/* for each timer, we have an count buffer, an compare buffer and an
++ * observation buffer
++ */
++
++/* WARNING - timer 4 has no buffer reg, and it's observation is at +4 */
++
++#define S3C2410_TCNTB(tmr)    S3C2410_TIMERREG2(tmr, 0x00)
++#define S3C2410_TCMPB(tmr)    S3C2410_TIMERREG2(tmr, 0x04)
++#define S3C2410_TCNTO(tmr)    S3C2410_TIMERREG2(tmr, (((tmr) == 4) ? 0x04 : 0x08))
++
++#define S3C2410_TCON_T4RELOAD     (1<<22)
++#define S3C2410_TCON_T4MANUALUPD  (1<<21)
++#define S3C2410_TCON_T4START      (1<<20)
++
++#define S3C2410_TCON_T3RELOAD     (1<<19)
++#define S3C2410_TCON_T3INVERT     (1<<18)
++#define S3C2410_TCON_T3MANUALUPD  (1<<17)
++#define S3C2410_TCON_T3START      (1<<16)
++
++#define S3C2410_TCON_T2RELOAD     (1<<15)
++#define S3C2410_TCON_T2INVERT     (1<<14)
++#define S3C2410_TCON_T2MANUALUPD  (1<<13)
++#define S3C2410_TCON_T2START      (1<<12)
++
++#define S3C2410_TCON_T1RELOAD     (1<<11)
++#define S3C2410_TCON_T1INVERT     (1<<10)
++#define S3C2410_TCON_T1MANUALUPD  (1<<9)
++#define S3C2410_TCON_T1START      (1<<8)
++
++#define S3C2410_TCON_T0DEADZONE   (1<<4)
++#define S3C2410_TCON_T0RELOAD     (1<<3)
++#define S3C2410_TCON_T0INVERT     (1<<2)
++#define S3C2410_TCON_T0MANUALUPD  (1<<1)
++#define S3C2410_TCON_T0START      (1<<0)
++
++#endif /* ASMARM_ARCH_S3C2410_TIMER_H */
++
++
++
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/asm-arm/arch-s3c2410/S3C2410-watchdog.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,40 @@
++/* linux/include/asm-arm/arch-s3c2410/S3C2410-watchdog.h
++ *
++ * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
++ *                    http://www.simtec.co.uk/products/SWLINUX/
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * S3C2410 Watchdog timer control
++ *
++ *  Changelog:
++ *    21-06-2003     BJD     Created file
++*/
++
++#ifndef ASMARM_ARCH_S3C2410_WATCHDOG_H
++#define ASMARM_ARCH_S3C2410_WATCHDOG_H
++
++#define S3C2410_WDOGREG(x) ((x) + S3C2410_VA_WATCHDOG)
++
++#define S3C2410_WTCON      S3C2410_WDOGREG(0x00)
++#define S3C2410_WTDAT      S3C2410_WDOGREG(0x04)
++#define S3C2410_WTCNT      S3C2410_WDOGREG(0x08)
++
++/* the watchdog can either generate a reset pulse, or an interrupt. */
++
++#define S3C2410_WTCON_RSTEN   (0x01)
++#define S3C2410_WTCON_INTEN   (1<<2)
++#define S3C2410_WTCON_ENABLE  (1<<5)
++
++#define S3C2410_WTCON_DIV16   (0<<3)
++#define S3C2410_WTCON_DIV32   (1<<3)
++#define S3C2410_WTCON_DIV64   (2<<3)
++#define S3C2410_WTCON_DIV128  (3<<3)
++
++#define S3C2410_WTCON_PRESCALE(x) ((x) << 8)
++
++#endif /* ASMARM_ARCH_S3C2410_WATCHDOG_H */
++
++
+--- linux-2.4.25/include/asm-arm/bugs.h~2.4.25-vrs2.patch	2000-09-19 00:15:23.000000000 +0200
++++ linux-2.4.25/include/asm-arm/bugs.h	2004-03-31 17:15:09.000000000 +0200
+@@ -10,8 +10,17 @@
+ #ifndef __ASM_BUGS_H
+ #define __ASM_BUGS_H
+ 
++#include <linux/config.h>
+ #include <asm/proc-fns.h>
+ 
+-#define check_bugs() cpu_check_bugs()
++extern void check_writebuffer_bugs(void);
++
++static inline void check_bugs(void)
++{
++#ifdef CONFIG_CPU_32
++	check_writebuffer_bugs();
++#endif
++	cpu_check_bugs();
++}
+ 
+ #endif
+--- linux-2.4.25/include/asm-arm/div64.h~2.4.25-vrs2.patch	2000-01-13 22:30:31.000000000 +0100
++++ linux-2.4.25/include/asm-arm/div64.h	2004-03-31 17:15:09.000000000 +0200
+@@ -4,9 +4,13 @@
+ /* We're not 64-bit, but... */
+ #define do_div(n,base)						\
+ ({								\
+-	int __res;						\
+-	__res = ((unsigned long)n) % (unsigned int)base;	\
+-	n = ((unsigned long)n) / (unsigned int)base;		\
++	register int __res asm("r2") = base;			\
++	register unsigned long long __n asm("r0") = n;		\
++	asm("bl do_div64"					\
++		: "=r" (__n), "=r" (__res)			\
++		: "0" (__n), "1" (__res)			\
++		: "r3", "ip", "lr", "cc");			\
++	n = __n;						\
+ 	__res;							\
+ })
+ 
+--- linux-2.4.25/include/asm-arm/elf.h~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/include/asm-arm/elf.h	2004-03-31 17:15:09.000000000 +0200
+@@ -45,8 +45,8 @@
+ 
+ #define ELF_ET_DYN_BASE	(2 * TASK_SIZE / 3)
+ 
+-/* When the program starts, a1 contains a pointer to a function to be 
+-   registered with atexit, as per the SVR4 ABI.  A value of 0 means we 
++/* When the program starts, a1 contains a pointer to a function to be
++   registered with atexit, as per the SVR4 ABI.  A value of 0 means we
+    have no such handler.  */
+ #define ELF_PLAT_INIT(_r, load_addr)	(_r)->ARM_r0 = 0
+ 
+--- linux-2.4.25/include/asm-arm/mach/dma.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/mach/dma.h	2004-03-31 17:15:09.000000000 +0200
+@@ -41,6 +41,7 @@
+ 	unsigned int	dma_base;	/* Controller base address	*/
+ 	int		dma_irq;	/* Controller IRQ		*/
+ 	struct scatterlist cur_sg;	/* Current controller buffer	*/
++	unsigned int    state;          /* RiscPC DMA status            */
+ 
+ 	struct dma_ops	*d_ops;
+ };
+--- linux-2.4.25/include/asm-arm/mach/serial_at91rm9200.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/mach/serial_at91rm9200.h	2004-03-31 17:15:09.000000000 +0200
+@@ -10,7 +10,6 @@
+ #include <linux/config.h>
+ 
+ struct uart_port;
+-struct uart_info;
+ 
+ /*
+  * This is a temporary structure for registering these
+@@ -22,11 +21,11 @@
+ 	void	(*enable_ms)(struct uart_port *);
+ 	void	(*pm)(struct uart_port *, u_int, u_int);
+ 	int	(*set_wake)(struct uart_port *, u_int);
+-	int	(*open)(struct uart_port *, struct uart_info *);
+-	void	(*close)(struct uart_port *, struct uart_info *);
++	int	(*open)(struct uart_port *);
++	void	(*close)(struct uart_port *);
+ };
+ 
+-#if defined(CONFIG_SERIAL_AT91RM9200)
++#if defined(CONFIG_SERIAL_AT91)
+ void at91rm9200_register_uart_fns(struct at91rm9200_port_fns *fns);
+ void at91rm9200_register_uart(int idx, int port);
+ #else
+--- linux-2.4.25/include/asm-arm/proc-armv/processor.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/proc-armv/processor.h	2004-03-31 17:15:09.000000000 +0200
+@@ -54,7 +54,9 @@
+ 		regs->ARM_cpsr = USR_MODE;				\
+ 	else								\
+ 		regs->ARM_cpsr = USR26_MODE;				\
+-	regs->ARM_pc = pc;		/* pc */			\
++        if (elf_hwcap & HWCAP_THUMB && pc & 1)                          \
++                regs->ARM_cpsr |= PSR_T_BIT;                            \
++        regs->ARM_pc = pc & ~1;         /* pc */                        \
+ 	regs->ARM_sp = sp;		/* sp */			\
+ 	regs->ARM_r2 = stack[2];	/* r2 (envp) */			\
+ 	regs->ARM_r1 = stack[1];	/* r1 (argv) */			\
+--- linux-2.4.25/include/asm-arm/proc-armv/ptrace.h~2.4.25-vrs2.patch	2000-11-28 02:07:59.000000000 +0100
++++ linux-2.4.25/include/asm-arm/proc-armv/ptrace.h	2004-03-31 17:15:09.000000000 +0200
+@@ -33,6 +33,16 @@
+ #define CC_N_BIT	(1 << 31)
+ #define PCMASK		0
+ 
++/* 2.5 versions */
++#define PSR_T_BIT	0x00000020
++#define PSR_F_BIT	0x00000040
++#define PSR_I_BIT	0x00000080
++#define PSR_J_BIT	0x01000000
++#define PSR_V_BIT	0x10000000
++#define PSR_C_BIT	0x20000000
++#define PSR_Z_BIT	0x40000000
++#define PSR_N_BIT	0x80000000
++
+ #ifndef __ASSEMBLY__
+ 
+ /* this struct defines the way the registers are stored on the
+--- linux-2.4.25/include/asm-arm/proc-armv/uaccess.h~2.4.25-vrs2.patch	2001-10-25 22:53:55.000000000 +0200
++++ linux-2.4.25/include/asm-arm/proc-armv/uaccess.h	2004-03-31 17:15:09.000000000 +0200
+@@ -12,12 +12,11 @@
+  * Note that this is actually 0x1,0000,0000
+  */
+ #define KERNEL_DS	0x00000000
+-#define USER_DS		PAGE_OFFSET
++#define USER_DS		TASK_SIZE
+ 
+ static inline void set_fs (mm_segment_t fs)
+ {
+ 	current->addr_limit = fs;
+-
+ 	modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER);
+ }
+ 
+@@ -38,7 +37,7 @@
+ 		: "cc"); \
+ 	(flag == 0); })
+ 
+-#define __put_user_asm_byte(x,addr,err)				\
++#define __put_user_asm_byte(x,__pu_addr,err)			\
+ 	__asm__ __volatile__(					\
+ 	"1:	strbt	%1,[%2],#0\n"				\
+ 	"2:\n"							\
+@@ -51,18 +50,18 @@
+ 	"	.align	3\n"					\
+ 	"	.long	1b, 3b\n"				\
+ 	"	.previous"					\
+-	: "=r" (err)						\
+-	: "r" (x), "r" (addr), "i" (-EFAULT), "0" (err))
++	: "+r" (err)						\
++	: "r" (x), "r" (__pu_addr), "i" (-EFAULT)		\
++	: "cc")
+ 
+-#define __put_user_asm_half(x,addr,err)				\
++#define __put_user_asm_half(x,__pu_addr,err)			\
+ ({								\
+ 	unsigned long __temp = (unsigned long)(x);		\
+-	unsigned long __ptr  = (unsigned long)(addr);		\
+-	__put_user_asm_byte(__temp, __ptr, err);		\
+-	__put_user_asm_byte(__temp >> 8, __ptr + 1, err);	\
++	__put_user_asm_byte(__temp, __pu_addr, err);		\
++	__put_user_asm_byte(__temp >> 8, __pu_addr + 1, err);	\
+ })
+ 
+-#define __put_user_asm_word(x,addr,err)				\
++#define __put_user_asm_word(x,__pu_addr,err)			\
+ 	__asm__ __volatile__(					\
+ 	"1:	strt	%1,[%2],#0\n"				\
+ 	"2:\n"							\
+@@ -75,8 +74,28 @@
+ 	"	.align	3\n"					\
+ 	"	.long	1b, 3b\n"				\
+ 	"	.previous"					\
+-	: "=r" (err)						\
+-	: "r" (x), "r" (addr), "i" (-EFAULT), "0" (err))
++	: "+r" (err)						\
++	: "r" (x), "r" (__pu_addr), "i" (-EFAULT)		\
++	: "cc")
++
++#define __put_user_asm_dword(x,__pu_addr,err)			\
++	__asm__ __volatile__(					\
++	"1:	strt	%R2, [%1], #4\n"			\
++	"2:	strt	%Q2, [%1], #0\n"			\
++	"3:\n"							\
++	"	.section .fixup,\"ax\"\n"			\
++	"	.align	2\n"					\
++	"4:	mov	%0, %3\n"				\
++	"	b	3b\n"					\
++	"	.previous\n"					\
++	"	.section __ex_table,\"a\"\n"			\
++	"	.align	3\n"					\
++	"	.long	1b, 4b\n"				\
++	"	.long	2b, 4b\n"				\
++	"	.previous"					\
++	: "+r" (err), "+r" (__pu_addr)				\
++	: "r" (x), "i" (-EFAULT)				\
++	: "cc")
+ 
+ #define __get_user_asm_byte(x,addr,err)				\
+ 	__asm__ __volatile__(					\
+@@ -92,18 +111,18 @@
+ 	"	.align	3\n"					\
+ 	"	.long	1b, 3b\n"				\
+ 	"	.previous"					\
+-	: "=r" (err), "=&r" (x)					\
+-	: "r" (addr), "i" (-EFAULT), "0" (err))
++	: "+r" (err), "=&r" (x)					\
++	: "r" (addr), "i" (-EFAULT)				\
++	: "cc")
+ 
+-#define __get_user_asm_half(x,addr,err)				\
++#define __get_user_asm_half(x,__gu_addr,err)			\
+ ({								\
+-	unsigned long __b1, __b2, __ptr = (unsigned long)addr;	\
+-	__get_user_asm_byte(__b1, __ptr, err);			\
+-	__get_user_asm_byte(__b2, __ptr + 1, err);		\
++	unsigned long __b1, __b2;				\
++	__get_user_asm_byte(__b1, __gu_addr, err);		\
++	__get_user_asm_byte(__b2, __gu_addr + 1, err);		\
+ 	(x) = __b1 | (__b2 << 8);				\
+ })
+ 
+-
+ #define __get_user_asm_word(x,addr,err)				\
+ 	__asm__ __volatile__(					\
+ 	"1:	ldrt	%1,[%2],#0\n"				\
+@@ -118,8 +137,9 @@
+ 	"	.align	3\n"					\
+ 	"	.long	1b, 3b\n"				\
+ 	"	.previous"					\
+-	: "=r" (err), "=&r" (x)					\
+-	: "r" (addr), "i" (-EFAULT), "0" (err))
++	: "+r" (err), "=&r" (x)					\
++	: "r" (addr), "i" (-EFAULT)				\
++	: "cc")
+ 
+ extern unsigned long __arch_copy_from_user(void *to, const void *from, unsigned long n);
+ #define __do_copy_from_user(to,from,n)				\
+--- linux-2.4.25/include/asm-arm/proc-fns.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/proc-fns.h	2004-03-31 17:15:09.000000000 +0200
+@@ -76,6 +76,30 @@
+ #   define CPU_NAME arm926
+ #  endif
+ # endif
++# ifdef CONFIG_CPU_ARM1020
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   define CPU_NAME arm1020
++#  endif
++# endif
++# ifdef CONFIG_CPU_ARM1020E
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   define CPU_NAME arm1020E
++#  endif
++# endif
++# ifdef CONFIG_CPU_ARM1022
++#  ifdef CPU_NAME
++#   undef  MULTI_CPU
++#   define MULTI_CPU
++#  else
++#   define CPU_NAME arm1022
++#  endif
++# endif
+ # ifdef CONFIG_CPU_ARM1026
+ #  ifdef CPU_NAME
+ #   undef  MULTI_CPU
+--- linux-2.4.25/include/asm-arm/processor.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/processor.h	2004-03-31 17:15:09.000000000 +0200
+@@ -43,6 +43,7 @@
+ #include <asm/atomic.h>
+ #include <asm/ptrace.h>
+ #include <asm/arch/memory.h>
++#include <asm/elf.h>
+ #include <asm/proc/processor.h>
+ #include <asm/types.h>
+ 
+--- linux-2.4.25/include/asm-arm/system.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/system.h	2004-03-31 17:15:09.000000000 +0200
+@@ -29,6 +29,10 @@
+ 
+ void die_if_kernel(const char *str, struct pt_regs *regs, int err);
+ 
++void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
++				       struct pt_regs *),
++		     int sig, const char *name);
++
+ #include <asm/proc-fns.h>
+ 
+ #define xchg(ptr,x) \
+@@ -89,6 +93,14 @@
+ #define sti()			local_irq_enable()
+ #define clf()			__clf()
+ #define stf()			__stf()
++
++#define irqs_disabled()			\
++({					\
++	unsigned long flags;		\
++	local_save_flags(flags);	\
++	flags & PSR_I_BIT;		\
++})
++
+ #define save_flags(x)		local_save_flags(x)
+ #define restore_flags(x)	local_irq_restore(x)
+ #define save_flags_cli(x)	local_irq_save(x)
+--- linux-2.4.25/include/asm-arm/termios.h~2.4.25-vrs2.patch	2001-06-12 04:15:27.000000000 +0200
++++ linux-2.4.25/include/asm-arm/termios.h	2004-03-31 17:15:09.000000000 +0200
+@@ -47,6 +47,8 @@
+ #define TIOCM_OUT2	0x4000
+ #define TIOCM_LOOP	0x8000
+ 
++#define TIOCM_MODEM_BITS	TIOCM_OUT2	/* IRDA support */
++
+ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+ 
+ /* line disciplines */
+--- linux-2.4.25/include/asm-arm/uaccess.h~2.4.25-vrs2.patch	2001-10-25 22:53:55.000000000 +0200
++++ linux-2.4.25/include/asm-arm/uaccess.h	2004-03-31 17:15:09.000000000 +0200
+@@ -74,14 +74,14 @@
+ 	   __asm__ __volatile__ ("bl	__get_user_" #__s		\
+ 		: "=&r" (__e), "=r" (__r1)				\
+ 		: "0" (__p)						\
+-		: __i)
++		: __i, "cc")
+ 
+ #define get_user(x,p)							\
+ 	({								\
+ 		const register typeof(*(p)) *__p asm("r0") = (p);	\
+ 		register typeof(*(p)) __r1 asm("r1");			\
+ 		register int __e asm("r0");				\
+-		switch (sizeof(*(p))) {					\
++		switch (sizeof(*(__p))) {				\
+ 		case 1:							\
+ 			__get_user_x(__r1, __p, __e, 1, "lr");		\
+ 	       		break;						\
+@@ -100,8 +100,31 @@
+ 		__e;							\
+ 	})
+ 
+-#define __get_user(x,p)		__get_user_nocheck((x),(p),sizeof(*(p)))
+-#define __get_user_error(x,p,e)	__get_user_nocheck_error((x),(p),sizeof(*(p)),(e))
++#define __get_user(x,ptr)						\
++({									\
++	long __gu_err = 0;						\
++	__get_user_err((x),(ptr),__gu_err);				\
++	__gu_err;							\
++})
++
++#define __get_user_error(x,ptr,err)					\
++({									\
++	__get_user_err((x),(ptr),err);					\
++	(void) 0;							\
++})
++
++#define __get_user_err(x,ptr,err)					\
++do {									\
++	unsigned long __gu_addr = (unsigned long)(ptr);			\
++	unsigned long __gu_val;						\
++	switch (sizeof(*(ptr))) {					\
++	case 1:	__get_user_asm_byte(__gu_val,__gu_addr,err);	break;	\
++	case 2:	__get_user_asm_half(__gu_val,__gu_addr,err);	break;	\
++	case 4:	__get_user_asm_word(__gu_val,__gu_addr,err);	break;	\
++	default: (__gu_val) = __get_user_bad();				\
++	}								\
++	(x) = (__typeof__(*(ptr)))__gu_val;				\
++} while (0)
+ 
+ extern int __put_user_1(void *, unsigned int);
+ extern int __put_user_2(void *, unsigned int);
+@@ -113,22 +136,22 @@
+ 	   __asm__ __volatile__ ("bl	__put_user_" #__s		\
+ 		: "=&r" (__e)						\
+ 		: "0" (__p), "r" (__r1)					\
+-		: __i)
++		: __i, "cc")
+ 
+ #define put_user(x,p)							\
+ 	({								\
+ 		const register typeof(*(p)) __r1 asm("r1") = (x);	\
+ 		const register typeof(*(p)) *__p asm("r0") = (p);	\
+ 		register int __e asm("r0");				\
+-		switch (sizeof(*(p))) {					\
++		switch (sizeof(*(__p))) {				\
+ 		case 1:							\
+-			__put_user_x(__r1, __p, __e, 1, "r2", "lr");	\
++			__put_user_x(__r1, __p, __e, 1, "ip", "lr");	\
+ 			break;						\
+ 		case 2:							\
+-			__put_user_x(__r1, __p, __e, 2, "r2", "lr");	\
++			__put_user_x(__r1, __p, __e, 2, "ip", "lr");	\
+ 			break;						\
+ 		case 4:							\
+-			__put_user_x(__r1, __p, __e, 4, "r2", "lr");	\
++			__put_user_x(__r1, __p, __e, 4, "ip", "lr");	\
+ 			break;						\
+ 		case 8:							\
+ 			__put_user_x(__r1, __p, __e, 8, "ip", "lr");	\
+@@ -138,8 +161,31 @@
+ 		__e;							\
+ 	})
+ 
+-#define __put_user(x,p)		__put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p)))
+-#define __put_user_error(x,p,e)	__put_user_nocheck_error((x),(p),sizeof(*(p)),(e))
++#define __put_user(x,ptr)						\
++({									\
++	long __pu_err = 0;						\
++	__put_user_err((x),(ptr),__pu_err);				\
++	__pu_err;							\
++})
++
++#define __put_user_error(x,ptr,err)					\
++({									\
++	__put_user_err((x),(ptr),err);					\
++	(void) 0;							\
++})
++
++#define __put_user_err(x,ptr,err)					\
++do {									\
++	unsigned long __pu_addr = (unsigned long)(ptr); 		\
++	__typeof__(*(ptr)) __pu_val = (x);				\
++	switch (sizeof(*(ptr))) {					\
++	case 1: __put_user_asm_byte(__pu_val,__pu_addr,err);	break;	\
++	case 2: __put_user_asm_half(__pu_val,__pu_addr,err);	break;	\
++	case 4: __put_user_asm_word(__pu_val,__pu_addr,err);	break;	\
++	case 8:	__put_user_asm_dword(__pu_val,__pu_addr,err);	break;	\
++	default: __put_user_bad();					\
++	}								\
++} while (0)
+ 
+ static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n)
+ {
+@@ -209,82 +255,4 @@
+ 	return res;
+ }
+ 
+-/*
+- * These are the work horses of the get/put_user functions
+- */
+-#if 0
+-#define __get_user_check(x,ptr,size)					\
+-({									\
+-	long __gu_err = -EFAULT, __gu_val = 0;				\
+-	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
+-	if (access_ok(VERIFY_READ,__gu_addr,size)) {			\
+-		__gu_err = 0;						\
+-		__get_user_size(__gu_val,__gu_addr,(size),__gu_err);	\
+-	}								\
+-	(x) = (__typeof__(*(ptr)))__gu_val;				\
+-	__gu_err;							\
+-})
+-#endif
+-
+-#define __get_user_nocheck(x,ptr,size)					\
+-({									\
+-	long __gu_err = 0, __gu_val;					\
+-	__get_user_size(__gu_val,(ptr),(size),__gu_err);		\
+-	(x) = (__typeof__(*(ptr)))__gu_val;				\
+-	__gu_err;							\
+-})
+-
+-#define __get_user_nocheck_error(x,ptr,size,err)			\
+-({									\
+-	long __gu_val;							\
+-	__get_user_size(__gu_val,(ptr),(size),(err));			\
+-	(x) = (__typeof__(*(ptr)))__gu_val;				\
+-	(void) 0;							\
+-})
+-
+-#define __put_user_check(x,ptr,size)					\
+-({									\
+-	long __pu_err = -EFAULT;					\
+-	__typeof__(*(ptr)) *__pu_addr = (ptr);				\
+-	if (access_ok(VERIFY_WRITE,__pu_addr,size)) {			\
+-		__pu_err = 0;						\
+-		__put_user_size((x),__pu_addr,(size),__pu_err);		\
+-	}								\
+-	__pu_err;							\
+-})
+-
+-#define __put_user_nocheck(x,ptr,size)					\
+-({									\
+-	long __pu_err = 0;						\
+-	__typeof__(*(ptr)) *__pu_addr = (ptr);				\
+-	__put_user_size((x),__pu_addr,(size),__pu_err);			\
+-	__pu_err;							\
+-})
+-
+-#define __put_user_nocheck_error(x,ptr,size,err)			\
+-({									\
+-	__put_user_size((x),(ptr),(size),err);				\
+-	(void) 0;							\
+-})
+-
+-#define __get_user_size(x,ptr,size,retval)				\
+-do {									\
+-	switch (size) {							\
+-	case 1:	__get_user_asm_byte(x,ptr,retval);	break;		\
+-	case 2:	__get_user_asm_half(x,ptr,retval);	break;		\
+-	case 4:	__get_user_asm_word(x,ptr,retval);	break;		\
+-	default: (x) = __get_user_bad();				\
+-	}								\
+-} while (0)
+-
+-#define __put_user_size(x,ptr,size,retval)				\
+-do {									\
+-	switch (size) {							\
+-	case 1: __put_user_asm_byte(x,ptr,retval);	break;		\
+-	case 2: __put_user_asm_half(x,ptr,retval);	break;		\
+-	case 4: __put_user_asm_word(x,ptr,retval);	break;		\
+-	default: __put_user_bad();					\
+-	}								\
+-} while (0)
+-
+ #endif /* _ASMARM_UACCESS_H */
+--- linux-2.4.25/include/asm-arm/unistd.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-arm/unistd.h	2004-03-31 17:15:09.000000000 +0200
+@@ -31,7 +31,7 @@
+ #define __NR_write			(__NR_SYSCALL_BASE+  4)
+ #define __NR_open			(__NR_SYSCALL_BASE+  5)
+ #define __NR_close			(__NR_SYSCALL_BASE+  6)
+-#define __NR_waitpid			(__NR_SYSCALL_BASE+  7)
++					/* 7 was sys_waitpid */
+ #define __NR_creat			(__NR_SYSCALL_BASE+  8)
+ #define __NR_link			(__NR_SYSCALL_BASE+  9)
+ #define __NR_unlink			(__NR_SYSCALL_BASE+ 10)
+@@ -41,8 +41,8 @@
+ #define __NR_mknod			(__NR_SYSCALL_BASE+ 14)
+ #define __NR_chmod			(__NR_SYSCALL_BASE+ 15)
+ #define __NR_lchown			(__NR_SYSCALL_BASE+ 16)
+-#define __NR_break			(__NR_SYSCALL_BASE+ 17)
+-
++					/* 17 was sys_break */
++					/* 18 was sys_stat */
+ #define __NR_lseek			(__NR_SYSCALL_BASE+ 19)
+ #define __NR_getpid			(__NR_SYSCALL_BASE+ 20)
+ #define __NR_mount			(__NR_SYSCALL_BASE+ 21)
+@@ -52,14 +52,14 @@
+ #define __NR_stime			(__NR_SYSCALL_BASE+ 25)
+ #define __NR_ptrace			(__NR_SYSCALL_BASE+ 26)
+ #define __NR_alarm			(__NR_SYSCALL_BASE+ 27)
+-
++					/* 28 was sys_fstat */
+ #define __NR_pause			(__NR_SYSCALL_BASE+ 29)
+ #define __NR_utime			(__NR_SYSCALL_BASE+ 30)
+-#define __NR_stty			(__NR_SYSCALL_BASE+ 31)
+-#define __NR_gtty			(__NR_SYSCALL_BASE+ 32)
++					/* 31 was sys_stty */
++					/* 32 was sys_gtty */
+ #define __NR_access			(__NR_SYSCALL_BASE+ 33)
+ #define __NR_nice			(__NR_SYSCALL_BASE+ 34)
+-#define __NR_ftime			(__NR_SYSCALL_BASE+ 35)
++					/* 35 was sys_ftime */
+ #define __NR_sync			(__NR_SYSCALL_BASE+ 36)
+ #define __NR_kill			(__NR_SYSCALL_BASE+ 37)
+ #define __NR_rename			(__NR_SYSCALL_BASE+ 38)
+@@ -68,22 +68,23 @@
+ #define __NR_dup			(__NR_SYSCALL_BASE+ 41)
+ #define __NR_pipe			(__NR_SYSCALL_BASE+ 42)
+ #define __NR_times			(__NR_SYSCALL_BASE+ 43)
+-#define __NR_prof			(__NR_SYSCALL_BASE+ 44)
++					/* 44 was sys_prof */
+ #define __NR_brk			(__NR_SYSCALL_BASE+ 45)
+ #define __NR_setgid			(__NR_SYSCALL_BASE+ 46)
+ #define __NR_getgid			(__NR_SYSCALL_BASE+ 47)
+-#define __NR_signal			(__NR_SYSCALL_BASE+ 48)
++					/* 48 was sys_signal */
+ #define __NR_geteuid			(__NR_SYSCALL_BASE+ 49)
+ #define __NR_getegid			(__NR_SYSCALL_BASE+ 50)
+ #define __NR_acct			(__NR_SYSCALL_BASE+ 51)
+ #define __NR_umount2			(__NR_SYSCALL_BASE+ 52)
+-#define __NR_lock			(__NR_SYSCALL_BASE+ 53)
++					/* 53 was sys_lock */
+ #define __NR_ioctl			(__NR_SYSCALL_BASE+ 54)
+ #define __NR_fcntl			(__NR_SYSCALL_BASE+ 55)
+-#define __NR_mpx			(__NR_SYSCALL_BASE+ 56)
++					/* 56 was sys_mpx */
+ #define __NR_setpgid			(__NR_SYSCALL_BASE+ 57)
+ #define __NR_ulimit			(__NR_SYSCALL_BASE+ 58)
+-
++					/* 58 was sys_ulimit */
++					/* 59 was sys_olduname */
+ #define __NR_umask			(__NR_SYSCALL_BASE+ 60)
+ #define __NR_chroot			(__NR_SYSCALL_BASE+ 61)
+ #define __NR_ustat			(__NR_SYSCALL_BASE+ 62)
+@@ -92,8 +93,8 @@
+ #define __NR_getpgrp			(__NR_SYSCALL_BASE+ 65)
+ #define __NR_setsid			(__NR_SYSCALL_BASE+ 66)
+ #define __NR_sigaction			(__NR_SYSCALL_BASE+ 67)
+-#define __NR_sgetmask			(__NR_SYSCALL_BASE+ 68)
+-#define __NR_ssetmask			(__NR_SYSCALL_BASE+ 69)
++					/* 68 was sys_sgetmask */
++					/* 69 was sys_ssetmask */
+ #define __NR_setreuid			(__NR_SYSCALL_BASE+ 70)
+ #define __NR_setregid			(__NR_SYSCALL_BASE+ 71)
+ #define __NR_sigsuspend			(__NR_SYSCALL_BASE+ 72)
+@@ -108,7 +109,7 @@
+ #define __NR_setgroups			(__NR_SYSCALL_BASE+ 81)
+ #define __NR_select			(__NR_SYSCALL_BASE+ 82)
+ #define __NR_symlink			(__NR_SYSCALL_BASE+ 83)
+-
++					/* 84 was sys_lstat */
+ #define __NR_readlink			(__NR_SYSCALL_BASE+ 85)
+ #define __NR_uselib			(__NR_SYSCALL_BASE+ 86)
+ #define __NR_swapon			(__NR_SYSCALL_BASE+ 87)
+@@ -122,10 +123,10 @@
+ #define __NR_fchown			(__NR_SYSCALL_BASE+ 95)
+ #define __NR_getpriority		(__NR_SYSCALL_BASE+ 96)
+ #define __NR_setpriority		(__NR_SYSCALL_BASE+ 97)
+-#define __NR_profil			(__NR_SYSCALL_BASE+ 98)
++					/* 98 was sys_profil */
+ #define __NR_statfs			(__NR_SYSCALL_BASE+ 99)
+ #define __NR_fstatfs			(__NR_SYSCALL_BASE+100)
+-#define __NR_ioperm			(__NR_SYSCALL_BASE+101)
++					/* 101 was sys_ioperm */
+ #define __NR_socketcall			(__NR_SYSCALL_BASE+102)
+ #define __NR_syslog			(__NR_SYSCALL_BASE+103)
+ #define __NR_setitimer			(__NR_SYSCALL_BASE+104)
+@@ -133,10 +134,10 @@
+ #define __NR_stat			(__NR_SYSCALL_BASE+106)
+ #define __NR_lstat			(__NR_SYSCALL_BASE+107)
+ #define __NR_fstat			(__NR_SYSCALL_BASE+108)
+-
+-
++					/* 109 was sys_uname */
++					/* 110 was sys_iopl */
+ #define __NR_vhangup			(__NR_SYSCALL_BASE+111)
+-#define __NR_idle			(__NR_SYSCALL_BASE+112)
++					/* 112 was sys_idle */
+ #define __NR_syscall			(__NR_SYSCALL_BASE+113) /* syscall to call a syscall! */
+ #define __NR_wait4			(__NR_SYSCALL_BASE+114)
+ #define __NR_swapoff			(__NR_SYSCALL_BASE+115)
+@@ -147,7 +148,7 @@
+ #define __NR_clone			(__NR_SYSCALL_BASE+120)
+ #define __NR_setdomainname		(__NR_SYSCALL_BASE+121)
+ #define __NR_uname			(__NR_SYSCALL_BASE+122)
+-#define __NR_modify_ldt			(__NR_SYSCALL_BASE+123)
++					/* 123 was sys_modify_ldt */
+ #define __NR_adjtimex			(__NR_SYSCALL_BASE+124)
+ #define __NR_mprotect			(__NR_SYSCALL_BASE+125)
+ #define __NR_sigprocmask		(__NR_SYSCALL_BASE+126)
+@@ -161,7 +162,7 @@
+ #define __NR_bdflush			(__NR_SYSCALL_BASE+134)
+ #define __NR_sysfs			(__NR_SYSCALL_BASE+135)
+ #define __NR_personality		(__NR_SYSCALL_BASE+136)
+-#define __NR_afs_syscall		(__NR_SYSCALL_BASE+137) /* Syscall for Andrew File System */
++					/* 137 was sys_afs_syscall */
+ #define __NR_setfsuid			(__NR_SYSCALL_BASE+138)
+ #define __NR_setfsgid			(__NR_SYSCALL_BASE+139)
+ #define __NR__llseek			(__NR_SYSCALL_BASE+140)
+@@ -190,7 +191,7 @@
+ #define __NR_mremap			(__NR_SYSCALL_BASE+163)
+ #define __NR_setresuid			(__NR_SYSCALL_BASE+164)
+ #define __NR_getresuid			(__NR_SYSCALL_BASE+165)
+-#define __NR_vm86			(__NR_SYSCALL_BASE+166)
++					/* 166 was sys_vm86 */
+ #define __NR_query_module		(__NR_SYSCALL_BASE+167)
+ #define __NR_poll			(__NR_SYSCALL_BASE+168)
+ #define __NR_nfsservctl			(__NR_SYSCALL_BASE+169)
+--- linux-2.4.25/include/asm-i386/ide.h~2.4.25-vrs2.patch	2003-06-13 16:51:38.000000000 +0200
++++ linux-2.4.25/include/asm-i386/ide.h	2004-03-31 17:15:09.000000000 +0200
+@@ -23,39 +23,15 @@
+ # endif
+ #endif
+ 
+-static __inline__ int ide_default_irq(ide_ioreg_t base)
+-{
+-	switch (base) {
+-		case 0x1f0: return 14;
+-		case 0x170: return 15;
+-		case 0x1e8: return 11;
+-		case 0x168: return 10;
+-		case 0x1e0: return 8;
+-		case 0x160: return 12;
+-		default:
+-			return 0;
+-	}
+-}
+-
+-static __inline__ ide_ioreg_t ide_default_io_base(int index)
+-{
+-	switch (index) {
+-		case 0:	return 0x1f0;
+-		case 1:	return 0x170;
+-		case 2: return 0x1e8;
+-		case 3: return 0x168;
+-		case 4: return 0x1e0;
+-		case 5: return 0x160;
+-		default:
+-			return 0;
+-	}
+-}
++#define ide_default_io_base(i)	((ide_ioreg_t)0)
++#define ide_default_irq(b)	(0)
+ 
+ static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+ {
+ 	ide_ioreg_t reg = data_port;
+ 	int i;
+ 
++	memset(hw, 0, sizeof(*hw));
+ 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ 		hw->io_ports[i] = reg;
+ 		reg += 1;
+@@ -63,7 +39,7 @@
+ 	if (ctrl_port) {
+ 		hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+ 	} else {
+-		hw->io_ports[IDE_CONTROL_OFFSET] = hw->io_ports[IDE_DATA_OFFSET] + 0x206;
++		hw->io_ports[IDE_CONTROL_OFFSET] = data_port + 0x206;
+ 	}
+ 	if (irq != NULL)
+ 		*irq = 0;
+@@ -74,14 +50,25 @@
+ {
+ #ifndef CONFIG_BLK_DEV_IDEPCI
+ 	hw_regs_t hw;
+-	int index;
+ 
+-	for(index = 0; index < MAX_HWIFS; index++) {
+-		memset(&hw, 0, sizeof hw);
+-		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+-		hw.irq = ide_default_irq(ide_default_io_base(index));
+-		ide_register_hw(&hw, NULL);
+-	}
++	ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL);
++	hw.irq = 14;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x170, 0x376, NULL);
++	hw.irq = 15;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x1e8, 0x3ee, NULL);
++	hw.irq = 11;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x168, 0x36e, NULL);
++	hw.irq = 10;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x1e0, 0x3e6, NULL);
++	hw.irq = 8;
++	ide_register_hw(&hw, NULL);
++	ide_init_hwif_ports(&hw, 0x160, 0x366, NULL);
++	hw.irq = 12;
++	ide_register_hw(&hw, NULL);
+ #endif /* CONFIG_BLK_DEV_IDEPCI */
+ }
+ 
+--- linux-2.4.25/include/asm-i386/param.h~2.4.25-vrs2.patch	2000-10-27 20:04:43.000000000 +0200
++++ linux-2.4.25/include/asm-i386/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -3,6 +3,16 @@
+ 
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#if HZ == 100
++/* X86 is defined to provide userspace with a world where HZ=100
++   We have to do this, (x*const)/const2 isnt optimised out because its not
++   a null operation as it might overflow.. */
++#define hz_to_std(a) (a)
++#else
++#define hz_to_std(a) ((a)*(100/HZ)+((a)*(100%HZ))/HZ)
++#endif
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	4096
+--- linux-2.4.25/include/asm-i386/pgtable.h~2.4.25-vrs2.patch	2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.25/include/asm-i386/pgtable.h	2004-03-31 17:15:09.000000000 +0200
+@@ -361,7 +361,6 @@
+ #endif /* !__ASSEMBLY__ */
+ 
+ /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
+-#define PageSkip(page)		(0)
+ #define kern_addr_valid(addr)	(1)
+ 
+ #define io_remap_page_range remap_page_range
+--- linux-2.4.25/include/asm-ia64/param.h~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/include/asm-ia64/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -8,6 +8,10 @@
+  *	David Mosberger-Tang <davidm@hpl.hp.com>
+  */
+ 
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
++
+ #define EXEC_PAGESIZE	65536
+ 
+ #ifndef NGROUPS
+--- linux-2.4.25/include/asm-m68k/param.h~2.4.25-vrs2.patch	2001-01-04 22:00:55.000000000 +0100
++++ linux-2.4.25/include/asm-m68k/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -3,6 +3,9 @@
+ 
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	8192
+--- linux-2.4.25/include/asm-mips/ide.h~2.4.25-vrs2.patch	2003-08-25 13:44:43.000000000 +0200
++++ linux-2.4.25/include/asm-mips/ide.h	2004-03-31 17:15:09.000000000 +0200
+@@ -27,7 +27,7 @@
+ 	int (*ide_default_irq)(ide_ioreg_t base);
+ 	ide_ioreg_t (*ide_default_io_base)(int index);
+ 	void (*ide_init_hwif_ports)(hw_regs_t *hw, ide_ioreg_t data_port,
+-	                            ide_ioreg_t ctrl_port, int *irq);
++				    ide_ioreg_t ctrl_port, int *irq);
+ };
+ 
+ extern struct ide_ops *ide_ops;
+--- linux-2.4.25/include/asm-ppc/param.h~2.4.25-vrs2.patch	2003-06-13 16:51:38.000000000 +0200
++++ linux-2.4.25/include/asm-ppc/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -3,6 +3,9 @@
+ 
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	4096
+--- linux-2.4.25/include/asm-s390/param.h~2.4.25-vrs2.patch	2001-02-13 23:13:44.000000000 +0100
++++ linux-2.4.25/include/asm-s390/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -11,6 +11,9 @@
+ 
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	4096
+--- linux-2.4.25/include/asm-sh/param.h~2.4.25-vrs2.patch	2001-01-04 22:19:13.000000000 +0100
++++ linux-2.4.25/include/asm-sh/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -3,6 +3,9 @@
+ 
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	4096
+--- linux-2.4.25/include/asm-sparc/param.h~2.4.25-vrs2.patch	2000-10-30 23:34:12.000000000 +0100
++++ linux-2.4.25/include/asm-sparc/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -4,6 +4,9 @@
+ 
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
+--- linux-2.4.25/include/asm-sparc64/ide.h~2.4.25-vrs2.patch	2003-06-13 16:51:38.000000000 +0200
++++ linux-2.4.25/include/asm-sparc64/ide.h	2004-03-31 17:15:09.000000000 +0200
+@@ -25,21 +25,12 @@
+ # endif
+ #endif
+ 
+-static __inline__ int ide_default_irq(ide_ioreg_t base)
+-{
+-	return 0;
+-}
+-
+-static __inline__ ide_ioreg_t ide_default_io_base(int index)
+-{
+-	return 0;
+-}
+-
+ static __inline__ void ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq)
+ {
+-	ide_ioreg_t reg =  data_port;
++	ide_ioreg_t reg = data_port;
+ 	int i;
+ 
++	memset(&hw, 0, sizeof(hw));
+ 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
+ 		hw->io_ports[i] = reg;
+ 		reg += 1;
+@@ -60,16 +51,6 @@
+  */
+ static __inline__ void ide_init_default_hwifs(void)
+ {
+-#ifndef CONFIG_BLK_DEV_IDEPCI
+-	hw_regs_t hw;
+-	int index;
+-
+-	for (index = 0; index < MAX_HWIFS; index++) {
+-		ide_init_hwif_ports(&hw, ide_default_io_base(index), 0, NULL);
+-		hw.irq = ide_default_irq(ide_default_io_base(index));
+-		ide_register_hw(&hw, NULL);
+-	}
+-#endif /* CONFIG_BLK_DEV_IDEPCI */
+ }
+ 
+ #undef  SUPPORT_SLOW_DATA_PORTS
+--- linux-2.4.25/include/asm-sparc64/param.h~2.4.25-vrs2.patch	2000-10-30 23:34:12.000000000 +0100
++++ linux-2.4.25/include/asm-sparc64/param.h	2004-03-31 17:15:09.000000000 +0200
+@@ -4,6 +4,9 @@
+ 
+ #ifndef HZ
+ #define HZ 100
++#ifdef __KERNEL__
++#define hz_to_std(a) (a)
++#endif
+ #endif
+ 
+ #define EXEC_PAGESIZE	8192    /* Thanks for sun4's we carry baggage... */
+--- linux-2.4.25/include/linux/console_struct.h~2.4.25-vrs2.patch	2003-06-13 16:51:38.000000000 +0200
++++ linux-2.4.25/include/linux/console_struct.h	2004-03-31 17:15:09.000000000 +0200
+@@ -7,6 +7,8 @@
+  * Fields marked with [#] must be set by the low-level driver.
+  * Fields marked with [!] can be changed by the low-level driver
+  * to achieve effects such as fast scrolling by changing the origin.
++ *
++ *  11/07/1998	RMK	Changed vc_state to be a function pointer
+  */
+ 
+ #ifndef _LINUX_CONSOLE_STRUCT_H_
+@@ -34,7 +36,11 @@
+ 	unsigned short	vc_s_complement_mask;	/* Saved mouse pointer mask */
+ 	unsigned int	vc_x, vc_y;		/* Cursor position */
+ 	unsigned int	vc_top, vc_bottom;	/* Scrolling region */
++#ifdef CONSOLE_WIP
++	int (*vc_state)(int currcons, struct tty_struct *tty, unsigned int c);
++#else
+ 	unsigned int	vc_state;		/* Escape sequence parser state */
++#endif
+ 	unsigned int	vc_npar,vc_par[NPAR];	/* Parameters of current escape sequence */
+ 	unsigned long	vc_origin;		/* [!] Start of real screen */
+ 	unsigned long	vc_scr_end;		/* [!] End of real screen */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/linux/cpufreq.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,94 @@
++/*
++ *  linux/include/linux/cpufreq.h
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ * $Id$
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef _LINUX_CPUFREQ_H
++#define _LINUX_CPUFREQ_H
++
++#include <linux/config.h>
++#include <linux/notifier.h>
++
++#ifndef CONFIG_SMP
++#define cpufreq_current(cpu)	((void)(cpu), __cpufreq_cur)
++#define cpufreq_max(cpu)	((void)(cpu), __cpufreq_max)
++#define cpufreq_min(cpu)	((void)(cpu), __cpufreq_min)
++#else
++/*
++ * Should be something like:
++ *
++ * typedef struct {
++ *	u_int current;
++ *	u_int max;
++ *	u_int min;
++ * } __cacheline_aligned cpufreq_info_t;
++ *
++ * static cpufreq_info_t cpufreq_info;
++ *
++ * #define cpufreq_current(cpu)	(cpufreq_info[cpu].current)
++ * #define cpufreq_max(cpu)	(cpufreq_info[cpu].max)
++ * #define cpufreq_min(cpu)	(cpufreq_info[cpu].min)
++ *
++ * Maybe we should find some other per-cpu structure to
++ * bury this in?
++ */
++#error fill in SMP version
++#endif
++
++struct cpufreq_info {
++	unsigned int old_freq;
++	unsigned int new_freq;
++};
++
++/*
++ * The max and min frequency rates that the registered device
++ * can tolerate.  Never set any element this structure directly -
++ * always use cpu_updateminmax.
++ */
++struct cpufreq_minmax {
++	unsigned int min_freq;
++	unsigned int max_freq;
++	unsigned int cur_freq;
++	unsigned int new_freq;
++};
++
++static inline
++void cpufreq_updateminmax(void *arg, unsigned int min, unsigned int max)
++{
++	struct cpufreq_minmax *minmax = arg;
++
++	if (minmax->min_freq < min)
++		minmax->min_freq = min;
++	if (minmax->max_freq > max)
++		minmax->max_freq = max;
++}
++
++#define CPUFREQ_MINMAX		(0)
++#define CPUFREQ_PRECHANGE	(1)
++#define CPUFREQ_POSTCHANGE	(2)
++
++int cpufreq_register_notifier(struct notifier_block *nb);
++int cpufreq_unregister_notifier(struct notifier_block *nb);
++
++int cpufreq_setmax(void);
++int cpufreq_restore(void);
++int cpufreq_set(unsigned int khz);
++unsigned int cpufreq_get(int cpu);
++
++/*
++ * These two functions are only available at init time.
++ */
++void cpufreq_init(unsigned int khz,
++		  unsigned int min_freq,
++		  unsigned int max_freq);
++
++void cpufreq_setfunctions(unsigned int (*validate)(unsigned int),
++			  void (*setspeed)(unsigned int));
++
++#endif
+--- linux-2.4.25/include/linux/i2c-id.h~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/include/linux/i2c-id.h	2004-03-31 17:15:09.000000000 +0200
+@@ -20,16 +20,16 @@
+     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
+ /* ------------------------------------------------------------------------- */
+ 
+-/* $Id$ */
++/* $Id$ */
+ 
+ #ifndef I2C_ID_H
+ #define I2C_ID_H
+ /*
+  * This file is part of the i2c-bus package and contains the identifier
+  * values for drivers, adapters and other folk populating these serial
+- * worlds. 
++ * worlds.
+  *
+- * These will change often (i.e. additions) , therefore this has been 
++ * These will change often (i.e. additions) , therefore this has been
+  * separated from the functional interface definitions of the i2c api.
+  *
+  */
+@@ -38,10 +38,10 @@
+  * ---- Driver types -----------------------------------------------------
+  *       device id name + number        function description, i2c address(es)
+  *
+- *  Range 1000-1999 range is defined in sensors/sensors.h 
+- *  Range 0x100 - 0x1ff is for V4L2 Common Components 
++ *  Range 1000-1999 range is defined in sensors/sensors.h
++ *  Range 0x100 - 0x1ff is for V4L2 Common Components
+  *  Range 0xf000 - 0xffff is reserved for local experimentation, and should
+- *        never be used in official drivers 
++ *        never be used in official drivers
+  */
+ 
+ #define I2C_DRIVERID_MSP3400	 1
+@@ -90,7 +90,12 @@
+ #define I2C_DRIVERID_DRP3510	43     /* ADR decoder (Astra Radio)	*/
+ #define I2C_DRIVERID_SP5055	44     /* Satellite tuner		*/
+ #define I2C_DRIVERID_STV0030	45     /* Multipurpose switch		*/
++#define I2C_DRIVERID_SAA7108	46     /* video decoder, image scaler   */
++#define I2C_DRIVERID_DS1307	47     /* DS1307 real time clock	*/
+ #define I2C_DRIVERID_ADV7175	48     /* ADV 7175/7176 video encoder	*/
++#define I2C_DRIVERID_ZR36067	49     /* Zoran 36067 video encoder	*/
++#define I2C_DRIVERID_ZR36120	50     /* Zoran 36120 video encoder	*/
++#define I2C_DRIVERID_24LC32A	51     /* Microchip 24LC32A 32k EEPROM	*/
+ #define I2C_DRIVERID_MAX1617	56     /* temp sensor			*/
+ #define I2C_DRIVERID_SAA7191	57     /* video decoder                 */
+ #define I2C_DRIVERID_INDYCAM	58     /* SGI IndyCam			*/
+@@ -102,8 +107,10 @@
+ 
+ #define I2C_DRIVERID_I2CDEV	900
+ #define I2C_DRIVERID_I2CPROC	901
++#define I2C_DRIVERID_ARP        902    /* SMBus ARP Client              */
++#define I2C_DRIVERID_ALERT      903    /* SMBus Alert Responder Client  */
+ 
+-/* IDs --   Use DRIVERIDs 1000-1999 for sensors. 
++/* IDs --   Use DRIVERIDs 1000-1999 for sensors.
+    These were originally in sensors.h in the lm_sensors package */
+ #define I2C_DRIVERID_LM78 1002
+ #define I2C_DRIVERID_LM75 1003
+@@ -131,6 +138,12 @@
+ #define I2C_DRIVERID_ADM1024 1025
+ #define I2C_DRIVERID_IT87 1026
+ #define I2C_DRIVERID_CH700X 1027 /* single driver for CH7003-7009 digital pc to tv encoders */
++#define I2C_DRIVERID_FSCPOS 1028
++#define I2C_DRIVERID_FSCSCY 1029
++#define I2C_DRIVERID_PCF8591 1030
++#define I2C_DRIVERID_SMSC47M1 1031
++#define I2C_DRIVERID_VT1211 1032
++#define I2C_DRIVERID_LM92 1033
+ 
+ /*
+  * ---- Adapter types ----------------------------------------------------
+@@ -147,7 +160,8 @@
+ #define I2C_ALGO_ISA 	0x050000	/* lm_sensors ISA pseudo-adapter */
+ #define I2C_ALGO_SAA7146 0x060000	/* SAA 7146 video decoder bus	*/
+ #define I2C_ALGO_ACB 	0x070000	/* ACCESS.bus algorithm         */
+-
++#define I2C_ALGO_IIC    0x080000 	/* ITE IIC bus */
++#define I2C_ALGO_SAA7134 0x090000
+ #define I2C_ALGO_EC     0x100000        /* ACPI embedded controller     */
+ 
+ #define I2C_ALGO_MPC8XX 0x110000	/* MPC8xx PowerPC I2C algorithm */
+@@ -156,13 +170,15 @@
+ 
+ #define I2C_ALGO_SGI	0x130000	/* SGI algorithm		*/
+ 
++#define I2C_ALGO_OCP    0x120000	/* IBM or otherwise On-chip I2C algorithm */
++
+ #define I2C_ALGO_EXP	0x800000	/* experimental			*/
+ 
+ #define I2C_ALGO_MASK	0xff0000	/* Mask for algorithms		*/
+ #define I2C_ALGO_SHIFT	0x10	/* right shift to get index values 	*/
+ 
+ #define I2C_HW_ADAPS	0x10000		/* # adapter types		*/
+-#define I2C_HW_MASK	0xffff		
++#define I2C_HW_MASK	0xffff
+ 
+ 
+ /* hw specific modules that are defined per algorithm layer
+@@ -182,9 +198,13 @@
+ #define I2C_HW_B_I810	0x0a	/* Intel I810 				*/
+ #define I2C_HW_B_VOO	0x0b	/* 3dfx Voodoo 3 / Banshee      	*/
+ #define I2C_HW_B_PPORT  0x0c	/* Primitive parallel port adapter	*/
++#define I2C_HW_B_SAVG	0x0d	/* Savage 4                     	*/
+ #define I2C_HW_B_RIVA	0x10	/* Riva based graphics cards		*/
+ #define I2C_HW_B_IOC	0x11	/* IOC bit-wiggling			*/
+ #define I2C_HW_B_TSUNA  0x12	/* DEC Tsunami chipset			*/
++#define I2C_HW_B_FRODO	0x13	/* 2d3D, Inc. SA-1110 Development Board */
++#define I2C_HW_B_OMAHA  0x14    /* Omaha I2C interface                  */
++#define I2C_HW_B_GUIDE  0x15    /* Guide bit-basher                     */
+ 
+ /* --- PCF 8584 based algorithms					*/
+ #define I2C_HW_P_LP	0x00	/* Parallel port interface		*/
+@@ -197,6 +217,12 @@
+ /* --- MPC8xx PowerPC adapters						*/
+ #define I2C_HW_MPC8XX_EPON 0x00	/* Eponymous MPC8xx I2C adapter 	*/
+ 
++/* --- ITE based algorithms						*/
++#define I2C_HW_I_IIC	0x00	/* controller on the ITE */
++
++/* --- PowerPC on-chip adapters						*/
++#define I2C_HW_OCP 0x00	/* IBM on-chip I2C adapter 	*/
++
+ /* --- Broadcom SiByte adapters						*/
+ #define I2C_HW_SIBYTE	0x00
+ 
+--- linux-2.4.25/include/linux/ide.h~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/include/linux/ide.h	2004-03-31 17:15:09.000000000 +0200
+@@ -287,7 +287,9 @@
+  * Check for an interrupt and acknowledge the interrupt status
+  */
+ struct hwif_s;
++struct ide_drive_s;
+ typedef int (ide_ack_intr_t)(struct hwif_s *);
++typedef void (ide_xfer_data_t)(struct ide_drive_s *, void *, unsigned int);
+ 
+ #ifndef NO_DMA
+ #define NO_DMA  255
+@@ -311,10 +313,14 @@
+ typedef struct hw_regs_s {
+ 	ide_ioreg_t	io_ports[IDE_NR_PORTS];	/* task file registers */
+ 	int		irq;			/* our irq number */
+-	int		dma;			/* our dma entry */
++	int		dma;			/* our dma number */
+ 	ide_ack_intr_t	*ack_intr;		/* acknowledge interrupt */
++	ide_xfer_data_t	*ide_output_data;	/* write data to i/face */
++	ide_xfer_data_t	*ide_input_data;	/* read data from i/face */
++	ide_xfer_data_t	*atapi_output_bytes;	/* write bytes to i/face */
++	ide_xfer_data_t	*atapi_input_bytes;	/* read bytes from i/face */
+ 	void		*priv;			/* interface specific data */
+-	hwif_chipset_t  chipset;
++	hwif_chipset_t	chipset;
+ 	sata_ioreg_t	sata_scr[SATA_NR_PORTS];
+ 	sata_ioreg_t	sata_misc[SATA_NR_PORTS];
+ } hw_regs_t;
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/linux/l3/algo-bit.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,39 @@
++/*
++ *  linux/include/linux/l3/algo-bit.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ * L3 Bus bit-banging algorithm.  Derived from i2c-algo-bit.h by
++ * Simon G. Vogl.
++ */
++#ifndef L3_ALGO_BIT_H
++#define L3_ALGO_BIT_H 1
++
++#include <linux/l3/l3.h>
++
++struct l3_algo_bit_data {
++	void (*setdat) (void *data, int state);
++	void (*setclk) (void *data, int state);
++	void (*setmode)(void *data, int state);
++	void (*setdir) (void *data, int in);	/* set data direction */
++	int  (*getdat) (void *data);
++
++	void *data;
++
++	/* bus timings (us) */
++	int	data_hold;
++	int	data_setup;
++	int	clock_high;
++	int	mode_hold;
++	int	mode_setup;
++	int	mode;
++};
++
++int l3_bit_add_bus(struct l3_adapter *);
++int l3_bit_del_bus(struct l3_adapter *);
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/linux/l3/l3.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,208 @@
++/*
++ *  linux/include/linux/l3/l3.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License.
++ *
++ * Derived from i2c.h by Simon G. Vogl
++ */
++#ifndef L3_H
++#define L3_H
++
++struct l3_msg {
++	unsigned char	addr;	/* slave address	*/
++	unsigned char	flags;		
++#define L3_M_RD		0x01
++#define L3_M_NOADDR	0x02
++	unsigned short	len;	/* msg length		*/
++	unsigned char	*buf;	/* pointer to msg data	*/
++};
++
++#ifdef __KERNEL__
++
++#include <linux/types.h>
++#include <linux/list.h>
++
++struct l3_client;
++
++struct l3_ops {
++	int	(*open)(struct l3_client *);
++	int	(*command)(struct l3_client *, int cmd, void *arg);
++	void	(*close)(struct l3_client *);
++};
++
++/*
++ * A driver is capable of handling one or more physical devices present on
++ * L3 adapters. This information is used to inform the driver of adapter
++ * events.
++ */
++struct l3_driver {
++	/*
++	 * This name is used to uniquely identify the driver.
++	 * It should be the same as the module name.
++	 */
++	char			name[32];
++
++	/*
++	 * Notifies the driver that a new client wishes to use its
++	 * services.  Note that the module use count will be increased
++	 * prior to this function being called.  In addition, the
++	 * clients driver and adapter fields will have been setup.
++	 */
++	int			(*attach_client)(struct l3_client *);
++
++	/*
++	 * Notifies the driver that the client has finished with its
++	 * services, and any memory that it allocated for this client
++	 * should be cleaned up.  In addition the chip should be
++	 * shut down.
++	 */
++	void			(*detach_client)(struct l3_client *);
++
++	/*
++	 * Possible operations on the driver.
++	 */
++	struct l3_ops		*ops;
++
++	/*
++	 * Module structure, if any.	
++	 */
++	struct module		*owner;
++
++	/*
++	 * drivers list
++	 */
++	struct list_head	drivers;
++};
++
++struct l3_adapter;
++
++struct l3_algorithm {
++	/* textual description */
++	char name[32];
++
++	/* perform bus transactions */
++	int (*xfer)(struct l3_adapter *, struct l3_msg msgs[], int num);
++};
++
++struct semaphore;
++
++/*
++ * l3_adapter is the structure used to identify a physical L3 bus along
++ * with the access algorithms necessary to access it.
++ */
++struct l3_adapter {
++	/*
++	 * This name is used to uniquely identify the adapter.
++	 * It should be the same as the module name.
++	 */
++	char			name[32];
++
++	/*
++	 * the algorithm to access the bus
++	 */
++	struct l3_algorithm	*algo;
++
++	/*
++	 * Algorithm specific data
++	 */
++	void			*algo_data;
++
++	/*
++	 * This may be NULL, or should point to the module struct
++	 */
++	struct module		*owner;
++
++	/*
++	 * private data for the adapter
++	 */
++	void			*data;
++
++	/*
++	 * Our lock.  Unlike the i2c layer, we allow this to be used for
++	 * other stuff, like the i2c layer lock.  Some people implement
++	 * i2c stuff using the same signals as the l3 bus.
++	 */
++	struct semaphore	*lock;
++
++	/*
++	 * List of attached clients.
++	 */
++	struct list_head	clients;
++
++	/*
++	 * List of all adapters.
++	 */
++	struct list_head	adapters;
++};
++
++/*
++ * l3_client identifies a single device (i.e. chip) that is connected to an 
++ * L3 bus. The behaviour is defined by the routines of the driver. This
++ * function is mainly used for lookup & other admin. functions.
++ */
++struct l3_client {
++	struct l3_adapter	*adapter;	/* the adapter we sit on	*/
++	struct l3_driver	*driver;	/* and our access routines	*/
++	void			*driver_data;	/* private driver data		*/
++	struct list_head	__adap;
++};
++
++
++extern int l3_add_adapter(struct l3_adapter *);
++extern int l3_del_adapter(struct l3_adapter *);
++
++extern int l3_add_driver(struct l3_driver *);
++extern int l3_del_driver(struct l3_driver *);
++
++extern int l3_attach_client(struct l3_client *, const char *, const char *);
++extern int l3_detach_client(struct l3_client *);
++
++extern int l3_transfer(struct l3_adapter *, struct l3_msg msgs[], int);
++extern int l3_write(struct l3_client *, int, const char *, int);
++extern int l3_read(struct l3_client *, int, char *, int);
++
++/**
++ * l3_command - send a command to a L3 device driver
++ * @client: registered client structure
++ * @cmd: device driver command
++ * @arg: device driver arguments
++ *
++ * Ask the L3 device driver to perform some function.  Further information
++ * should be sought from the device driver in question.
++ *
++ * Returns negative error code on failure.
++ */
++static inline int l3_command(struct l3_client *clnt, int cmd, void *arg)
++{
++	struct l3_ops *ops = clnt->driver->ops;
++	int ret = -EINVAL;
++
++	if (ops && ops->command)
++		ret = ops->command(clnt, cmd, arg);
++
++	return ret;
++}
++
++static inline int l3_open(struct l3_client *clnt)
++{
++	struct l3_ops *ops = clnt->driver->ops;
++	int ret = 0;
++
++	if (ops && ops->open)
++		ret = ops->open(clnt);
++	return ret;
++}
++
++static inline void l3_close(struct l3_client *clnt)
++{
++	struct l3_ops *ops = clnt->driver->ops;
++	if (ops && ops->close)
++		ops->close(clnt);
++}
++#endif
++
++#endif /* L3_H */
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/linux/l3/uda1341.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,50 @@
++/*
++ *  linux/include/linux/l3/uda1341.h
++ *
++ * Philips UDA1341 mixer device driver
++ *
++ * Copyright (c) 2000 Nicolas Pitre <nico@cam.org>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ */
++
++#define UDA1341_NAME "uda1341"
++
++struct uda1341_cfg {
++	unsigned int fs:16;
++	unsigned int format:3;
++};
++
++#define FMT_I2S		0
++#define FMT_LSB16	1
++#define FMT_LSB18	2
++#define FMT_LSB20	3
++#define FMT_MSB		4
++#define FMT_LSB16MSB	5
++#define FMT_LSB18MSB	6
++#define FMT_LSB20MSB	7
++
++#define L3_UDA1341_CONFIGURE	0x13410001
++
++struct l3_gain {
++	unsigned int	left:8;
++	unsigned int	right:8;
++	unsigned int	unused:8;
++	unsigned int	channel:8;
++};
++
++#define L3_SET_VOLUME		0x13410002
++#define L3_SET_TREBLE		0x13410003
++#define L3_SET_BASS		0x13410004
++#define L3_SET_GAIN		0x13410005
++
++struct l3_agc {
++	unsigned int	level:8;
++	unsigned int	enable:1;
++	unsigned int	attack:7;
++	unsigned int	decay:8;
++	unsigned int	channel:8;
++};
++
++#define L3_INPUT_AGC		0x13410006
+--- linux-2.4.25/include/linux/mm.h~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/include/linux/mm.h	2004-03-31 17:15:09.000000000 +0200
+@@ -685,6 +685,12 @@
+ 
+ extern struct page * vmalloc_to_page(void *addr);
+ 
++#ifndef __arm__
++#define memc_update_addr(x,y,z)
++#define memc_update_mm(x)
++#define memc_clear(x,y)
++#endif
++
+ #endif /* __KERNEL__ */
+ 
+ #endif
+--- linux-2.4.25/include/linux/pci.h~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/include/linux/pci.h	2004-03-31 17:15:09.000000000 +0200
+@@ -410,6 +410,7 @@
+ 
+ 	char		name[90];	/* device name */
+ 	char		slot_name[8];	/* slot name */
++	u32		saved_state[16]; /* for saving the config space before suspend */
+ 	int		active;		/* ISAPnP: device is active */
+ 	int		ro;		/* ISAPnP: read only */
+ 	unsigned short	regs;		/* ISAPnP: supported registers */
+@@ -496,6 +497,8 @@
+ 
+ struct pbus_set_ranges_data
+ {
++	int found_vga:1;
++	int prefetch_valid:1;
+ 	unsigned long io_start, io_end;
+ 	unsigned long mem_start, mem_end;
+ 	unsigned long prefetch_start, prefetch_end;
+@@ -637,6 +640,8 @@
+ int pci_restore_state(struct pci_dev *dev, u32 *buffer);
+ int pci_set_power_state(struct pci_dev *dev, int state);
+ int pci_enable_wake(struct pci_dev *dev, u32 state, int enable);
++int pci_generic_suspend_save(struct pci_dev *pdev, u32 state);
++int pci_generic_resume_restore(struct pci_dev *pdev);
+ 
+ /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
+ 
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/linux/pld/pld_epxa.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,35 @@
++#ifndef __LINUX_EPXAPLD_H
++#define __LINUX_EPXAPLD_H
++
++/*
++ *  linux/drivers/char/pld/epxapld.h
++ *
++ *  Pld driver for Altera EPXA Excalibur devices
++ *
++ *  Copyright 2001 Altera 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
++ *
++ *  $Id$
++ *
++ */
++#define PLD_IOC_MAGIC 'p'
++#if !defined(KERNEL) || defined(CONFIG_PLD_HOTSWAP)
++#define PLD_IOC_ADD_PLD_DEV _IOW(PLD_IOC_MAGIC, 0xa0, struct pldhs_dev_desc)
++#define PLD_IOC_REMOVE_PLD_DEVS _IO(PLD_IOC_MAGIC, 0xa1)
++#define PLD_IOC_SET_INT_MODE _IOW(PLD_IOC_MAGIC, 0xa2, int)
++#endif
++
++#endif
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/linux/pld/pld_hotswap.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,87 @@
++#ifndef __LINUX_PLD_HOTSWAP_H
++#define __LINUX_PLD_HOTSWAP_H
++/*
++ *  linux/drivers/char/pld/pld_hotswap.h
++ *
++ *  Pld driver for Altera EPXA Excalibur devices
++ *
++ *  Copyright 2001 Altera 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
++ *
++ *  $Id$
++ *
++ */
++
++/*
++ * The pld_hotswap ops contain the basic operation required for adding
++ * and removing devices from the system.
++ */
++
++struct pldhs_dev_info{
++       unsigned int size;
++       unsigned short vendor_id;
++       unsigned short product_id;
++       unsigned char fsize;
++       unsigned char nsize;
++       unsigned short pssize;
++       unsigned short cmdsize;
++       unsigned char irq;
++       unsigned char version;
++       unsigned int base_addr;
++       unsigned int reg_size;
++};
++
++struct pldhs_dev_desc{
++       struct pldhs_dev_info* info;
++       char* name;
++       void* data;
++};
++
++#include <linux/pld/pld_epxa.h>
++
++
++#ifdef __KERNEL__
++struct pld_hotswap_ops{
++       struct list_head list;
++       char* name;
++       int (*add_device)(struct pldhs_dev_info *dev_info, void* dev_ps_data);
++       int (*remove_devices)(void);
++       int (*proc_read)(char* buf,char** start,off_t offset,int count,int *eof,void *data);
++};
++
++/*
++ * These functions are called by the device drivers to register functions
++ * which should be called when devices are added and removed
++ */
++extern int pldhs_register_driver(struct pld_hotswap_ops *drv);
++extern int pldhs_unregister_driver(char *driver);
++
++/*
++ * These functions are called by the pld loader to add and remove
++ * device instances from the system. The call the functions regsistered
++ * the the particular deriver for this purpose
++ */
++extern int pldhs_add_device(struct pldhs_dev_info* dev_info,char *drv_name, void* dev_ps_data);
++extern int pldhs_remove_devices(void);
++
++/* Macro for formatting data to appear in the proc/pld file */
++#define PLDHS_READ_PROC_DATA(buf,name,index,base,irq,ps_string) \
++                    sprintf(buf,":%s:%d Base Address, %#lx, IRQ, %d#\n%s\n",\
++                    name,index,base,irq,ps_string)
++
++#endif
++
++#endif
+--- linux-2.4.25/include/linux/serial.h~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/include/linux/serial.h	2004-03-31 17:15:09.000000000 +0200
+@@ -48,7 +48,7 @@
+ 	unsigned char	*iomem_base;
+ 	unsigned short	iomem_reg_shift;
+ 	unsigned int	port_high;
+-	int	reserved[1];
++	unsigned long	iomap_base;	/* cookie passed into ioremap */
+ };
+ 
+ /*
+--- linux-2.4.25/include/linux/serialP.h~2.4.25-vrs2.patch	2002-08-03 02:39:45.000000000 +0200
++++ linux-2.4.25/include/linux/serialP.h	2004-03-31 17:15:09.000000000 +0200
+@@ -157,8 +157,8 @@
+ 	struct pci_dev		*dev;
+ };
+ 
+-extern int pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable);
+-extern int pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable);
++//extern int pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable);
++//extern int pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable);
+ 
+ #ifndef PCI_ANY_ID
+ #define PCI_ANY_ID (~0)
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/include/linux/serial_core.h	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,441 @@
++/*
++ *  linux/drivers/char/serial_core.h
++ *
++ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ *  $Id$
++ */
++
++/*
++ * The type definitions.  These are from Ted Ts'o's serial.h
++ */
++#define PORT_UNKNOWN	0
++#define PORT_8250	1
++#define PORT_16450	2
++#define PORT_16550	3
++#define PORT_16550A	4
++#define PORT_CIRRUS	5
++#define PORT_16650	6
++#define PORT_16650V2	7
++#define PORT_16750	8
++#define PORT_STARTECH	9
++#define PORT_16C950	10
++#define PORT_16654	11
++#define PORT_16850	12
++#define PORT_RSA	13
++#define PORT_NS16550A	14
++#define PORT_MAX_8250	14	/* max port ID */
++
++/*
++ * ARM specific type numbers.  These are not currently guaranteed
++ * to be implemented, and will change in the future.  These are
++ * separate so any additions to the old serial.c that occur before
++ * we are merged can be easily merged here.
++ */
++#define PORT_AMBA	32
++#define PORT_CLPS711X	33
++#define PORT_SA1100	34
++#define PORT_UART00	35
++#define PORT_21285	37
++
++/* Sparc type numbers.  */
++#define PORT_SUNZILOG	38
++#define PORT_SUNSAB	39
++
++/* NEC v850.  */
++#define PORT_NB85E_UART	40
++
++/* NEC PC-9800 */
++#define PORT_8251_PC98	41
++#define PORT_19K_PC98	42
++#define PORT_FIFO_PC98	43
++#define PORT_VFAST_PC98	44
++#define PORT_PC9861	45
++#define PORT_PC9801_101	46
++
++/* DZ */
++#define PORT_DZ		47
++
++#define PORT_OMAHA	48
++#define PORT_AT91RM9200	49
++
++
++#ifdef __KERNEL__
++
++#include <linux/config.h>
++#include <linux/interrupt.h>
++#include <linux/circ_buf.h>
++#include <linux/serial.h>
++#include <linux/spinlock.h>
++
++struct uart_port;
++struct uart_info;
++struct serial_struct;
++
++/*
++ * This structure describes all the operations that can be
++ * done on the physical hardware.
++ */
++struct uart_ops {
++	unsigned int	(*tx_empty)(struct uart_port *);
++	void		(*set_mctrl)(struct uart_port *, unsigned int mctrl);
++	unsigned int	(*get_mctrl)(struct uart_port *);
++	void		(*stop_tx)(struct uart_port *, unsigned int tty_stop);
++	void		(*start_tx)(struct uart_port *, unsigned int tty_start);
++	void		(*send_xchar)(struct uart_port *, char ch);
++	void		(*stop_rx)(struct uart_port *);
++	void		(*enable_ms)(struct uart_port *);
++	void		(*break_ctl)(struct uart_port *, int ctl);
++	int		(*startup)(struct uart_port *);
++	void		(*shutdown)(struct uart_port *);
++	void		(*change_speed)(struct uart_port *, unsigned int cflag, unsigned int iflag, unsigned int quot);
++	void		(*pm)(struct uart_port *, unsigned int state, unsigned int oldstate);
++	int		(*set_wake)(struct uart_port *, unsigned int state);
++
++	/*
++	 * Return a string describing the type of the port
++	 */
++	const char *(*type)(struct uart_port *);
++
++	/*
++	 * Release IO and memory resources used by the port.
++	 * This includes iounmap if necessary.
++	 */
++	void		(*release_port)(struct uart_port *);
++
++	/*
++	 * Request IO and memory resources used by the port.
++	 * This includes iomapping the port if necessary.
++	 */
++	int		(*request_port)(struct uart_port *);
++	void		(*config_port)(struct uart_port *, int);
++	int		(*verify_port)(struct uart_port *, struct serial_struct *);
++	int		(*ioctl)(struct uart_port *, unsigned int, unsigned long);
++};
++
++#define UART_CONFIG_TYPE	(1 << 0)
++#define UART_CONFIG_IRQ		(1 << 1)
++
++struct uart_icount {
++	__u32	cts;
++	__u32	dsr;
++	__u32	rng;
++	__u32	dcd;
++	__u32	rx;
++	__u32	tx;
++	__u32	frame;
++	__u32	overrun;
++	__u32	parity;
++	__u32	brk;
++	__u32	buf_overrun;
++};
++
++struct uart_port {
++	spinlock_t		lock;			/* port lock */
++	unsigned int		iobase;			/* in/out[bwl] */
++	char			*membase;		/* read/write[bwl] */
++	unsigned char		fifosize;		/* tx fifo size */
++	unsigned char		x_char;			/* xon/xoff char */
++	unsigned char		regshift;		/* reg offset shift */
++	unsigned char		iotype;			/* io access style */
++
++#define UPIO_PORT		(0)
++#define UPIO_HUB6		(1)
++#define UPIO_MEM		(2)
++
++	unsigned int		read_status_mask;	/* driver specific */
++	unsigned int		ignore_status_mask;	/* driver specific */
++
++	struct uart_info	*info;			/* pointer to parent info */
++	struct uart_icount	icount;			/* statistics */
++
++	struct console		*cons;			/* struct console, if any */
++	unsigned long		sysrq;			/* sysrq timeout */
++
++	unsigned int		flags;
++
++#define UPF_HUP_NOTIFY		ASYNC_HUP_NOTIFY
++#define UPF_FOURPORT		ASYNC_FOURPORT
++#define UPF_SAK			ASYNC_SAK
++#define UPF_SPLIT_TERMIOS	ASYNC_SPLIT_TERMIOS
++#define UPF_SPD_MASK		(0x1030)
++#define UPF_SPD_HI		(0x0010)
++#define UPF_SPD_VHI		(0x0020)
++#define UPF_SPD_CUST		(0x0030)
++#define UPF_SPD_SHI		(0x1000)
++#define UPF_SPD_WARP		(0x1010)
++#define UPF_SKIP_TEST		ASYNC_SKIP_TEST
++#define UPF_AUTO_IRQ		ASYNC_AUTO_IRQ
++#define UPF_SESSION_LOCKOUT	ASYNC_SESSION_LOCKOUT
++#define UPF_PGRP_LOCKOUT	ASYNCPGRP_LOCKOUT
++#define UPF_CALLOUT_NOHUP	ASYNC_CALLOUT_NOHUP
++#define UPF_HARDPPS_CD		ASYNC_HARDPPS_CD
++				/* 12 */
++#define UPF_LOW_LATENCY		ASYNC_LOW_LATENCY
++#define UPF_BUGGY_UART		ASYNC_BUGGY_UART
++#define UPF_AUTOPROBE		ASYNC_AUTOPROBE
++#define UPF_MAGIC_MULTIPLIER	(1 << 16)
++#define UPF_BOOT_ONLYMCA	ASYNC_BOOT_ONLYMCA
++#define UPF_CONS_FLOW		ASYNC_CONS_FLOW
++#define UPF_SHARE_IRQ		ASYNC_SHARE_IRQ
++#define UPF_BOOT_AUTOCONF	ASYNC_BOOT_AUTOCONF
++#define UPF_RESOURCES		(1 << 30)
++#define UPF_IOREMAP		(1 << 31)
++
++#define UPF_CHANGE_MASK		(0x17fff)
++#define UPF_USR_MASK		(UPF_SPD_MASK|UPF_LOW_LATENCY)
++
++	unsigned int		mctrl;			/* current modem ctrl settings */
++	unsigned int		timeout;		/* character-based timeout */
++	unsigned int		type;			/* port type */
++	struct uart_ops		*ops;
++	unsigned int		uartclk;		/* base uart clock */
++	unsigned int		custom_divisor;
++	unsigned int		irq;			/* irq number */
++	unsigned int		line;			/* port index */
++	unsigned long		mapbase;		/* for ioremap */
++	unsigned char		hub6;			/* this should be in the 8250 driver */
++	unsigned char		unused[7];
++};
++
++/*
++ * This is the state information which is persistent across opens.
++ * The low level driver must not to touch any elements contained
++ * within.
++ */
++struct uart_state {
++	unsigned int		close_delay;
++	unsigned int		closing_wait;
++
++#define USF_CLOSING_WAIT_INF	(0)
++#define USF_CLOSING_WAIT_NONE	(65535)
++
++	struct termios		normal_termios;
++	struct termios		callout_termios;
++
++	int			count;
++	struct uart_info	*info;
++	struct uart_port	*port;
++
++	struct semaphore	sem;
++#ifdef CONFIG_PM
++	struct pm_dev		*pm;
++#endif
++};
++
++#define UART_XMIT_SIZE 1024
++/*
++ * This is the state information which is only valid when the port
++ * is open; it may be freed by the core driver once the device has
++ * been closed.  Either the low level driver or the core can modify
++ * stuff here.
++ */
++struct uart_info {
++	struct tty_struct	*tty;
++	struct circ_buf		xmit;
++	unsigned int		flags;
++
++/*
++ * These are the flags that specific to info->flags, and reflect our
++ * internal state.  They can not be accessed via port->flags.  Low
++ * level drivers must not change these, but may query them instead.
++ */
++#define UIF_CHECK_CD		ASYNC_CHECK_CD
++#define UIF_CTS_FLOW		ASYNC_CTS_FLOW
++#define UIF_CALLOUT_ACTIVE	ASYNC_CALLOUT_ACTIVE
++#define UIF_NORMAL_ACTIVE	ASYNC_NORMAL_ACTIVE
++#define UIF_INITIALIZED		ASYNC_INITIALIZED
++
++	unsigned char		*tmpbuf;
++	struct semaphore	tmpbuf_sem;
++
++	unsigned int		driver_priv;
++	int			blocked_open;
++	pid_t			session;
++	pid_t			pgrp;
++
++	struct tasklet_struct	tlet;
++
++	wait_queue_head_t	open_wait;
++	wait_queue_head_t	delta_msr_wait;
++};
++
++/* number of characters left in xmit buffer before we ask for more */
++#define WAKEUP_CHARS		256
++
++struct module;
++struct tty_driver;
++
++struct uart_driver {
++	struct module		*owner;
++	int			 normal_major;
++	const char		*normal_name;
++	struct tty_driver	*normal_driver;
++	int			 callout_major;
++	const char		*callout_name;
++	struct tty_driver	*callout_driver;
++	struct tty_struct	**table;
++	struct termios		**termios;
++	struct termios		**termios_locked;
++	int			 minor;
++	int			 nr;
++	struct console		*cons;
++
++	/*
++	 * these are private; the low level driver should not
++	 * touch these; they should be initialised to NULL
++	 */
++	struct uart_state	*state;
++};
++
++void uart_write_wakeup(struct uart_port *port);
++struct uart_port *uart_get_console(struct uart_port *ports, int nr,
++				   struct console *c);
++void uart_parse_options(char *options, int *baud, int *parity, int *bits,
++			int *flow);
++int uart_set_options(struct uart_port *port, struct console *co, int baud,
++		     int parity, int bits, int flow);
++
++/*
++ * Port/driver registration/removal
++ */
++int uart_register_driver(struct uart_driver *uart);
++void uart_unregister_driver(struct uart_driver *uart);
++void uart_unregister_port(struct uart_driver *reg, int line);
++int uart_register_port(struct uart_driver *reg, struct uart_port *port);
++int uart_add_one_port(struct uart_driver *reg, struct uart_port *port);
++int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port);
++
++#define uart_circ_empty(circ)		((circ)->head == (circ)->tail)
++#define uart_circ_clear(circ)		((circ)->head = (circ)->tail = 0)
++
++#define uart_circ_chars_pending(circ)	\
++	(CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))
++
++#define uart_circ_chars_free(circ)	\
++	(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))
++
++#define uart_tx_stopped(port)		\
++	((port)->info->tty->stopped || (port)->info->tty->hw_stopped)
++
++/*
++ * The following are helper functions for the low level drivers.
++ */
++#ifdef SUPPORT_SYSRQ
++static inline int
++uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
++		       struct pt_regs *regs)
++{
++	if (port->sysrq) {
++		if (ch && time_before(jiffies, port->sysrq)) {
++			handle_sysrq(ch, regs, NULL, NULL);
++			port->sysrq = 0;
++			return 1;
++		}
++		port->sysrq = 0;
++	}
++	return 0;
++}
++#else
++#define uart_handle_sysrq_char(port,ch,regs)	(0)
++#endif
++
++/*
++ * We do the SysRQ and SAK checking like this...
++ */
++static inline int uart_handle_break(struct uart_port *port)
++{
++	struct uart_info *info = port->info;
++#ifdef SUPPORT_SYSRQ
++	if (port->cons && port->cons->index == port->line) {
++		if (!port->sysrq) {
++			port->sysrq = jiffies + HZ*5;
++			return 1;
++		}
++		port->sysrq = 0;
++	}
++#endif
++	if (port->flags & UPF_SAK)
++		do_SAK(info->tty);
++	return 0;
++}
++
++/**
++ *	uart_handle_dcd_change - handle a change of carrier detect state
++ *	@port: uart_port structure for the open port
++ *	@status: new carrier detect status, nonzero if active
++ */
++static inline void
++uart_handle_dcd_change(struct uart_port *port, unsigned int status)
++{
++	struct uart_info *info = port->info;
++
++	port->icount.dcd++;
++
++#ifdef CONFIG_HARD_PPS
++	if ((port->flags & UPF_HARDPPS_CD) && status)
++		hardpps();
++#endif
++
++	if (info->flags & UIF_CHECK_CD) {
++		if (status)
++			wake_up_interruptible(&info->open_wait);
++		else if (!((info->flags & UIF_CALLOUT_ACTIVE) &&
++			   (port->flags & UPF_CALLOUT_NOHUP))) {
++			if (info->tty)
++				tty_hangup(info->tty);
++		}
++	}
++}
++
++/**
++ *	uart_handle_cts_change - handle a change of clear-to-send state
++ *	@port: uart_port structure for the open port
++ *	@status: new clear to send status, nonzero if active
++ */
++static inline void
++uart_handle_cts_change(struct uart_port *port, unsigned int status)
++{
++	struct uart_info *info = port->info;
++	struct tty_struct *tty = info->tty;
++
++	port->icount.cts++;
++
++	if (info->flags & UIF_CTS_FLOW) {
++		if (tty->hw_stopped) {
++			if (status) {
++				tty->hw_stopped = 0;
++				port->ops->start_tx(port, 0);
++				uart_write_wakeup(port);
++			}
++		} else {
++			if (!status) {
++				tty->hw_stopped = 1;
++				port->ops->stop_tx(port, 0);
++			}
++		}
++	}
++}
++
++/*
++ *	UART_ENABLE_MS - determine if port should enable modem status irqs
++ */
++#define UART_ENABLE_MS(port,cflag)	((port)->flags & UPF_HARDPPS_CD || \
++					 (cflag) & CRTSCTS || \
++					 !((cflag) & CLOCAL))
++
++#endif
+--- linux-2.4.25/include/linux/serial_reg.h~2.4.25-vrs2.patch	2001-05-02 01:05:00.000000000 +0200
++++ linux-2.4.25/include/linux/serial_reg.h	2004-03-31 17:15:09.000000000 +0200
+@@ -121,6 +121,7 @@
+ /*
+  * These are the definitions for the Modem Control Register
+  */
++#define UART_MCR_AFE	0x20	/* Enable auto-RTS/CTS (TI16C750) */
+ #define UART_MCR_LOOP	0x10	/* Enable loopback test mode */
+ #define UART_MCR_OUT2	0x08	/* Out2 complement */
+ #define UART_MCR_OUT1	0x04	/* Out1 complement */
+--- linux-2.4.25/include/linux/zlib.h~2.4.25-vrs2.patch	2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.25/include/linux/zlib.h	2004-03-31 17:15:09.000000000 +0200
+@@ -31,7 +31,7 @@
+ #ifndef _ZLIB_H
+ #define _ZLIB_H
+ 
+-#include <linux/zconf.h>
++#include "zconf.h"
+ 
+ #ifdef __cplusplus
+ extern "C" {
+--- linux-2.4.25/init/do_mounts.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/init/do_mounts.c	2004-03-31 17:15:09.000000000 +0200
+@@ -888,7 +888,7 @@
+  */
+ void prepare_namespace(void)
+ {
+-	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
++	int is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR || MAJOR(ROOT_DEV) == 31;
+ #ifdef CONFIG_ALL_PPC
+ 	extern void arch_discover_root(void);
+ 	arch_discover_root();
+@@ -951,6 +951,7 @@
+ static unsigned inptr;   /* index of next byte to be processed in inbuf */
+ static unsigned outcnt;  /* bytes in output buffer */
+ static int exit_code;
++static int unzip_error;
+ static long bytes_out;
+ static int crd_infd, crd_outfd;
+ 
+@@ -998,13 +999,17 @@
+ /* ===========================================================================
+  * Fill the input buffer. This is called only when the buffer is empty
+  * and at least one byte is really needed.
++ * Returning -1 does not guarantee that gunzip() will ever return.
+  */
+ static int __init fill_inbuf(void)
+ {
+ 	if (exit_code) return -1;
+ 	
+ 	insize = read(crd_infd, inbuf, INBUFSIZ);
+-	if (insize == 0) return -1;
++	if (insize == 0) {
++		error("RAMDISK: ran out of compressed data\n");
++		return -1;
++	}
+ 
+ 	inptr = 1;
+ 
+@@ -1018,10 +1023,15 @@
+ static void __init flush_window(void)
+ {
+     ulg c = crc;         /* temporary variable */
+-    unsigned n;
++    unsigned n, written;
+     uch *in, ch;
+     
+-    write(crd_outfd, window, outcnt);
++    written = write(crd_outfd, window, outcnt);
++    if (written != outcnt && unzip_error == 0) {
++	printk(KERN_ERR "RAMDISK: incomplete write (%d != %d), "
++	       "only wrote %ld\n", written, outcnt, bytes_out);
++	unzip_error = 1;
++    }
+     in = window;
+     for (n = 0; n < outcnt; n++) {
+ 	    ch = *in++;
+@@ -1036,6 +1046,7 @@
+ {
+ 	printk(KERN_ERR "%s", x);
+ 	exit_code = 1;
++	unzip_error = 1;
+ }
+ 
+ static int __init crd_load(int in_fd, int out_fd)
+@@ -1064,6 +1075,8 @@
+ 	}
+ 	makecrc();
+ 	result = gunzip();
++	if (unzip_error)
++		result = 1;
+ 	kfree(inbuf);
+ 	kfree(window);
+ 	return result;
+--- linux-2.4.25/kernel/Makefile~2.4.25-vrs2.patch	2001-09-17 06:22:40.000000000 +0200
++++ linux-2.4.25/kernel/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -9,16 +9,19 @@
+ 
+ O_TARGET := kernel.o
+ 
+-export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o printk.o
++export-objs = signal.o sys.o kmod.o context.o ksyms.o pm.o exec_domain.o \
++	      printk.o fork.o cpufreq.o
+ 
+-obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
++obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
+ 	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
+ 	    sysctl.o acct.o capability.o ptrace.o timer.o user.o \
+ 	    signal.o sys.o kmod.o context.o
+ 
++obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
+ obj-$(CONFIG_UID16) += uid16.o
+ obj-$(CONFIG_MODULES) += ksyms.o
+ obj-$(CONFIG_PM) += pm.o
++obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+ 
+ ifneq ($(CONFIG_IA64),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/kernel/cpufreq.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,536 @@
++/*
++ *  linux/kernel/cpufreq.c
++ *
++ *  Copyright (C) 2001 Russell King
++ *
++ *  $Id$
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * CPU speed changing core functionality.  We provide the following
++ * services to the system:
++ *  - notifier lists to inform other code of the freq change both
++ *    before and after the freq change.
++ *  - the ability to change the freq speed
++ *
++ * ** You'll need to add CTL_CPU = 10 to include/linux/sysctl.h if
++ * it's not already present.
++ *
++ * When this appears in the kernel, the sysctl enums will move to
++ * include/linux/sysctl.h
++ */
++#include <linux/config.h>
++#include <linux/types.h>
++#include <linux/module.h>
++#include <linux/notifier.h>
++#include <linux/cpufreq.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/fs.h>
++#include <linux/sysctl.h>
++
++#include <asm/semaphore.h>
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <linux/interrupt.h>	/* requires system.h */
++
++/*
++ * This list is for kernel code that needs to handle
++ * changes to devices when the CPU clock speed changes.
++ */
++static struct notifier_block *cpufreq_notifier_list;
++static DECLARE_MUTEX_LOCKED(cpufreq_sem);
++static unsigned long cpufreq_ref_loops;
++static unsigned int cpufreq_ref_freq;
++static int cpufreq_initialised;
++static unsigned int (*cpufreq_validatespeed)(unsigned int);
++static void (*cpufreq_setspeed)(unsigned int);
++
++#ifndef CONFIG_SMP
++static unsigned int __cpufreq_max;
++static unsigned int __cpufreq_min;
++static unsigned int __cpufreq_cur;
++#endif
++
++static unsigned long scale(unsigned long ref, u_int div, u_int mult)
++{
++	unsigned long new_jiffy_l, new_jiffy_h;
++
++	/*
++	 * Recalculate loops_per_jiffy.  We do it this way to
++	 * avoid math overflow on 32-bit machines.  Maybe we
++	 * should make this architecture dependent?  If you have
++	 * a better way of doing this, please replace!
++	 *
++	 *    new = old * mult / div
++	 */
++	new_jiffy_h = ref / div;
++	new_jiffy_l = (ref % div) / 100;
++	new_jiffy_h *= mult;
++	new_jiffy_l = new_jiffy_l * mult / div;
++
++	return new_jiffy_h + new_jiffy_l * 100;
++}
++
++/*
++ * cpufreq_max command line parameter.  Use:
++ *  cpufreq=59000-221000
++ * to set the CPU frequency to 59 to 221MHz.
++ */
++static int __init cpufreq_setup(char *str)
++{
++	unsigned int min, max;
++	int i;
++
++	min = 0;
++	max = simple_strtoul(str, &str, 0);
++	if (*str == '-') {
++		min = max;
++		max = simple_strtoul(str + 1, NULL, 0);
++	}
++
++	for (i = 0; i < smp_num_cpus; i++) {
++		cpufreq_max(i) = max;
++		cpufreq_min(i) = min;
++	}
++
++	return 1;
++}
++
++__setup("cpufreq=", cpufreq_setup);
++
++/**
++ *	cpufreq_register_notifier - register a driver with cpufreq
++ *	@nb: notifier function to register
++ *
++ *	Add a driver to the list of drivers that which to be notified about
++ *	CPU clock rate changes. The driver will be called three times on
++ *	clock change.
++ *
++ *	This function may sleep, and has the same return conditions as
++ *	notifier_chain_register.
++ */
++int cpufreq_register_notifier(struct notifier_block *nb)
++{
++	int ret;
++
++	down(&cpufreq_sem);
++	ret = notifier_chain_register(&cpufreq_notifier_list, nb);
++	up(&cpufreq_sem);
++
++	return ret;
++}
++
++EXPORT_SYMBOL(cpufreq_register_notifier);
++
++/**
++ *	cpufreq_unregister_notifier - unregister a driver with cpufreq
++ *	@nb: notifier block to be unregistered
++ *
++ *	Remove a driver from the CPU frequency notifier lists.
++ *
++ *	This function may sleep, and has the same return conditions as
++ *	notifier_chain_unregister.
++ */
++int cpufreq_unregister_notifier(struct notifier_block *nb)
++{
++	int ret;
++
++	down(&cpufreq_sem);
++	ret = notifier_chain_unregister(&cpufreq_notifier_list, nb);
++	up(&cpufreq_sem);
++
++	return ret;
++}
++
++EXPORT_SYMBOL(cpufreq_unregister_notifier);
++
++/*
++ * This notifier alters the system "loops_per_jiffy" for the clock
++ * speed change.  We ignore CPUFREQ_MINMAX here.
++ */
++static void adjust_jiffies(unsigned long val, struct cpufreq_info *ci)
++{
++	if ((val == CPUFREQ_PRECHANGE  && ci->old_freq < ci->new_freq) ||
++	    (val == CPUFREQ_POSTCHANGE && ci->old_freq > ci->new_freq))
++	    	loops_per_jiffy = scale(cpufreq_ref_loops, cpufreq_ref_freq,
++					ci->new_freq);
++}
++
++#ifdef CONFIG_PM
++/**
++ *	cpufreq_restore - restore the CPU clock frequency after resume
++ *
++ *	Restore the CPU clock frequency so that our idea of the current
++ *	frequency reflects the actual hardware.
++ */
++int cpufreq_restore(void)
++{
++	unsigned long old_cpus;
++	int cpu = smp_processor_id();
++	int ret;
++
++	if (!cpufreq_initialised)
++		panic("cpufreq_restore() called before initialisation!");
++	if (in_interrupt())
++		panic("cpufreq_restore() called from interrupt context!");
++
++	/*
++	 * Bind to the current CPU.
++	 */
++	old_cpus = current->cpus_allowed;
++	current->cpus_allowed = 1UL << cpu_logical_map(cpu);
++
++	down(&cpufreq_sem);
++
++	ret = -ENXIO;
++	if (cpufreq_setspeed) {
++		cpufreq_setspeed(cpufreq_current(cpu));
++		ret = 0;
++	}
++
++	up(&cpufreq_sem);
++
++	current->cpus_allowed = old_cpus;
++
++	return ret;
++}
++
++EXPORT_SYMBOL_GPL(cpufreq_restore);
++#endif
++
++/**
++ *	cpu_setfreq - change the CPU clock frequency.
++ *	@freq: frequency (in kHz) at which we should run.
++ *
++ *	Set the CPU clock frequency, informing all registered users of
++ *	the change. We bound the frequency according to the cpufreq_max
++ *	command line parameter, and the parameters the registered users
++ *	will allow.
++ *
++ *	This function must be called from process context, and on the
++ *	cpu that we wish to change the frequency of.
++ *
++ *	We return 0 if successful. (we are currently always successful).
++ */
++int cpufreq_set(unsigned int freq)
++{
++	unsigned long old_cpus;
++	struct cpufreq_info clkinfo;
++	struct cpufreq_minmax minmax;
++	int cpu = smp_processor_id();
++	int ret;
++
++	if (!cpufreq_initialised)
++		panic("cpufreq_set() called before initialisation!");
++	if (in_interrupt())
++		panic("cpufreq_set() called from interrupt context!");
++
++	/*
++	 * Bind to the current CPU.
++	 */
++	old_cpus = current->cpus_allowed;
++	current->cpus_allowed = 1UL << cpu_logical_map(cpu);
++
++	down(&cpufreq_sem);
++	ret = -ENXIO;
++	if (!cpufreq_setspeed || !cpufreq_validatespeed)
++		goto out;
++
++	/*
++	 * Don't allow the CPU to be clocked over the limit.
++	 */
++	minmax.min_freq = cpufreq_min(cpu);
++	minmax.max_freq = cpufreq_max(cpu);
++	minmax.cur_freq = cpufreq_current(cpu);
++	minmax.new_freq = freq;
++
++	/*
++	 * Find out what the registered devices will currently tolerate,
++	 * and limit the requested clock rate to these values.  Drivers
++	 * must not rely on the 'new_freq' value - it is only a guide.
++	 */
++	notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_MINMAX, &minmax);
++	if (freq < minmax.min_freq)
++		freq = minmax.min_freq;
++	if (freq > minmax.max_freq)
++		freq = minmax.max_freq;
++
++	/*
++	 * Ask the CPU specific code to validate the speed.  If the speed
++	 * is not acceptable, make it acceptable.  Current policy is to
++	 * round the frequency down to the value the processor actually
++	 * supports.
++	 */
++	freq = cpufreq_validatespeed(freq);
++
++	if (cpufreq_current(cpu) != freq) {
++		clkinfo.old_freq = cpufreq_current(cpu);
++		clkinfo.new_freq = freq;
++
++		notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_PRECHANGE,
++				    &clkinfo);
++
++		adjust_jiffies(CPUFREQ_PRECHANGE, &clkinfo);
++
++		/*
++		 * Actually set the CPU frequency.
++		 */
++		cpufreq_setspeed(freq);
++		cpufreq_current(cpu) = freq;
++		adjust_jiffies(CPUFREQ_POSTCHANGE, &clkinfo);
++
++		notifier_call_chain(&cpufreq_notifier_list, CPUFREQ_POSTCHANGE,
++				    &clkinfo);
++	}
++
++	ret = 0;
++
++ out:
++	up(&cpufreq_sem);
++
++	current->cpus_allowed = old_cpus;
++
++	return ret;
++}
++
++EXPORT_SYMBOL_GPL(cpufreq_set);
++
++/**
++ *	cpufreq_setmax - set the CPU to maximum frequency
++ *
++ *	Sets the CPU this function is executed on to maximum frequency.
++ */
++int cpufreq_setmax(void)
++{
++	return cpufreq_set(cpufreq_max(smp_processor_id()));
++}
++
++EXPORT_SYMBOL_GPL(cpufreq_setmax);
++
++/**
++ *	cpufreq_get - return the current CPU clock frequency in 1kHz
++ *	@cpu: cpu number to obtain frequency for
++ *
++ *	Returns the specified CPUs frequency in kHz.
++ */
++unsigned int cpufreq_get(int cpu)
++{
++	if (!cpufreq_initialised)
++		panic("cpufreq_get() called before initialisation!");
++	return cpufreq_current(cpu);
++}
++
++EXPORT_SYMBOL(cpufreq_get);
++
++#ifdef CONFIG_SYSCTL
++
++static int
++cpufreq_procctl(ctl_table *ctl, int write, struct file *filp,
++		void *buffer, size_t *lenp)
++{
++	char buf[16], *p;
++	int cpu = 0, len, left = *lenp;
++
++	if (!left || (filp->f_pos && !write)) {
++		*lenp = 0;
++		return 0;
++	}
++
++	if (write) {
++		unsigned int freq;
++
++		len = left;
++		if (left > sizeof(buf))
++			left = sizeof(buf);
++		if (copy_from_user(buf, buffer, left))
++			return -EFAULT;
++		buf[sizeof(buf) - 1] = '\0';
++
++		freq = simple_strtoul(buf, &p, 0);
++		cpufreq_set(freq);
++	} else {
++		len = sprintf(buf, "%d\n", cpufreq_get(cpu));
++		if (len > left)
++			len = left;
++		if (copy_to_user(buffer, buf, len))
++			return -EFAULT;
++	}
++
++	*lenp = len;
++	filp->f_pos += len;
++	return 0;
++}
++
++static int
++cpufreq_sysctl(ctl_table *table, int *name, int nlen,
++	       void *oldval, size_t *oldlenp,
++	       void *newval, size_t newlen, void **context)
++{
++	int cpu = 0;
++
++	if (oldval && oldlenp) {
++		size_t oldlen;
++
++		if (get_user(oldlen, oldlenp))
++			return -EFAULT;
++
++		if (oldlen != sizeof(unsigned int))
++			return -EINVAL;
++
++		if (put_user(cpufreq_get(cpu), (unsigned int *)oldval) ||
++		    put_user(sizeof(unsigned int), oldlenp))
++			return -EFAULT;
++	}
++	if (newval && newlen) {
++		unsigned int freq;
++
++		if (newlen != sizeof(unsigned int))
++			return -EINVAL;
++
++		if (get_user(freq, (unsigned int *)newval))
++			return -EFAULT;
++
++		cpufreq_set(freq);
++	}
++	return 1;
++}
++
++enum {
++	CPU_NR_FREQ_MAX = 1,
++	CPU_NR_FREQ_MIN = 2,
++	CPU_NR_FREQ = 3
++};
++
++static ctl_table ctl_cpu_vars[4] = {
++	{
++		ctl_name:	CPU_NR_FREQ_MAX,
++		procname:	"speed-max",
++		data:		&cpufreq_max(0),
++		maxlen:		sizeof(cpufreq_max(0)),
++		mode:		0444,
++		proc_handler:	proc_dointvec,
++	},
++	{
++		ctl_name:	CPU_NR_FREQ_MIN,
++		procname:	"speed-min",
++		data:		&cpufreq_min(0),
++		maxlen:		sizeof(cpufreq_min(0)),
++		mode:		0444,
++		proc_handler:	proc_dointvec,
++	},
++	{
++		ctl_name:	CPU_NR_FREQ,
++		procname:	"speed",
++		mode:		0644,
++		proc_handler:	cpufreq_procctl,
++		strategy:	cpufreq_sysctl,
++	},
++	{
++		ctl_name:	0,
++	}
++};
++
++enum {
++	CPU_NR = 1,
++};
++
++static ctl_table ctl_cpu_nr[2] = {
++	{
++		ctl_name:	CPU_NR,
++		procname:	"0",
++		mode:		0555,
++		child:		ctl_cpu_vars,
++	},
++	{
++		ctl_name:	0,
++	}
++};
++
++static ctl_table ctl_cpu[2] = {
++	{
++		ctl_name:	CTL_CPU,
++		procname:	"cpu",
++		mode:		0555,
++		child:		ctl_cpu_nr,
++	},
++	{
++		ctl_name:	0,
++	}
++};
++
++static inline void cpufreq_sysctl_init(void)
++{
++	register_sysctl_table(ctl_cpu, 0);
++}
++
++#else
++#define cpufreq_sysctl_init()
++#endif
++
++/**
++ *	cpufreq_setfunctions - Set CPU clock functions
++ *	@validate: pointer to validation function
++ *	@setspeed: pointer to setspeed function
++ */
++void
++cpufreq_setfunctions(unsigned int (*validate)(unsigned int),
++		     void (*setspeed)(unsigned int))
++{
++	down(&cpufreq_sem);
++	cpufreq_validatespeed = validate;
++	cpufreq_setspeed = setspeed;
++	up(&cpufreq_sem);
++}
++
++EXPORT_SYMBOL_GPL(cpufreq_setfunctions);
++
++/**
++ *	cpufreq_init - Initialise the cpufreq core
++ *	@freq: current CPU clock speed.
++ *	@min_freq: minimum CPU clock speed.
++ *	@max_freq: maximum CPU clock speed.
++ *
++ *	Initialise the cpufreq core. If the cpufreq_max command line
++ *	parameter has not been specified, we set the maximum clock rate
++ *	to the current CPU clock rate.
++ */
++void cpufreq_init(unsigned int freq,
++		  unsigned int min_freq,
++		  unsigned int max_freq)
++{
++	/*
++	 * If the user doesn't tell us their maximum frequency,
++	 * or if it is invalid, use the values determined 
++	 * by the cpufreq-arch-specific initialization functions.
++	 * The validatespeed code is responsible for limiting
++	 * this further.
++	 */
++	if (max_freq && ((cpufreq_max(0) == 0) || (cpufreq_max(0) > max_freq)))
++		cpufreq_max(0) = max_freq;
++	if (min_freq && ((cpufreq_min(0) == 0) || (cpufreq_min(0) < min_freq)))
++		cpufreq_min(0) = min_freq;
++
++	if (cpufreq_max(0) == 0)
++		cpufreq_max(0) = freq;
++
++	printk(KERN_INFO "CPU clock: %d.%03d MHz (%d.%03d-%d.%03d MHz)\n",
++		freq / 1000, freq % 1000,
++		cpufreq_min(0) / 1000, cpufreq_min(0) % 1000,
++		cpufreq_max(0) / 1000, cpufreq_max(0) % 1000);
++
++	cpufreq_ref_loops = loops_per_jiffy;
++	cpufreq_ref_freq = freq;
++	cpufreq_current(smp_processor_id()) = freq;
++
++	cpufreq_initialised = 1;
++	up(&cpufreq_sem);
++
++	cpufreq_sysctl_init();
++}
++
++EXPORT_SYMBOL_GPL(cpufreq_init);
+--- linux-2.4.25/kernel/exit.c~2.4.25-vrs2.patch	2002-11-29 00:53:15.000000000 +0100
++++ linux-2.4.25/kernel/exit.c	2004-03-31 17:15:09.000000000 +0200
+@@ -587,7 +587,7 @@
+ 	return retval;
+ }
+ 
+-#if !defined(__alpha__) && !defined(__ia64__)
++#if !defined(__alpha__) && !defined(__ia64__) && !defined(__arm__)
+ 
+ /*
+  * sys_waitpid() remains for compatibility. waitpid() should be
+--- linux-2.4.25/kernel/fork.c~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/kernel/fork.c	2004-03-31 17:15:09.000000000 +0200
+@@ -75,7 +75,11 @@
+ 	 * value: the thread structures can take up at most half
+ 	 * of memory.
+ 	 */
++#if THREAD_SIZE > PAGE_SIZE
+ 	max_threads = mempages / (THREAD_SIZE/PAGE_SIZE) / 8;
++#else
++	max_threads = (mempages * PAGE_SIZE) / (8 * THREAD_SIZE);
++#endif
+ 
+ 	init_task.rlim[RLIMIT_NPROC].rlim_cur = max_threads/2;
+ 	init_task.rlim[RLIMIT_NPROC].rlim_max = max_threads/2;
+@@ -220,6 +224,7 @@
+ 
+ fail_nomem:
+ 	flush_tlb_mm(current->mm);
++	memc_update_mm(mm);
+ 	return retval;
+ }
+ 
+--- linux-2.4.25/kernel/ksyms.c~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/kernel/ksyms.c	2004-03-31 17:15:09.000000000 +0200
+@@ -345,6 +345,7 @@
+ 
+ /* tty routines */
+ EXPORT_SYMBOL(tty_hangup);
++EXPORT_SYMBOL(tty_vhangup);
+ EXPORT_SYMBOL(tty_wait_until_sent);
+ EXPORT_SYMBOL(tty_check_change);
+ EXPORT_SYMBOL(tty_hung_up_p);
+@@ -439,9 +440,11 @@
+ EXPORT_SYMBOL(kiobuf_wait_for_io);
+ 
+ /* dma handling */
++#ifdef CONFIG_GENERIC_ISA_DMA
+ EXPORT_SYMBOL(request_dma);
+ EXPORT_SYMBOL(free_dma);
+ EXPORT_SYMBOL(dma_spin_lock);
++#endif
+ #ifdef HAVE_DISABLE_HLT
+ EXPORT_SYMBOL(disable_hlt);
+ EXPORT_SYMBOL(enable_hlt);
+--- linux-2.4.25/kernel/signal.c~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/kernel/signal.c	2004-03-31 17:15:09.000000000 +0200
+@@ -778,8 +778,8 @@
+ 	info.si_uid = tsk->uid;
+ 
+ 	/* FIXME: find out whether or not this is supposed to be c*time. */
+-	info.si_utime = tsk->times.tms_utime;
+-	info.si_stime = tsk->times.tms_stime;
++	info.si_utime = hz_to_std(tsk->times.tms_utime);
++	info.si_stime = hz_to_std(tsk->times.tms_stime);
+ 
+ 	status = tsk->exit_code & 0x7f;
+ 	why = SI_KERNEL;	/* shouldn't happen */
+@@ -1277,7 +1277,7 @@
+ #endif /* __sparc__ */
+ #endif
+ 
+-#if !defined(__alpha__) && !defined(__ia64__)
++#if !defined(__alpha__) && !defined(__ia64__) && !defined(__arm__)
+ /*
+  * For backwards compatibility.  Functionality superseded by sigprocmask.
+  */
+@@ -1305,7 +1305,8 @@
+ }
+ #endif /* !defined(__alpha__) */
+ 
+-#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__)
++#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips__) && \
++    !defined(__arm__)
+ /*
+  * For backwards compatibility.  Functionality superseded by sigaction.
+  */
+@@ -1322,4 +1323,4 @@
+ 
+ 	return ret ? ret : (unsigned long)old_sa.sa.sa_handler;
+ }
+-#endif /* !alpha && !__ia64__ && !defined(__mips__) */
++#endif /* !alpha && !__ia64__ && !defined(__mips__) && !defined(__arm__) */
+--- linux-2.4.25/kernel/sys.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/kernel/sys.c	2004-03-31 17:15:09.000000000 +0200
+@@ -801,16 +801,23 @@
+ 
+ asmlinkage long sys_times(struct tms * tbuf)
+ {
++	struct tms temp;
++
+ 	/*
+ 	 *	In the SMP world we might just be unlucky and have one of
+ 	 *	the times increment as we use it. Since the value is an
+ 	 *	atomically safe type this is just fine. Conceptually its
+ 	 *	as if the syscall took an instant longer to occur.
+ 	 */
+-	if (tbuf)
+-		if (copy_to_user(tbuf, &current->times, sizeof(struct tms)))
++	if (tbuf) {
++		temp.tms_utime = hz_to_std(current->times.tms_utime);
++		temp.tms_stime = hz_to_std(current->times.tms_stime);
++		temp.tms_cutime = hz_to_std(current->times.tms_cutime);
++		temp.tms_cstime = hz_to_std(current->times.tms_cstime);
++		if (copy_to_user(tbuf, &temp, sizeof(struct tms)))
+ 			return -EFAULT;
+-	return jiffies;
++	}
++	return hz_to_std(jiffies);
+ }
+ 
+ /*
+--- linux-2.4.25/lib/string.c~2.4.25-vrs2.patch	2002-08-03 02:39:46.000000000 +0200
++++ linux-2.4.25/lib/string.c	2004-03-31 17:15:09.000000000 +0200
+@@ -188,10 +188,10 @@
+  */
+ char * strchr(const char * s, int c)
+ {
+-	for(; *s != (char) c; ++s)
+-		if (*s == '\0')
+-			return NULL;
+-	return (char *) s;
++	for(; *s != '\0'; ++s)
++		if (*s == (char) c)
++			return (char *) s;
++	return NULL;
+ }
+ #endif
+ 
+--- linux-2.4.25/mm/Makefile~2.4.25-vrs2.patch	2002-08-03 02:39:46.000000000 +0200
++++ linux-2.4.25/mm/Makefile	2004-03-31 17:15:09.000000000 +0200
+@@ -18,4 +18,5 @@
+ 
+ obj-$(CONFIG_HIGHMEM) += highmem.o
+ 
++obj-y += debug.o
+ include $(TOPDIR)/Rules.make
+--- /dev/null	2003-09-23 19:59:22.000000000 +0200
++++ linux-2.4.25/mm/debug.c	2004-03-31 17:15:09.000000000 +0200
+@@ -0,0 +1,159 @@
++/*
++ * linux/mm/debug.c
++ *
++ *  Copyright (C) 2001 Russell King.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Dump out page information on SysRQ-G, and provide show_page_info()
++ *
++ *  You are advised to use a serial console with this patch - it
++ *  saturates a 38400baud link for 1 minute on a 32MB machine.
++ */
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/pagemap.h>
++#include <linux/sysrq.h>
++#include <linux/init.h>
++
++/*
++ * We print out the following information for each page in the system:
++ *	address: use count, age, mapping, [RSsr] rD [acd]
++ *
++ * The flags are:
++ *	R - reserved
++ *	S - in swapcache
++ *	s - slab page
++ *
++ *	r - referenced
++ *	D - dirty
++ *
++ *	a - active page
++ */
++static void page_detail(struct page *page)
++{
++	if (!page)
++		return;
++
++	printk("%p: %2d %p [%c%c%c] %c%c [%c]\n",
++			page_address(page),
++			page_count(page),
++			page->mapping,
++
++			PageReserved(page) ? 'R' : '-',
++			PageSwapCache(page) ? 'S' : '-',
++			PageSlab(page) ? 's' : '-',
++
++			PageReferenced(page) ? 'r' : '-',
++			PageDirty(page) ? 'D' : '-',
++
++			PageActive(page) ? 'a' : '-');
++}
++
++/*
++ * This version collects statistics
++ */
++static int anon_pages, slab_pages, resvd_pages, unused_pages;
++
++static void page_statistics(struct page *page)
++{
++	if (page) {
++		if (PageReserved(page))
++			resvd_pages++;
++		else if (PageSlab(page))
++			slab_pages++;
++		else if (!page_count(page))
++			unused_pages ++;
++		else if (!page->mapping)
++			anon_pages ++;
++		return;
++	}
++
++	printk("  anon: %d, slab: %d, reserved: %d, free: %d\n",
++		anon_pages, slab_pages, resvd_pages, unused_pages);
++}
++
++static void show_zone_info(zone_t *zone, void (*fn)(struct page *))
++{
++	int i;
++
++	printk("  total %ld, free %ld\n",
++		zone->size, zone->free_pages);
++
++	anon_pages    = 0;
++	slab_pages    = 0;
++	resvd_pages   = 0;
++	unused_pages  = 0;
++
++	for (i = 0; i < zone->size; i++) {
++		struct page *page = zone->zone_mem_map + i;
++
++		fn(page);
++	}
++
++	fn(NULL);
++}
++
++static void show_node_info(pg_data_t *pg, void (*fn)(struct page *))
++{
++	int type;
++
++	for (type = 0; type < MAX_NR_ZONES; type++) {
++		zone_t *zone = pg->node_zones + type;
++
++		if (zone->size == 0)
++			continue;
++
++		printk("----- Zone %d ------\n", type);
++
++		show_zone_info(zone, fn);
++	}
++}
++
++static void __show_page_info(void (*fn)(struct page *))
++{
++	pg_data_t *pg;
++	int pgdat = 0;
++
++	for (pg = pgdat_list; pg; pg = pg->node_next) {
++
++		printk("===== Node %d =====\n", pgdat++);
++
++		show_node_info(pg, fn);
++	}	
++}
++
++void show_page_info(void)
++{
++	__show_page_info(page_detail);
++}
++
++static void
++show_pg_info(int key, struct pt_regs *regs, struct kbd_struct *kd,
++	     struct tty_struct *tty)
++{
++	void (*fn)(struct page *);
++	show_mem();
++	if (key == 'g')
++		fn = page_detail;
++	else
++		fn = page_statistics;
++	__show_page_info(fn);
++}
++
++static struct sysrq_key_op page_info_op = {
++	handler:	show_pg_info,
++	help_msg:	"paGeinfo",
++	action_msg:	"Page Info",
++};
++
++static int __init debug_mm_init(void)
++{
++	register_sysrq_key('g', &page_info_op);
++	register_sysrq_key('h', &page_info_op);
++	return 0;
++}
++
++__initcall(debug_mm_init);
+--- linux-2.4.25/mm/filemap.c~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/mm/filemap.c	2004-03-31 17:15:09.000000000 +0200
+@@ -2210,10 +2210,14 @@
+ 	pte_t pte = *ptep;
+ 
+ 	if (pte_present(pte)) {
+-		struct page *page = pte_page(pte);
+-		if (VALID_PAGE(page) && !PageReserved(page) && ptep_test_and_clear_dirty(ptep)) {
+-			flush_tlb_page(vma, address);
+-			set_page_dirty(page);
++		unsigned long pfn = pte_pfn(pte);
++
++		if (pfn_valid(pfn)) {
++			struct page *page = pfn_to_page(pfn);
++			if (!PageReserved(page) && ptep_test_and_clear_dirty(ptep)) {
++				flush_tlb_page(vma, address);
++				set_page_dirty(page);
++			}
+ 		}
+ 	}
+ 	return 0;
+--- linux-2.4.25/mm/memory.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/mm/memory.c	2004-03-31 17:15:09.000000000 +0200
+@@ -77,8 +77,13 @@
+  */
+ void __free_pte(pte_t pte)
+ {
+-	struct page *page = pte_page(pte);
+-	if ((!VALID_PAGE(page)) || PageReserved(page))
++	unsigned long pfn = pte_pfn(pte);
++	struct page *page;
++
++	if (!pfn_valid(pfn))
++		return;
++	page = pfn_to_page(pfn);
++	if (PageReserved(page))
+ 		return;
+ 	if (pte_dirty(pte))
+ 		set_page_dirty(page);		
+@@ -232,6 +237,7 @@
+ 			do {
+ 				pte_t pte = *src_pte;
+ 				struct page *ptepage;
++				unsigned long pfn;
+ 				
+ 				/* copy_one_pte */
+ 
+@@ -241,9 +247,11 @@
+ 					swap_duplicate(pte_to_swp_entry(pte));
+ 					goto cont_copy_pte_range;
+ 				}
+-				ptepage = pte_page(pte);
+-				if ((!VALID_PAGE(ptepage)) || 
+-				    PageReserved(ptepage))
++				pfn = pte_pfn(pte);
++				if (!pfn_valid(pfn))
++					goto cont_copy_pte_range;
++				ptepage = pfn_to_page(pfn);
++				if (PageReserved(ptepage))
+ 					goto cont_copy_pte_range;
+ 
+ 				/* If it's a COW mapping, write protect it both in the parent and the child */
+@@ -314,9 +322,13 @@
+ 		if (pte_none(pte))
+ 			continue;
+ 		if (pte_present(pte)) {
+-			struct page *page = pte_page(pte);
+-			if (VALID_PAGE(page) && !PageReserved(page))
+-				freed ++;
++			unsigned long pfn = pte_pfn(pte);
++
++			if (pfn_valid(pfn)) {
++				struct page *page = pfn_to_page(pfn);
++				if (!PageReserved(page))
++					freed ++;
++			}
+ 			/* This will eventually call __free_pte on the pte. */
+ 			tlb_remove_page(tlb, ptep, address + offset);
+ 		} else {
+@@ -354,17 +366,37 @@
+ 	return freed;
+ }
+ 
++void unmap_page_range(mmu_gather_t *tlb, struct mm_struct *mm, unsigned long address, unsigned long end)
++{
++	int freed = 0;
++	pgd_t * dir;
++
++	if (address >= end)
++		BUG();
++	dir = pgd_offset(mm, address);
++	do {
++		freed += zap_pmd_range(tlb, dir, address, end - address);
++		address = (address + PGDIR_SIZE) & PGDIR_MASK;
++		dir++;
++	} while (address && (address < end));
++
++	/*
++	 * Update rss for the mm_struct (not necessarily current->mm)
++	 * Notice that rss is an unsigned long.
++	 */
++	if (mm->rss > freed)
++		mm->rss -= freed;
++	else
++		mm->rss = 0;
++}
++
+ /*
+  * remove user pages in a given range.
+  */
+ void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size)
+ {
+-	mmu_gather_t *tlb;
+-	pgd_t * dir;
+ 	unsigned long start = address, end = address + size;
+-	int freed = 0;
+-
+-	dir = pgd_offset(mm, address);
++	mmu_gather_t *tlb;
+ 
+ 	/*
+ 	 * This is a long-lived spinlock. That's fine.
+@@ -377,25 +409,10 @@
+ 		BUG();
+ 	spin_lock(&mm->page_table_lock);
+ 	flush_cache_range(mm, address, end);
+-	tlb = tlb_gather_mmu(mm);
+ 
+-	do {
+-		freed += zap_pmd_range(tlb, dir, address, end - address);
+-		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+-		dir++;
+-	} while (address && (address < end));
+-
+-	/* this will flush any remaining tlb entries */
++	tlb = tlb_gather_mmu(mm);
++	unmap_page_range(tlb, mm, address, end);
+ 	tlb_finish_mmu(tlb, start, end);
+-
+-	/*
+-	 * Update rss for the mm_struct (not necessarily current->mm)
+-	 * Notice that rss is an unsigned long.
+-	 */
+-	if (mm->rss > freed)
+-		mm->rss -= freed;
+-	else
+-		mm->rss = 0;
+ 	spin_unlock(&mm->page_table_lock);
+ }
+ 
+@@ -407,6 +424,7 @@
+ 	pgd_t *pgd;
+ 	pmd_t *pmd;
+ 	pte_t *ptep, pte;
++	unsigned long pfn;
+ 
+ 	pgd = pgd_offset(mm, address);
+ 	if (pgd_none(*pgd) || pgd_bad(*pgd))
+@@ -423,8 +441,11 @@
+ 	pte = *ptep;
+ 	if (pte_present(pte)) {
+ 		if (!write ||
+-		    (pte_write(pte) && pte_dirty(pte)))
+-			return pte_page(pte);
++		    (pte_write(pte) && pte_dirty(pte))) {
++			pfn = pte_pfn(pte);
++			if (pfn_valid(pfn))
++				return pfn_to_page(pfn);
++		}
+ 	}
+ 
+ out:
+@@ -439,7 +460,8 @@
+ 
+ static inline struct page * get_page_map(struct page *page)
+ {
+-	if (!VALID_PAGE(page))
++	unsigned long pfn = page_to_pfn(page);
++	if (!pfn_valid(pfn))
+ 		return 0;
+ 	return page;
+ }
+@@ -826,22 +848,22 @@
+ 	unsigned long phys_addr, pgprot_t prot)
+ {
+ 	unsigned long end;
++	unsigned long pfn;
+ 
+ 	address &= ~PMD_MASK;
+ 	end = address + size;
+ 	if (end > PMD_SIZE)
+ 		end = PMD_SIZE;
++	pfn = phys_addr >> PAGE_SHIFT;
+ 	do {
+-		struct page *page;
+ 		pte_t oldpage;
+ 		oldpage = ptep_get_and_clear(pte);
+ 
+-		page = virt_to_page(__va(phys_addr));
+-		if ((!VALID_PAGE(page)) || PageReserved(page))
+- 			set_pte(pte, mk_pte_phys(phys_addr, prot));
++		if (!pfn_valid(pfn) || PageReserved(pfn_to_page(pfn)))
++ 			set_pte(pte, pfn_pte(pfn, prot));
+ 		forget_pte(oldpage);
+ 		address += PAGE_SIZE;
+-		phys_addr += PAGE_SIZE;
++		pfn++;
+ 		pte++;
+ 	} while (address && (address < end));
+ }
+@@ -949,10 +971,11 @@
+ 	unsigned long address, pte_t *page_table, pte_t pte)
+ {
+ 	struct page *old_page, *new_page;
++	unsigned long pfn = pte_pfn(pte);
+ 
+-	old_page = pte_page(pte);
+-	if (!VALID_PAGE(old_page))
++	if (!pfn_valid(pfn))
+ 		goto bad_wp_page;
++	old_page = pte_page(pte);
+ 
+ 	if (!TryLockPage(old_page)) {
+ 		int reuse = can_share_swap_page(old_page);
+@@ -996,7 +1019,7 @@
+ 
+ bad_wp_page:
+ 	spin_unlock(&mm->page_table_lock);
+-	printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
++	printk("do_wp_page: bogus page at address %08lx\n", address);
+ 	return -1;
+ no_mem:
+ 	page_cache_release(old_page);
+--- linux-2.4.25/mm/mmap.c~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/mm/mmap.c	2004-03-31 17:15:09.000000000 +0200
+@@ -18,6 +18,9 @@
+ 
+ #include <asm/uaccess.h>
+ #include <asm/pgalloc.h>
++#include <asm/tlb.h>
++
++extern void unmap_page_range(mmu_gather_t *tlb, struct mm_struct *mm, unsigned long start, unsigned long end);
+ 
+ /*
+  * WARNING: the debugging will use recursive algorithms so never enable this
+@@ -915,6 +918,8 @@
+ 	 * old method of shifting the VA >> by PGDIR_SHIFT doesn't work.
+ 	 */
+ 	start_index = pgd_index(first);
++	if (start_index < FIRST_USER_PGD_NR)
++		start_index = FIRST_USER_PGD_NR;
+ 	end_index = pgd_index(last);
+ 	if (end_index > start_index) {
+ 		clear_page_tables(mm, start_index, end_index - start_index);
+@@ -1046,7 +1051,6 @@
+ 	len = PAGE_ALIGN(len);
+ 	if (!len)
+ 		return addr;
+-
+ 	if ((addr + len) > TASK_SIZE || (addr + len) < addr)
+ 		return -EINVAL;
+ 
+@@ -1135,45 +1139,58 @@
+ /* Release all mmaps. */
+ void exit_mmap(struct mm_struct * mm)
+ {
++	mmu_gather_t *tlb;
+ 	struct vm_area_struct * mpnt;
+ 
+ 	release_segments(mm);
+ 	spin_lock(&mm->page_table_lock);
++
++	tlb = tlb_gather_mmu(mm);
++
++	flush_cache_mm(mm);
++	mpnt = mm->mmap;
++	while (mpnt) {
++		unsigned long start = mpnt->vm_start;
++		unsigned long end = mpnt->vm_end;
++
++		mm->map_count--;
++		remove_shared_vm_struct(mpnt);
++		unmap_page_range(tlb, mm, start, end);
++		mpnt = mpnt->vm_next;
++	}
++
++	/* This is just debugging */
++	if (mm->map_count)
++		BUG();
++
++	tlb_finish_mmu(tlb, 0, TASK_SIZE);
++
+ 	mpnt = mm->mmap;
+ 	mm->mmap = mm->mmap_cache = NULL;
+ 	mm->mm_rb = RB_ROOT;
+ 	mm->rss = 0;
+-	spin_unlock(&mm->page_table_lock);
+ 	mm->total_vm = 0;
+ 	mm->locked_vm = 0;
+ 
+-	flush_cache_mm(mm);
++	spin_unlock(&mm->page_table_lock);
++
++	clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);
++
++	/*
++	 * Walk the list again, actually closing and freeing it
++	 * without holding any MM locks.
++	 */
+ 	while (mpnt) {
+ 		struct vm_area_struct * next = mpnt->vm_next;
+-		unsigned long start = mpnt->vm_start;
+-		unsigned long end = mpnt->vm_end;
+-		unsigned long size = end - start;
+-
+ 		if (mpnt->vm_ops) {
+ 			if (mpnt->vm_ops->close)
+ 				mpnt->vm_ops->close(mpnt);
+ 		}
+-		mm->map_count--;
+-		remove_shared_vm_struct(mpnt);
+-		zap_page_range(mm, start, size);
+ 		if (mpnt->vm_file)
+ 			fput(mpnt->vm_file);
+ 		kmem_cache_free(vm_area_cachep, mpnt);
+ 		mpnt = next;
+ 	}
+-
+-	/* This is just debugging */
+-	if (mm->map_count)
+-		BUG();
+-
+-	clear_page_tables(mm, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);
+-
+-	flush_tlb_mm(mm);
+ }
+ 
+ /* Insert vm structure into process list sorted by address
+--- linux-2.4.25/mm/slab.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/mm/slab.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1391,7 +1391,7 @@
+ #if DEBUG
+ # define CHECK_NR(pg)						\
+ 	do {							\
+-		if (!VALID_PAGE(pg)) {				\
++		if (!virt_addr_valid(pg)) {			\
+ 			printk(KERN_ERR "kfree: out of range ptr %lxh.\n", \
+ 				(unsigned long)objp);		\
+ 			BUG();					\
+@@ -1950,12 +1950,12 @@
+ 	name = cachep->name; 
+ 	{
+ 	char tmp; 
+-	mm_segment_t	old_fs;
++	mm_segment_t old_fs;
+ 	old_fs = get_fs();
+ 	set_fs(KERNEL_DS);
+ 	if (__get_user(tmp, name)) 
+ 		name = "broken"; 
+-	set_fs(old_fs);
++	set_fs (old_fs);
+ 	}       
+ 
+ 	seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u",
+--- linux-2.4.25/mm/vmalloc.c~2.4.25-vrs2.patch	2003-08-25 13:44:44.000000000 +0200
++++ linux-2.4.25/mm/vmalloc.c	2004-03-31 17:15:09.000000000 +0200
+@@ -44,8 +44,13 @@
+ 		if (pte_none(page))
+ 			continue;
+ 		if (pte_present(page)) {
+-			struct page *ptpage = pte_page(page);
+-			if (VALID_PAGE(ptpage) && (!PageReserved(ptpage)))
++			unsigned long pfn = pte_pfn(page);
++			struct page *ptpage;
++
++			if (!pfn_valid(pfn))
++				continue;
++			ptpage = pfn_to_page(pfn);
++			if (!PageReserved(ptpage))
+ 				__free_page(ptpage);
+ 			continue;
+ 		}
+--- linux-2.4.25/mm/vmscan.c~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/mm/vmscan.c	2004-03-31 17:15:09.000000000 +0200
+@@ -121,6 +121,7 @@
+ drop_pte:
+ 		mm->rss--;
+ 		UnlockPage(page);
++		memc_clear(vma->vm_mm, page);
+ 		{
+ 			int freeable = page_count(page) - !!page->buffers <= 2;
+ 			page_cache_release(page);
+@@ -206,13 +207,16 @@
+ 
+ 	do {
+ 		if (pte_present(*pte)) {
+-			struct page *page = pte_page(*pte);
++			unsigned long pfn = pte_pfn(*pte);
+ 
+-			if (VALID_PAGE(page) && !PageReserved(page)) {
+-				count -= try_to_swap_out(mm, vma, address, pte, page, classzone);
+-				if (!count) {
+-					address += PAGE_SIZE;
+-					break;
++			if (pfn_valid(pfn)) {
++				struct page *page = pfn_to_page(pfn);
++				if (!PageReserved(page)) {
++					count -= try_to_swap_out(mm, vma, address, pte, page, classzone);
++					if (!count) {
++						address += PAGE_SIZE;
++						break;
++					}
+ 				}
+ 			}
+ 		}
+--- linux-2.4.25/net/irda/af_irda.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/net/irda/af_irda.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1176,7 +1176,7 @@
+ #endif /* CONFIG_IRDA_ULTRA */
+ 	kfree(self);
+ 	MOD_DEC_USE_COUNT;
+-	
++
+ 	return;
+ }
+ 
+@@ -2571,19 +2571,15 @@
+ 	sock_register(&irda_family_ops);
+ 
+ 	irda_packet_type.type = htons(ETH_P_IRDA);
+-        dev_add_pack(&irda_packet_type);
++	dev_add_pack(&irda_packet_type);
+ 
+ 	register_netdevice_notifier(&irda_dev_notifier);
+-
+ 	irda_init();
+ #ifdef MODULE
+- 	irda_device_init();  /* Called by init/main.c when non-modular */
++	irda_device_init();  /* Called by init/main.c when non-modular */
+ #endif
+ 	return 0;
+ }
+-#ifdef MODULE
+-module_init(irda_proto_init);	/* If non-module, called from init/main.c */
+-#endif
+ 
+ /*
+  * Function irda_proto_cleanup (void)
+@@ -2591,25 +2587,27 @@
+  *    Remove IrDA protocol layer
+  *
+  */
+-#ifdef MODULE
+-void irda_proto_cleanup(void)
++static void __exit irda_proto_cleanup(void)
+ {
+ 	irda_packet_type.type = htons(ETH_P_IRDA);
+-        dev_remove_pack(&irda_packet_type);
++	dev_remove_pack(&irda_packet_type);
++
++	unregister_netdevice_notifier(&irda_dev_notifier);
+ 
+-        unregister_netdevice_notifier(&irda_dev_notifier);
+-	
+ 	sock_unregister(PF_IRDA);
++
+ 	irda_cleanup();
+-	
+-        return;
+ }
++
++#ifdef MODULE
++module_init(irda_proto_init);
+ module_exit(irda_proto_cleanup);
+- 
++
+ MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+-MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem"); 
++MODULE_DESCRIPTION("The Linux IrDA Protocol Subsystem");
+ MODULE_LICENSE("GPL");
+ #ifdef CONFIG_IRDA_DEBUG
+ MODULE_PARM(irda_debug, "1l");
+ #endif
+-#endif /* MODULE */
++#endif
++
+--- linux-2.4.25/net/irda/iriap.c~2.4.25-vrs2.patch	2002-11-29 00:53:16.000000000 +0100
++++ linux-2.4.25/net/irda/iriap.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1004,18 +1004,20 @@
+ 			
+ 			switch (attrib->value->type) {
+ 			case IAS_INTEGER:
+-				len += sprintf(buf+len, "%d\n", 
++				len += sprintf(buf+len, "%d", 
+ 					       attrib->value->t.integer);
+ 				break;
+ 			case IAS_STRING:
+-				len += sprintf(buf+len, "\"%s\"\n", 
++				len += sprintf(buf+len, "\"%s\"", 
+ 					       attrib->value->t.string);
+ 				break;
+ 			case IAS_OCT_SEQ:
+-				len += sprintf(buf+len, "octet sequence (%d bytes)\n", attrib->value->len);
++				len += sprintf(buf+len,
++					       "octet sequence (%d bytes)",
++					       attrib->value->len);
+ 				break;
+ 			case IAS_MISSING:
+-				len += sprintf(buf+len, "missing\n");
++				len += sprintf(buf+len, "missing");
+ 				break;
+ 			default:
+ 				IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__);
+@@ -1027,6 +1029,7 @@
+ 				hashbin_get_next(obj->attribs);
+ 		}
+ 	        obj = (struct ias_object *) hashbin_get_next(objects);
++		len += sprintf(buf+len, "\n");
+  	} 
+ 	restore_flags(flags);
+ 
+--- linux-2.4.25/net/irda/irlan/irlan_common.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/net/irda/irlan/irlan_common.c	2004-03-31 17:15:09.000000000 +0200
+@@ -317,6 +317,9 @@
+ 
+ 	del_timer(&self->watchdog_timer);
+ 
++	/* since irlan_do_*_event gobble the skb, we must get it once -- rmk */
++	skb_get(skb);
++
+ 	/* If you want to pass the skb to *both* state machines, you will
+ 	 * need to skb_clone() it, so that you don't free it twice.
+ 	 * As the state machines don't need it, git rid of it here...
+--- linux-2.4.25/net/irda/irlap_event.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/net/irda/irlap_event.c	2004-03-31 17:15:09.000000000 +0200
+@@ -532,7 +532,7 @@
+ #endif /* CONFIG_IRDA_ULTRA */
+ 	case RECV_TEST_CMD:
+ 		/* Remove test frame header */
+-		skb_pull(skb, sizeof(struct test_frame));
++		skb_pull(skb, 10 /*sizeof(struct test_frame)*/);
+ 
+ 		/* 
+ 		 * Send response. This skb will not be sent out again, and
+@@ -740,7 +740,7 @@
+ 
+ 	switch (event) {
+ 	case CONNECT_RESPONSE:
+-		skb_pull(skb, sizeof(struct snrm_frame));
++		skb_pull(skb, 11 /*sizeof(struct snrm_frame)*/);
+ 
+ 		ASSERT(self->netdev != NULL, return -1;);
+ 
+@@ -870,7 +870,7 @@
+ 
+ 			ASSERT(self->netdev != NULL, return -1;);
+ 
+-			skb_pull(skb, sizeof(struct snrm_frame));
++			skb_pull(skb, 11 /*sizeof(struct snrm_frame)*/);
+ 
+ 			irlap_qos_negotiate(self, skb);
+ 			
+@@ -902,7 +902,7 @@
+ 		/* Negotiate connection parameters */
+ 		ASSERT(skb->len > 10, return -1;);
+ 
+-		skb_pull(skb, sizeof(struct ua_frame));
++		skb_pull(skb, 10 /*sizeof(struct ua_frame)*/);
+ 
+ 		ASSERT(self->netdev != NULL, return -1;);
+ 
+--- linux-2.4.25/net/irda/irlap_frame.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/net/irda/irlap_frame.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1,5 +1,5 @@
+ /*********************************************************************
+- *                
++ *
+  * Filename:      irlap_frame.c
+  * Version:       1.0
+  * Description:   Build and transmit IrLAP frames
+@@ -8,18 +8,18 @@
+  * Created at:    Tue Aug 19 10:27:26 1997
+  * Modified at:   Wed Jan  5 08:59:04 2000
+  * Modified by:   Dag Brattli <dagb@cs.uit.no>
+- * 
+- *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>, 
++ *
++ *     Copyright (c) 1998-2000 Dag Brattli <dagb@cs.uit.no>,
+  *     All Rights Reserved.
+  *     Copyright (c) 2000-2001 Jean Tourrilhes <jt@hpl.hp.com>
+- *     
+- *     This program is free software; you can redistribute it and/or 
+- *     modify it under the terms of the GNU General Public License as 
+- *     published by the Free Software Foundation; either version 2 of 
++ *
++ *     This program is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of
+  *     the License, or (at your option) any later version.
+  *
+  *     Neither Dag Brattli nor University of Troms� admit liability nor
+- *     provide warranty for any of this software. This material is 
++ *     provide warranty for any of this software. This material is
+  *     provided "AS-IS" and at no charge.
+  *
+  ********************************************************************/
+@@ -29,11 +29,12 @@
+ #include <linux/if_ether.h>
+ #include <linux/netdevice.h>
+ #include <linux/irda.h>
+- 
++
+ #include <net/pkt_sched.h>
+ #include <net/sock.h>
+- 
++
+ #include <asm/byteorder.h>
++#include <asm/unaligned.h>
+ 
+ #include <net/irda/irda.h>
+ #include <net/irda/irda_device.h>
+@@ -46,18 +47,18 @@
+ /*
+  * Function irlap_insert_info (self, skb)
+  *
+- *    Insert minimum turnaround time and speed information into the skb. We 
++ *    Insert minimum turnaround time and speed information into the skb. We
+  *    need to do this since it's per packet relevant information. Safe to
+  *    have this function inlined since it's only called from one place
+  */
+-static inline void irlap_insert_info(struct irlap_cb *self, 
++static inline void irlap_insert_info(struct irlap_cb *self,
+ 				     struct sk_buff *skb)
+ {
+ 	struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb;
+ 
+-	/*  
++	/*
+ 	 * Insert MTT (min. turn time) and speed into skb, so that the
+-	 * device driver knows which settings to use 
++	 * device driver knows which settings to use
+ 	 */
+ 	cb->magic = LAP_MAGIC;
+ 	cb->mtt = self->mtt_required;
+@@ -65,15 +66,15 @@
+ 
+ 	/* Reset */
+ 	self->mtt_required = 0;
+-	
+-	/* 
+-	 * Delay equals negotiated BOFs count, plus the number of BOFs to 
+-	 * force the negotiated minimum turnaround time 
++
++	/*
++	 * Delay equals negotiated BOFs count, plus the number of BOFs to
++	 * force the negotiated minimum turnaround time
+ 	 */
+ 	cb->xbofs = self->bofs_count;
+ 	cb->next_xbofs = self->next_bofs;
+ 	cb->xbofs_delay = self->xbofs_delay;
+-	
++
+ 	/* Reset XBOF's delay (used only for getting min turn time) */
+ 	self->xbofs_delay = 0;
+ 	/* Put the correct xbofs value for the next packet */
+@@ -104,7 +105,7 @@
+  *
+  *    Transmits a connect SNRM command frame
+  */
+-void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos) 
++void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
+ {
+ 	struct sk_buff *skb;
+ 	struct snrm_frame *frame;
+@@ -118,7 +119,7 @@
+ 	if (!skb)
+ 		return;
+ 
+-	frame = (struct snrm_frame *) skb_put(skb, 2); 
++	frame = (struct snrm_frame *) skb_put(skb, 2);
+ 
+ 	/* Insert connection address field */
+ 	if (qos)
+@@ -128,17 +129,17 @@
+ 
+ 	/* Insert control field */
+  	frame->control = SNRM_CMD | PF_BIT;
+-	
++
+ 	/*
+-	 *  If we are establishing a connection then insert QoS paramerters 
++	 *  If we are establishing a connection then insert QoS paramerters
+ 	 */
+ 	if (qos) {
+ 		skb_put(skb, 9); /* 21 left */
+-		frame->saddr = cpu_to_le32(self->saddr);
+-		frame->daddr = cpu_to_le32(self->daddr);
++		put_unaligned(cpu_to_le32(self->saddr), &frame->saddr);
++		put_unaligned(cpu_to_le32(self->daddr), &frame->daddr);
+ 
+ 		frame->ncaddr = self->caddr;
+-				
++
+ 		ret = irlap_insert_qos_negotiation_params(self, skb);
+ 		if (ret < 0) {
+ 			dev_kfree_skb(skb);
+@@ -154,13 +155,13 @@
+  *    Received SNRM (Set Normal Response Mode) command frame
+  *
+  */
+-static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, 
+-				struct irlap_info *info) 
++static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb,
++				struct irlap_info *info)
+ {
+ 	struct snrm_frame *frame;
+ 
+ 	frame = (struct snrm_frame *) skb->data;
+-	
++
+ 	if (skb->len >= sizeof(struct snrm_frame)) {
+ 		/* Copy the new connection address ignoring the C/R bit */
+ 		info->caddr = frame->ncaddr & 0xFE;
+@@ -170,11 +171,11 @@
+ 			IRDA_DEBUG(3, "%s(), invalid connection address!\n", __FUNCTION__);
+ 			return;
+ 		}
+-		
++
+ 		/* Copy peer device address */
+-		info->daddr = le32_to_cpu(frame->saddr);
+-		info->saddr = le32_to_cpu(frame->daddr);
+-		
++		info->daddr = le32_to_cpu(get_unaligned(&frame->saddr));
++		info->saddr = le32_to_cpu(get_unaligned(&frame->daddr));
++
+ 		/* Only accept if addressed directly to us */
+ 		if (info->saddr != self->saddr) {
+ 			IRDA_DEBUG(2, "%s(), not addressed to us!\n", __FUNCTION__);
+@@ -198,9 +199,9 @@
+ 	struct sk_buff *skb;
+ 	struct ua_frame *frame;
+ 	int ret;
+-	
++
+ 	IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies);
+-	
++
+ 	ASSERT(self != NULL, return;);
+ 	ASSERT(self->magic == LAP_MAGIC, return;);
+ 
+@@ -212,13 +213,13 @@
+ 		return;
+ 
+ 	frame = (struct ua_frame *) skb_put(skb, 10);
+-	
++
+ 	/* Build UA response */
+ 	frame->caddr = self->caddr;
+  	frame->control = UA_RSP | PF_BIT;
+ 
+-	frame->saddr = cpu_to_le32(self->saddr);
+-	frame->daddr = cpu_to_le32(self->daddr);
++	put_unaligned(cpu_to_le32(self->saddr), &frame->saddr);
++	put_unaligned(cpu_to_le32(self->daddr), &frame->daddr);
+ 
+ 	/* Should we send QoS negotiation parameters? */
+ 	if (qos) {
+@@ -243,7 +244,7 @@
+ {
+ 	struct sk_buff *skb = NULL;
+ 	__u8 *frame;
+-	
++
+ 	ASSERT(self != NULL, return;);
+ 	ASSERT(self->magic == LAP_MAGIC, return;);
+ 
+@@ -252,7 +253,7 @@
+ 		return;
+ 
+ 	frame = skb_put( skb, 2);
+-	
++
+ 	if (self->state == LAP_NDM)
+ 		frame[0] = CBROADCAST;
+ 	else
+@@ -260,7 +261,7 @@
+ 
+ 	frame[1] = DM_RSP | PF_BIT;
+ 
+-	irlap_queue_xmit(self, skb);	
++	irlap_queue_xmit(self, skb);
+ }
+ 
+ /*
+@@ -269,11 +270,11 @@
+  *    Send disconnect (DISC) frame
+  *
+  */
+-void irlap_send_disc_frame(struct irlap_cb *self) 
++void irlap_send_disc_frame(struct irlap_cb *self)
+ {
+ 	struct sk_buff *skb = NULL;
+ 	__u8 *frame;
+-	
++
+ 	IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ 
+ 	ASSERT(self != NULL, return;);
+@@ -284,7 +285,7 @@
+ 		return;
+ 
+ 	frame = skb_put(skb, 2);
+-	
++
+ 	frame[0] = self->caddr | CMD_FRAME;
+ 	frame[1] = DISC_CMD | PF_BIT;
+ 
+@@ -295,17 +296,17 @@
+  * Function irlap_send_discovery_xid_frame (S, s, command)
+  *
+  *    Build and transmit a XID (eXchange station IDentifier) discovery
+- *    frame. 
++ *    frame.
+  */
+-void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, 
+-				    __u8 command, discovery_t *discovery) 
++void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
++				    __u8 command, discovery_t *discovery)
+ {
+ 	struct sk_buff *skb = NULL;
+ 	struct xid_frame *frame;
+-	__u32 bcast = BROADCAST;
++	__u32 bcast = BROADCAST, daddr;
+ 	__u8 *info;
+ 
+- 	IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__, s, S, 
++ 	IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__, s, S,
+ 		   command);
+ 
+ 	ASSERT(self != NULL, return;);
+@@ -328,13 +329,14 @@
+ 	}
+ 	frame->ident = XID_FORMAT;
+ 
+-	frame->saddr = cpu_to_le32(self->saddr);
+-
+ 	if (command)
+-		frame->daddr = cpu_to_le32(bcast);
++		daddr = bcast;
+ 	else
+-		frame->daddr = cpu_to_le32(discovery->daddr);
+-	
++		daddr = discovery->daddr;
++
++	put_unaligned(cpu_to_le32(self->saddr), &frame->saddr);
++	put_unaligned(cpu_to_le32(daddr), &frame->daddr);
++
+ 	switch (S) {
+ 	case 1:
+ 		frame->flags = 0x00;
+@@ -353,10 +355,10 @@
+ 		break;
+ 	}
+ 
+-	frame->slotnr = s; 
++	frame->slotnr = s;
+ 	frame->version = 0x00;
+ 
+-	/*  
++	/*
+ 	 *  Provide info for final slot only in commands, and for all
+ 	 *  responses. Send the second byte of the hint only if the
+ 	 *  EXTENSION bit is set in the first byte.
+@@ -365,7 +367,7 @@
+ 		int len;
+ 
+ 		if (discovery->hints.byte[0] & HINT_EXTENSION) {
+-			info = skb_put(skb, 2);		
++			info = skb_put(skb, 2);
+ 			info[0] = discovery->hints.byte[0];
+ 			info[1] = discovery->hints.byte[1];
+ 		} else {
+@@ -378,7 +380,7 @@
+ 		len = IRDA_MIN(discovery->name_len, skb_tailroom(skb));
+ 		info = skb_put(skb, len);
+ 		memcpy(info, discovery->nickname, len);
+-	} 
++	}
+ 	irlap_queue_xmit(self, skb);
+ }
+ 
+@@ -388,9 +390,9 @@
+  *    Received a XID discovery response
+  *
+  */
+-static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, 
+-					 struct sk_buff *skb, 
+-					 struct irlap_info *info) 
++static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self,
++					 struct sk_buff *skb,
++					 struct irlap_info *info)
+ {
+ 	struct xid_frame *xid;
+ 	discovery_t *discovery = NULL;
+@@ -404,8 +406,8 @@
+ 
+ 	xid = (struct xid_frame *) skb->data;
+ 
+-	info->daddr = le32_to_cpu(xid->saddr);
+-	info->saddr = le32_to_cpu(xid->daddr);
++	info->daddr = le32_to_cpu(get_unaligned(&xid->saddr));
++	info->saddr = le32_to_cpu(get_unaligned(&xid->daddr));
+ 
+ 	/* Make sure frame is addressed to us */
+ 	if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
+@@ -439,11 +441,11 @@
+ 		discovery->charset = discovery_info[1];
+ 		text = (char *) &discovery_info[2];
+ 	}
+-	/* 
+-	 *  Terminate info string, should be safe since this is where the 
++	/*
++	 *  Terminate info string, should be safe since this is where the
+ 	 *  FCS bytes resides.
+ 	 */
+-	skb->data[skb->len] = '\0'; 
++	skb->data[skb->len] = '\0';
+ 	strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
+ 	discovery->name_len = strlen(discovery->nickname);
+ 
+@@ -458,9 +460,9 @@
+  *    Received a XID discovery command
+  *
+  */
+-static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, 
+-					 struct sk_buff *skb, 
+-					 struct irlap_info *info) 
++static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
++					 struct sk_buff *skb,
++					 struct irlap_info *info)
+ {
+ 	struct xid_frame *xid;
+ 	discovery_t *discovery = NULL;
+@@ -469,8 +471,8 @@
+ 
+ 	xid = (struct xid_frame *) skb->data;
+ 
+-	info->daddr = le32_to_cpu(xid->saddr);
+-	info->saddr = le32_to_cpu(xid->daddr);
++	info->daddr = le32_to_cpu(get_unaligned(&xid->saddr));
++	info->saddr = le32_to_cpu(get_unaligned(&xid->daddr));
+ 
+ 	/* Make sure frame is addressed to us */
+ 	if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) {
+@@ -497,11 +499,11 @@
+ 		return;
+ 	}
+ 	info->s = xid->slotnr;
+-	
++
+ 	discovery_info = skb_pull(skb, sizeof(struct xid_frame));
+ 
+-	/* 
+-	 *  Check if last frame 
++	/*
++	 *  Check if last frame
+ 	 */
+ 	if (info->s == 0xff) {
+ 		/* Check if things are sane at this point... */
+@@ -518,7 +520,7 @@
+ 			WARNING("%s(), unable to malloc!\n", __FUNCTION__);
+ 			return;
+ 		}
+-	      
++
+ 		discovery->daddr = info->daddr;
+ 		discovery->saddr = self->saddr;
+ 		discovery->timestamp = jiffies;
+@@ -533,11 +535,11 @@
+ 			discovery->charset = discovery_info[1];
+ 			text = (char *) &discovery_info[2];
+ 		}
+-		/* 
+-		 *  Terminate string, should be safe since this is where the 
++		/*
++		 *  Terminate string, should be safe since this is where the
+ 		 *  FCS bytes resides.
+ 		 */
+-		skb->data[skb->len] = '\0'; 
++		skb->data[skb->len] = '\0';
+ 		strncpy(discovery->nickname, text, NICKNAME_MAX_LEN);
+ 		discovery->name_len = strlen(discovery->nickname);
+ 
+@@ -554,7 +556,7 @@
+  *    Build and transmit RR (Receive Ready) frame. Notice that it is currently
+  *    only possible to send RR frames with the poll bit set.
+  */
+-void irlap_send_rr_frame(struct irlap_cb *self, int command) 
++void irlap_send_rr_frame(struct irlap_cb *self, int command)
+ {
+ 	struct sk_buff *skb;
+ 	__u8 *frame;
+@@ -562,9 +564,9 @@
+ 	skb = dev_alloc_skb(16);
+ 	if (!skb)
+ 		return;
+-	
++
+ 	frame = skb_put(skb, 2);
+-	
++
+ 	frame[0] = self->caddr;
+ 	frame[0] |= (command) ? CMD_FRAME : 0;
+ 
+@@ -576,7 +578,7 @@
+ /*
+  * Function irlap_send_rd_frame (self)
+  *
+- *    Request disconnect. Used by a secondary station to request the 
++ *    Request disconnect. Used by a secondary station to request the
+  *    disconnection of the link.
+  */
+ void irlap_send_rd_frame(struct irlap_cb *self)
+@@ -587,9 +589,9 @@
+ 	skb = dev_alloc_skb(16);
+ 	if (!skb)
+ 		return;
+-	
++
+ 	frame = skb_put(skb, 2);
+-	
++
+ 	frame[0] = self->caddr;
+ 	frame[1] = RD_RSP | PF_BIT;
+ 
+@@ -603,8 +605,8 @@
+  *    making it inline since its called only from one single place
+  *    (irlap_driver_rcv).
+  */
+-static inline void irlap_recv_rr_frame(struct irlap_cb *self, 
+-				       struct sk_buff *skb, 
++static inline void irlap_recv_rr_frame(struct irlap_cb *self,
++				       struct sk_buff *skb,
+ 				       struct irlap_info *info, int command)
+ {
+ 	info->nr = skb->data[1] >> 5;
+@@ -620,7 +622,7 @@
+ {
+ 	struct sk_buff *skb = NULL;
+ 	__u8 *frame;
+-	
++
+ 	ASSERT( self != NULL, return;);
+ 	ASSERT( self->magic == LAP_MAGIC, return;);
+ 
+@@ -629,7 +631,7 @@
+ 		return;
+ 
+ 	frame = skb_put( skb, 2);
+-	
++
+ 	frame[0] = self->caddr;
+ 	frame[0] |= (command) ? CMD_FRAME : 0;
+ 
+@@ -639,7 +641,7 @@
+ 
+ 	frame[2] = 0;
+ 
+-   	IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies); 
++   	IRDA_DEBUG(4, "%s(), vr=%d, %ld\n", __FUNCTION__, self->vr, jiffies);
+ 
+ 	irlap_queue_xmit(self, skb);
+ }
+@@ -650,8 +652,8 @@
+  *    Received RNR (Receive Not Ready) frame from peer station
+  *
+  */
+-static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, 
+-				 struct irlap_info *info, int command) 
++static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb,
++				 struct irlap_info *info, int command)
+ {
+ 	info->nr = skb->data[1] >> 5;
+ 
+@@ -663,13 +665,13 @@
+ 		irlap_do_event(self, RECV_RNR_RSP, skb, info);
+ }
+ 
+-static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, 
++static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb,
+ 				 struct irlap_info *info, int command)
+ {
+ 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+ 
+ 	info->nr = skb->data[1] >> 5;
+-	
++
+ 	/* Check if this is a command or a response frame */
+ 	if (command)
+ 		irlap_do_event(self, RECV_REJ_CMD, skb, info);
+@@ -677,13 +679,13 @@
+ 		irlap_do_event(self, RECV_REJ_RSP, skb, info);
+ }
+ 
+-static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, 
++static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb,
+ 				  struct irlap_info *info, int command)
+ {
+ 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+ 
+ 	info->nr = skb->data[1] >> 5;
+-	
++
+ 	/* Check if this is a command or a response frame */
+ 	if (command)
+ 		irlap_do_event(self, RECV_SREJ_CMD, skb, info);
+@@ -691,7 +693,7 @@
+ 		irlap_do_event(self, RECV_SREJ_RSP, skb, info);
+ }
+ 
+-static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, 
++static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb,
+ 				  struct irlap_info *info, int command)
+ {
+ 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+@@ -709,9 +711,9 @@
+  *    Received UA (Unnumbered Acknowledgement) frame
+  *
+  */
+-static inline void irlap_recv_ua_frame(struct irlap_cb *self, 
+-				       struct sk_buff *skb, 
+-				       struct irlap_info *info) 
++static inline void irlap_recv_ua_frame(struct irlap_cb *self,
++				       struct sk_buff *skb,
++				       struct irlap_info *info)
+ {
+ 	irlap_do_event(self, RECV_UA_RSP, skb, info);
+ }
+@@ -728,25 +730,25 @@
+ 
+ 	if (skb->data[1] == I_FRAME) {
+ 
+-		/*  
++		/*
+ 		 *  Insert frame sequence number (Vs) in control field before
+ 		 *  inserting into transmit window queue.
+ 		 */
+ 		skb->data[1] = I_FRAME | (self->vs << 1);
+-		
++
+ 		/* Copy buffer */
+ 		tx_skb = skb_clone(skb, GFP_ATOMIC);
+ 		if (tx_skb == NULL) {
+ 			return;
+ 		}
+-		
+-		/* 
+-		 *  Insert frame in store, in case of retransmissions 
++
++		/*
++		 *  Insert frame in store, in case of retransmissions
+ 		 */
+ 		skb_queue_tail(&self->wx_list, skb_get(skb));
+-		
++
+ 		self->vs = (self->vs + 1) % 8;
+-		self->ack_required = FALSE;		
++		self->ack_required = FALSE;
+ 		self->window -= 1;
+ 
+ 		irlap_send_i_frame( self, tx_skb, CMD_FRAME);
+@@ -761,40 +763,40 @@
+  *
+  *    Send I(nformation) frame as primary with poll bit set
+  */
+-void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) 
++void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb)
+ {
+ 	struct sk_buff *tx_skb;
+ 
+ 	/* Stop P timer */
+ 	del_timer(&self->poll_timer);
+-		
++
+ 	/* Is this reliable or unreliable data? */
+ 	if (skb->data[1] == I_FRAME) {
+-		
+-		/*  
++
++		/*
+ 		 *  Insert frame sequence number (Vs) in control field before
+ 		 *  inserting into transmit window queue.
+ 		 */
+ 		skb->data[1] = I_FRAME | (self->vs << 1);
+-		
++
+ 		/* Copy buffer */
+ 		tx_skb = skb_clone(skb, GFP_ATOMIC);
+ 		if (tx_skb == NULL) {
+ 			return;
+ 		}
+-		
+-		/* 
+-		 *  Insert frame in store, in case of retransmissions 
++
++		/*
++		 *  Insert frame in store, in case of retransmissions
+ 		 */
+ 		skb_queue_tail(&self->wx_list, skb_get(skb));
+-		
+-		/*  
++
++		/*
+ 		 *  Set poll bit if necessary. We do this to the copied
+ 		 *  skb, since retransmitted need to set or clear the poll
+-		 *  bit depending on when they are sent.  
++		 *  bit depending on when they are sent.
+ 		 */
+ 		tx_skb->data[1] |= PF_BIT;
+-		
++
+ 		self->vs = (self->vs + 1) % 8;
+ 		self->ack_required = FALSE;
+ 
+@@ -827,8 +829,8 @@
+  *    Send I(nformation) frame as secondary with final bit set
+  *
+  */
+-void irlap_send_data_secondary_final(struct irlap_cb *self, 
+-				     struct sk_buff *skb) 
++void irlap_send_data_secondary_final(struct irlap_cb *self,
++				     struct sk_buff *skb)
+ {
+ 	struct sk_buff *tx_skb = NULL;
+ 
+@@ -839,26 +841,26 @@
+ 	/* Is this reliable or unreliable data? */
+ 	if (skb->data[1] == I_FRAME) {
+ 
+-		/*  
++		/*
+ 		 *  Insert frame sequence number (Vs) in control field before
+ 		 *  inserting into transmit window queue.
+ 		 */
+ 		skb->data[1] = I_FRAME | (self->vs << 1);
+-		
++
+ 		tx_skb = skb_clone(skb, GFP_ATOMIC);
+ 		if (tx_skb == NULL) {
+ 			return;
+-		}		
++		}
+ 
+ 		/* Insert frame in store */
+ 		skb_queue_tail(&self->wx_list, skb_get(skb));
+-		
++
+ 		tx_skb->data[1] |= PF_BIT;
+-		
+-		self->vs = (self->vs + 1) % 8; 
++
++		self->vs = (self->vs + 1) % 8;
+ 		self->ack_required = FALSE;
+-		
+-		irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
++
++		irlap_send_i_frame(self, tx_skb, RSP_FRAME);
+ 	} else {
+ 		if (self->ack_required) {
+ 			irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
+@@ -885,32 +887,32 @@
+  *    Send I(nformation) frame as secondary without final bit set
+  *
+  */
+-void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb) 
++void irlap_send_data_secondary(struct irlap_cb *self, struct sk_buff *skb)
+ {
+ 	struct sk_buff *tx_skb = NULL;
+ 
+ 	/* Is this reliable or unreliable data? */
+ 	if (skb->data[1] == I_FRAME) {
+-		
+-		/*  
++
++		/*
+ 		 *  Insert frame sequence number (Vs) in control field before
+ 		 *  inserting into transmit window queue.
+ 		 */
+ 		skb->data[1] = I_FRAME | (self->vs << 1);
+-		
++
+ 		tx_skb = skb_clone(skb, GFP_ATOMIC);
+ 		if (tx_skb == NULL) {
+ 			return;
+-		}		
+-		
++		}
++
+ 		/* Insert frame in store */
+ 		skb_queue_tail(&self->wx_list, skb_get(skb));
+-		
++
+ 		self->vs = (self->vs + 1) % 8;
+-		self->ack_required = FALSE;		
++		self->ack_required = FALSE;
+ 		self->window -= 1;
+ 
+-		irlap_send_i_frame(self, tx_skb, RSP_FRAME); 
++		irlap_send_i_frame(self, tx_skb, RSP_FRAME);
+ 	} else {
+ 		irlap_send_ui_frame(self, skb_get(skb), self->caddr, RSP_FRAME);
+ 		self->window -= 1;
+@@ -920,8 +922,8 @@
+ /*
+  * Function irlap_resend_rejected_frames (nr)
+  *
+- *    Resend frames which has not been acknowledged. Should be safe to 
+- *    traverse the list without locking it since this function will only be 
++ *    Resend frames which has not been acknowledged. Should be safe to
++ *    traverse the list without locking it since this function will only be
+  *    called from interrupt context (BH)
+  */
+ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
+@@ -943,8 +945,8 @@
+ 	while (skb != NULL) {
+ 		irlap_wait_min_turn_around(self, &self->qos_tx);
+ 
+-		/* We copy the skb to be retransmitted since we will have to 
+-		 * modify it. Cloning will confuse packet sniffers 
++		/* We copy the skb to be retransmitted since we will have to
++		 * modify it. Cloning will confuse packet sniffers
+ 		 */
+ 		/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+ 		tx_skb = skb_copy(skb, GFP_ATOMIC);
+@@ -959,17 +961,17 @@
+ 		/* Clear old Nr field + poll bit */
+ 		tx_skb->data[1] &= 0x0f;
+ 
+-		/* 
++		/*
+ 		 *  Set poll bit on the last frame retransmitted
+ 		 */
+ 	 	if (count-- == 1)
+ 	 		tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
+ 		else
+ 			tx_skb->data[1] &= ~PF_BIT; /* Clear p/f bit */
+-	      	
++
+ 		irlap_send_i_frame(self, tx_skb, command);
+ 
+-		/* 
++		/*
+ 		 *  If our skb is the last buffer in the list, then
+ 		 *  we are finished, if not, move to the next sk-buffer
+ 		 */
+@@ -979,23 +981,23 @@
+ 			skb = skb->next;
+ 	}
+ #if 0 /* Not yet */
+-	/* 
++	/*
+ 	 *  We can now fill the window with additinal data frames
+ 	 */
+ 	while (skb_queue_len( &self->txq) > 0) {
+-		
++
+ 		IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__);
+-		if ((skb_queue_len( &self->txq) > 0) && 
++		if ((skb_queue_len( &self->txq) > 0) &&
+ 		    (self->window > 0)) {
+-			skb = skb_dequeue( &self->txq); 
++			skb = skb_dequeue( &self->txq);
+ 			ASSERT(skb != NULL, return;);
+ 
+ 			/*
+-			 *  If send window > 1 then send frame with pf 
++			 *  If send window > 1 then send frame with pf
+ 			 *  bit cleared
+-			 */ 
+-			if ((self->window > 1) && 
+-			    skb_queue_len(&self->txq) > 0) 
++			 */
++			if ((self->window > 1) &&
++			    skb_queue_len(&self->txq) > 0)
+ 			{
+ 				irlap_send_data_primary(self, skb);
+ 			} else {
+@@ -1023,14 +1025,14 @@
+ 	if (skb != NULL) {
+ 		irlap_wait_min_turn_around(self, &self->qos_tx);
+ 
+-		/* We copy the skb to be retransmitted since we will have to 
+-		 * modify it. Cloning will confuse packet sniffers 
++		/* We copy the skb to be retransmitted since we will have to
++		 * modify it. Cloning will confuse packet sniffers
+ 		 */
+ 		/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+ 		tx_skb = skb_copy(skb, GFP_ATOMIC);
+ 		if (!tx_skb) {
+ 			IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__);
+-			return;	
++			return;
+ 		}
+ 		/* Unlink tx_skb from list */
+ 		tx_skb->next = tx_skb->prev = NULL;
+@@ -1041,7 +1043,7 @@
+ 
+ 		/*  Set poll/final bit */
+ 		tx_skb->data[1] |= PF_BIT; /* Set p/f bit */
+-	      	
++
+ 		irlap_send_i_frame(self, tx_skb, command);
+ 	}
+ }
+@@ -1052,15 +1054,15 @@
+  *    Contruct and transmit an Unnumbered Information (UI) frame
+  *
+  */
+-void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
++void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
+ 			 __u8 caddr, int command)
+ {
+ 	IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
+-	
++
+ 	ASSERT(self != NULL, return;);
+ 	ASSERT(self->magic == LAP_MAGIC, return;);
+ 	ASSERT(skb != NULL, return;);
+-	
++
+ 	/* Insert connection address */
+ 	skb->data[0] = caddr | ((command) ? CMD_FRAME : 0);
+ 
+@@ -1072,13 +1074,13 @@
+  *
+  *    Contruct and transmit Information (I) frame
+  */
+-void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, 
+-			int command) 
++void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb,
++			int command)
+ {
+ 	/* Insert connection address */
+ 	skb->data[0] = self->caddr;
+ 	skb->data[0] |= (command) ? CMD_FRAME : 0;
+-	
++
+ 	/* Insert next to receive (Vr) */
+ 	skb->data[1] |= (self->vr << 5);  /* insert nr */
+ 
+@@ -1091,9 +1093,9 @@
+  *    Receive and parse an I (Information) frame, no harm in making it inline
+  *    since it's called only from one single place (irlap_driver_rcv).
+  */
+-static inline void irlap_recv_i_frame(struct irlap_cb *self, 
+-				      struct sk_buff *skb, 
+-				      struct irlap_info *info, int command) 
++static inline void irlap_recv_i_frame(struct irlap_cb *self,
++				      struct sk_buff *skb,
++				      struct irlap_info *info, int command)
+ {
+ 	info->nr = skb->data[1] >> 5;          /* Next to receive */
+ 	info->pf = skb->data[1] & PF_BIT;      /* Final bit */
+@@ -1112,7 +1114,7 @@
+  *    Receive and parse an Unnumbered Information (UI) frame
+  *
+  */
+-static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, 
++static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb,
+ 				struct irlap_info *info)
+ {
+ 	IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
+@@ -1128,19 +1130,19 @@
+  *    Received Frame Reject response.
+  *
+  */
+-static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, 
+-				  struct irlap_info *info) 
++static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb,
++				  struct irlap_info *info)
+ {
+ 	__u8 *frame;
+ 	int w, x, y, z;
+ 
+ 	IRDA_DEBUG(0, "%s()\n", __FUNCTION__);
+-	
++
+ 	ASSERT(self != NULL, return;);
+ 	ASSERT(self->magic == LAP_MAGIC, return;);
+ 	ASSERT(skb != NULL, return;);
+ 	ASSERT(info != NULL, return;);
+-	
++
+ 	frame = skb->data;
+ 
+ 	info->nr = frame[2] >> 5;          /* Next to receive */
+@@ -1151,11 +1153,11 @@
+ 	x = frame[3] & 0x02;
+ 	y = frame[3] & 0x04;
+ 	z = frame[3] & 0x08;
+-	
++
+ 	if (w) {
+ 		IRDA_DEBUG(0, "Rejected control field is undefined or not "
+ 		      "implemented.\n");
+-	} 
++	}
+ 	if (x) {
+ 		IRDA_DEBUG(0, "Rejected control field was invalid because it "
+ 		      "contained a non permitted I field.\n");
+@@ -1178,7 +1180,7 @@
+  *    Send a test frame response
+  *
+  */
+-void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr, 
++void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
+ 			   struct sk_buff *cmd)
+ {
+ 	struct sk_buff *skb;
+@@ -1191,7 +1193,7 @@
+ 
+ 	/* Broadcast frames must include saddr and daddr fields */
+ 	if (caddr == CBROADCAST) {
+-		frame = (struct test_frame *) 
++		frame = (struct test_frame *)
+ 			skb_put(skb, sizeof(struct test_frame));
+ 
+ 		/* Insert the swapped addresses */
+@@ -1218,28 +1220,28 @@
+  *    Receive a test frame
+  *
+  */
+-static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, 
++static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb,
+ 				  struct irlap_info *info, int command)
+ {
+ 	struct test_frame *frame;
+ 
+ 	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+-	
++
+ 	frame = (struct test_frame *) skb->data;
+-		
++
+ 	/* Broadcast frames must carry saddr and daddr fields */
+ 	if (info->caddr == CBROADCAST) {
+ 		if (skb->len < sizeof(struct test_frame)) {
+ 			IRDA_DEBUG(0, "%s() test frame to short!\n", __FUNCTION__);
+ 			return;
+ 		}
+-		
++
+ 		/* Read and swap addresses */
+-		info->daddr = le32_to_cpu(frame->saddr);
+-		info->saddr = le32_to_cpu(frame->daddr);
++		info->daddr = le32_to_cpu(get_unaligned(&frame->saddr));
++		info->saddr = le32_to_cpu(get_unaligned(&frame->daddr));
+ 
+ 		/* Make sure frame is addressed to us */
+-		if ((info->saddr != self->saddr) && 
++		if ((info->saddr != self->saddr) &&
+ 		    (info->saddr != BROADCAST)) {
+ 			return;
+ 		}
+@@ -1254,18 +1256,18 @@
+ /*
+  * Function irlap_driver_rcv (skb, netdev, ptype)
+  *
+- *    Called when a frame is received. Dispatches the right receive function 
++ *    Called when a frame is received. Dispatches the right receive function
+  *    for processing of the frame.
+  *
+  */
+-int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, 
++int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev,
+ 		     struct packet_type *ptype)
+ {
+ 	struct irlap_info info;
+ 	struct irlap_cb *self;
+ 	int command;
+ 	__u8 control;
+-	
++
+ 	/* FIXME: should we get our own field? */
+ 	self = (struct irlap_cb *) dev->atalk_ptr;
+ 
+@@ -1281,10 +1283,10 @@
+ 		dev_kfree_skb(skb);
+ 		return -1;
+ 	}
+-	
++
+ 	command    = skb->data[0] & CMD_FRAME;
+ 	info.caddr = skb->data[0] & CBROADCAST;
+-	
++
+ 	info.pf      = skb->data[1] &  PF_BIT;
+ 	info.control = skb->data[1] & ~PF_BIT; /* Mask away poll/final bit */
+ 
+@@ -1295,7 +1297,7 @@
+ 		IRDA_DEBUG(0, "%s(), wrong connection address!\n", __FUNCTION__);
+ 		goto out;
+ 	}
+-	/*  
++	/*
+ 	 *  Optimize for the common case and check if the frame is an
+ 	 *  I(nformation) frame. Only I-frames have bit 0 set to 0
+ 	 */
+@@ -1304,11 +1306,11 @@
+ 		goto out;
+ 	}
+ 	/*
+-	 *  We now check is the frame is an S(upervisory) frame. Only 
++	 *  We now check is the frame is an S(upervisory) frame. Only
+ 	 *  S-frames have bit 0 set to 1 and bit 1 set to 0
+ 	 */
+ 	if (~control & 0x02) {
+-		/* 
++		/*
+ 		 *  Received S(upervisory) frame, check which frame type it is
+ 		 *  only the first nibble is of interest
+ 		 */
+@@ -1332,8 +1334,8 @@
+ 		}
+ 		goto out;
+ 	}
+-	/* 
+-	 *  This must be a C(ontrol) frame 
++	/*
++	 *  This must be a C(ontrol) frame
+ 	 */
+ 	switch (control) {
+ 	case XID_RSP:
+@@ -1369,6 +1371,6 @@
+ 		break;
+ 	}
+ out:
+-	dev_kfree_skb(skb); 
++	dev_kfree_skb(skb);
+ 	return 0;
+ }
+--- linux-2.4.25/net/irda/irttp.c~2.4.25-vrs2.patch	2003-11-28 19:26:21.000000000 +0100
++++ linux-2.4.25/net/irda/irttp.c	2004-03-31 17:15:09.000000000 +0200
+@@ -1665,8 +1665,8 @@
+ 		}
+ 		self->rx_sdu_size = 0;
+ 	}
+-
+-	/*
++  
++  	/*
+ 	 * It's not trivial to keep track of how many credits are available
+ 	 * by incrementing at each packet, because delivery may fail 
+ 	 * (irttp_do_data_indication() may requeue the frame) and because
+@@ -1676,7 +1676,7 @@
+ 	 * to send remote_credit.
+ 	 * No need to spinlock, write is atomic and self correcting...
+ 	 * Jean II
+-	 */
++  	 */
+ 	self->avail_credit = (self->initial_credit -
+ 			      (self->remote_credit +
+ 			       skb_queue_len(&self->rx_queue) +
+--- linux-2.4.25/net/sched/Config.in~2.4.25-vrs2.patch	2004-02-18 14:36:32.000000000 +0100
++++ linux-2.4.25/net/sched/Config.in	2004-03-31 17:15:09.000000000 +0200
+@@ -3,9 +3,9 @@
+ # 
+ tristate '  CBQ packet scheduler' CONFIG_NET_SCH_CBQ
+ tristate '  HTB packet scheduler' CONFIG_NET_SCH_HTB
+-tristate '  CSZ packet scheduler' CONFIG_NET_SCH_CSZ
++dep_tristate '  CSZ packet scheduler (experimental)' CONFIG_NET_SCH_CSZ $CONFIG_EXPERIMENTAL
+ #tristate '  H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ
+-tristate '  H-FSC packet scheduler' CONFIG_NET_SCH_HFSC
++tristate '  H-FSC packet scheduler' CONFIG_NET_SCH_HFCS
+ if [ "$CONFIG_ATM" = "y" -o "$CONFIG_ATM" = "m" ]; then
+    dep_tristate '  ATM pseudo-scheduler' CONFIG_NET_SCH_ATM $CONFIG_ATM
+ fi
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch
index e69de29bb2..79ba036323 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/disable-pcmcia-probe.patch
@@ -0,0 +1,17 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe	2003-05-13 11:18:23.000000000 +0200
++++ linux/drivers/pcmcia/Config.in	2004-05-27 13:59:50.000000000 +0200
+@@ -15,9 +15,6 @@
+ tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+ if [ "$CONFIG_PCMCIA" != "n" ]; then
+    # yes, I really mean the following...
+-   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then
+-      define_bool CONFIG_PCMCIA_PROBE y
+-   fi
+    if [ "$CONFIG_PCI" != "n" ]; then
+       bool '  CardBus support' CONFIG_CARDBUS
+    fi
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch
index e69de29bb2..57218a7d1a 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mkdep.patch
@@ -0,0 +1,16 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.25/Makefile~mkdep	2004-03-31 17:15:12.000000000 +0200
++++ linux-2.4.25/Makefile	2004-03-31 17:18:50.000000000 +0200
+@@ -502,7 +502,7 @@
+ ifdef CONFIG_MODVERSIONS
+ 	$(MAKE) update-modverfile
+ endif
+-	scripts/mkdep -- `find $(FINDHPATH) \( -name SCCS -o -name .svn \) -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
++	$(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)	
+ 	scripts/mkdep -- init/*.c > .depend
+ 
+ ifdef CONFIG_MODVERSIONS
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch
index e69de29bb2..4393e2ea83 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/mppe-20040216.patch
@@ -0,0 +1,1225 @@
+
+#
+# Patch managed by http://www.holgerschurig.de/patcher.html
+#
+
+--- linux-2.4.25/drivers/net/Config.in~mppe-20040216
++++ linux-2.4.25/drivers/net/Config.in
+@@ -327,6 +327,7 @@
+    dep_tristate '  PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP
+    dep_tristate '  PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP
+    dep_tristate '  PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP
++   dep_tristate '  PPP MPPE compression (encryption)' CONFIG_PPP_MPPE $CONFIG_PPP
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+       dep_tristate '  PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP
+    fi
+--- /dev/null
++++ linux-2.4.25/drivers/net/arcfour.c
+@@ -0,0 +1,75 @@
++/*
++ * arcfour.c
++ * by Frank Cusack <frank@google.com>
++ * 100% public domain
++ *
++ * Implemented from the description in _Applied Cryptography_, 2nd ed.
++ *
++ * ** Distribution ** of this software is unlimited and unrestricted.
++ *
++ * ** Use ** of this software is almost certainly legal; however, refer
++ * to <http://theory.lcs.mit.edu/~rivest/faq.html>.
++ */
++
++#include "arcfour.h"
++#if defined(__linux__)
++#include <linux/string.h>
++#endif
++
++#define swap(a, b)		\
++{				\
++    unsigned char t = b;	\
++    b = a;			\
++    a = t;			\
++}
++
++/*
++ * Initialize arcfour from a key.
++ */
++void
++arcfour_setkey(arcfour_context *context, const unsigned char *key,
++	       unsigned keylen)
++{
++    unsigned i, j;
++    unsigned char K[256];
++
++    context->i = context->j = 0;
++
++    for (i = 0; i < 256; i++) {
++	context->S[i] = i;
++	K[i] = key[i % keylen];
++    }
++
++    j = 0;
++    for (i = 0; i < 256; i++) {
++	j = (j + context->S[i] + K[i]) % 256;
++	swap(context->S[i], context->S[j]);
++    }
++
++    memset(K, 0, sizeof(K));
++}
++
++/*
++ * plaintext -> ciphertext (or vice versa)
++ */
++void
++arcfour_encrypt(arcfour_context *context, const unsigned char *in, unsigned len,
++		unsigned char *out)
++{
++    unsigned i = context->i;
++    unsigned j = context->j;
++    unsigned char *S = context->S;
++    unsigned char K;
++
++    while (len--) {
++	i = (i + 1) % 256;
++	j = (j + S[i]) % 256;
++	swap(S[i], S[j]);
++	K = S[(S[i] + S[j]) % 256];
++	*out++ = *in++ ^ K;
++    }
++
++    context->i = i;
++    context->j = j;
++}
++
+--- /dev/null
++++ linux-2.4.25/drivers/net/arcfour.h
+@@ -0,0 +1,17 @@
++/* arcfour.h */
++
++#ifndef _ARCFOUR_H
++#define _ARCFOUR_H
++
++typedef struct {
++    unsigned i;
++    unsigned j;
++    unsigned char S[256];
++} arcfour_context;
++
++extern void arcfour_setkey(arcfour_context *, const unsigned char *, unsigned);
++extern void arcfour_encrypt(arcfour_context *, const unsigned char *, unsigned,
++			    unsigned char *);
++#define arcfour_decrypt arcfour_encrypt
++
++#endif /* _ARCFOUR_H */
+--- linux-2.4.25/drivers/net/ppp_generic.c~mppe-20040216
++++ linux-2.4.25/drivers/net/ppp_generic.c
+@@ -102,6 +102,7 @@
+ 	spinlock_t	rlock;		/* lock for receive side 58 */
+ 	spinlock_t	wlock;		/* lock for transmit side 5c */
+ 	int		mru;		/* max receive unit 60 */
++	int		mru_alloc;	/* MAX(1500,MRU) for dev_alloc_skb() */
+ 	unsigned int	flags;		/* control bits 64 */
+ 	unsigned int	xstate;		/* transmit state bits 68 */
+ 	unsigned int	rstate;		/* receive state bits 6c */
+@@ -129,6 +130,7 @@
+ 	struct sock_fprog pass_filter;	/* filter for packets to pass */
+ 	struct sock_fprog active_filter;/* filter for pkts to reset idle */
+ #endif /* CONFIG_PPP_FILTER */
++	int		xpad;		/* ECP or CCP (MPPE) transmit padding */
+ };
+ 
+ /*
+@@ -552,7 +554,9 @@
+ 	case PPPIOCSMRU:
+ 		if (get_user(val, (int *) arg))
+ 			break;
+-		ppp->mru = val;
++		ppp->mru_alloc = ppp->mru = val;
++		if (ppp->mru_alloc < PPP_MRU)
++		    ppp->mru_alloc = PPP_MRU;	/* increase for broken peers */
+ 		err = 0;
+ 		break;
+ 
+@@ -1031,8 +1035,8 @@
+ 	/* try to do packet compression */
+ 	if ((ppp->xstate & SC_COMP_RUN) && ppp->xc_state != 0
+ 	    && proto != PPP_LCP && proto != PPP_CCP) {
+-		new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len,
+-				    GFP_ATOMIC);
++		new_skb = alloc_skb(ppp->dev->mtu + ppp->dev->hard_header_len
++				    + ppp->xpad, GFP_ATOMIC);
+ 		if (new_skb == 0) {
+ 			printk(KERN_ERR "PPP: no memory (comp pkt)\n");
+ 			goto drop;
+@@ -1044,15 +1048,28 @@
+ 		/* compressor still expects A/C bytes in hdr */
+ 		len = ppp->xcomp->compress(ppp->xc_state, skb->data - 2,
+ 					   new_skb->data, skb->len + 2,
+-					   ppp->dev->mtu + PPP_HDRLEN);
++					   ppp->dev->mtu + ppp->xpad
++					   + PPP_HDRLEN);
+ 		if (len > 0 && (ppp->flags & SC_CCP_UP)) {
+ 			kfree_skb(skb);
+ 			skb = new_skb;
+ 			skb_put(skb, len);
+ 			skb_pull(skb, 2);	/* pull off A/C bytes */
+-		} else {
++		} else if (len == 0) {
+ 			/* didn't compress, or CCP not up yet */
+ 			kfree_skb(new_skb);
++		} else {
++			/*
++			 * (len < 0)
++			 * MPPE requires that we do not send unencrypted
++			 * frames.  The compressor will return -1 if we
++			 * should drop the frame.  We cannot simply test
++			 * the compress_proto because MPPE and MPPC share
++			 * the same number.
++			 */
++			printk(KERN_ERR "ppp: compressor dropped pkt\n");
++			kfree_skb(new_skb);
++			goto drop;
+ 		}
+ 	}
+ 
+@@ -1540,14 +1557,15 @@
+ 	int len;
+ 
+ 	if (proto == PPP_COMP) {
+-		ns = dev_alloc_skb(ppp->mru + PPP_HDRLEN);
++		ns = dev_alloc_skb(ppp->mru_alloc + PPP_HDRLEN);
+ 		if (ns == 0) {
+ 			printk(KERN_ERR "ppp_decompress_frame: no memory\n");
+ 			goto err;
+ 		}
+ 		/* the decompressor still expects the A/C bytes in the hdr */
+ 		len = ppp->rcomp->decompress(ppp->rc_state, skb->data - 2,
+-				skb->len + 2, ns->data, ppp->mru + PPP_HDRLEN);
++				skb->len + 2, ns->data,
++				ppp->mru_alloc + PPP_HDRLEN);
+ 		if (len < 0) {
+ 			/* Pass the compressed frame to pppd as an
+ 			   error indication. */
+@@ -1982,6 +2000,20 @@
+ 				ocomp->comp_free(ostate);
+ 			err = 0;
+ 		}
++		if (ccp_option[0] == CI_MPPE)
++			/*
++			 * pppd (userland) has reduced the MTU by MPPE_PAD,
++			 * to accomodate "compressor" growth.  We must
++			 * increase the space allocated for compressor
++			 * output in ppp_send_frame() accordingly.  Note
++			 * that from a purist's view, it may be more correct
++			 * to require multilink and fragment large packets,
++			 * but that seems inefficient compared to this
++			 * little trick.
++			 */
++			ppp->xpad = MPPE_PAD;
++		else
++			ppp->xpad = 0;
+ 
+ 	} else {
+ 		state = cp->decomp_alloc(ccp_option, data.length);
+@@ -2253,6 +2285,7 @@
+ 	/* Initialize the new ppp unit */
+ 	ppp->file.index = unit;
+ 	ppp->mru = PPP_MRU;
++	ppp->mru_alloc = PPP_MRU;
+ 	init_ppp_file(&ppp->file, INTERFACE);
+ 	ppp->file.hdrlen = PPP_HDRLEN - 2;	/* don't count proto bytes */
+ 	for (i = 0; i < NUM_NP; ++i)
+--- /dev/null
++++ linux-2.4.25/drivers/net/ppp_mppe_compress.c
+@@ -0,0 +1,643 @@
++/*
++ *  ==FILEVERSION 20020521==
++ *
++ * ppp_mppe_compress.c - interface MPPE to the PPP code.
++ * This version is for use with Linux kernel 2.2.19+ and 2.4.x.
++ *
++ * By Frank Cusack <frank@google.com>.
++ * Copyright (c) 2002 Google, Inc.
++ * All rights reserved.
++ *
++ * Permission to use, copy, modify, and distribute this software and its
++ * documentation is hereby granted, provided that the above copyright
++ * notice appears in all copies.  This software is provided without any
++ * warranty, express or implied.
++ *
++ * Changelog:
++ *      2/15/04 - TS: added #include <version.h> and testing for Kernel
++ *                    version before using 
++ *                    MOD_DEC_USAGE_COUNT/MOD_INC_USAGE_COUNT which are
++ *                    depreciated in 2.6
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++
++#include <linux/ppp_defs.h>
++#include <linux/ppp-comp.h>
++
++#include "arcfour.h"
++#include "sha1.h"
++
++/*
++ * State for an MPPE (de)compressor.
++ */
++typedef struct ppp_mppe_state {
++    unsigned char	master_key[MPPE_MAX_KEY_LEN];
++    unsigned char	session_key[MPPE_MAX_KEY_LEN];
++    arcfour_context	arcfour_context; /* encryption state */
++    unsigned		keylen;		/* key length in bytes             */
++					/* NB: 128-bit == 16, 40-bit == 8! */
++					/* If we want to support 56-bit,   */
++					/* the unit has to change to bits  */
++    unsigned char	bits;		/* MPPE control bits */
++    unsigned		ccount;		/* 12-bit coherency count (seqno)  */
++    unsigned		stateful;	/* stateful mode flag */
++    int			discard;	/* stateful mode packet loss flag */
++    int			sanity_errors;	/* take down LCP if too many */
++    int			unit;
++    int			debug;
++    struct compstat	stats;
++} ppp_mppe_state;
++
++/* ppp_mppe_state.bits definitions */
++#define MPPE_BIT_A	0x80	/* Encryption table were (re)inititalized */
++#define MPPE_BIT_B	0x40	/* MPPC only (not implemented) */
++#define MPPE_BIT_C	0x20	/* MPPC only (not implemented) */
++#define MPPE_BIT_D	0x10	/* This is an encrypted frame */
++
++#define MPPE_BIT_FLUSHED	MPPE_BIT_A
++#define MPPE_BIT_ENCRYPTED	MPPE_BIT_D
++
++#define MPPE_BITS(p) ((p)[4] & 0xf0)
++#define MPPE_CCOUNT(p) ((((p)[4] & 0x0f) << 8) + (p)[5])
++#define MPPE_CCOUNT_SPACE 0x1000	/* The size of the ccount space */
++
++#define MPPE_OVHD	2		/* MPPE overhead/packet */
++#define SANITY_MAX	1600		/* Max bogon factor we will tolerate */
++
++static void	GetNewKeyFromSHA __P((unsigned char *StartKey,
++				      unsigned char *SessionKey,
++				      unsigned SessionKeyLength,
++				      unsigned char *InterimKey));
++static void	mppe_rekey __P((ppp_mppe_state *state, int));
++static void	*mppe_alloc __P((unsigned char *options, int optlen));
++static void	mppe_free __P((void *state));
++static int	mppe_init __P((void *state, unsigned char *options,
++			       int optlen, int unit, int debug, const char *));
++static int	mppe_comp_init __P((void *state, unsigned char *options,
++				    int optlen,
++				    int unit, int hdrlen, int debug));
++static int	mppe_decomp_init __P((void *state, unsigned char *options,
++				      int optlen, int unit,
++				      int hdrlen, int mru, int debug));
++static int	mppe_compress __P((void *state, unsigned char *ibuf,
++				   unsigned char *obuf,
++				   int isize, int osize));
++static void	mppe_incomp __P((void *state, unsigned char *ibuf, int icnt));
++static int	mppe_decompress __P((void *state, unsigned char *ibuf,
++				     int isize, unsigned char *obuf,int osize));
++static void	mppe_comp_reset __P((void *state));
++static void	mppe_decomp_reset __P((void *state));
++static void	mppe_comp_stats __P((void *state, struct compstat *stats));
++
++
++/*
++ * Key Derivation, from RFC 3078, RFC 3079.
++ * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
++ */
++static void
++GetNewKeyFromSHA(unsigned char *MasterKey, unsigned char *SessionKey,
++		 unsigned SessionKeyLength, unsigned char *InterimKey)
++{
++    SHA1_CTX Context;
++    unsigned char Digest[SHA1_SIGNATURE_SIZE];
++
++    unsigned char SHApad1[40] =
++    { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
++    unsigned char SHApad2[40] =
++    { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
++      0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
++      0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
++      0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
++
++    /* assert(SessionKeyLength <= SHA1_SIGNATURE_SIZE); */
++
++    SHA1_Init(&Context);
++    SHA1_Update(&Context, MasterKey, SessionKeyLength);
++    SHA1_Update(&Context, SHApad1, sizeof(SHApad1));
++    SHA1_Update(&Context, SessionKey, SessionKeyLength);
++    SHA1_Update(&Context, SHApad2, sizeof(SHApad2));
++    SHA1_Final(Digest, &Context);
++
++    memcpy(InterimKey, Digest, SessionKeyLength);
++}
++
++/*
++ * Perform the MPPE rekey algorithm, from RFC 3078, sec. 7.3.
++ * Well, not what's written there, but rather what they meant.
++ */
++static void
++mppe_rekey(ppp_mppe_state *state, int initial_key)
++{
++    unsigned char InterimKey[MPPE_MAX_KEY_LEN];
++
++    GetNewKeyFromSHA(state->master_key, state->session_key,
++		     state->keylen, InterimKey);
++    if (!initial_key) {
++	arcfour_setkey(&state->arcfour_context, InterimKey, state->keylen);
++	arcfour_encrypt(&state->arcfour_context, InterimKey, state->keylen,
++			state->session_key);
++    } else {
++	memcpy(state->session_key, InterimKey, state->keylen);
++    }
++    if (state->keylen == 8) {
++	/* See RFC 3078 */
++	state->session_key[0] = 0xd1;
++	state->session_key[1] = 0x26;
++	state->session_key[2] = 0x9e;
++    }
++    arcfour_setkey(&state->arcfour_context, state->session_key, state->keylen);
++}
++
++
++/*
++ * Allocate space for a (de)compressor.
++ */
++static void *
++mppe_alloc(unsigned char *options, int optlen)
++{
++    ppp_mppe_state *state;
++
++    if (optlen != CILEN_MPPE + sizeof(state->master_key)
++	|| options[0] != CI_MPPE
++	|| options[1] != CILEN_MPPE)
++	return NULL;
++
++    state = (ppp_mppe_state *) kmalloc(sizeof(*state), GFP_KERNEL);
++    if (state == NULL)
++	return NULL;
++
++/* 
++   Added to avoid module warnings about MOD_INC 
++   being depreciated in 2.6.x 
++*/ 
++#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) )
++    try_module_get(THIS_MODULE);
++#else
++    MOD_INC_USE_COUNT;
++#endif
++    memset(state, 0, sizeof(*state));
++
++    /* Save keys. */
++    memcpy(state->master_key, &options[CILEN_MPPE], sizeof(state->master_key));
++    memcpy(state->session_key, state->master_key, sizeof(state->master_key));
++    /*
++     * We defer initial key generation until mppe_init(), as mppe_alloc()
++     * is called frequently during negotiation.
++     */
++
++    return (void *) state;
++}
++
++/*
++ * Deallocate space for a (de)compressor.
++ */
++static void
++mppe_free(void *arg)
++{
++    ppp_mppe_state *state = (ppp_mppe_state *) arg;
++
++    if (state) {
++	kfree(state);
++/* 
++   Added to avoid module warnings about MOD_DEC_USE_COUNT 
++   being depreciated in 2.6.x 
++*/ 
++#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) )
++        module_put(THIS_MODULE);
++#else
++	MOD_DEC_USE_COUNT;
++#endif
++    }
++}
++
++
++/* 
++ * Initialize (de)compressor state.
++ */
++static int
++mppe_init(void *arg, unsigned char *options, int optlen, int unit, int debug,
++	  const char *debugstr)
++{
++    ppp_mppe_state *state = (ppp_mppe_state *) arg;
++    unsigned char mppe_opts;
++
++    if (optlen != CILEN_MPPE
++	|| options[0] != CI_MPPE
++	|| options[1] != CILEN_MPPE)
++	return 0;
++
++    MPPE_CI_TO_OPTS(&options[2], mppe_opts);
++    if (mppe_opts & MPPE_OPT_128)
++	state->keylen = 16;
++    else if (mppe_opts & MPPE_OPT_40)
++	state->keylen = 8;
++    else {
++	printk(KERN_WARNING "%s[%d]: unknown key length\n", debugstr, unit);
++	return 0;
++    }
++    if (mppe_opts & MPPE_OPT_STATEFUL)
++	state->stateful = 1;
++
++    /* Generate the initial session key. */
++    mppe_rekey(state, 1);
++
++    if (debug) {
++	int i;
++	char mkey[sizeof(state->master_key) * 2 + 1];
++	char skey[sizeof(state->session_key) * 2 + 1];
++
++	printk(KERN_DEBUG "%s[%d]: initialized with %d-bit %s mode\n", debugstr,
++	       unit, (state->keylen == 16)? 128: 40,
++	       (state->stateful)? "stateful": "stateless");
++
++	for (i = 0; i < sizeof(state->master_key); i++)
++	    sprintf(mkey + i * 2, "%.2x", state->master_key[i]);
++	for (i = 0; i < sizeof(state->session_key); i++)
++	    sprintf(skey + i * 2, "%.2x", state->session_key[i]);
++	printk(KERN_DEBUG "%s[%d]: keys: master: %s initial session: %s\n",
++	       debugstr, unit, mkey, skey);
++    }
++
++    /*
++     * Initialize the coherency count.  The initial value is not specified
++     * in RFC 3078, but we can make a reasonable assumption that it will
++     * start at 0.  Setting it to the max here makes the comp/decomp code
++     * do the right thing (determined through experiment).
++     */
++    state->ccount = MPPE_CCOUNT_SPACE - 1;
++
++    /*
++     * Note that even though we have initialized the key table, we don't
++     * set the FLUSHED bit.  This is contrary to RFC 3078, sec. 3.1.
++     */
++    state->bits = MPPE_BIT_ENCRYPTED;
++
++    state->unit  = unit;
++    state->debug = debug;
++
++    return 1;
++}
++
++
++
++static int
++mppe_comp_init(void *arg, unsigned char *options, int optlen, int unit,
++	       int hdrlen, int debug)
++{
++    /* ARGSUSED */
++    return mppe_init(arg, options, optlen, unit, debug, "mppe_comp_init");
++}
++
++/*
++ * We received a CCP Reset-Request (actually, we are sending a Reset-Ack),
++ * tell the compressor to rekey.  Note that we MUST NOT rekey for
++ * every CCP Reset-Request; we only rekey on the next xmit packet.
++ * We might get multiple CCP Reset-Requests if our CCP Reset-Ack is lost.
++ * So, rekeying for every CCP Reset-Request is broken as the peer will not
++ * know how many times we've rekeyed.  (If we rekey and THEN get another
++ * CCP Reset-Request, we must rekey again.)
++ */
++static void
++mppe_comp_reset(void *arg)
++{
++    ppp_mppe_state *state = (ppp_mppe_state *) arg;
++
++    state->bits |= MPPE_BIT_FLUSHED;
++}
++
++/*
++ * Compress (encrypt) a packet.
++ * It's strange to call this a compressor, since the output is always
++ * MPPE_OVHD + 2 bytes larger than the input.
++ */
++int
++mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
++	      int isize, int osize)
++{
++    ppp_mppe_state *state = (ppp_mppe_state *) arg;
++    int proto;
++
++    /*
++     * Check that the protocol is in the range we handle.
++     */
++    proto = PPP_PROTOCOL(ibuf);
++    if (proto < 0x0021 || proto > 0x00fa)
++	return 0;
++
++    /* Make sure we have enough room to generate an encrypted packet. */
++    if (osize < isize + MPPE_OVHD + 2) {
++	/* Drop the packet if we should encrypt it, but can't. */
++	printk(KERN_DEBUG "mppe_compress[%d]: osize too small! "
++	       "(have: %d need: %d)\n", state->unit,
++	       osize, osize + MPPE_OVHD + 2);
++	return -1;
++    }
++
++    osize = isize + MPPE_OVHD + 2;
++
++    /*
++     * Copy over the PPP header and set control bits.
++     */
++    obuf[0] = PPP_ADDRESS(ibuf);
++    obuf[1] = PPP_CONTROL(ibuf);
++    obuf[2] = PPP_COMP >> 8;		/* isize + MPPE_OVHD + 1 */
++    obuf[3] = PPP_COMP;			/* isize + MPPE_OVHD + 2 */
++    obuf += PPP_HDRLEN;
++
++    state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
++    if (state->debug >= 7)
++	printk(KERN_DEBUG "mppe_compress[%d]: ccount %d\n", state->unit,
++	       state->ccount);
++    obuf[0] = state->ccount >> 8;
++    obuf[1] = state->ccount & 0xff;
++
++    if (!state->stateful ||			/* stateless mode     */
++	((state->ccount & 0xff) == 0xff) ||	/* "flag" packet      */
++	(state->bits & MPPE_BIT_FLUSHED)) {	/* CCP Reset-Request  */
++	/* We must rekey */
++	if (state->debug && state->stateful)
++	    printk(KERN_DEBUG "mppe_compress[%d]: rekeying\n", state->unit);
++	mppe_rekey(state, 0);
++	state->bits |= MPPE_BIT_FLUSHED;
++    }
++    obuf[0] |= state->bits;
++    state->bits &= ~MPPE_BIT_FLUSHED;	/* reset for next xmit */
++
++    obuf  += MPPE_OVHD;
++    ibuf  += 2;	/* skip to proto field */
++    isize -= 2;
++
++    /* Encrypt packet */
++    arcfour_encrypt(&state->arcfour_context, ibuf, isize, obuf);
++
++    state->stats.unc_bytes += isize;
++    state->stats.unc_packets++;
++    state->stats.comp_bytes += osize;
++    state->stats.comp_packets++;
++
++    return osize;
++}
++
++/*
++ * Since every frame grows by MPPE_OVHD + 2 bytes, this is always going
++ * to look bad ... and the longer the link is up the worse it will get.
++ */
++static void
++mppe_comp_stats(void *arg, struct compstat *stats)
++{
++    ppp_mppe_state *state = (ppp_mppe_state *) arg;
++
++    *stats = state->stats;
++}
++
++
++static int
++mppe_decomp_init(void *arg, unsigned char *options, int optlen, int unit,
++		 int hdrlen, int mru, int debug)
++{
++    /* ARGSUSED */
++    return mppe_init(arg, options, optlen, unit, debug, "mppe_decomp_init");
++}
++
++/*
++ * We received a CCP Reset-Ack.  Just ignore it.
++ */
++static void
++mppe_decomp_reset(void *arg)
++{
++    /* ARGSUSED */
++    return;
++}
++
++/*
++ * Decompress (decrypt) an MPPE packet.
++ */
++int
++mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
++		int osize)
++{
++    ppp_mppe_state *state = (ppp_mppe_state *) arg;
++    unsigned ccount;
++    int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
++    int sanity = 0;
++
++    if (isize <= PPP_HDRLEN + MPPE_OVHD) {
++	if (state->debug)
++	    printk(KERN_DEBUG "mppe_decompress[%d]: short pkt (%d)\n",
++		   state->unit, isize);
++	return DECOMP_ERROR;
++    }
++
++    /* Make sure we have enough room to decrypt the packet. */
++    if (osize < isize - MPPE_OVHD - 2) {
++	printk(KERN_DEBUG "mppe_decompress[%d]: osize too small! "
++	       "(have: %d need: %d)\n", state->unit,
++	       osize, isize - MPPE_OVHD - 2);
++	return DECOMP_ERROR;
++    }
++    osize = isize - MPPE_OVHD - 2;
++
++    ccount = MPPE_CCOUNT(ibuf);
++    if (state->debug >= 7)
++	printk(KERN_DEBUG "mppe_decompress[%d]: ccount %d\n", state->unit,
++	       ccount);
++
++    /* sanity checks -- terminate with extreme prejudice */
++    if (!(MPPE_BITS(ibuf) & MPPE_BIT_ENCRYPTED)) {
++	printk(KERN_DEBUG "mppe_decompress[%d]: ENCRYPTED bit not set!\n",
++	       state->unit);
++	state->sanity_errors += 100;
++	sanity = 1;
++    }
++    if (!state->stateful && !flushed) {
++	printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set in "
++	       "stateless mode!\n", state->unit);
++	state->sanity_errors += 100;
++	sanity = 1;
++    }
++    if (state->stateful && ((ccount & 0xff) == 0xff) && !flushed) {
++	printk(KERN_DEBUG "mppe_decompress[%d]: FLUSHED bit not set on "
++	       "flag packet!\n", state->unit);
++	state->sanity_errors += 100;
++	sanity = 1;
++    }
++
++    if (sanity) {
++	if (state->sanity_errors < SANITY_MAX)
++	    return DECOMP_ERROR;
++	else
++	    /*
++	     * Take LCP down if the peer is sending too many bogons.
++	     * We don't want to do this for a single or just a few
++	     * instances since it could just be due to packet corruption.
++	     */
++	    return DECOMP_FATALERROR;
++    }
++
++    /*
++     * Check the coherency count.
++     */
++
++    if (!state->stateful) {
++	/* RFC 3078, sec 8.1.  Rekey for every packet. */
++	while (state->ccount != ccount) {
++	    mppe_rekey(state, 0);
++	    state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
++	}
++    } else {
++	/* RFC 3078, sec 8.2. */
++	if (!state->discard) {
++	    /* normal state */
++	    state->ccount = (state->ccount + 1) % MPPE_CCOUNT_SPACE;
++	    if (ccount != state->ccount) {
++		/*
++		 * (ccount > state->ccount)
++		 * Packet loss detected, enter the discard state.
++		 * Signal the peer to rekey (by sending a CCP Reset-Request).
++		 */
++		state->discard = 1;
++		return DECOMP_ERROR;
++	    }
++	} else {
++	    /* discard state */
++	   if (!flushed) {
++		/* ccp.c will be silent (no additional CCP Reset-Requests). */
++		return DECOMP_ERROR;
++	    } else {
++		/* Rekey for every missed "flag" packet. */
++		while ((ccount & ~0xff) != (state->ccount & ~0xff)) {
++		    mppe_rekey(state, 0);
++		    state->ccount = (state->ccount + 256) % MPPE_CCOUNT_SPACE;
++		}
++
++		/* reset */
++		state->discard = 0;
++		state->ccount = ccount;
++		/*
++		 * Another problem with RFC 3078 here.  It implies that the
++		 * peer need not send a Reset-Ack packet.  But RFC 1962
++		 * requires it.  Hopefully, M$ does send a Reset-Ack; even
++		 * though it isn't required for MPPE synchronization, it is
++		 * required to reset CCP state.
++		 */
++	    }
++	}
++	if (flushed)
++	    mppe_rekey(state, 0);
++    }
++
++    /*
++     * Fill in the first part of the PPP header.  The protocol field
++     * comes from the decrypted data.
++     */
++    obuf[0] = PPP_ADDRESS(ibuf);	/* +1 */
++    obuf[1] = PPP_CONTROL(ibuf);	/* +1 */
++    obuf  += 2;
++    ibuf  += PPP_HDRLEN + MPPE_OVHD;
++    isize -= PPP_HDRLEN + MPPE_OVHD;	/* -6 */
++					/* net osize: isize-4 */
++
++    /* And finally, decrypt the packet. */
++    arcfour_decrypt(&state->arcfour_context, ibuf, isize, obuf);
++
++    state->stats.unc_bytes += osize;
++    state->stats.unc_packets++;
++    state->stats.comp_bytes += isize;
++    state->stats.comp_packets++;
++
++    /* good packet credit */
++    state->sanity_errors >>= 1;
++
++    return osize;
++}
++
++/*
++ * Incompressible data has arrived (this should never happen!).
++ * We should probably drop the link if the protocol is in the range
++ * of what should be encrypted.  At the least, we should drop this
++ * packet.  (How to do this?)
++ */
++static void
++mppe_incomp(void *arg, unsigned char *ibuf, int icnt)
++{
++    ppp_mppe_state *state = (ppp_mppe_state *) arg;
++
++    if (state->debug &&
++	(PPP_PROTOCOL(ibuf) >= 0x0021 && PPP_PROTOCOL(ibuf) <= 0x00fa))
++	printk(KERN_DEBUG "mppe_incomp[%d]: incompressible (unencrypted) data! "
++	       "(proto %04x)\n", state->unit, PPP_PROTOCOL(ibuf));
++
++    state->stats.inc_bytes += icnt;
++    state->stats.inc_packets++;
++    state->stats.unc_bytes += icnt;
++    state->stats.unc_packets++;
++}
++
++/*************************************************************
++ * Module interface table
++ *************************************************************/
++
++/* These are in ppp.c (2.2.x) or ppp_generic.c (2.4.x) */
++extern int  ppp_register_compressor   (struct compressor *cp);
++extern void ppp_unregister_compressor (struct compressor *cp);
++
++/*
++ * Procedures exported to if_ppp.c.
++ */
++struct compressor ppp_mppe = {
++    CI_MPPE,		/* compress_proto */
++    mppe_alloc,		/* comp_alloc */
++    mppe_free,		/* comp_free */
++    mppe_comp_init,	/* comp_init */
++    mppe_comp_reset,	/* comp_reset */
++    mppe_compress,	/* compress */
++    mppe_comp_stats,	/* comp_stat */
++    mppe_alloc,		/* decomp_alloc */
++    mppe_free,		/* decomp_free */
++    mppe_decomp_init,	/* decomp_init */
++    mppe_decomp_reset,	/* decomp_reset */
++    mppe_decompress,	/* decompress */
++    mppe_incomp,	/* incomp */
++    mppe_comp_stats,	/* decomp_stat */
++};
++
++/* 2.2 compatibility defines */
++#ifndef __init
++#define __init
++#endif
++#ifndef __exit
++#define __exit
++#endif
++#ifndef MODULE_LICENSE
++#define MODULE_LICENSE(license)
++#endif
++
++int __init
++ppp_mppe_init(void)
++{  
++    int answer = ppp_register_compressor(&ppp_mppe);
++
++    if (answer == 0)
++	printk(KERN_INFO "PPP MPPE Compression module registered\n");
++    return answer;
++}
++
++void __exit
++ppp_mppe_cleanup(void)
++{
++    ppp_unregister_compressor(&ppp_mppe);
++}
++
++module_init(ppp_mppe_init);
++module_exit(ppp_mppe_cleanup);
++MODULE_LICENSE("BSD without advertisement clause");
+--- /dev/null
++++ linux-2.4.25/drivers/net/sha1.c
+@@ -0,0 +1,185 @@
++/*
++ * ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c
++ * 
++ * SHA-1 in C
++ * By Steve Reid <steve@edmweb.com>
++ * 100% Public Domain
++ * 
++ * Test Vectors (from FIPS PUB 180-1)
++ * "abc"
++ * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
++ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
++ * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
++ * A million repetitions of "a"
++ * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
++ */
++
++/* #define SHA1HANDSOFF * Copies data before messing with it. */
++
++#if defined(__linux__)
++#include <asm/byteorder.h>
++#include <linux/string.h>
++#elif defined(__solaris__)
++#include <sys/isa_defs.h>
++#include <sys/ddi.h>
++#include <sys/sunddi.h>
++#define memcpy(d, s, c) bcopy(s, d, c)
++#define memset(d, b, c) bzero(d, c)
++#endif
++
++#include "sha1.h"
++
++static void SHA1_Transform(unsigned long[5], const unsigned char[64]);
++
++#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
++
++/* blk0() and blk() perform the initial expand. */
++/* I got the idea of expanding during the round function from SSLeay */
++#if defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN)
++#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
++    |(rol(block->l[i],8)&0x00FF00FF))
++#elif defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)
++#define blk0(i) block->l[i]
++#else
++#error Endianness not defined
++#endif
++#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
++    ^block->l[(i+2)&15]^block->l[i&15],1))
++
++/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
++#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
++#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
++#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
++#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
++#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
++
++
++/* Hash a single 512-bit block. This is the core of the algorithm. */
++
++static void
++SHA1_Transform(unsigned long state[5], const unsigned char buffer[64])
++{
++    unsigned long a, b, c, d, e;
++    typedef union {
++	unsigned char c[64];
++	unsigned long l[16];
++    } CHAR64LONG16;
++    CHAR64LONG16 *block;
++
++#ifdef SHA1HANDSOFF
++    static unsigned char workspace[64];
++    block = (CHAR64LONG16 *) workspace;
++    memcpy(block, buffer, 64);
++#else
++    block = (CHAR64LONG16 *) buffer;
++#endif
++    /* Copy context->state[] to working vars */
++    a = state[0];
++    b = state[1];
++    c = state[2];
++    d = state[3];
++    e = state[4];
++    /* 4 rounds of 20 operations each. Loop unrolled. */
++    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
++    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
++    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
++    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
++    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
++    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
++    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
++    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
++    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
++    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
++    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
++    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
++    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
++    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
++    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
++    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
++    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
++    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
++    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
++    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
++    /* Add the working vars back into context.state[] */
++    state[0] += a;
++    state[1] += b;
++    state[2] += c;
++    state[3] += d;
++    state[4] += e;
++    /* Wipe variables */
++    a = b = c = d = e = 0;
++}
++
++
++/* SHA1Init - Initialize new context */
++
++void
++SHA1_Init(SHA1_CTX *context)
++{
++    /* SHA1 initialization constants */
++    context->state[0] = 0x67452301;
++    context->state[1] = 0xEFCDAB89;
++    context->state[2] = 0x98BADCFE;
++    context->state[3] = 0x10325476;
++    context->state[4] = 0xC3D2E1F0;
++    context->count[0] = context->count[1] = 0;
++}
++
++
++/* Run your data through this. */
++
++void
++SHA1_Update(SHA1_CTX *context, const unsigned char *data, unsigned int len)
++{
++    unsigned int i, j;
++
++    j = (context->count[0] >> 3) & 63;
++    if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
++    context->count[1] += (len >> 29);
++    if ((j + len) > 63) {
++	memcpy(&context->buffer[j], data, (i = 64-j));
++	SHA1_Transform(context->state, context->buffer);
++	for ( ; i + 63 < len; i += 64) {
++	    SHA1_Transform(context->state, &data[i]);
++	}
++	j = 0;
++    }
++    else
++	i = 0;
++
++    memcpy(&context->buffer[j], &data[i], len - i);
++}
++
++
++/* Add padding and return the message digest. */
++
++void
++SHA1_Final(unsigned char digest[20], SHA1_CTX *context)
++{
++    unsigned long i, j;
++    unsigned char finalcount[8];
++
++    for (i = 0; i < 8; i++) {
++        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
++         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
++    }
++    SHA1_Update(context, (unsigned char *) "\200", 1);
++    while ((context->count[0] & 504) != 448) {
++	SHA1_Update(context, (unsigned char *) "\0", 1);
++    }
++    SHA1_Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
++    for (i = 0; i < 20; i++) {
++	digest[i] = (unsigned char)
++		     ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
++    }
++    /* Wipe variables */
++    i = j = 0;
++    memset(context->buffer, 0, 64);
++    memset(context->state, 0, 20);
++    memset(context->count, 0, 8);
++    memset(&finalcount, 0, 8);
++#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */
++    SHA1Transform(context->state, context->buffer);
++#endif
++}
++
+--- /dev/null
++++ linux-2.4.25/drivers/net/sha1.h
+@@ -0,0 +1,18 @@
++/* sha1.h */
++
++#ifndef _SHA1_H
++#define _SHA1_H
++
++typedef struct {
++    unsigned long state[5];
++    unsigned long count[2];
++    unsigned char buffer[64];
++} SHA1_CTX;
++
++#define SHA1_SIGNATURE_SIZE 20
++
++extern void SHA1_Init(SHA1_CTX *);
++extern void SHA1_Update(SHA1_CTX *, const unsigned char *, unsigned int);
++extern void SHA1_Final(unsigned char[SHA1_SIGNATURE_SIZE], SHA1_CTX *);
++
++#endif /* _SHA1_H */
+--- linux-2.4.25/include/linux/ppp-comp.h~mppe-20040216
++++ linux-2.4.25/include/linux/ppp-comp.h
+@@ -187,6 +187,100 @@
+ #define DEFLATE_CHK_SEQUENCE	0
+ 
+ /*
++ * Definitions for MPPE.
++ */
++
++#define CI_MPPE			18	/* config option for MPPE */
++#define CILEN_MPPE		6	/* length of config option */
++
++#define MPPE_PAD		4	/* MPPE growth per frame */
++#define MPPE_MAX_KEY_LEN	16	/* largest key length (128-bit) */
++
++/* option bits for ccp_options.mppe */
++#define MPPE_OPT_40		0x01	/* 40 bit */
++#define MPPE_OPT_128		0x02	/* 128 bit */
++#define MPPE_OPT_STATEFUL	0x04	/* stateful mode */
++/* unsupported opts */
++#define MPPE_OPT_56		0x08	/* 56 bit */
++#define MPPE_OPT_MPPC		0x10	/* MPPC compression */
++#define MPPE_OPT_D		0x20	/* Unknown */
++#define MPPE_OPT_UNSUPPORTED (MPPE_OPT_56|MPPE_OPT_MPPC|MPPE_OPT_D)
++#define MPPE_OPT_UNKNOWN	0x40	/* Bits !defined in RFC 3078 were set */
++
++/*
++ * This is not nice ... the alternative is a bitfield struct though.
++ * And unfortunately, we cannot share the same bits for the option
++ * names above since C and H are the same bit.  We could do a u_int32
++ * but then we have to do a htonl() all the time and/or we still need
++ * to know which octet is which.
++ */
++#define MPPE_C_BIT		0x01	/* MPPC */
++#define MPPE_D_BIT		0x10	/* Obsolete, usage unknown */
++#define MPPE_L_BIT		0x20	/* 40-bit */
++#define MPPE_S_BIT		0x40	/* 128-bit */
++#define MPPE_M_BIT		0x80	/* 56-bit, not supported */
++#define MPPE_H_BIT		0x01	/* Stateless (in a different byte) */
++
++/* Does not include H bit; used for least significant octet only. */
++#define MPPE_ALL_BITS (MPPE_D_BIT|MPPE_L_BIT|MPPE_S_BIT|MPPE_M_BIT|MPPE_H_BIT)
++
++/* Build a CI from mppe opts (see RFC 3078) */
++#define MPPE_OPTS_TO_CI(opts, ci)		\
++    do {					\
++	u_char *ptr = ci; /* u_char[4] */	\
++						\
++	/* H bit */				\
++	if (opts & MPPE_OPT_STATEFUL)		\
++	    *ptr++ = 0x0;			\
++	else					\
++	    *ptr++ = MPPE_H_BIT;		\
++	*ptr++ = 0;				\
++	*ptr++ = 0;				\
++						\
++	/* S,L bits */				\
++	*ptr = 0;				\
++	if (opts & MPPE_OPT_128)		\
++	    *ptr |= MPPE_S_BIT;			\
++	if (opts & MPPE_OPT_40)			\
++	    *ptr |= MPPE_L_BIT;			\
++	/* M,D,C bits not supported */		\
++    } while (/* CONSTCOND */ 0)
++
++/* The reverse of the above */
++#define MPPE_CI_TO_OPTS(ci, opts)		\
++    do {					\
++	u_char *ptr = ci; /* u_char[4] */	\
++						\
++	opts = 0;				\
++						\
++	/* H bit */				\
++	if (!(ptr[0] & MPPE_H_BIT))		\
++	    opts |= MPPE_OPT_STATEFUL;		\
++						\
++	/* S,L bits */				\
++	if (ptr[3] & MPPE_S_BIT)		\
++	    opts |= MPPE_OPT_128;		\
++	if (ptr[3] & MPPE_L_BIT)		\
++	    opts |= MPPE_OPT_40;		\
++						\
++	/* M,D,C bits */			\
++	if (ptr[3] & MPPE_M_BIT)		\
++	    opts |= MPPE_OPT_56;		\
++	if (ptr[3] & MPPE_D_BIT)		\
++	    opts |= MPPE_OPT_D;			\
++	if (ptr[3] & MPPE_C_BIT)		\
++	    opts |= MPPE_OPT_MPPC;		\
++						\
++	/* Other bits */			\
++	if (ptr[0] & ~MPPE_H_BIT)		\
++	    opts |= MPPE_OPT_UNKNOWN;		\
++	if (ptr[1] || ptr[2])			\
++	    opts |= MPPE_OPT_UNKNOWN;		\
++	if (ptr[3] & ~MPPE_ALL_BITS)		\
++	    opts |= MPPE_OPT_UNKNOWN;		\
++    } while (/* CONSTCOND */ 0)
++
++/*
+  * Definitions for other, as yet unsupported, compression methods.
+  */
+ 
+--- linux-2.4.25/drivers/net/Makefile~mppe-20040216
++++ linux-2.4.25/drivers/net/Makefile
+@@ -18,8 +18,9 @@
+ export-objs     :=	8390.o arlan.o aironet4500_core.o aironet4500_card.o \
+ 			ppp_async.o ppp_generic.o slhc.o pppox.o auto_irq.o \
+ 			net_init.o mii.o
+-list-multi	:=	rcpci.o
++list-multi	:=	rcpci.o ppp_mppe.o
+ rcpci-objs	:=	rcpci45.o rclanmtl.o
++ppp_mppe-objs   :=      ppp_mppe_compress.o sha1.o arcfour.o
+ 
+ ifeq ($(CONFIG_TULIP),y)
+   obj-y += tulip/tulip.o
+@@ -163,6 +164,14 @@
+ obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
+ obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
+ 
++ifeq ($(CONFIG_PPP_MPPE),y)
++  obj-y += $(ppp_mppe-objs)
++else
++  ifeq ($(CONFIG_PPP_MPPE),m)
++    obj-m += ppp_mppe.o
++  endif
++endif
++
+ obj-$(CONFIG_SLIP) += slip.o
+ ifeq ($(CONFIG_SLIP_COMPRESSED),y)
+   obj-$(CONFIG_SLIP) += slhc.o
+@@ -269,3 +278,7 @@
+ 
+ rcpci.o: $(rcpci-objs)
+ 	$(LD) -r -o $@ $(rcpci-objs)
++
++ppp_mppe.o: $(ppp_mppe-objs)
++	$(LD) -r -o $@ $(ppp_mppe-objs)
++
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch
index e69de29bb2..c4f7758b3c 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/scrolling-area.patch
@@ -0,0 +1,18 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.25/drivers/video/fbcon.c~scrolling-area.patch	2003-08-25 13:44:42.000000000 +0200
++++ linux-2.4.25/drivers/video/fbcon.c	2004-03-31 17:15:13.000000000 +0200
+@@ -110,8 +110,8 @@
+ #  define DPRINTK(fmt, args...)
+ #endif
+ 
+-#define LOGO_H			80
+-#define LOGO_W			80
++#define LOGO_H			400
++#define LOGO_W			800
+ #define LOGO_LINE	(LOGO_W/8)
+ 
+ struct display fb_display[MAX_NR_CONSOLES];
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff
index e69de29bb2..dfdbd99237 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-apm.diff
@@ -0,0 +1,799 @@
+--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/arch/arm/mach-sa1100/pm-common.c	1970-01-01 01:00:00.000000000 +0100
++++ arch/arm/mach-sa1100/pm-common.c	2004-07-04 14:56:34.000000000 +0200
+@@ -0,0 +1,268 @@
++/*
++ * SA1100 Power Management Routines
++ *
++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * History:
++ *
++ * 2001-02-06:	Cliff Brake         Initial code
++ *
++ * 2001-02-25:	Sukjae Cho <sjcho@east.isi.edu> &
++ * 		Chester Kuo <chester@linux.org.tw>
++ * 			Save more value for the resume function! Support
++ * 			Bitsy/Assabet/Freebird board
++ *
++ * 2001-08-29:	Nicolas Pitre <nico@cam.org>
++ * 			Cleaned up, pushed platform dependent stuff
++ * 			in the platform specific files.
++ *
++ * 2002-05-27:	Nicolas Pitre	Killed sleep.h and the kmalloced save array.
++ * 				Storage is local on the stack now.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/sysctl.h>
++#include <linux/errno.h>
++#include <linux/cpufreq.h>
++
++#include <asm/hardware.h>
++#include <asm/memory.h>
++#include <asm/system.h>
++#include <asm/leds.h>
++#include <asm/uaccess.h>
++
++
++#ifdef CONFIG_IPAQ_HANDHELD
++#include <asm/arch-sa1100/h3600_asic.h>
++#endif
++
++#define __KERNEL_SYSCALLS__
++#include <linux/unistd.h>
++
++/*
++ * Debug macros
++ */
++#undef DEBUG
++
++
++
++static char pm_helper_path[128] = "/sbin/pm_helper";
++extern int exec_usermodehelper(char *path, char **argv, char **envp);
++int debug_pm = 0;
++static int pm_helper_veto = 0;
++
++static int
++run_sbin_pm_helper( pm_request_t action )
++{
++	int i;
++	char *argv[3], *envp[8];
++
++	if (!pm_helper_path[0])
++		return 2;
++
++	if ( action != PM_SUSPEND && action != PM_RESUME )
++		return 1;
++
++	/* Be root */
++	current->uid = current->gid = 0;
++
++	i = 0;
++	argv[i++] = pm_helper_path;
++	argv[i++] = (action == PM_RESUME ? "resume" : "suspend");
++	argv[i] = 0;
++
++	i = 0;
++	/* minimal command environment */
++	envp[i++] = "HOME=/";
++	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++	envp[i] = 0;
++
++	/* other stuff we want to pass to /sbin/pm_helper */
++	return exec_usermodehelper (argv [0], argv, envp);
++}
++
++/*
++ * If pm_suggest_suspend_hook is non-NULL, it is called by pm_suggest_suspend.
++ */
++int (*pm_suggest_suspend_hook)(int state);
++EXPORT_SYMBOL(pm_suggest_suspend_hook);
++
++/*
++ * If pm_use_sbin_pm_helper is nonzero, then run_sbin_pm_helper is called before suspend and after resume
++ */
++int pm_use_sbin_pm_helper = 1;
++EXPORT_SYMBOL(pm_use_sbin_pm_helper);
++
++/*
++ * If sysctl_pm_do_suspend_hook is non-NULL, it is called by sysctl_pm_do_suspend.
++ * If it returns a true value, then pm_suspend is not called. 
++ * Use this to hook in apmd, for now.
++ */
++int (*pm_sysctl_suspend_hook)(int state);
++EXPORT_SYMBOL(pm_sysctl_suspend_hook);
++
++int pm_suspend(void);
++
++int pm_suggest_suspend(void)
++{
++	int retval;
++
++	if (pm_suggest_suspend_hook) {
++		if (pm_suggest_suspend_hook(PM_SUSPEND))
++			return 0;
++	}
++	
++	if (pm_use_sbin_pm_helper) {
++		pid_t pid;
++		int res;
++		int status = 0;
++		unsigned int old_fs;
++        	
++		pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_SUSPEND, 0 );
++		if ( pid < 0 )
++			return pid;
++
++		if (debug_pm)
++			printk(KERN_CRIT "%s:%d got pid=%d\n", __FUNCTION__, __LINE__, pid);	
++        		
++		old_fs = get_fs ();
++		set_fs (get_ds ());
++		res = waitpid(pid, &status, __WCLONE);
++		set_fs (old_fs);
++	
++		if ( pid != res ) {
++			if (debug_pm)
++				printk(KERN_CRIT ": waitpid returned %d (exit_code=%d); not suspending\n", res, status );
++	        	
++			return -1;
++		}
++        		
++		/*if ( WIFEXITED(status) && ( WIFEXITSTATUS(status) != 0 )) {*/
++		if (( status & 0xff7f ) != 0 ) {
++			if (pm_helper_veto) {
++				if (debug_pm)
++					printk(KERN_CRIT "%s: SUSPEND WAS CANCELLED BY pm_helper (exit status %d)\n", __FUNCTION__, status >> 8);
++				return -1;
++			} else {
++				if (debug_pm)
++					printk(KERN_CRIT "%s: pm_helper returned %d, but going ahead anyway\n", __FUNCTION__, status >> 8);
++			}
++		}
++	}
++
++	if (debug_pm)
++		printk(KERN_CRIT "%s: REALLY SUSPENDING NOW\n", __FUNCTION__ );
++
++	if (pm_sysctl_suspend_hook) {
++		if (pm_sysctl_suspend_hook(PM_SUSPEND))
++			return 0;
++	}
++
++	retval = pm_suspend();
++	if (retval) {
++		if (debug_pm)
++			printk(KERN_CRIT "pm_suspend returned %d\n", retval);
++		return retval;
++	}
++
++	if (pm_use_sbin_pm_helper) {
++		pid_t pid;
++        	
++		if (debug_pm)
++			printk(KERN_CRIT "%s: running pm_helper for wakeup\n", __FUNCTION__);
++
++		pid = kernel_thread ((int (*) (void *)) run_sbin_pm_helper, (void *) PM_RESUME, 0 );
++		if ( pid < 0 )
++			return pid;
++        		
++		if ( pid != waitpid ( pid, NULL, __WCLONE ))
++			return -1;
++	}
++
++	return 0;
++}
++
++EXPORT_SYMBOL(pm_suggest_suspend);
++
++
++/*
++ * Send us to sleep.
++ */
++int pm_suspend(void)
++{
++	int retval;
++
++	retval = pm_send_all(PM_SUSPEND, (void *)3);
++	if ( retval )
++		return retval;
++
++#ifdef CONFIG_IPAQ_HANDHELD
++	retval = h3600_power_management(PM_SUSPEND);
++	if (retval) {
++		pm_send_all(PM_RESUME, (void *)0);
++		return retval;
++	}
++#endif
++
++	retval = pm_do_suspend();
++
++#ifdef CONFIG_IPAQ_HANDHELD
++	/* Allow the power management routines to override resuming */
++	while ( h3600_power_management(PM_RESUME) )
++		retval = pm_do_suspend();
++#endif
++
++	pm_send_all(PM_RESUME, (void *)0);
++
++	return retval;
++}
++EXPORT_SYMBOL(pm_suspend);
++
++#ifdef CONFIG_SYSCTL
++/*
++ * ARGH!  ACPI people defined CTL_ACPI in linux/acpi.h rather than
++ * linux/sysctl.h.
++ *
++ * This means our interface here won't survive long - it needs a new
++ * interface.  Quick hack to get this working - use sysctl id 9999.
++ */
++#warning ACPI broke the kernel, this interface needs to be fixed up.
++#define CTL_ACPI 9999
++#define ACPI_S1_SLP_TYP 19
++
++static struct ctl_table pm_table[] =
++{
++/*	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&sysctl_pm_suspend},*/
++	{2, "helper", pm_helper_path, sizeof(pm_helper_path), 0644, NULL, (proc_handler *)&proc_dostring},
++	{3, "debug", &debug_pm, sizeof(debug_pm), 0644, NULL, (proc_handler *)&proc_dointvec},
++	{4, "helper_veto", &pm_helper_veto, sizeof(pm_helper_veto), 0644, NULL, (proc_handler *)&proc_dointvec},
++	{0}
++};
++
++static struct ctl_table pm_dir_table[] =
++{
++	{CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
++	{0}
++};
++
++/*
++ * Initialize power interface
++ */
++static int __init pm_init(void)
++{
++	register_sysctl_table(pm_dir_table, 1);
++	return 0;
++}
++
++__initcall(pm_init);
++
++#endif
++
+--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/arch/arm/mach-sa1100/apm.c	2004-07-01 21:10:30.000000000 +0200
++++ arch/arm/mach-sa1100/apm.c	2004-07-04 14:53:38.000000000 +0200
+@@ -32,9 +32,7 @@
+ 
+ #include <asm/system.h>
+ #include <asm/hardware.h>
+-#if FIXME
+ #include <asm/arch-sa1100/pm.h>
+-#endif
+ 
+ #ifdef CONFIG_IPAQ_HANDHELD
+ #include <asm/arch-sa1100/h3600_hal.h>
+@@ -92,6 +91,8 @@
+ 	int		magic;
+ 	struct apm_user *	next;
+ 	int		suser: 1;
++	int		writer: 1;
++	int		reader: 1;
+ 	int		suspend_wait: 1;
+ 	int		suspend_result;
+ 	int		suspends_pending;
+@@ -111,7 +112,7 @@
+ /*
+  * Local variables
+  */
+-//static int			suspends_pending;
++static int			suspends_pending;
+ //static int			standbys_pending;
+ //static int			ignore_normal_resume;
+ 
+@@ -129,8 +130,6 @@
+ #else
+ static int			power_off = 1;
+ #endif
+-static int			exit_kapmd;
+-static int			kapmd_running;
+ 
+ static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
+ static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+@@ -190,6 +189,42 @@
+ 	return as->events[as->event_tail];
+ }
+ 
++static void queue_event(apm_event_t event, struct apm_user *sender)
++{
++	struct apm_user *	as;
++
++	if (user_list == NULL)
++		return;
++	for (as = user_list; as != NULL; as = as->next) {
++		if ((as == sender) || (!as->reader))
++			continue;
++		as->event_head = (as->event_head + 1) % APM_MAX_EVENTS;
++		if (as->event_head == as->event_tail) {
++			static int notified;
++
++			if (notified++ == 0)
++			    printk(KERN_ERR "apm: an event queue overflowed\n");
++			as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS;
++		}
++		as->events[as->event_head] = event;
++		if ((!as->suser) || (!as->writer))
++			continue;
++		switch (event) {
++		case APM_SYS_SUSPEND:
++		case APM_USER_SUSPEND:
++			as->suspends_pending++;
++			suspends_pending++;
++			break;
++
++		case APM_SYS_STANDBY:
++		case APM_USER_STANDBY:
++			as->standbys_pending++;
++			break;
++		}
++	}
++	wake_up_interruptible(&apm_waitqueue);
++}
++
+ static int check_apm_user(struct apm_user *as, const char *func)
+ {
+ 	if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) {
+@@ -228,7 +263,6 @@
+ 	i = count;
+ 	while ((i >= sizeof(event)) && !queue_empty(as)) {
+ 		event = get_queued_event(as);
+-                printk("  do_read: event=%d\n", event);
+ 		if (copy_to_user(buf, &event, sizeof(event))) {
+ 			if (i < count)
+ 				break;
+@@ -280,9 +314,17 @@
+ 		return -EPERM;
+ 	switch (cmd) {
+         case APM_IOC_SUSPEND:
+-#if FIXME
+-		pm_suggest_suspend();
+-#endif
++		if (as->suspends_read > 0) {
++			as->suspends_read--;
++			as->suspends_pending--;
++			suspends_pending--;
++		} else {
++			queue_event(APM_USER_SUSPEND, as);
++		}
++
++		if (suspends_pending <= 0)
++			wake_up(&apm_suspend_waitqueue);
++		
+ 		break;
+ 	default:
+ 		return -EINVAL;
+@@ -299,6 +341,20 @@
+ 		return 0;
+ 	filp->private_data = NULL;
+ 	lock_kernel();
++	if (user_list == as)
++		user_list = as->next;
++	else {
++		struct apm_user *	as1;
++
++		for (as1 = user_list;
++		     (as1 != NULL) && (as1->next != as);
++		     as1 = as1->next)
++			;
++		if (as1 == NULL)
++			printk(KERN_ERR "apm: filp not in user list\n");
++		else
++			as1->next = as->next;
++	}
+ 	unlock_kernel();
+ 	kfree(as);
+ 	return 0;
+@@ -326,6 +382,8 @@
+ 	 * privileged operation -- cevans
+ 	 */
+ 	as->suser = capable(CAP_SYS_ADMIN);
++	as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
++	as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
+ 	as->next = user_list;
+ 	user_list = as;
+ 	filp->private_data = as;
+@@ -409,34 +467,6 @@
+ 	return p - buf;
+ }
+ 
+-#ifndef MODULE
+-static int __init apm_setup(char *str)
+-{
+-	int	invert;
+-
+-	while ((str != NULL) && (*str != '\0')) {
+-		if (strncmp(str, "off", 3) == 0)
+-			apm_disabled = 1;
+-		if (strncmp(str, "on", 2) == 0)
+-			apm_disabled = 0;
+-		invert = (strncmp(str, "no-", 3) == 0);
+-		if (invert)
+-			str += 3;
+-		if (strncmp(str, "debug", 5) == 0)
+-			debug = !invert;
+-		if ((strncmp(str, "power-off", 9) == 0) ||
+-		    (strncmp(str, "power_off", 9) == 0))
+-			power_off = !invert;
+-		str = strchr(str, ',');
+-		if (str != NULL)
+-			str += strspn(str, ", \t");
+-	}
+-	return 1;
+-}
+-
+-__setup("apm=", apm_setup);
+-#endif
+-
+ static struct file_operations apm_bios_fops = {
+ 	owner:		THIS_MODULE,
+ 	read:		do_read,
+@@ -454,6 +484,48 @@
+ 
+ #define APM_INIT_ERROR_RETURN	return -1
+ 
++static pid_t apmd_pid;
++static DECLARE_COMPLETION(apmd_exited);
++
++static int apm(void *unused)
++{
++	unsigned short	bx;
++	unsigned short	cx;
++	unsigned short	dx;
++	int		error;
++	char *		power_stat;
++	char *		bat_stat;
++	DECLARE_WAITQUEUE(wait, current);
++	struct apm_user au, *as;
++
++	lock_kernel();
++
++	daemonize();
++
++	strcpy(current->comm, "kapmd");
++
++	as = &au;
++	as->magic = APM_BIOS_MAGIC;
++	as->event_tail = as->event_head = 0;
++	as->suspends_pending = as->standbys_pending = 0;
++	as->suspends_read = as->standbys_read = 0;
++	as->suser = 1;
++	as->writer = 1;
++	as->reader = 0;
++
++	while (!signal_pending (current)) {
++		interruptible_sleep_on(&apm_suspend_waitqueue);
++
++		pm_suggest_suspend();
++
++		queue_event(APM_NORMAL_RESUME, as);
++	}
++
++	unlock_kernel();
++
++	complete_and_exit(&apmd_exited, 0);
++}
++
+ /*
+  * Just start the APM thread. We do NOT want to do APM BIOS
+  * calls from anything but the APM thread, if for no other reason
+@@ -492,6 +564,8 @@
+ 
+ 	misc_register(&apm_device);
+ 
++	apmd_pid = kernel_thread(apm, NULL, 0);
++
+ 	return 0;
+ }
+ 
+@@ -499,11 +573,10 @@
+ {
+ 	misc_deregister(&apm_device);
+ 	remove_proc_entry("apm", NULL);
++	kill_proc (apmd_pid, SIGTERM, 1);
++	wait_for_completion(&apmd_exited);
+ 	if (power_off)
+ 		pm_power_off = NULL;
+-	exit_kapmd = 1;
+-	while (kapmd_running)
+-		schedule();
+ 	pm_active = 0;
+ }
+ 
+@@ -512,6 +585,7 @@
+ 
+ MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell");
+ MODULE_DESCRIPTION("A minimal emulation of APM");
++MODULE_LICENSE("GPL");
+ MODULE_PARM(debug, "i");
+ MODULE_PARM_DESC(debug, "Enable debug mode");
+ MODULE_PARM(power_off, "i");
+diff -bBaruN /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/include/asm-arm/arch-sa1100/pm.h include/asm-arm/arch/pm.h
+--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/include/asm-arm/arch-sa1100/pm.h	1970-01-01 01:00:00.000000000 +0100
++++ include/asm-arm/arch-sa1100/pm.h	2004-07-04 16:47:18.000000000 +0200
+@@ -0,0 +1,20 @@
++/*
++ *
++ * Declarations for ARM Linux Power Management
++ *
++ * Copyright 2002 Compaq Computer Corporation.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Author: Jamey Hicks.
++ *
++ */
++
++
++extern int (*pm_suggest_suspend_hook)(int state);
++extern int (*pm_sysctl_suspend_hook)(int state);
++extern int pm_use_sbin_pm_helper; 
++extern int pm_suspend(void);
++extern int pm_suggest_suspend(void); /* triggers /sbin/pm_helper or queueing event to apmd */
+--- /mnt/bdisk/openembedded/oetmp/work/opensimpad-64+0-2.4.25-vrs2-pxa1-jpm1-r6/linux-2.4.25/arch/arm/mach-sa1100/Makefile	2004-07-04 19:39:48.000000000 +0200
++++ arch/arm/mach-sa1100/Makefile	2004-07-04 17:11:35.000000000 +0200
+@@ -19,7 +19,7 @@
+ 		flexanet.o freebird.o frodo.o generic.o h3600.o \
+ 		huw_webpanel.o irq.o sa1111.o sa1111-pcibuf.o \
+ 		system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o simputer.o ssp.o \
+-		simpad.o
++		simpad.o pm-sa1100.o
+ 
+ # These aren't present yet, and prevents a plain -ac kernel building.
+ # hwtimer.o
+@@ -105,7 +105,7 @@
+ obj-$(CONFIG_SA1100_USB_CHAR) += usb-char.o
+ 
+ # Miscelaneous functions
+-obj-$(CONFIG_PM) += pm.o sleep.o
++obj-$(CONFIG_PM) += pm-sa1100.o sleep.o
+ obj-$(CONFIG_APM) += apm.o
+ 
+ # SIMpad specific
+--- /mnt/bdisk/openembedded/oetmp/work/opensimpad-64+0-2.4.25-vrs2-pxa1-jpm1-r6/linux-2.4.25/arch/arm/mach-sa1100/pm-sa1100.c	1970-01-01 01:00:00.000000000 +0100
++++ arch/arm/mach-sa1100/pm-sa1100.c	2004-07-04 17:11:11.000000000 +0200
+@@ -0,0 +1,225 @@
++/*
++ * SA1100 Power Management Routines
++ *
++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License.
++ *
++ * History:
++ *
++ * 2001-02-06:	Cliff Brake         Initial code
++ *
++ * 2001-02-25:	Sukjae Cho <sjcho@east.isi.edu> &
++ * 		Chester Kuo <chester@linux.org.tw>
++ * 			Save more value for the resume function! Support
++ * 			Bitsy/Assabet/Freebird board
++ *
++ * 2001-08-29:	Nicolas Pitre <nico@cam.org>
++ * 			Cleaned up, pushed platform dependent stuff
++ * 			in the platform specific files.
++ *
++ * 2002-05-27:	Nicolas Pitre	Killed sleep.h and the kmalloced save array.
++ * 				Storage is local on the stack now.
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pm.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/sysctl.h>
++#include <linux/errno.h>
++#include <linux/cpufreq.h>
++
++#include <asm/hardware.h>
++#include <asm/memory.h>
++#include <asm/system.h>
++#include <asm/leds.h>
++
++
++#ifdef CONFIG_IPAQ_HANDHELD
++#include <asm/arch/h3600_asic.h>
++#endif
++
++#define __KERNEL_SYSCALLS__
++#include <linux/unistd.h>
++
++extern void sa1100_cpu_suspend(void);
++extern void sa1100_cpu_resume(void);
++extern int debug_pm;
++
++#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
++#define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
++
++/*
++ * List of global SA11x0 peripheral registers to preserve.
++ * More ones like CP and general purpose register values are preserved
++ * with the stack location in sleep.S.
++ */
++enum {	SLEEP_SAVE_START = 0,
++
++	SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
++	SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
++
++	SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR,
++	SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
++
++	SLEEP_SAVE_ICMR,
++#ifdef CONFIG_SA1100_SIMPAD
++	SLEEP_SAVE_MECR, /* needed by SIMpad to get PCMCIA working after resume */
++#endif
++	SLEEP_SAVE_Ser1SDCR0,
++
++        SLEEP_SAVE_PWER,
++        SLEEP_SAVE_MSC1, SLEEP_SAVE_MSC2,
++
++	SLEEP_SAVE_SIZE
++};
++
++
++int pm_do_suspend(void)
++{
++	unsigned long sleep_save[SLEEP_SAVE_SIZE];
++
++	cli();
++
++	leds_event(led_stop);
++
++	/* preserve current time */
++	RCNR = xtime.tv_sec;
++
++	/* save vital registers */
++	SAVE(OSCR);
++	SAVE(OSMR0);
++	SAVE(OSMR1);
++	SAVE(OSMR2);
++	SAVE(OSMR3);
++	SAVE(OIER);
++
++	SAVE(GPDR);
++	SAVE(GRER);
++	SAVE(GFER);
++	SAVE(GAFR);
++
++	SAVE(PPDR);
++	SAVE(PPSR);
++	SAVE(PPAR);
++	SAVE(PSDR);
++
++	SAVE(Ser1SDCR0);
++
++	SAVE(ICMR);
++#ifdef CONFIG_SA1100_SIMPAD
++	SAVE(MECR);
++#endif
++        SAVE(PWER);
++        SAVE(MSC1);
++        SAVE(MSC2);
++
++	/* ... maybe a global variable initialized by arch code to set this? */
++	GRER &= PWER;
++	GFER &= PWER;
++	// Ugly, but I need the AC inserted event
++	// In the future, we're going to care about DCD and USB interrupts as well
++	if ( machine_is_h3800()) {
++#ifdef CONFIG_IPAQ_HANDHELD
++		GFER = GPIO_H3800_AC_IN;
++#endif
++	} else {
++		GFER = 0;
++		if (machine_is_jornada56x()) {
++			/* jca */
++			GFER = PWER;
++			ICMR |= PWER;
++		}
++	}
++	GEDR = GEDR;
++
++	/* Clear previous reset status */
++	RCSR = RCSR_HWR | RCSR_SWR | RCSR_WDR | RCSR_SMR;
++
++	/* set resume return address */
++	PSPR = virt_to_phys(sa1100_cpu_resume);
++
++	/* go zzz */
++	sa1100_cpu_suspend();
++
++	/* ensure not to come back here if it wasn't intended */
++	PSPR = 0;
++
++	if (debug_pm)
++		printk(KERN_CRIT "*** made it back from resume\n");
++
++#ifdef CONFIG_IPAQ_HANDHELD
++	if ( machine_is_ipaq()) {
++		ipaq_model_ops.gedr = GEDR;
++		ipaq_model_ops.icpr = ICPR;
++	}
++#endif
++
++	/* restore registers */
++	RESTORE(GPDR);
++	RESTORE(GRER);
++	RESTORE(GFER);
++	RESTORE(GAFR);
++
++	/* clear any edge detect bit */
++	GEDR = GEDR;
++
++	RESTORE(PPDR);
++	RESTORE(PPSR);
++	RESTORE(PPAR);
++	RESTORE(PSDR);
++
++	RESTORE(Ser1SDCR0);
++
++	PSSR = PSSR_PH;
++
++	RESTORE(OSMR0);
++	RESTORE(OSMR1);
++	RESTORE(OSMR2);
++	RESTORE(OSMR3);
++	RESTORE(OSCR);
++	RESTORE(OIER);
++
++#ifdef CONFIG_IPAQ_HANDHELD
++/* OSMR0 may have fired before we went to sleep, but after interrupts
++   were shut off.  Set OSMR0 to something plausible */
++	OSMR0 = OSCR + LATCH;
++#endif
++	ICLR = 0;
++	ICCR = 1;
++	RESTORE(ICMR);
++#ifdef CONFIG_SA1100_SIMPAD
++	RESTORE(MECR);
++#endif
++	RESTORE(PWER);
++	RESTORE(MSC1);
++	RESTORE(MSC2);
++	/* restore current time */
++	xtime.tv_sec = RCNR;
++
++	leds_event(led_start);
++	
++	sti();
++
++	if (debug_pm)
++		printk("interrupts are enabled\n");
++
++	/*
++	 * Restore the CPU frequency settings.
++	 */
++#ifdef CONFIG_CPU_FREQ
++	cpufreq_restore();
++#endif
++	return 0;
++}
++
++unsigned long sleep_phys_sp(void *sp)
++{
++	return virt_to_phys(sp);
++}
++
++#include "pm-common.c"
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff
index e69de29bb2..50a4ff7628 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-backlight-if.diff
@@ -0,0 +1,97 @@
+--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/video/mq200fb.c	2004-07-01 21:10:30.000000000 +0200
++++ drivers/video/mq200fb.c	2004-07-03 20:58:59.000000000 +0200
+@@ -82,6 +82,20 @@
+ 	write:	proc_write_reg
+ };
+ 
++#ifdef CONFIG_SA1100_SIMPAD
++
++static ssize_t proc_read_light(struct file * file, char * buf,
++		size_t nbytes, loff_t *ppos);
++static ssize_t proc_write_light(struct file * file, const char * buffer,
++		size_t count, loff_t *ppos);
++
++static struct file_operations proc_light_operations = {
++	read:	proc_read_light,
++	write:	proc_write_light
++};
++#endif
++
++
+ typedef struct sa1110_reg_entry {
+ 	u32 phyaddr;
+ 	char* name;
+@@ -622,6 +636,20 @@
+        }
+     }
+ 
++#ifdef CONFIG_SA1100_SIMPAD
++	entry = create_proc_entry("backlight",
++				 S_IRWXU | S_IRWXG | S_IRWXO,
++				 mq200dir);
++	if(entry) {
++	  entry->proc_fops = &proc_light_operations;
++	} 
++    else {
++	  printk( KERN_ERR
++		  "mq200fb: can't create /proc/" MQ200_DIRNAME
++		  "/backlight\n");
++	  return(-ENOMEM);
++    }
++ #endif
+ 
+ #ifdef MQ_SA1110
+ 
+@@ -1879,7 +1907,7 @@
+ static void writeBrightness(void *pMQMMIO, int brightness)
+ {
+     unsigned long dutyCycle, pwmcontrol;
+-    int MAX_BRIGHT_REG = 0x000000fc; /* int 254 */
++    int MAX_BRIGHT_REG = 0x000000fe; /* int 254 */
+     
+     if(brightness > MAX_BRIGHT_REG)
+       return;
+@@ -1961,3 +1989,43 @@
+ 	return (count+endp-buffer);
+ }
+ 
++#ifdef CONFIG_SA1100_SIMPAD
++
++#define SIMPAD_BACKLIGHT_MASK	0x00a10044
++
++static int proc_read_light(struct file * file, char * buf,
++		size_t nbytes, loff_t *ppos)
++{
++	char outputbuf[15];
++	int count;
++	u32 pwmctl;
++	if (*ppos>0) /* Assume reading completed in previous read*/
++		return 0;
++
++	pwmctl = *((volatile *) mq200_p2v(0x4be0e03c));
++	pwmctl &= ~SIMPAD_BACKLIGHT_MASK;
++	pwmctl = pwmctl >> 8;	
++	pwmctl = 254 - pwmctl;
++		
++	count = sprintf(outputbuf, "%d\n",pwmctl);
++	*ppos+=count;
++	if (count>nbytes)  /* Assume output can be read at one time */
++		return -EINVAL;
++	if (copy_to_user(buf, outputbuf, count))
++		return -EFAULT;
++	return count;
++}
++
++static ssize_t proc_write_light(struct file * file, const char * buffer,
++		size_t count, loff_t *ppos)
++{
++	void * pMQMMIO = (void *) mqMmioAddr;
++	char *endp;
++	unsigned long newvalue = simple_strtoul(buffer,&endp,0);
++	if (newvalue > 254)
++		newvalue = 254;
++	writeBrightness(pMQMMIO,newvalue);
++	mq200_backlight(pMQMMIO,(int)newvalue);
++	return (count+endp-buffer);
++}
++#endif
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch
index e69de29bb2..938c34c67a 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-pm-updates.patch
@@ -0,0 +1,47 @@
+--- arch/arm/mach-sa1100/pm-sa1100.c	2004-07-14 01:21:38.000000000 +0200
++++ /home/fuchs/Projekte/simpad/kernel/linux-2.4.25/arch/arm/mach-sa1100/pm-sa1100.c	2004-07-22 00:41:57.000000000 +0200
+@@ -69,6 +69,7 @@
+ 	SLEEP_SAVE_ICMR,
+ #ifdef CONFIG_SA1100_SIMPAD
+ 	SLEEP_SAVE_MECR, /* needed by SIMpad to get PCMCIA working after resume */
++	SLEEP_SAVE_Ser4MCCR0, SLEEP_SAVE_Ser4MCSR, SLEEP_SAVE_Ser4MCCR1, /* touchscreen */	
+ #endif
+ 	SLEEP_SAVE_Ser1SDCR0,
+ 
+@@ -82,7 +83,7 @@
+ int pm_do_suspend(void)
+ {
+ 	unsigned long sleep_save[SLEEP_SAVE_SIZE];
+-
++	
+ 	cli();
+ 
+ 	leds_event(led_stop);
+@@ -113,10 +114,13 @@
+ 	SAVE(ICMR);
+ #ifdef CONFIG_SA1100_SIMPAD
+ 	SAVE(MECR);
+-#endif
+-        SAVE(PWER);
+-        SAVE(MSC1);
+-        SAVE(MSC2);
++	SAVE(Ser4MCCR0);
++	SAVE(Ser4MCSR);
++	SAVE(Ser4MCCR1);
++#endif
++	SAVE(PWER);
++	SAVE(MSC1);
++	SAVE(MSC2);
+ 
+ 	/* ... maybe a global variable initialized by arch code to set this? */
+ 	GRER &= PWER;
+@@ -194,6 +198,9 @@
+ 	RESTORE(ICMR);
+ #ifdef CONFIG_SA1100_SIMPAD
+ 	RESTORE(MECR);
++	RESTORE(Ser4MCCR0);
++	RESTORE(Ser4MCSR);
++	RESTORE(Ser4MCCR1);
+ #endif
+ 	RESTORE(PWER);
+ 	RESTORE(MSC1);
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff
index e69de29bb2..c07dafd17a 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-switches-input.diff
@@ -0,0 +1,126 @@
+--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/misc/switches.h	2004-07-01 21:10:30.000000000 +0200
++++ drivers/misc/switches.h	2004-07-03 23:45:46.000000000 +0200
+@@ -25,4 +25,14 @@
+ extern int  switches_ucb1x00_init(void);
+ extern void switches_ucb1x00_exit(void);
+ 
++#ifdef CONFIG_SA1100_SIMPAD	
++#define SIMPAD_KEY_SUSPEND	0x0002
++#define SIMPAD_KEY_WWW		0x0008
++#define SIMPAD_KEY_ENTER	0x0010
++#define SIMPAD_KEY_UP		0x0020
++#define SIMPAD_KEY_DOWN		0x0040
++#define SIMPAD_KEY_LEFT		0x0080
++#define SIMPAD_KEY_RIGHT	0x0100
++#endif
++
+ #endif  /* !defined(_SWITCHES_H) */
+--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/misc/switches-core.c	2004-07-01 21:10:30.000000000 +0200
++++ drivers/misc/switches-core.c	2004-07-04 17:57:37.000000000 +0200
+@@ -16,6 +16,9 @@
+  *  11 September 2001 - UCB1200 driver framework support added.
+  *
+  *  19 December 2001 - separated out SA-1100 and UCB1x00 code.
++ *
++ *  3 July 2004 - Added generating of keyboard events. 
++ *                Florian Boor <florian@handhelds.org>
+  */
+ 
+ #include <linux/config.h>
+@@ -30,7 +33,11 @@
+ #include <linux/slab.h>
+ #include <linux/wait.h>
+ 
++#include <linux/input.h>
++
+ #include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/keyboard.h>
+ 
+ #include "switches.h"
+ 
+@@ -53,6 +60,19 @@
+ DECLARE_WAIT_QUEUE_HEAD(switches_wait);
+ LIST_HEAD(switches_event_queue);
+ 
++#ifdef CONFIG_INPUT
++static struct input_dev idev;
++	
++int 
++dummy_k_translate(unsigned char scancode, unsigned char *keycode, char raw_mode)
++{
++	*keycode = scancode;
++	return 1;
++}
++
++extern int (*k_translate)(unsigned char, unsigned char *, char);
++
++#endif
+ 
+ static ssize_t switches_read(struct file *file, char *buffer,
+ 			     size_t count, loff_t *pos)
+@@ -148,6 +168,31 @@
+ {
+ 	struct switches_action *action;
+ 
++#ifdef CONFIG_INPUT
++	/* create input events, the events to send depends on the platform */
++#ifdef CONFIG_SA1100_SIMPAD	
++	if (machine_is_simpad()) {
++		if (SWITCHES_COUNT(mask) > 0)
++		{
++			if (mask->events[0] & SIMPAD_KEY_SUSPEND)
++				input_report_key(&idev, KEY_POWER, (mask->states[0] & SIMPAD_KEY_SUSPEND) ? 1 : 0);
++			if (mask->events[0] & SIMPAD_KEY_ENTER)
++				input_report_key(&idev, KEY_ENTER, (mask->states[0] & SIMPAD_KEY_ENTER) ? 1 : 0);
++			if (mask->events[0] & SIMPAD_KEY_UP)
++				input_report_key(&idev, KEY_UP, (mask->states[0] & SIMPAD_KEY_UP) ? 1 : 0);
++			if (mask->events[0] & SIMPAD_KEY_DOWN)
++				input_report_key(&idev, KEY_DOWN, (mask->states[0] & SIMPAD_KEY_DOWN) ? 1 : 0);
++			if (mask->events[0] & SIMPAD_KEY_LEFT)
++				input_report_key(&idev, KEY_LEFT, (mask->states[0] & SIMPAD_KEY_LEFT) ? 1 : 0);
++			if (mask->events[0] & SIMPAD_KEY_RIGHT)
++				input_report_key(&idev, KEY_RIGHT, (mask->states[0] & SIMPAD_KEY_RIGHT) ? 1 : 0);
++			if (mask->events[0] & SIMPAD_KEY_WWW)
++				input_report_key(&idev, KEY_WWW, (mask->states[0] & SIMPAD_KEY_WWW) ? 1 : 0);
++		}
++	}
++#endif
++#endif
++	/* take care of switches device */
+ 	if ((switches_users > 0) && (SWITCHES_COUNT(mask) > 0)) {
+ 
+ 		if ((action = (struct switches_action *)
+@@ -197,6 +242,21 @@
+ 		return -EIO;
+ 	}
+ 
++#ifdef CONFIG_INPUT
++	/* init input driver stuff */
++	k_translate = dummy_k_translate;
++	idev.evbit[0] = BIT(EV_KEY); /* handle key events */
++
++	idev.keybit[LONG(KEY_SUSPEND)] |= BIT(KEY_SUSPEND);
++	idev.keybit[LONG(KEY_UP)] |= BIT(KEY_UP);
++	idev.keybit[LONG(KEY_DOWN)] |= BIT(KEY_DOWN);
++	idev.keybit[LONG(KEY_LEFT)] |= BIT(KEY_LEFT);
++	idev.keybit[LONG(KEY_RIGHT)] |= BIT(KEY_RIGHT);
++	idev.keybit[LONG(KEY_ENTER)] |= BIT(KEY_ENTER);
++	idev.keybit[LONG(KEY_WWW)] |= BIT(KEY_WWW);
++
++	input_register_device(&idev);
++#endif	
+ 	printk("Console switches initialized\n");
+ 
+ 	return 0;
+@@ -214,6 +274,10 @@
+ 	switches_ucb1x00_exit();
+ #endif
+ 
++#ifdef CONFIG_INPUT
++	input_unregister_device(&idev);
++#endif
++	
+ 	if (misc_deregister(&switches_misc) < 0)
+ 		printk(KERN_ERR "%s: unable to deregister misc device\n",
+ 		       SWITCHES_NAME);
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff
index e69de29bb2..08fffe5882 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/simpad-ts-noninput.diff
@@ -0,0 +1,11 @@
+--- /mnt/bdisk/openembedded/oetmp/base/opensimpad-2.4.25-vrs2-pxa1-jpm1-r5/linux-2.4.25/drivers/misc/ucb1x00-ts.c	2004-07-01 21:10:30.000000000 +0200
++++ drivers/misc/ucb1x00-ts.c	2004-07-04 02:00:56.000000000 +0200
+@@ -35,7 +35,7 @@
+ /*
+  * Define this if you want the UCB1x00 stuff to talk to the input layer
+  */
+-#ifdef CONFIG_INPUT
++#if defined(CONFIG_INPUT) && !defined(CONFIG_SA1100_SIMPAD)
+ #define USE_INPUT
+ #else
+ #undef USE_INPUT
diff --git a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch
index e69de29bb2..11fa5c7ad5 100644
--- a/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch
+++ b/linux/opensimpad-2.4.25-vrs2-pxa1-jpm1/sound-volume-reversed.patch
@@ -0,0 +1,16 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux-2.4.25/drivers/misc/ucb1x00-audio.c~sound-volume-reversed.patch	2004-03-31 17:15:12.000000000 +0200
++++ linux-2.4.25/drivers/misc/ucb1x00-audio.c	2004-03-31 17:15:13.000000000 +0200
+@@ -97,7 +97,7 @@
+ 				ucba->output_level = gain | gain << 8;
+ 				ucba->mod_cnt++;
+ 				ucba->ctrl_b = (ucba->ctrl_b & 0xff00) |
+-					       ((gain * 31) / 100);
++					       (((100-gain) * 31) / 100);
+ 				ucb1x00_reg_write(ucba->ucb, UCB_AC_B,
+ 						  ucba->ctrl_b);
+ 				ret = 0;
diff --git a/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2 b/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2
index e69de29bb2..ae8799e7a3 100644
--- a/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2
+++ b/linux/openzaurus-2.6.10-rc1-jl1/collie-config-2.6.7-jl2
@@ -0,0 +1,769 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+CONFIG_SHARP_LOCOMO=y
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+CONFIG_SA1100_COLLIE=y
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_STORK is not set
+# CONFIG_SA1100_SSP is not set
+# CONFIG_SA1100_USB is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_SA1100=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+
+#
+# General setup
+#
+CONFIG_DISCONTIGMEM=y
+CONFIG_ISA=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_CPU_FREQ is not set
+
+#
+# PCMCIA/CardBus support
+#
+CONFIG_PCMCIA=y
+# CONFIG_PCMCIA_DEBUG is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+
+#
+# Generic Driver Options
+#
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+CONFIG_APM=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_OBSOLETE_CHIPS=y
+# CONFIG_MTD_AMDSTD is not set
+CONFIG_MTD_SHARP=y
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_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_IPV6 is not set
+# CONFIG_NETFILTER 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_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_NETDEVICES is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN 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=y
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_KEYBOARD_LOCOMO=y
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC 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_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELEKTOR is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=1
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+# 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 is not set
+# CONFIG_NFSD is not set
+# CONFIG_EXPORTFS 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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_SA1100=y
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+CONFIG_USB_GADGET_SA1100=y
+CONFIG_USB_SA1100=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2 b/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2
index e69de29bb2..347657f8ec 100644
--- a/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2
+++ b/linux/openzaurus-2.6.10-rc1-jl1/husky-config-2.6.7-jl2
@@ -0,0 +1,855 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+CONFIG_ARCH_PXA=y
+CONFIG_PXA25x=y
+# CONFIG_PXA27x is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_SHARK is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
+
+#
+# Footbridge Implementations
+#
+
+#
+# IOP3xx Implementation Options
+#
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_IOP321 is not set
+
+#
+# IOP3xx Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
+#
+# Intel PXA250/210 Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_ARCH_PXA_IDP is not set
+# CONFIG_ARCH_PXA_CERF is not set
+# CONFIG_COTULLA_DMA is not set
+# CONFIG_SABINAL_DISCOVERY is not set
+# CONFIG_ARCH_SABINAL is not set
+# CONFIG_ARCH_PXA_POODLE is not set
+# CONFIG_POODLE_TR0 is not set
+CONFIG_ARCH_PXA_CORGI=y
+# CONFIG_MACH_CORGI is not set
+CONFIG_MACH_HUSKY=y
+# CONFIG_CORGI_TR0 is not set
+CONFIG_CORGI_LCD_BUFF=y
+# CONFIG_ARCH_PXA_SHEPHERD is not set
+CONFIG_ARCH_PXA_HUSKY=y
+# CONFIG_ARCH_PXA_BOXER is not set
+CONFIG_ARCH_SHARP_SL=y
+CONFIG_SL_CCCR_CHANGE=y
+CONFIG_SL_CCCR242=y
+
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_SA1100_ADSBITSY is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_COLLIE is not set
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_GRAPHICSMASTER is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_PT_SYSTEM3 is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_STORK is not set
+# CONFIG_SA1100_SSP is not set
+# CONFIG_SA1100_USB is not set
+
+#
+# Processor Type
+#
+# CONFIG_CPU_32v3 is not set
+# CONFIG_CPU_32v4 is not set
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM922T is not set
+# CONFIG_PLD is not set
+# CONFIG_CPU_ARM926T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+# CONFIG_CPU_SA1100 is not set
+CONFIG_CPU_32=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_XSCALE=y
+
+CONFIG_SPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_v4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+
+##### CONFIG_BATT=y
+# CONFIG_XSCALE_CACHE_ERRATA is not set
+##### CONFIG_ARM_THUMB=y
+##### CONFIG_ARM_FCSE=y
+# CONFIG_DISCONTIGMEM is not set
+##### CONFIG_PREEMPT=y
+##### CONFIG_LOCK_BREAK=y
+
+#
+# Processor Features
+#
+
+#
+# General setup
+#
+CONFIG_DISCONTIGMEM=y
+CONFIG_ISA=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+# CONFIG_CPU_FREQ is not set
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# above was not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+
+#
+# Generic Driver Options
+#
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+CONFIG_APM=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttyS0,9600n8 console=tty0 noinitrd root=/dev/mtdblock4 rootfstype=jffs2"
+
+# CONFIG_CMDLINE="console=null root=/dev/mtdblock2 mtdparts=sharpsl-nand:7168k@0k(smf),25600k@7168k(root),-(home) jffs2_orphaned_inodes=delete rootfstype=jffs2"
+# CONFIG_CMDLINE="root=/dev/mtdblock4 rootfstype=jffs2 jffs2_orphaned_inodes=delete console=null mem=16M"
+
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+#CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+# CONFIG_MTD_GEN_PROBE is not set
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_SA1100=y
+# CONFIG_MTD_EDB7312 is not set
+#### CONFIG_MTD_SHARP_SL=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+####CONFIG_MTD_NAND=y
+####CONFIG_MTD_NAND_ECC=y
+####CONFIG_MTD_NAND_VERIFY_WRITE=y
+####CONFIG_MTD_NAND_POST_BADBLOCK=y
+# CONFIG_MTD_NAND_ERASE_BY_FORCE is not set
+####CONFIG_MTD_NAND_LOGICAL_ADDRESS_ACCESS=y
+####CONFIG_MTD_NAND_PAGE_CACHE=y
+####CONFIG_MTD_NAND_SHARP_SL_CORGI=y
+####CONFIG_MTD_NAND_SHARP_SL=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_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_IPV6 is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q 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_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETDEVICES is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN 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=y
+CONFIG_INPUT_TSDEV_SCREEN_X=640
+CONFIG_INPUT_TSDEV_SCREEN_Y=480
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+CONFIG_SHARP_LOCOMO=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+
+# CONFIG_KEYBOARD_COLLIE 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
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SL7X0_POWER_KEY_OFF=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_SA1100 is not set
+# CONFIG_SERIAL_SA1100_CONSOLE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_PXA=y
+CONFIG_SERIAL_PXA_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_ELEKTOR is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=1
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+# 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 is not set
+# CONFIG_NFSD is not set
+# CONFIG_EXPORTFS 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_INTERMEZZO_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+####CONFIG_FB=y
+####CONFIG_FB_CORGI=y
+####CONFIG_SL_SYSCLK100=y
+# CONFIG_FB_SA1100 is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+
+# BJL - Check these out later
+#CONFIG_FBCON_CFB16=y
+#CONFIG_FBCON_ADVANCED=y
+#CONFIG_FBCON_ROTATE_R=y
+
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_SOUND=y
+# CONFIG_SOUND_CORGI=y
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_GADGET_PXA2XX=y
+CONFIG_USB_PXA2XX=y
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+# CONFIG_USB_SA1100 is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff b/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff
index e69de29bb2..5d69785a47 100644
--- a/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff
+++ b/linux/openzaurus-2.6.10-rc1-jl1/patch-2.6.5-rp1.diff
@@ -0,0 +1,881 @@
+diff -uNr linux-2.6.5-orig/arch/arm/Kconfig linux-2.6.5/arch/arm/Kconfig
+--- linux-2.6.5-orig/arch/arm/Kconfig	2004-06-14 20:31:51.000000000 +0100
++++ linux-2.6.5/arch/arm/Kconfig	2004-06-14 20:33:06.000000000 +0100
+@@ -500,7 +500,7 @@
+ 
+ config LEDS
+ 	bool "Timer and CPU usage LEDs"
+-	depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T
++	depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T
+ 	help
+ 	  If you say Y here, the LEDs on your machine will be used
+ 	  to provide useful information about your current system status.
+@@ -513,8 +513,8 @@
+ 	  system, but the driver will do nothing.
+ 
+ config LEDS_TIMER
+-	bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_P720T)
+-	depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T
++	bool "Timer LED" if LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_P720T)
++	depends on ARCH_NETWINDER || ARCH_EBSA110 || ARCH_EBSA285 || ARCH_FTVPCI || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_CDB89712 || ARCH_P720T
+ 	default y if ARCH_EBSA110
+ 	help
+ 	  If you say Y here, one of the system LEDs (the green one on the
+@@ -529,7 +529,7 @@
+ 
+ config LEDS_CPU
+ 	bool "CPU usage LED"
+-	depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || ARCH_INTEGRATOR || ARCH_P720T)
++	depends on LEDS && (ARCH_NETWINDER || ARCH_EBSA285 || ARCH_SHARK || ARCH_CO285 || ARCH_SA1100 || ARCH_LUBBOCK || ARCH_PXA_IDP || MACH_POODLE || MACH_HUSKY || ARCH_INTEGRATOR || ARCH_P720T)
+ 	help
+ 	  If you say Y here, the red LED will be used to give a good real
+ 	  time indication of CPU usage, by lighting whenever the idle task
+diff -uNr linux-2.6.5-orig/arch/arm/Makefile linux-2.6.5/arch/arm/Makefile
+--- linux-2.6.5-orig/arch/arm/Makefile	2004-06-14 20:31:51.000000000 +0100
++++ linux-2.6.5/arch/arm/Makefile	2004-06-14 20:33:06.000000000 +0100
+@@ -54,8 +54,8 @@
+ tune-$(CONFIG_CPU_V6)		:=-mtune=strongarm
+ 
+ # Need -Uarm for gcc < 3.x
+-CFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm
+-AFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -msoft-float -Wa,-mno-fpu
++CFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -malignment-traps -msoft-float
++AFLAGS		+=-mapcs-32 $(arch-y) $(tune-y) -msoft-float
+ 
+ #Default value
+ DATAADDR	:= .
+diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/Makefile linux-2.6.5/arch/arm/boot/compressed/Makefile
+--- linux-2.6.5-orig/arch/arm/boot/compressed/Makefile	2004-06-14 20:31:52.000000000 +0100
++++ linux-2.6.5/arch/arm/boot/compressed/Makefile	2004-06-14 20:33:06.000000000 +0100
+@@ -55,14 +55,18 @@
+ OBJS		+= head-xscale.o
+ endif
+ 
++ifeq ($(CONFIG_DEBUG_ICEDCC),y)
++OBJS            += ice-dcc.o
++endif
++
+ SEDFLAGS	= s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/
+ 
+ targets       := vmlinux vmlinux.lds piggy piggy.gz piggy.o \
+                  font.o head.o $(OBJS)
+ EXTRA_CFLAGS  := -fpic
+-EXTRA_AFLAGS  := -traditional
++EXTRA_AFLAGS  :=
+ 
+-LDFLAGS_vmlinux := -p -X \
++LDFLAGS_vmlinux := -p --no-undefined -X \
+ 	$(shell $(CC) $(CFLAGS) --print-libgcc-file-name) -T
+ 
+ $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \
+diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/head-xscale.S linux-2.6.5/arch/arm/boot/compressed/head-xscale.S
+--- linux-2.6.5-orig/arch/arm/boot/compressed/head-xscale.S	2004-06-14 20:31:52.000000000 +0100
++++ linux-2.6.5/arch/arm/boot/compressed/head-xscale.S	2004-06-14 20:33:06.000000000 +0100
+@@ -52,6 +52,18 @@
+ 		mov	r7, #MACH_TYPE_POODLE
+ #endif
+ 
++#ifdef CONFIG_MACH_CORGI
++@		mov	r7, #MACH_TYPE_CORGI
++		mov	r7, #0xa7
++		add 	r7, r7, #0x100
++#endif
++
++#ifdef CONFIG_MACH_HUSKY
++@		mov	r7, #MACH_TYPE_HUSKY
++		mov	r7, #0xde
++		add 	r7, r7, #0x100
++#endif
++
+ #ifdef CONFIG_ARCH_IQ80310
+ 		/*
+ 		 * Crank the CPU up to 733MHz
+diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/head.S linux-2.6.5/arch/arm/boot/compressed/head.S
+--- linux-2.6.5-orig/arch/arm/boot/compressed/head.S	2004-06-14 20:31:53.000000000 +0100
++++ linux-2.6.5/arch/arm/boot/compressed/head.S	2004-06-14 20:33:06.000000000 +0100
+@@ -10,6 +10,8 @@
+ #include <linux/config.h>
+ #include <linux/linkage.h>
+ 
++#define DEBUG 1
++
+ /*
+  * Debugging stuff
+  *
+@@ -25,6 +27,12 @@
+ 		.macro	writeb, rb
+ 		str	\rb, [r3, #0x160]
+ 		.endm
++#elif defined(CONFIG_DEBUG_ICEDCC)
++		.macro	loadsp, rb
++		.endm
++		.macro writeb, rb
++		mcr	p14, 0, \rb, c0, c1, 0
++		.endm
+ #elif defined(CONFIG_FOOTBRIDGE)
+ 		.macro	loadsp,	rb
+ 		mov	\rb, #0x7c000000
+@@ -67,6 +75,19 @@
+ 		.macro	writeb, rb
+ 		str	\rb, [r3, #0x14]	@ UTDR
+ 		.endm
++#elif defined(CONFIG_ARCH_IXP4XX)
++		.macro	loadsp, rb
++		mov	\rb, #0xc8000000
++		.endm
++		.macro	writeb, rb
++		str	\rb, [r3, #0]
++#elif defined(CONFIG_ARCH_LH7A40X)
++		.macro	loadsp, rb
++		ldr	\rb, =0x80000700	@ UART2 UARTBASE
++		.endm
++		.macro	writeb, rb
++		strb	\rb, [r3, #0]
++		.endm
+ #else
+ #error no serial architecture defined
+ #endif
+@@ -332,11 +353,19 @@
+ 		mov	r8, r0, lsr #18
+ 		mov	r8, r8, lsl #18		@ start of RAM
+ 		add	r9, r8, #0x10000000	@ a reasonable RAM size
+-		mov	r1, #0x12
++@#ifdef CONFIG_CPU_XSCALE
++		mov	r1, #0x02
++@#else
++@		mov	r1, #0x12
++@#endif
+ 		orr	r1, r1, #3 << 10
+ 		add	r2, r3, #16384
+ 1:		cmp	r1, r8			@ if virt > start of RAM
+-		orrhs	r1, r1, #0x0c		@ set cacheable, bufferable
++@#ifdef CONFIG_XSCALE_CACHE_ERRATA
++		orrhs	r1, r1, #0x08           @ set cacheable, not bufferable
++@#else
++@		orrhs	r1, r1, #0x0c		@ set cacheable, bufferable
++@#endif
+ 		cmp	r1, r9			@ if virt > end of RAM
+ 		bichs	r1, r1, #0x0c		@ clear cacheable, bufferable
+ 		str	r1, [r0], #4		@ 1:1 mapping
+diff -uNr linux-2.6.5-orig/arch/arm/boot/compressed/vmlinux.lds.in linux-2.6.5/arch/arm/boot/compressed/vmlinux.lds.in
+--- linux-2.6.5-orig/arch/arm/boot/compressed/vmlinux.lds.in	2004-06-14 20:31:53.000000000 +0100
++++ linux-2.6.5/arch/arm/boot/compressed/vmlinux.lds.in	2004-06-14 20:33:06.000000000 +0100
+@@ -47,7 +47,7 @@
+   .bss			: { *(.bss) }
+   _end = .;
+ 
+-  .stack (NOLOAD)	: { *(.stack) }
++  .stack 	: { *(.stack) }
+ 
+   .stab 0		: { *(.stab) }
+   .stabstr 0		: { *(.stabstr) }
+diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/Kconfig linux-2.6.5/arch/arm/mach-pxa/Kconfig
+--- linux-2.6.5-orig/arch/arm/mach-pxa/Kconfig	2004-06-14 20:31:53.000000000 +0100
++++ linux-2.6.5/arch/arm/mach-pxa/Kconfig	2004-06-14 20:33:06.000000000 +0100
+@@ -13,10 +13,23 @@
+ 	bool "SHARP Poodle"
+ 	depends on ARCH_PXA
+ 
++config MACH_CORGI
++	bool "SHARP Corgi (SL-C700)"
++	depends on ARCH_PXA 
++
++config MACH_SHEPHERD
++	bool "SHARP Shepherd (SL-C750)"
++	depends on ARCH_PXA 
++
++config MACH_HUSKY
++	bool "SHARP Husky (SL-C760)"
++	depends on ARCH_PXA 
++
+ config SHARP_LOCOMO
+ 	bool "SHARP LoCoMo support"
+ 	default Y
+-	depends MACH_POODLE
++	depends MACH_POODLE || MACH_CORGI || MACH_HUSKY
++
+ 
+ endmenu
+ 
+diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/Makefile linux-2.6.5/arch/arm/mach-pxa/Makefile
+--- linux-2.6.5-orig/arch/arm/mach-pxa/Makefile	2004-06-14 20:31:54.000000000 +0100
++++ linux-2.6.5/arch/arm/mach-pxa/Makefile	2004-06-14 20:33:06.000000000 +0100
+@@ -9,12 +9,18 @@
+ obj-$(CONFIG_ARCH_LUBBOCK)	+= lubbock.o
+ obj-$(CONFIG_ARCH_PXA_IDP)	+= idp.o
+ obj-$(CONFIG_MACH_POODLE)	+= poodle.o
++obj-$(CONFIG_MACH_CORGI)	+= corgi.o
++obj-$(CONFIG_MACH_SHEPHERD)	+= corgi.o
++obj-$(CONFIG_MACH_HUSKY)	+= corgi.o
+ 
+ # Support for blinky lights
+ led-y := leds.o
+ led-$(CONFIG_ARCH_LUBBOCK)	+= leds-lubbock.o
+ led-$(CONFIG_ARCH_PXA_IDP)	+= leds-idp.o
+ led-$(CONFIG_MACH_POODLE)	+= leds-poodle.o
++led-$(CONFIG_MACH_CORGI)	+= leds-corgi.o
++led-$(CONFIG_MACH_SHEPHERD)	+= leds-corgi.o
++led-$(CONFIG_MACH_HUSKY)	+= leds-corgi.o
+ 
+ obj-$(CONFIG_LEDS) += $(led-y)
+ 
+diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/corgi.c linux-2.6.5/arch/arm/mach-pxa/corgi.c
+--- linux-2.6.5-orig/arch/arm/mach-pxa/corgi.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.5/arch/arm/mach-pxa/corgi.c	2004-06-14 20:33:19.000000000 +0100
+@@ -0,0 +1,178 @@
++/*
++ * linux/arch/arm/mach-pxa/corgi.c
++ *
++ *  Support for the SHARP Corgi Board.
++ *  
++ *  Copyright:	Lineo Japan Inc.
++ *
++ * Based on:
++ *  linux/arch/arm/mach-pxa/lubbock.c
++ *
++ *  Support for the Intel DBPXA250 Development Platform.
++ *  
++ *  Author:	Nicolas Pitre
++ *  Created:	Jun 15, 2001
++ *  Copyright:	MontaVista Software Inc.
++ *  
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ *
++ * Change Log
++ *  12-Dec-2002 Sharp Corporation for Corgi
++ *  01-Apr-2003 Sharp for Shepherd
++ *
++ *  Mar 10, 2004: Lots of changes to port to 2.6 by John Lenz
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/major.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++
++#include <asm/setup.h>
++#include <asm/memory.h>
++#include <asm/mach-types.h>
++#include <asm/hardware.h>
++#include <asm/irq.h>
++
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++#include <asm/mach/irq.h>
++
++#include <asm/arch/irq.h>
++#include <asm/arch/corgi.h>
++
++#include "generic.h"
++
++static void __init scoop_init(void)
++{
++
++#define	CORGI_SCP_INIT_DATA(adr,dat)	(((adr)<<16)|(dat))
++#define	CORGI_SCP_INIT_DATA_END	((unsigned long)-1)
++	static const unsigned long scp_init[] =
++	{
++		CORGI_SCP_INIT_DATA(CORGI_SCP_MCR,0x0140),  // 00
++		CORGI_SCP_INIT_DATA(CORGI_SCP_MCR,0x0100),
++		CORGI_SCP_INIT_DATA(CORGI_SCP_CDR,0x0000),  // 04
++		CORGI_SCP_INIT_DATA(CORGI_SCP_CPR,0x0000),  // 0C
++		CORGI_SCP_INIT_DATA(CORGI_SCP_CCR,0x0000),  // 10
++		CORGI_SCP_INIT_DATA(CORGI_SCP_IMR,0x0000),  // 18
++		CORGI_SCP_INIT_DATA(CORGI_SCP_IRM,0x00FF),  // 14
++		CORGI_SCP_INIT_DATA(CORGI_SCP_ISR,0x0000),  // 1C
++		CORGI_SCP_INIT_DATA(CORGI_SCP_IRM,0x0000),
++		CORGI_SCP_INIT_DATA(CORGI_SCP_GPCR,CORGI_SCP_IO_DIR),  // 20
++		CORGI_SCP_INIT_DATA(CORGI_SCP_GPWR,CORGI_SCP_IO_OUT),  // 24
++		CORGI_SCP_INIT_DATA_END
++	};
++	int	i;
++	for(i=0; scp_init[i] != CORGI_SCP_INIT_DATA_END; i++)
++	{
++		int	adr = scp_init[i] >> 16;
++		CORGI_SCP_REG(adr) = scp_init[i] & 0xFFFF;
++	}
++}
++
++static void __init corgi_init_irq(void)
++{
++	pxa_init_irq();
++
++	/* setup extra corgi irqs */
++
++	/* i2c initialize */
++	//i2c_init(); RPP Fixme!
++
++	/* scoop initialize */
++	scoop_init();
++
++	/* initialize SSP & CS */
++	/*pxa_ssp_init();*/
++}
++
++#if 0
++static void __init
++fixup_corgi(struct machine_desc *desc, struct param_struct *params,
++		char **cmdline, struct meminfo *mi)
++{
++#if defined(CONFIG_MACH_SHEPHERD) || defined(CONFIG_MACH_HUSKY)
++	SET_BANK (0, 0xa0000000, 64*1024*1024);
++#else
++	SET_BANK (0, 0xa0000000, 32*1024*1024);
++#endif
++	mi->nr_banks      = 1;
++#if defined(CONFIG_BLK_DEV_INITRD)
++	setup_ramdisk (1, 0, 0, 8192);
++	setup_initrd (__phys_to_virt(0xa1000000), 4*1024*1024);
++	ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
++#elif defined(CONFIG_MTD)
++	ROOT_DEV = MKDEV(31, 0);	/* /dev/mtdblock0 */
++#endif
++
++#ifdef CONFIG_SHARPSL_BOOTLDR_PARAMS
++	if (params->u1.s.page_size != PAGE_SIZE) {
++	    params->u1.s.page_size = PAGE_SIZE;
++	    params->u1.s.nr_pages = 32 * 1024 * 1024 / PAGE_SIZE;
++	    params->u1.s.ramdisk_size = 0;
++	    params->u1.s.flags = FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT;
++	    params->u1.s.rootdev = ROOT_DEV;
++	    params->u1.s.initrd_start = 0;
++	    params->u1.s.initrd_size = 0;
++	    params->u1.s.rd_start = 0;
++	    params->u1.s.system_rev = 0;
++	    params->u1.s.system_serial_low = 0;
++	    params->u1.s.system_serial_high = 0;
++	    strcpy(params->commandline, CONFIG_CMDLINE);
++	}
++#endif
++}
++#endif
++
++static struct map_desc corgi_io_desc[] __initdata = {
++ /* virtual     physical    length      */
++  { 0xf1000000, 0x08000000, 0x01000000, MT_DEVICE }, /* LCDC (readable for Qt driver) */
++  { 0xf2000000, 0x10800000, 0x00001000, MT_DEVICE }, /* SCOOP */
++  { 0xf2100000, 0x0C000000, 0x00001000, MT_DEVICE }, /* Nand Flash */
++  { 0xef000000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */
++};
++
++static void __init corgi_map_io(void)
++{
++	pxa_map_io();
++	iotable_init(corgi_io_desc,ARRAY_SIZE(corgi_io_desc));
++
++#if 0
++	/* This enables the BTUART */
++	CKEN |= CKEN7_BTUART;
++	set_GPIO_mode(GPIO42_BTRXD_MD);
++	set_GPIO_mode(GPIO43_BTTXD_MD);
++	set_GPIO_mode(GPIO44_BTCTS_MD);
++	set_GPIO_mode(GPIO45_BTRTS_MD);
++#endif
++
++	/* setup sleep mode values */
++	PWER  = 0x00000002;
++	PFER  = 0x00000000;
++	PRER  = 0x00000002;
++	PGSR0 = 0x0158C000;
++	PGSR1 = 0x00FF0080;
++	PGSR2 = 0x0001C004;
++	PCFR |= PCFR_OPDE;
++}
++
++#if defined(CONFIG_MACH_SHEPHERD)
++MACHINE_START(SHEPHERD, "SHARP Shepherd")
++#elseif defined(CONFIG_MACH_HUSKY)
++MACHINE_START(HUSKY, "SHARP Husky")
++#else
++MACHINE_START(CORGI, "SHARP Corgi")
++#endif
++	BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
++#ifdef CONFIG_SHARPSL_BOOTLDR_PARAMS
++	BOOT_PARAMS(0xa0000100)
++#endif
++/*	FIXUP(fixup_corgi)*/
++	MAPIO(corgi_map_io)
++	INITIRQ(corgi_init_irq)
++MACHINE_END
+diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/leds-corgi.c linux-2.6.5/arch/arm/mach-pxa/leds-corgi.c
+--- linux-2.6.5-orig/arch/arm/mach-pxa/leds-corgi.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.5/arch/arm/mach-pxa/leds-corgi.c	2004-06-14 20:33:19.000000000 +0100
+@@ -0,0 +1,135 @@
++/*
++ * linux/arch/arm/mach-pxa/leds-corgi.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Copied from arch/arm/mach-sa1100/leds-collie.c
++ * ChangeLog:
++ * 	- John Lenz <4/27/04> - added support for new locomo device model
++ */
++
++#include <linux/config.h>
++#include <linux/init.h>
++#include <linux/device.h>
++
++#include <asm/hardware.h>
++#include <asm/hardware/locomo.h>
++#include <asm/leds.h>
++#include <asm/system.h>
++
++#include "leds.h"
++
++#define LED_STATE_ENABLED	1
++#define LED_STATE_CLAIMED	2
++
++static struct locomo_dev *locomo_dev = NULL;
++static unsigned int led_state;
++static unsigned int hw_led0_state = 0;
++static unsigned int hw_led1_state = 0;
++
++#define	LED_ONOFF_MASK (LOCOMO_LPT_TOFL|LOCOMO_LPT_TOFH)
++#define	LED_OFF(REG) ((REG)|=LOCOMO_LPT_TOFL)
++#define	LED_ON(REG) ((REG)=((REG)&~LED_ONOFF_MASK)|LOCOMO_LPT_TOFH)
++#define LED_FLIP(REG)	((REG)^=LED_ONOFF_MASK)
++
++void corgi_leds_event(led_event_t evt)
++{
++        unsigned long flags;
++
++	local_irq_save(flags);
++
++        switch (evt) {
++        case led_start:
++                led_state = LED_STATE_ENABLED;
++		LED_ON(hw_led0_state);
++		LED_ON(hw_led1_state);
++                break;
++
++        case led_stop:
++                led_state &= ~LED_STATE_ENABLED;
++                break;
++
++        case led_claim:
++                led_state |= LED_STATE_CLAIMED;
++		LED_ON(hw_led0_state);
++		LED_ON(hw_led1_state);
++                break;
++
++        case led_release:
++                led_state &= ~LED_STATE_CLAIMED;
++		LED_ON(hw_led0_state);
++		LED_ON(hw_led1_state);
++                break;
++
++#ifdef CONFIG_LEDS_TIMER
++        case led_timer:
++                if (!(led_state & LED_STATE_CLAIMED)) {
++			LED_FLIP(hw_led0_state);
++		}
++                break;
++#endif
++
++#ifdef CONFIG_LEDS_CPU
++        case led_idle_start:
++		/* LED off when system is idle */
++                if (!(led_state & LED_STATE_CLAIMED))
++			LED_OFF(hw_led1_state);
++                break;
++
++        case led_idle_end:
++                if (!(led_state & LED_STATE_CLAIMED))
++			LED_ON(hw_led1_state);
++                break;
++#endif
++
++	default:
++		break;
++        }
++
++	
++        if  (locomo_dev && led_state & LED_STATE_ENABLED) {
++		locomo_writel(hw_led0_state, locomo_dev->mapbase + LOCOMO_LPT0);
++		locomo_writel(hw_led1_state, locomo_dev->mapbase + LOCOMO_LPT1);
++        }
++
++	local_irq_restore(flags);
++}
++
++static int corgiled_probe(struct locomo_dev *dev) {
++	/* set up the initial led states, since due to the init order,
++	 * corgi_leds_event(led_start) might have been called before this */
++        /*if  (led_state & LED_STATE_ENABLED) {
++		//LCM_LPT0 = hw_led0_state;
++		locomo_writel(hw_led0_state, dev->mapbase + LOCOMO_LPT0);
++		//LCM_LPT1 = hw_led1_state;
++		locomo_writel(hw_led1_state, dev->mapbase + LOCOMO_LPT1);
++        }*/
++	locomo_dev = dev;
++	return 0;
++}
++
++static int corgiled_remove(struct locomo_dev *dev) {
++	locomo_dev = NULL;
++	return 0;
++}
++
++static struct locomo_driver corgiled_driver = {
++	.drv = {
++		.name = "locomoled"
++	},
++	.devid	= LOCOMO_DEVID_LED,
++	.probe	= corgiled_probe,
++	.remove	= corgiled_remove,
++};
++
++static int __init corgiled_init(void) {
++	return locomo_driver_register(&corgiled_driver);
++}
++
++device_initcall(corgiled_init);
++
++MODULE_AUTHOR("John Lenz <jelenz@wisc.edu>");
++MODULE_DESCRIPTION("LoCoMo Corgi LED driver");
++MODULE_LICENSE("GPL");
+diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/leds.c linux-2.6.5/arch/arm/mach-pxa/leds.c
+--- linux-2.6.5-orig/arch/arm/mach-pxa/leds.c	2004-06-14 20:31:54.000000000 +0100
++++ linux-2.6.5/arch/arm/mach-pxa/leds.c	2004-06-14 20:33:06.000000000 +0100
+@@ -24,7 +24,8 @@
+ 		leds_event = idp_leds_event;
+ 	if (machine_is_poodle())
+ 		leds_event = poodle_leds_event;
+-
++	if (machine_is_corgi())
++		leds_event = corgi_leds_event;
+ 	leds_event(led_start);
+ 	return 0;
+ }
+diff -uNr linux-2.6.5-orig/arch/arm/mach-pxa/leds.h linux-2.6.5/arch/arm/mach-pxa/leds.h
+--- linux-2.6.5-orig/arch/arm/mach-pxa/leds.h	2004-06-14 20:31:54.000000000 +0100
++++ linux-2.6.5/arch/arm/mach-pxa/leds.h	2004-06-14 20:33:06.000000000 +0100
+@@ -10,3 +10,4 @@
+ extern void lubbock_leds_event(led_event_t evt);
+ extern void idp_leds_event(led_event_t evt);
+ extern void poodle_leds_event(led_event_t evt);
++extern void corgi_leds_event(led_event_t evt);
+diff -uNr linux-2.6.5-orig/arch/arm/tools/mach-types linux-2.6.5/arch/arm/tools/mach-types
+--- linux-2.6.5-orig/arch/arm/tools/mach-types	2004-06-14 20:31:55.000000000 +0100
++++ linux-2.6.5/arch/arm/tools/mach-types	2004-06-14 20:33:06.000000000 +0100
+@@ -485,3 +485,4 @@
+ vr1000			MACH_VR1000		VR1000			475
+ deisterpxa		MACH_DEISTERPXA		DEISTERPXA		476
+ bcm1160			MACH_BCM1160		BCM1160			477
++husky			MACH_HUSKY		HUSKY			478
+\ No newline at end of file
+diff -uNr linux-2.6.5-orig/drivers/serial/8250.c linux-2.6.5/drivers/serial/8250.c
+--- linux-2.6.5-orig/drivers/serial/8250.c	2004-06-14 20:31:55.000000000 +0100
++++ linux-2.6.5/drivers/serial/8250.c	2004-06-14 20:33:06.000000000 +0100
+@@ -169,7 +169,8 @@
+ 	{ "ST16654",	64,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+ 	{ "XR16850",	128,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH },
+ 	{ "RSA",	2048,	UART_CLEAR_FIFO | UART_USE_FIFO },
+-	{ "NS16550A",	16,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI }
++	{ "NS16550A",	16,	UART_CLEAR_FIFO | UART_USE_FIFO | UART_NATSEMI },
++	{ "XScale",	32,	UART_CLEAR_FIFO | UART_USE_FIFO  },
+ };
+ 
+ static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset)
+@@ -1499,6 +1500,8 @@
+ 	up->ier &= ~UART_IER_MSI;
+ 	if (UART_ENABLE_MS(&up->port, termios->c_cflag))
+ 		up->ier |= UART_IER_MSI;
++	if (up->port.type == PORT_XSCALE)
++		up->ier |= UART_IER_UUE | UART_IER_RTOIE;
+ 
+ 	serial_out(up, UART_IER, up->ier);
+ 
+@@ -1930,7 +1933,11 @@
+ 	 *	First save the UER then disable the interrupts
+ 	 */
+ 	ier = serial_in(up, UART_IER);
+-	serial_out(up, UART_IER, 0);
++
++	if (up->port.type == PORT_XSCALE)
++		serial_out(up, UART_IER, UART_IER_UUE);
++	else
++		serial_out(up, UART_IER, 0);
+ 
+ 	/*
+ 	 *	Now, do each character
+diff -uNr linux-2.6.5-orig/include/asm-arm/arch-pxa/corgi.h linux-2.6.5/include/asm-arm/arch-pxa/corgi.h
+--- linux-2.6.5-orig/include/asm-arm/arch-pxa/corgi.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.5/include/asm-arm/arch-pxa/corgi.h	2004-06-14 20:33:19.000000000 +0100
+@@ -0,0 +1,219 @@
++/*
++ * linux/include/asm-arm/arch-pxa/corgi.h
++ * 
++ * (C) Copyright 2001 Lineo Japan, Inc.
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ *
++ * Based on:
++ *
++ * linux/include/asm-arm/arch-sa1100/collie.h
++ * 
++ * This file contains the hardware specific definitions for Collie
++ *
++ * (C) Copyright 2001 Lineo Japan, Inc.
++ * 
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ * 
++ * ChangeLog:
++ *   04-06-2001 Lineo Japan, Inc.
++ *   04-16-2001 SHARP Corporation
++ *
++ *   Mar 10, 2004: Updates to 2.6 by John Lenz
++ */
++#ifndef __ASM_ARCH_CORGI_H
++#define __ASM_ARCH_CORGI_H  1
++
++/*
++ * LCDC internal I/O mappings
++ *
++ * We have the following mapping:
++ *      phys            virt
++ *      08000000        f1000000
++ */
++
++
++
++/*
++ * SCOOP internal I/O mappings
++ *
++ * We have the following mapping:
++ *      phys            virt
++ *      10800000        f2000000
++ */
++
++
++#define CF_BUF_CTRL_BASE 0xF2000000
++
++#define	CORGI_SCP_REG(adr) (*(volatile unsigned short*)(CF_BUF_CTRL_BASE+(adr)))
++
++#define	CORGI_SCP_MCR  0x00
++#define	CORGI_SCP_CDR  0x04
++#define	CORGI_SCP_CSR  0x08
++#define	CORGI_SCP_CPR  0x0C
++#define	CORGI_SCP_CCR  0x10
++#define	CORGI_SCP_IRR  0x14
++#define	CORGI_SCP_IRM  0x14
++#define	CORGI_SCP_IMR  0x18
++#define	CORGI_SCP_ISR  0x1C
++#define	CORGI_SCP_GPCR 0x20
++#define	CORGI_SCP_GPWR 0x24
++#define	CORGI_SCP_GPRR 0x28
++#define	CORGI_SCP_REG_MCR	CORGI_SCP_REG(CORGI_SCP_MCR)
++#define	CORGI_SCP_REG_CDR	CORGI_SCP_REG(CORGI_SCP_CDR)
++#define	CORGI_SCP_REG_CSR	CORGI_SCP_REG(CORGI_SCP_CSR)
++#define	CORGI_SCP_REG_CPR	CORGI_SCP_REG(CORGI_SCP_CPR)
++#define	CORGI_SCP_REG_CCR	CORGI_SCP_REG(CORGI_SCP_CCR)
++#define	CORGI_SCP_REG_IRR	CORGI_SCP_REG(CORGI_SCP_IRR)
++#define	CORGI_SCP_REG_IRM	CORGI_SCP_REG(CORGI_SCP_IRM)
++#define	CORGI_SCP_REG_IMR	CORGI_SCP_REG(CORGI_SCP_IMR)
++#define	CORGI_SCP_REG_ISR	CORGI_SCP_REG(CORGI_SCP_ISR)
++#define	CORGI_SCP_REG_GPCR	CORGI_SCP_REG(CORGI_SCP_GPCR)
++#define	CORGI_SCP_REG_GPWR	CORGI_SCP_REG(CORGI_SCP_GPWR)
++#define	CORGI_SCP_REG_GPRR	CORGI_SCP_REG(CORGI_SCP_GPRR)
++
++#define CORGI_SCP_GPCR_PA22	( 1 << 12 )
++#define CORGI_SCP_GPCR_PA21	( 1 << 11 )
++#define CORGI_SCP_GPCR_PA20	( 1 << 10 )
++#define CORGI_SCP_GPCR_PA19	( 1 << 9 )
++#define CORGI_SCP_GPCR_PA18	( 1 << 8 )
++#define CORGI_SCP_GPCR_PA17	( 1 << 7 )
++#define CORGI_SCP_GPCR_PA16	( 1 << 6 )
++#define CORGI_SCP_GPCR_PA15	( 1 << 5 )
++#define CORGI_SCP_GPCR_PA14	( 1 << 4 )
++#define CORGI_SCP_GPCR_PA13	( 1 << 3 )
++#define CORGI_SCP_GPCR_PA12	( 1 << 2 )
++#define CORGI_SCP_GPCR_PA11	( 1 << 1 )
++
++
++/*
++ * GPIOs
++ */
++#define CORGI_SCP_LED_GREEN		CORGI_SCP_GPCR_PA11
++#define CORGI_SCP_SWA			CORGI_SCP_GPCR_PA12
++#define CORGI_SCP_SWB			CORGI_SCP_GPCR_PA13
++#define CORGI_SCP_MUTE_L		CORGI_SCP_GPCR_PA14
++#define CORGI_SCP_MUTE_R		CORGI_SCP_GPCR_PA15
++#define CORGI_SCP_AKIN_PULLUP		CORGI_SCP_GPCR_PA16
++#define CORGI_SCP_APM_ON		CORGI_SCP_GPCR_PA17
++#define CORGI_SCP_BACKLIGHT_CONT	CORGI_SCP_GPCR_PA18
++#define CORGI_SCP_MIC_BIAS		CORGI_SCP_GPCR_PA19
++
++
++#define CORGI_SCP_IO_DIR	( CORGI_SCP_LED_GREEN | CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R | \
++				  CORGI_SCP_AKIN_PULLUP | CORGI_SCP_APM_ON | CORGI_SCP_BACKLIGHT_CONT | \
++				  CORGI_SCP_MIC_BIAS )
++#define CORGI_SCP_IO_OUT	( CORGI_SCP_MUTE_L | CORGI_SCP_MUTE_R )
++#define CORGI_GPIO_CO		16
++
++
++/*
++ * Flash Memory mappings
++ *
++ * We have the following mapping:
++ *                      phys            virt
++ *      boot ROM        00000000        ef000000
++ *      NAND Flash      0C000000	f2100000
++ */
++#define NAND_FLASH_REG_BASE 0xf2100000
++#define CORGI_CPLD_REG(ofst) (*(volatile unsigned char*)(NAND_FLASH_REG_BASE+(ofst)))
++
++/* register offset */
++#define CORGI_ECCLPLB		0x00	/* line parity 7 - 0 bit */
++#define CORGI_ECCLPUB		0x04	/* line parity 15 - 8 bit */
++#define CORGI_ECCCP		0x08	/* column parity 5 - 0 bit */
++#define CORGI_ECCCNTR		0x0C	/* ECC byte counter */
++#define CORGI_ECCCLRR		0x10	/* cleare ECC */
++#define CORGI_FLASHIO		0x14	/* Flash I/O */
++#define CORGI_FLASHCTL		0x18	/* Flash Control */
++
++/* Flash control bit */
++#define CORGI_FLRYBY		(1 << 5)
++#define CORGI_FLCE1		(1 << 4)
++#define CORGI_FLWP		(1 << 3)
++#define CORGI_FLALE		(1 << 2)
++#define CORGI_FLCLE		(1 << 1)
++#define CORGI_FLCE0		(1 << 0)
++
++
++
++
++/*
++CORGI_ * LED
++ */
++#define CORGI_GPIO_LED_ORANGE		(13)
++//#define CORGI_SCP_LED_GREEN		CORGI_SCP_GPCR_PA11
++
++
++/*
++ * GPIOs
++ */
++/* PXA GPIOs */
++#define CORGI_GPIO_KEY_INT		(0)	/* key interrupt */
++#define CORGI_GPIO_AC_IN		(1)
++#define CORGI_GPIO_TP_INT		(5)	/* Touch Panel interrupt */
++#define CORGI_GPIO_WAKEUP		(3)
++#define CORGI_GPIO_IR_ON		(22)
++#define CORGI_GPIO_AK_INT		(4)	// Remote Controller
++#define CORGI_GPIO_HP_IN		GPIO_AK_INT
++#define CORGI_GPIO_CF_IRQ		(17)
++//#define CORGI_GPIO_CF_PRDY		(17)
++#define CORGI_GPIO_LED_ORANGE		(13)
++#define CORGI_GPIO_CF_CD		(14)
++#define CORGI_GPIO_SD_PWR		(33)
++#define CORGI_GPIO_nSD_CLK		(6)
++#define CORGI_GPIO_nSD_WP		(7)
++#define CORGI_GPIO_nSD_INT		(10)
++#define CORGI_GPIO_nSD_DETECT		(9)
++#define CORGI_GPIO_MAIN_BAT_LOW		(11)
++#define CORGI_GPIO_BAT_COVER		(11)
++#define CORGI_GPIO_ADC_TEMP_ON		(21)
++#define CORGI_GPIO_CHRG_ON		(38)
++#define CORGI_GPIO_CHRG_FULL		(16)
++#define CORGI_GPIO_USB_PULLUP		(45)
++#define CORGI_GPIO_HSYNC		(44)
++
++/* KeyBoard */
++#define CORGI_KEY_STROBE_NUM		(12)
++#define CORGI_KEY_SENSE_NUM		(8)
++#define CORGI_GPIO_ALL_STROBE_BIT	(0x00003ffc)
++#define CORGI_GPIO_HIGH_SENSE_BIT	(0xfc000000)
++#define CORGI_GPIO_HIGH_SENSE_RSHIFT	(26)
++#define CORGI_GPIO_LOW_SENSE_BIT	(0x00000003)
++#define CORGI_GPIO_LOW_SENSE_LSHIFT	(6)
++#define CORGI_GPIO_STROBE_BIT(a)	GPIO_bit(66+(a))
++#define CORGI_GPIO_SENSE_BIT(a)		GPIO_bit(58+(a))
++#define CORGI_GAFR_ALL_STROBE_BIT	(0x0ffffff0)
++#define CORGI_GAFR_HIGH_SENSE_BIT	(0xfff00000)
++#define CORGI_GAFR_LOW_SENSE_BIT	(0x0000000f)
++#define CORGI_GPIO_KEY_SENSE(a)		(58+(a))
++
++
++/*
++ * Interrupts
++ */
++/* PXA GPIOs */
++#define CORGI_IRQ_GPIO_KEY_INT		IRQ_GPIO(0)
++#define CORGI_IRQ_GPIO_AC_IN		IRQ_GPIO(1)
++#define CORGI_IRQ_GPIO_AK_INT		IRQ_GPIO(4)
++#define CORGI_IRQ_GPIO_HP_IN		IRQ_GPIO_AK_INT
++#define CORGI_IRQ_GPIO_TP_INT		IRQ_GPIO(5)
++#define CORGI_IRQ_GPIO_WAKEUP		IRQ_GPIO(3)
++#define CORGI_IRQ_GPIO_CO		IRQ_GPIO(16)
++#define CORGI_IRQ_GPIO_CF_IRQ		IRQ_GPIO(17)
++#define CORGI_IRQ_GPIO_CF_CD		IRQ_GPIO(14)
++#define CORGI_IRQ_GPIO_nSD_INT		IRQ_GPIO(10)
++#define CORGI_IRQ_GPIO_nSD_DETECT	IRQ_GPIO(9)
++#define CORGI_IRQ_GPIO_MAIN_BAT_LOW	IRQ_GPIO(11)
++#define CORGI_IRQ_GPIO_KEY_SENSE(a)	IRQ_GPIO(58+(a))
++
++
++// CS
++#define CORGI_CS_MAX1111	1
++#define CORGI_CS_ADS7846	2
++#define CORGI_CS_LZ9JG18	3
++
++#endif /* __ASM_ARCH_CORGI_H  */
++
+diff -uNr linux-2.6.5-orig/include/asm-arm/thread_info.h linux-2.6.5/include/asm-arm/thread_info.h
+--- linux-2.6.5-orig/include/asm-arm/thread_info.h	2004-06-14 20:31:55.000000000 +0100
++++ linux-2.6.5/include/asm-arm/thread_info.h	2004-06-14 20:33:06.000000000 +0100
+@@ -108,8 +108,8 @@
+ #define TI_CPU		20
+ #define TI_CPU_DOMAIN	24
+ #define TI_CPU_SAVE	28
+-#define TI_USED_MATH	76
+-#define TI_FPSTATE	(TI_USED_MATH+16)
++#define TI_USED_CP	76
++#define TI_FPSTATE	(TI_USED_CP+16)
+ 
+ #endif
+ 
+diff -uNr linux-2.6.5-orig/include/linux/serial_core.h linux-2.6.5/include/linux/serial_core.h
+--- linux-2.6.5-orig/include/linux/serial_core.h	2004-06-14 20:31:56.000000000 +0100
++++ linux-2.6.5/include/linux/serial_core.h	2004-06-14 20:33:06.000000000 +0100
+@@ -38,7 +38,8 @@
+ #define PORT_16850	12
+ #define PORT_RSA	13
+ #define PORT_NS16550A	14
+-#define PORT_MAX_8250	14	/* max port ID */
++#define PORT_XSCALE	15
++#define PORT_MAX_8250	15	/* max port ID */
+ 
+ /*
+  * ARM specific type numbers.  These are not currently guaranteed
+diff -uNr linux-2.6.5-orig/include/linux/serial_reg.h linux-2.6.5/include/linux/serial_reg.h
+--- linux-2.6.5-orig/include/linux/serial_reg.h	2004-06-14 20:31:56.000000000 +0100
++++ linux-2.6.5/include/linux/serial_reg.h	2004-06-14 20:33:06.000000000 +0100
+@@ -141,7 +141,7 @@
+ #define UART_MSR_ANY_DELTA 0x0F	/* Any of the delta bits! */
+ 
+ /*
+- * The Intel PXA2xx chip defines those bits
++ * The Intel XScale on-chip UARTs define these bits
+  */
+ #define UART_IER_DMAE	0x80	/* DMA Requests Enable */
+ #define UART_IER_UUE	0x40	/* UART Unit Enable */
+diff -uNr linux-2.6.5-orig/arch/arm/boot/Makefile linux-2.6.5/arch/arm/boot/Makefile
+--- linux-2.6.5-orig/arch/arm/boot/Makefile	2004-04-04 04:36:18.000000000 +0100
++++ linux-2.6.5/arch/arm/boot/Makefile	2004-06-14 21:36:21.000000000 +0100
+@@ -69,6 +69,8 @@
+ ZBSSADDR	:= ALIGN(4)
+ endif
+ 
++OBJCOPYFLAGS_zImage := --pad-to `(arm-linux-readelf -l arch/arm/boot/compressed/vmlinux | grep LOAD | awk '{ print $$6 }')`
++
+ export	ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS PARAMS_PHYS
+ 
+ targets := Image zImage bootpImage
diff --git a/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2 b/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2
index e69de29bb2..dc773136f4 100644
--- a/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2
+++ b/linux/openzaurus-2.6.10-rc1-jl1/poodle-config-2.6.7-jl2
@@ -0,0 +1,708 @@
+#
+# Automatically generated make config: don't edit
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_STANDALONE=y
+CONFIG_BROKEN_ON_SMP=y
+
+#
+# General setup
+#
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_HOTPLUG=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+CONFIG_ARCH_PXA=y
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE_PB is not set
+
+#
+# Intel PXA2xx Implementations
+#
+# CONFIG_ARCH_LUBBOCK is not set
+# CONFIG_MACH_MAINSTONE is not set
+# CONFIG_ARCH_PXA_IDP is not set
+CONFIG_MACH_POODLE=y
+CONFIG_SHARP_LOCOMO=y
+CONFIG_PXA25x=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_XSCALE=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5T=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_MINICACHE=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+CONFIG_XSCALE_PMU=y
+
+#
+# General setup
+#
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+
+#
+# PCMCIA/CardBus support
+#
+# CONFIG_PCMCIA is not set
+
+#
+# At least one math emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+
+#
+# Generic Driver Options
+#
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_PM=y
+CONFIG_PREEMPT=y
+CONFIG_APM=y
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="noinitrd root=/dev/mtdblock2 rootfstype=jffs2"
+CONFIG_LEDS=y
+CONFIG_LEDS_TIMER=y
+CONFIG_LEDS_CPU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=1
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_EDB7312 is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+# CONFIG_NETLINK_DEV is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_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_IPV6 is not set
+# CONFIG_NETFILTER 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_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_NETDEVICES is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_SCSI is not set
+
+#
+# Fusion MPT device support
+#
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN 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=y
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=y
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_LOCOMO 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
+
+#
+# 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_PXA is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+# CONFIG_I2C_CHARDEV is not set
+
+#
+# I2C Algorithms
+#
+CONFIG_I2C_ALGOBIT=m
+# CONFIG_I2C_ALGOPCF is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+CONFIG_I2C_ISA=m
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_SCx200_ACB is not set
+
+#
+# Hardware Sensors Chip support
+#
+# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+
+#
+# Other I2C Chip support
+#
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+
+#
+# Video For Linux
+#
+
+#
+# Video Adapters
+#
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=1
+# CONFIG_JFFS2_FS_NAND is not set
+CONFIG_CRAMFS=y
+# 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 is not set
+# CONFIG_NFSD is not set
+# CONFIG_EXPORTFS 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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_PXA=y
+# CONFIG_FB_PXA_PARAMETERS is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_PCI_CONSOLE=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# Misc devices
+#
+
+#
+# USB support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_NET2280 is not set
+CONFIG_USB_GADGET_PXA2XX=y
+CONFIG_USB_PXA2XX=y
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_SA1100 is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_ETH is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# Kernel hacking
+#
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch
index e69de29bb2..eacada33f5 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluecard_cs.patch
@@ -0,0 +1,11 @@
+--- linux-orig/drivers/bluetooth/bluecard_cs.c	2004-02-16 10:51:46.000000000 +0300
++++ linux/drivers/bluetooth/bluecard_cs.c	2004-02-17 03:45:31.000000000 +0300
+@@ -102,7 +102,7 @@
+ 
+ 
+ /* Default baud rate: 57600, 115200, 230400 or 460800 */
+-#define DEFAULT_BAUD_RATE  230400
++#define DEFAULT_BAUD_RATE  460800
+ 
+ 
+ /* Hardware states */
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch
index e69de29bb2..f2ea0d699b 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bluetooth-2.4.18-mh11.patch
@@ -0,0 +1,31393 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/arch/alpha/config.in~bluetooth-2.4.18-mh11	2004-01-25 23:28:10.000000000 +0100
++++ linux/arch/alpha/config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -372,9 +372,7 @@
+ source drivers/usb/Config.in
+ source drivers/input/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+--- linux/arch/arm/config.in~bluetooth-2.4.18-mh11	2004-01-25 23:28:31.000000000 +0100
++++ linux/arch/arm/config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -796,9 +796,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+--- linux/arch/i386/config.in~bluetooth-2.4.18-mh11	2004-01-25 23:28:31.000000000 +0100
++++ linux/arch/i386/config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -415,9 +415,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+--- linux/arch/ppc/config.in~bluetooth-2.4.18-mh11	2004-01-25 23:28:11.000000000 +0100
++++ linux/arch/ppc/config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -390,9 +390,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+--- linux/arch/sparc/config.in~bluetooth-2.4.18-mh11	2004-01-25 23:28:11.000000000 +0100
++++ linux/arch/sparc/config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -252,9 +252,7 @@
+ 
+ source fs/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Watchdog'
+--- linux/arch/sparc64/config.in~bluetooth-2.4.18-mh11	2004-01-25 23:28:11.000000000 +0100
++++ linux/arch/sparc64/config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -284,9 +284,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Watchdog'
+--- linux/arch/sparc64/kernel/ioctl32.c~bluetooth-2.4.18-mh11	2002-02-25 20:37:56.000000000 +0100
++++ linux/arch/sparc64/kernel/ioctl32.c	2004-01-25 23:37:39.000000000 +0100
+@@ -92,6 +92,7 @@
+ 
+ #include <net/bluetooth/bluetooth.h>
+ #include <net/bluetooth/hci.h>
++#include <net/bluetooth/rfcomm.h>
+ 
+ #include <linux/usb.h>
+ #include <linux/usbdevice_fs.h>
+@@ -3822,6 +3823,15 @@
+ 	return err;
+ }
+ 
++/* Bluetooth ioctls */
++#define HCIUARTSETPROTO	_IOW('U', 200, int)
++#define HCIUARTGETPROTO	_IOR('U', 201, int)
++
++#define BNEPCONNADD	_IOW('B', 200, int)
++#define BNEPCONNDEL	_IOW('B', 201, int)
++#define BNEPGETCONNLIST	_IOR('B', 210, int)
++#define BNEPGETCONNINFO	_IOR('B', 211, int)
++
+ struct mtd_oob_buf32 {
+ 	u32 start;
+ 	u32 length;
+@@ -3878,6 +3888,11 @@
+ 	return ((0 == ret) ? 0 : -EFAULT);
+ }	
+ 
++#define CMTPCONNADD	_IOW('C', 200, int)
++#define CMTPCONNDEL	_IOW('C', 201, int)
++#define CMTPGETCONNLIST	_IOR('C', 210, int)
++#define CMTPGETCONNINFO	_IOR('C', 211, int)
++
+ struct ioctl_trans {
+ 	unsigned int cmd;
+ 	unsigned int handler;
+@@ -4540,6 +4555,21 @@
+ COMPATIBLE_IOCTL(HCISETSCAN)
+ COMPATIBLE_IOCTL(HCISETAUTH)
+ COMPATIBLE_IOCTL(HCIINQUIRY)
++COMPATIBLE_IOCTL(HCIUARTSETPROTO)
++COMPATIBLE_IOCTL(HCIUARTGETPROTO)
++COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
++COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
++COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
++COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
++COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
++COMPATIBLE_IOCTL(BNEPCONNADD)
++COMPATIBLE_IOCTL(BNEPCONNDEL)
++COMPATIBLE_IOCTL(BNEPGETCONNLIST)
++COMPATIBLE_IOCTL(BNEPGETCONNINFO)
++COMPATIBLE_IOCTL(CMTPCONNADD)
++COMPATIBLE_IOCTL(CMTPCONNDEL)
++COMPATIBLE_IOCTL(CMTPGETCONNLIST)
++COMPATIBLE_IOCTL(CMTPGETCONNINFO)
+ /* Misc. */
+ COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
+ COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
+--- linux/CREDITS~bluetooth-2.4.18-mh11	2004-01-25 23:28:29.000000000 +0100
++++ linux/CREDITS	2004-01-25 23:37:39.000000000 +0100
+@@ -1317,6 +1317,15 @@
+ S: Provo, Utah 84606-5607
+ S: USA
+ 
++N: Marcel Holtmann
++E: marcel@holtmann.org
++W: http://www.holtmann.org
++D: Maintainer of the Linux Bluetooth Subsystem
++D: Author and maintainer of the various Bluetooth HCI drivers
++D: Author and maintainer of the CAPI message transport protocol driver
++D: Various other Bluetooth related patches, cleanups and fixes
++S: Germany
++
+ N: Rob W. W. Hooft
+ E: hooft@EMBL-Heidelberg.DE
+ D: Shared libs for graphics-tools and for the f2c compiler
+@@ -2555,6 +2564,7 @@
+ N: Aristeu Sergio Rozanski Filho
+ E: aris@conectiva.com.br
+ D: Support for EtherExpress 10 ISA (i82595) in eepro driver
++D: User level driver support for input
+ S: Conectiva S.A.
+ S: R. Tocantins, 89 - Cristo Rei
+ S: 80050-430 - Curitiba - Paran�
+--- linux/Documentation/Configure.help~bluetooth-2.4.18-mh11	2004-01-25 23:28:31.000000000 +0100
++++ linux/Documentation/Configure.help	2004-01-25 23:37:39.000000000 +0100
+@@ -2847,14 +2847,6 @@
+ 
+   If unsure, say N.
+ 
+-HCI EMU (virtual device) driver
+-CONFIG_BLUEZ_HCIEMU
+-  Bluetooth Virtual HCI device driver.
+-  This driver is required if you want to use HCI Emulation software.
+-
+-  Say Y here to compile support for Virtual HCI devices into the
+-  kernel or say M to compile it as module (hci_usb.o).
+-
+ # Choice: alphatype
+ Alpha system type
+ CONFIG_ALPHA_GENERIC
+@@ -11067,6 +11059,12 @@
+ 
+   If unsure, say N.
+ 
++Hotplug firmware loading support (EXPERIMENTAL)
++CONFIG_FW_LOADER
++  This option is provided for the case where no in-kernel-tree modules require
++  hotplug firmware loading support, but a module built outside the kernel tree
++  does.
++
+ Use PCI shared memory for NIC registers
+ CONFIG_TULIP_MMIO
+   Use PCI shared memory for the NIC registers, rather than going through 
+@@ -12967,6 +12965,15 @@
+   accessible under char device 13:64+ - /dev/input/eventX in a generic
+   way.  This is the future ...
+ 
++CONFIG_INPUT_UINPUT
++  Say Y here if you want to support user level drivers for input
++  subsystem accessible under char device 10:223 - /dev/input/uinput.
++
++  This driver is also available as a module ( = code which can be
++  inserted in and removed from the running kernel whenever you want).
++  The module will be called uinput.o.  If you want to compile it as a
++  module, say M here and read <file:Documentation/modules.txt>.	    
++
+ USB Scanner support
+ CONFIG_USB_SCANNER
+   Say Y here if you want to connect a USB scanner to your computer's
+@@ -19986,11 +19993,15 @@
+   Bluetooth can be found at <http://www.bluetooth.com/>.
+ 
+   Linux Bluetooth subsystem consist of several layers:
+-               HCI Core (device and connection manager, scheduler)
++               BlueZ Core (HCI device and connection manager, scheduler)
+                HCI Device drivers (interface to the hardware)
+                L2CAP Module (L2CAP protocol)
++               SCO Module (SCO links)
++               RFCOMM Module (RFCOMM protocol)
++               BNEP Module (BNEP protocol)
++               CMTP Module (CMTP protocol)
+ 
+-  Say Y here to enable Linux Bluetooth support and to build HCI Core
++  Say Y here to enable Linux Bluetooth support and to build BlueZ Core
+   layer.
+ 
+   To use Linux Bluetooth subsystem, you will need several user-space
+@@ -19998,7 +20009,7 @@
+   Bluetooth kernel modules are provided in the BlueZ package.
+   For more information, see <http://bluez.sourceforge.net/>.
+ 
+-  If you want to compile HCI Core as module (hci.o) say M here.
++  If you want to compile BlueZ Core as module (bluez.o) say M here.
+ 
+ L2CAP protocol support
+ CONFIG_BLUEZ_L2CAP
+@@ -20009,15 +20020,91 @@
+   Say Y here to compile L2CAP support into the kernel or say M to
+   compile it as module (l2cap.o).
+ 
++SCO links support
++CONFIG_BLUEZ_SCO
++  SCO link provides voice transport over Bluetooth. SCO support is
++  required for voice applications like Headset and Audio.
++
++  Say Y here to compile SCO support into the kernel or say M to
++  compile it as module (sco.o).
++
++RFCOMM protocol support
++CONFIG_BLUEZ_RFCOMM
++  RFCOMM provides connection oriented stream transport. RFCOMM
++  support is required for Dialup Networking, OBEX and other Bluetooth
++  applications.
++
++  Say Y here to compile RFCOMM support into the kernel or say M to
++  compile it as module (rfcomm.o).
++
++RFCOMM TTY emulation support
++CONFIG_BLUEZ_RFCOMM_TTY
++  This option enables TTY emulation support for RFCOMM channels.
++
++BNEP protocol support
++CONFIG_BLUEZ_BNEP
++  BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
++  emulation layer on top of Bluetooth. BNEP is required for Bluetooth
++  PAN (Personal Area Network).
++
++  To use BNEP, you will need user-space utilities provided in the 
++  BlueZ-PAN package.
++  For more information, see <http://bluez.sourceforge.net>.
++
++  Say Y here to compile BNEP support into the kernel or say M to
++  compile it as module (bnep.o).
++
++CMTP protocol support
++CONFIG_BLUEZ_CMTP
++  CMTP (CAPI Message Transport Protocol) is a transport layer
++  for CAPI messages. CMTP is required for the Bluetooth Common
++  ISDN Access Profile.
++
++  Say Y here to compile CMTP support into the kernel or say M to
++  compile it as module (cmtp.o).
++
++BNEP multicast filter support
++CONFIG_BLUEZ_BNEP_MC_FILTER
++  This option enables the multicast filter support for BNEP.
++
++BNEP protocol filter support
++CONFIG_BLUEZ_BNEP_PROTO_FILTER
++  This option enables the protocol filter support for BNEP.
++
+ HCI UART driver
+ CONFIG_BLUEZ_HCIUART
+   Bluetooth HCI UART driver.
+   This driver is required if you want to use Bluetooth devices with
+-  serial port interface.
++  serial port interface. You will also need this driver if you have 
++  UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card 
++  adapter and BrainBoxes Bluetooth PC Card.
+ 
+   Say Y here to compile support for Bluetooth UART devices into the
+   kernel or say M to compile it as module (hci_uart.o).
+ 
++HCI UART (H4) protocol support 
++CONFIG_BLUEZ_HCIUART_H4
++  UART (H4) is serial protocol for communication between Bluetooth 
++  device and host. This protocol is required for most Bluetooth devices 
++  with UART interface, including PCMCIA and CF cards. 
++
++  Say Y here to compile support for HCI UART (H4) protocol.
++
++HCI BCSP protocol support 
++CONFIG_BLUEZ_HCIUART_BCSP
++  BCSP (BlueCore Serial Protocol) is serial protocol for communication 
++  between Bluetooth device and host. This protocol is required for non
++  USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and 
++  CF cards.
++
++  Say Y here to compile support for HCI BCSP protocol.
++
++HCI BCSP transmit CRC with every BCSP packet
++CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++  If you say Y here, a 16-bit CRC checksum will be transmitted along with
++  every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
++  This increases reliability, but slightly reduces efficiency.
++
+ HCI USB driver
+ CONFIG_BLUEZ_HCIUSB
+   Bluetooth HCI USB driver.
+@@ -20027,7 +20114,16 @@
+   Say Y here to compile support for Bluetooth USB devices into the
+   kernel or say M to compile it as module (hci_usb.o).
+ 
+-HCI VHCI virtual HCI device driver
++HCI USB SCO (voice) support
++CONFIG_BLUEZ_HCIUSB_SCO
++  This option enables the SCO support in the HCI USB driver. You need this
++  to transmit voice data with your Bluetooth USB device. And your device
++  must also support sending SCO data over the HCI layer, because some of
++  them sends the SCO data to an internal PCM adapter.
++ 
++  Say Y here to compile support for HCI SCO data.
++ 
++HCI VHCI Virtual HCI device driver
+ CONFIG_BLUEZ_HCIVHCI
+   Bluetooth Virtual HCI device driver.
+   This driver is required if you want to use HCI Emulation software.
+@@ -20035,6 +20131,66 @@
+   Say Y here to compile support for virtual HCI devices into the
+   kernel or say M to compile it as module (hci_vhci.o).
+ 
++HCI BFUSB device driver
++CONFIG_BLUEZ_HCIBFUSB
++  Bluetooth HCI BlueFRITZ! USB driver.
++  This driver provides support for Bluetooth USB devices with AVM
++  interface:
++     AVM BlueFRITZ! USB
++
++  Say Y here to compile support for HCI BFUSB devices into the
++  kernel or say M to compile it as module (bfusb.o).
++
++HCI DTL1 (PC Card) device driver
++CONFIG_BLUEZ_HCIDTL1
++  Bluetooth HCI DTL1 (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  Nokia DTL1 interface:
++     Nokia Bluetooth Card
++     Socket Bluetooth CF Card
++
++  Say Y here to compile support for HCI DTL1 devices into the
++  kernel or say M to compile it as module (dtl1_cs.o).
++
++HCI BT3C (PC Card) device driver
++CONFIG_BLUEZ_HCIBT3C
++  Bluetooth HCI BT3C (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  3Com BT3C interface:
++     3Com Bluetooth Card (3CRWB6096)
++     HP Bluetooth Card
++
++  The HCI BT3C driver uses external firmware loader program provided in
++  the BlueFW package. For more information, see <http://bluez.sf.net>.
++
++  Say Y here to compile support for HCI BT3C devices into the
++  kernel or say M to compile it as module (bt3c_cs.o).
++
++HCI BlueCard (PC Card) device driver
++CONFIG_BLUEZ_HCIBLUECARD
++  Bluetooth HCI BlueCard (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  Anycom BlueCard interface:
++     Anycom Bluetooth PC Card
++     Anycom Bluetooth CF Card
++
++  Say Y here to compile support for HCI BlueCard devices into the
++  kernel or say M to compile it as module (bluecard_cs.o).
++
++HCI UART (PC Card) device driver
++CONFIG_BLUEZ_HCIBTUART
++  Bluetooth HCI UART (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  an UART interface:
++     Xircom CreditCard Bluetooth Adapter
++     Xircom RealPort2 Bluetooth Adapter
++     Sphinx PICO Card
++     H-Soft blue+Card
++     Cyber-blue Compact Flash Card
++
++  Say Y here to compile support for HCI UART devices into the
++  kernel or say M to compile it as module (btuart_cs.o).
++
+ # The following options are for Linux when running on the Hitachi
+ # SuperH family of RISC microprocessors.
+ 
+--- linux/Documentation/devices.txt~bluetooth-2.4.18-mh11	2001-11-07 23:46:01.000000000 +0100
++++ linux/Documentation/devices.txt	2004-01-25 23:37:39.000000000 +0100
+@@ -419,6 +419,7 @@
+ 		220 = /dev/mptctl	Message passing technology (MPT) control
+ 		221 = /dev/mvista/hssdsi	Montavista PICMG hot swap system driver
+ 		222 = /dev/mvista/hasi		Montavista PICMG high availability
++		223 = /dev/input/uinput		User level driver support for input
+ 		240-255			Reserved for local use
+ 
+  11 char	Raw keyboard device
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/Documentation/firmware_class/firmware_sample_driver.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,121 @@
++/*
++ * firmware_sample_driver.c -
++ *
++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
++ *
++ * Sample code on how to use request_firmware() from drivers.
++ *
++ * Note that register_firmware() is currently useless.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/string.h>
++
++#include "linux/firmware.h"
++
++#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
++char __init inkernel_firmware[] = "let's say that this is firmware\n";
++#endif
++
++static char ghost_device[] = "ghost0";
++
++static void sample_firmware_load(char *firmware, int size)
++{
++	u8 buf[size+1];
++	memcpy(buf, firmware, size);
++	buf[size] = '\0';
++	printk("firmware_sample_driver: firmware: %s\n", buf);
++}
++
++static void sample_probe_default(void)
++{
++	/* uses the default method to get the firmware */
++        const struct firmware *fw_entry;
++	printk("firmware_sample_driver: a ghost device got inserted :)\n");
++
++        if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0)
++	{
++		printk(KERN_ERR
++		       "firmware_sample_driver: Firmware not available\n");
++		return;
++	}
++	
++	sample_firmware_load(fw_entry->data, fw_entry->size);
++
++	release_firmware(fw_entry);
++
++	/* finish setting up the device */
++}
++static void sample_probe_specific(void)
++{
++	/* Uses some specific hotplug support to get the firmware from
++	 * userspace  directly into the hardware, or via some sysfs file */
++
++	/* NOTE: This currently doesn't work */
++
++	printk("firmware_sample_driver: a ghost device got inserted :)\n");
++
++        if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0)
++	{
++		printk(KERN_ERR
++		       "firmware_sample_driver: Firmware load failed\n");
++		return;
++	}
++	
++	/* request_firmware blocks until userspace finished, so at
++	 * this point the firmware should be already in the device */
++
++	/* finish setting up the device */
++}
++static void sample_probe_async_cont(const struct firmware *fw, void *context)
++{
++	if(!fw){
++		printk(KERN_ERR
++		       "firmware_sample_driver: firmware load failed\n");
++		return;
++	}
++
++	printk("firmware_sample_driver: device pointer \"%s\"\n",
++	       (char *)context);
++	sample_firmware_load(fw->data, fw->size);
++}
++static void sample_probe_async(void)
++{
++	/* Let's say that I can't sleep */
++	int error;
++	error = request_firmware_nowait (THIS_MODULE,
++					 "sample_driver_fw", ghost_device,
++					 "my device pointer",
++					 sample_probe_async_cont);
++	if(error){
++		printk(KERN_ERR 
++		       "firmware_sample_driver:"
++		       " request_firmware_nowait failed\n");
++	}
++}
++
++static int sample_init(void)
++{
++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
++	register_firmware("sample_driver_fw", inkernel_firmware,
++			  sizeof(inkernel_firmware));
++#endif
++	/* since there is no real hardware insertion I just call the
++	 * sample probe functions here */
++	sample_probe_specific();
++	sample_probe_default();
++	sample_probe_async();
++	return 0;
++}
++static void __exit sample_exit(void)
++{
++}
++
++module_init (sample_init);
++module_exit (sample_exit);
++
++MODULE_LICENSE("GPL");
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/Documentation/firmware_class/hotplug-script	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,16 @@
++#!/bin/sh
++
++# Simple hotplug script sample:
++# 
++# Both $DEVPATH and $FIRMWARE are already provided in the environment.
++
++HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
++
++echo 1 > /sysfs/$DEVPATH/loading
++cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
++echo 0 > /sysfs/$DEVPATH/loading
++
++# To cancel the load in case of error:
++#
++#	echo -1 > /sysfs/$DEVPATH/loading
++#
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/Documentation/firmware_class/README	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,58 @@
++
++ request_firmware() hotplug interface:
++ ------------------------------------
++	Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
++
++ Why:
++ ---
++
++ Today, the most extended way to use firmware in the Linux kernel is linking
++ it statically in a header file. Which has political and technical issues:
++
++  1) Some firmware is not legal to redistribute.
++  2) The firmware occupies memory permanently, even though it often is just
++     used once.
++  3) Some people, like the Debian crowd, don't consider some firmware free
++     enough and remove entire drivers (e.g.: keyspan).
++
++ about in-kernel persistence:
++ ---------------------------
++ Under some circumstances, as explained below, it would be interesting to keep
++ firmware images in non-swappable kernel memory or even in the kernel image
++ (probably within initramfs).
++
++ Note that this functionality has not been implemented.
++
++ - Why OPTIONAL in-kernel persistence may be a good idea sometimes:
++ 
++	- If the device that needs the firmware is needed to access the
++	  filesystem. When upon some error the device has to be reset and the
++	  firmware reloaded, it won't be possible to get it from userspace.
++	  e.g.:
++		- A diskless client with a network card that needs firmware.
++		- The filesystem is stored in a disk behind an scsi device
++		  that needs firmware.
++	- Replacing buggy DSDT/SSDT ACPI tables on boot.
++	  Note: this would require the persistent objects to be included
++	  within the kernel image, probably within initramfs.
++	  
++   And the same device can be needed to access the filesystem or not depending
++   on the setup, so I think that the choice on what firmware to make
++   persistent should be left to userspace.
++
++ - Why register_firmware()+__init can be useful:
++ 	- For boot devices needing firmware.
++	- To make the transition easier:
++		The firmware can be declared __init and register_firmware()
++		called on module_init. Then the firmware is warranted to be
++		there even if "firmware hotplug userspace" is not there yet or
++		it doesn't yet provide the needed firmware.
++		Once the firmware is widely available in userspace, it can be
++		removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE).
++
++	In either case, if firmware hotplug support is there, it can move the
++	firmware out of kernel memory into the real filesystem for later
++	usage.
++
++	Note: If persistence is implemented on top of initramfs,
++	register_firmware() may not be appropriate.
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/bfusb.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,781 @@
++/*
++ *
++ *  AVM BlueFRITZ! USB driver
++ *
++ *  Copyright (C) 2003  Marcel Holtmann <marcel@holtmann.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
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/skbuff.h>
++
++#include <linux/firmware.h>
++#include <linux/usb.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define VERSION "1.1"
++
++static struct usb_device_id bfusb_table[] = {
++	/* AVM BlueFRITZ! USB */
++	{ USB_DEVICE(0x057c, 0x2200) },
++
++	{ }	/* Terminating entry */
++};
++
++MODULE_DEVICE_TABLE(usb, bfusb_table);
++
++
++#define BFUSB_MAX_BLOCK_SIZE	256
++
++#define BFUSB_BLOCK_TIMEOUT	(HZ * 3)
++
++#define BFUSB_TX_PROCESS	1
++#define BFUSB_TX_WAKEUP		2
++
++#define BFUSB_MAX_BULK_TX	1
++#define BFUSB_MAX_BULK_RX	1
++
++struct bfusb {
++	struct hci_dev		hdev;
++
++	unsigned long		state;
++
++	struct usb_device	*udev;
++
++	unsigned int		bulk_in_ep;
++	unsigned int		bulk_out_ep;
++	unsigned int		bulk_pkt_size;
++
++	rwlock_t		lock;
++
++	struct sk_buff_head	transmit_q;
++
++	struct sk_buff		*reassembly;
++
++	atomic_t		pending_tx;
++	struct sk_buff_head	pending_q;
++	struct sk_buff_head	completed_q;
++};
++
++struct bfusb_scb {
++	struct urb *urb;
++};
++
++static void bfusb_tx_complete(struct urb *urb);
++static void bfusb_rx_complete(struct urb *urb);
++
++static struct urb *bfusb_get_completed(struct bfusb *bfusb)
++{
++	struct sk_buff *skb;
++	struct urb *urb = NULL;
++
++	BT_DBG("bfusb %p", bfusb);
++
++	skb = skb_dequeue(&bfusb->completed_q);
++	if (skb) {
++		urb = ((struct bfusb_scb *) skb->cb)->urb;
++		kfree_skb(skb);
++	}
++
++	return urb;
++}
++
++static inline void bfusb_unlink_urbs(struct bfusb *bfusb)
++{
++	struct sk_buff *skb;
++	struct urb *urb;
++
++	BT_DBG("bfusb %p", bfusb);
++
++	while ((skb = skb_dequeue(&bfusb->pending_q))) {
++		urb = ((struct bfusb_scb *) skb->cb)->urb;
++		usb_unlink_urb(urb);
++		skb_queue_tail(&bfusb->completed_q, skb);
++	}
++
++	while ((urb = bfusb_get_completed(bfusb)))
++		usb_free_urb(urb);
++}
++
++
++static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
++{
++	struct bfusb_scb *scb = (void *) skb->cb;
++	struct urb *urb = bfusb_get_completed(bfusb);
++	int err, pipe;
++
++	BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
++
++	if (!urb && !(urb = usb_alloc_urb(0)))
++		return -ENOMEM;
++
++	pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
++
++	FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len,
++			bfusb_tx_complete, skb);
++
++	urb->transfer_flags = USB_QUEUE_BULK;
++
++	scb->urb = urb;
++
++	skb_queue_tail(&bfusb->pending_q, skb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk tx submit failed urb %p err %d", 
++					bfusb->hdev.name, urb, err);
++		skb_unlink(skb);
++		usb_free_urb(urb);
++	} else
++		atomic_inc(&bfusb->pending_tx);
++
++	return err;
++}
++
++static void bfusb_tx_wakeup(struct bfusb *bfusb)
++{
++	struct sk_buff *skb;
++
++	BT_DBG("bfusb %p", bfusb);
++
++	if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
++		set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
++		return;
++	}
++
++	do {
++		clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
++
++		while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
++				(skb = skb_dequeue(&bfusb->transmit_q))) {
++			if (bfusb_send_bulk(bfusb, skb) < 0) {
++				skb_queue_head(&bfusb->transmit_q, skb);
++				break;
++			}
++		}
++
++	} while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
++
++	clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
++}
++
++static void bfusb_tx_complete(struct urb *urb)
++{
++	struct sk_buff *skb = (struct sk_buff *) urb->context;
++	struct bfusb *bfusb = (struct bfusb *) skb->dev;
++
++	BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
++
++	atomic_dec(&bfusb->pending_tx);
++
++	if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
++		return;
++
++	if (!urb->status)
++		bfusb->hdev.stat.byte_tx += skb->len;
++	else
++		bfusb->hdev.stat.err_tx++;
++
++	read_lock(&bfusb->lock);
++
++	skb_unlink(skb);
++	skb_queue_tail(&bfusb->completed_q, skb);
++
++	bfusb_tx_wakeup(bfusb);
++
++	read_unlock(&bfusb->lock);
++}
++
++
++static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
++{
++	struct bfusb_scb *scb;
++	struct sk_buff *skb;
++	int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
++
++	BT_DBG("bfusb %p urb %p", bfusb, urb);
++
++	if (!urb && !(urb = usb_alloc_urb(0)))
++		return -ENOMEM;
++
++	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
++		usb_free_urb(urb);
++		return -ENOMEM;
++	}
++
++	skb->dev = (void *) bfusb;
++
++	scb = (struct bfusb_scb *) skb->cb;
++	scb->urb = urb;
++
++	pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
++
++	FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size,
++			bfusb_rx_complete, skb);
++
++	urb->transfer_flags = USB_QUEUE_BULK;
++
++	skb_queue_tail(&bfusb->pending_q, skb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk rx submit failed urb %p err %d",
++					bfusb->hdev.name, urb, err);
++		skb_unlink(skb);
++		kfree_skb(skb);
++		usb_free_urb(urb);
++	}
++
++	return err;
++}
++
++static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
++{
++	BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
++
++	if (hdr & 0x10) {
++		BT_ERR("%s error in block", bfusb->hdev.name);
++		if (bfusb->reassembly)
++			kfree_skb(bfusb->reassembly);
++		bfusb->reassembly = NULL;
++		return -EIO;
++	}
++
++	if (hdr & 0x04) {
++		struct sk_buff *skb;
++		unsigned char pkt_type;
++		int pkt_len = 0;
++
++		if (bfusb->reassembly) {
++			BT_ERR("%s unexpected start block", bfusb->hdev.name);
++			kfree_skb(bfusb->reassembly);
++			bfusb->reassembly = NULL;
++		}
++
++		if (len < 1) {
++			BT_ERR("%s no packet type found", bfusb->hdev.name);
++			return -EPROTO;
++		}
++
++		pkt_type = *data++; len--;
++
++		switch (pkt_type) {
++		case HCI_EVENT_PKT:
++			if (len >= HCI_EVENT_HDR_SIZE) {
++				hci_event_hdr *hdr = (hci_event_hdr *) data;
++				pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
++			} else {
++				BT_ERR("%s event block is too short", bfusb->hdev.name);
++				return -EILSEQ;
++			}
++			break;
++
++		case HCI_ACLDATA_PKT:
++			if (len >= HCI_ACL_HDR_SIZE) {
++				hci_acl_hdr *hdr = (hci_acl_hdr *) data;
++				pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
++			} else {
++				BT_ERR("%s data block is too short", bfusb->hdev.name);
++				return -EILSEQ;
++			}
++			break;
++
++		case HCI_SCODATA_PKT:
++			if (len >= HCI_SCO_HDR_SIZE) {
++				hci_sco_hdr *hdr = (hci_sco_hdr *) data;
++				pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
++			} else {
++				BT_ERR("%s audio block is too short", bfusb->hdev.name);
++				return -EILSEQ;
++			}
++			break;
++		}
++
++		skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC);
++		if (!skb) {
++			BT_ERR("%s no memory for the packet", bfusb->hdev.name);
++			return -ENOMEM;
++		}
++
++		skb->dev = (void *) &bfusb->hdev;
++		skb->pkt_type = pkt_type;
++
++		bfusb->reassembly = skb;
++	} else {
++		if (!bfusb->reassembly) {
++			BT_ERR("%s unexpected continuation block", bfusb->hdev.name);
++			return -EIO;
++		}
++	}
++
++	if (len > 0)
++		memcpy(skb_put(bfusb->reassembly, len), data, len);
++
++	if (hdr & 0x08) {
++		hci_recv_frame(bfusb->reassembly);
++		bfusb->reassembly = NULL;
++	}
++
++	return 0;
++}
++
++static void bfusb_rx_complete(struct urb *urb)
++{
++	struct sk_buff *skb = (struct sk_buff *) urb->context;
++	struct bfusb *bfusb = (struct bfusb *) skb->dev;
++	unsigned char *buf = urb->transfer_buffer;
++	int count = urb->actual_length;
++	int err, hdr, len;
++
++	BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
++
++	if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
++		return;
++
++	read_lock(&bfusb->lock);
++
++	if (urb->status || !count)
++		goto resubmit;
++
++	bfusb->hdev.stat.byte_rx += count;
++
++	skb_put(skb, count);
++
++	while (count) {
++		hdr = buf[0] | (buf[1] << 8);
++
++		if (hdr & 0x4000) {
++			len = 0;
++			count -= 2;
++			buf   += 2;
++		} else {
++			len = (buf[2] == 0) ? 256 : buf[2];
++			count -= 3;
++			buf   += 3;
++		}
++
++		if (count < len) {
++			BT_ERR("%s block extends over URB buffer ranges",
++					bfusb->hdev.name);
++		}
++
++		if ((hdr & 0xe1) == 0xc1)
++			bfusb_recv_block(bfusb, hdr, buf, len);
++
++		count -= len;
++		buf   += len;
++	}
++
++	skb_unlink(skb);
++	kfree_skb(skb);
++
++	bfusb_rx_submit(bfusb, urb);
++
++	read_unlock(&bfusb->lock);
++
++	return;
++
++resubmit:
++	urb->dev = bfusb->udev;
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk resubmit failed urb %p err %d",
++					bfusb->hdev.name, urb, err);
++	}
++
++	read_unlock(&bfusb->lock);
++}
++
++
++static int bfusb_open(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++	unsigned long flags;
++	int i, err;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
++	MOD_INC_USE_COUNT;
++
++	write_lock_irqsave(&bfusb->lock, flags);
++
++	err = bfusb_rx_submit(bfusb, NULL);
++	if (!err) {
++		for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
++			bfusb_rx_submit(bfusb, NULL);
++	} else {
++		clear_bit(HCI_RUNNING, &hdev->flags);
++		MOD_DEC_USE_COUNT;
++	}
++
++	write_unlock_irqrestore(&bfusb->lock, flags);
++
++	return err;
++}
++
++static int bfusb_flush(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	skb_queue_purge(&bfusb->transmit_q);
++
++	return 0;
++}
++
++static int bfusb_close(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++	unsigned long flags;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
++	write_lock_irqsave(&bfusb->lock, flags);
++
++	bfusb_unlink_urbs(bfusb);
++	bfusb_flush(hdev);
++
++	write_unlock_irqrestore(&bfusb->lock, flags);
++
++	MOD_DEC_USE_COUNT;
++
++	return 0;
++}
++
++static int bfusb_send_frame(struct sk_buff *skb)
++{
++	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
++	struct bfusb *bfusb;
++	struct sk_buff *nskb;
++	unsigned char buf[3];
++	int sent = 0, size, count;
++
++	BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
++
++	if (!hdev) {
++		BT_ERR("Frame for unknown HCI device (hdev=NULL)");
++		return -ENODEV;
++	}
++
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return -EBUSY;
++
++	bfusb = (struct bfusb *) hdev->driver_data;
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++
++	count = skb->len;
++
++	/* Max HCI frame size seems to be 1511 + 1 */
++	if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for new packet");
++		return -ENOMEM;
++	}
++
++	nskb->dev = (void *) bfusb;
++
++	while (count) {
++		size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
++
++		buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0);
++		buf[1] = 0x00;
++		buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
++
++		memcpy(skb_put(nskb, 3), buf, 3);
++		memcpy(skb_put(nskb, size), skb->data + sent, size);
++
++		sent  += size;
++		count -= size;
++	}
++
++	/* Don't send frame with multiple size of bulk max packet */
++	if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
++		buf[0] = 0xdd;
++		buf[1] = 0x00;
++		memcpy(skb_put(nskb, 2), buf, 2);
++	}
++
++	read_lock(&bfusb->lock);
++
++	skb_queue_tail(&bfusb->transmit_q, nskb);
++	bfusb_tx_wakeup(bfusb);
++
++	read_unlock(&bfusb->lock);
++
++	kfree_skb(skb);
++
++	return 0;
++}
++
++static void bfusb_destruct(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	kfree(bfusb);
++}
++
++static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
++{
++	unsigned char *buf;
++	int err, pipe, len, size, sent = 0;
++
++	BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count);
++
++	BT_INFO("BlueFRITZ! USB loading firmware");
++
++	if (usb_set_configuration(bfusb->udev, 1) < 0) {
++		BT_ERR("Can't change to loading configuration");
++		return -EBUSY;
++	}
++
++	buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
++	if (!buf) {
++		BT_ERR("Can't allocate memory chunk for firmware");
++		return -ENOMEM;
++	}
++
++	pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
++
++	while (count) {
++		size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
++
++		memcpy(buf, firmware + sent, size);
++
++		err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
++					&len, BFUSB_BLOCK_TIMEOUT);
++
++		if (err || (len != size)) {
++			BT_ERR("Error in firmware loading");
++			goto error;
++		}
++
++		sent  += size;
++		count -= size;
++	}
++
++	if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
++				&len, BFUSB_BLOCK_TIMEOUT)) < 0) {
++		BT_ERR("Error in null packet request");
++		goto error;
++	}
++
++	if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) {
++		BT_ERR("Can't change to running configuration");
++		goto error;
++	}
++
++	BT_INFO("BlueFRITZ! USB device ready");
++
++	kfree(buf);
++	return 0;
++
++error:
++	kfree(buf);
++
++	pipe = usb_sndctrlpipe(bfusb->udev, 0);
++
++	usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
++				0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT);
++
++	return err;
++}
++
++static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
++{
++	const struct firmware *firmware;
++	char device[16];
++	struct usb_interface *iface;
++	struct usb_interface_descriptor *iface_desc;
++	struct usb_endpoint_descriptor *bulk_out_ep;
++	struct usb_endpoint_descriptor *bulk_in_ep;
++	struct hci_dev *hdev;
++	struct bfusb *bfusb;
++
++	BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id);
++
++	/* Check number of endpoints */
++	iface = &udev->actconfig->interface[0];
++	iface_desc = &iface->altsetting[0];
++
++	if (iface_desc->bNumEndpoints < 2)
++		return NULL;
++
++	bulk_out_ep = &iface_desc->endpoint[0];
++	bulk_in_ep  = &iface_desc->endpoint[1];
++
++	if (!bulk_out_ep || !bulk_in_ep) {
++		BT_ERR("Bulk endpoints not found");
++		goto done;
++	}
++
++	/* Initialize control structure and load firmware */
++	if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) {
++		BT_ERR("Can't allocate memory for control structure");
++		goto done;
++	}
++
++	memset(bfusb, 0, sizeof(struct bfusb));
++
++	bfusb->udev = udev;
++	bfusb->bulk_in_ep    = bulk_in_ep->bEndpointAddress;
++	bfusb->bulk_out_ep   = bulk_out_ep->bEndpointAddress;
++	bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize;
++
++	bfusb->lock = RW_LOCK_UNLOCKED;
++
++	bfusb->reassembly = NULL;
++
++	skb_queue_head_init(&bfusb->transmit_q);
++	skb_queue_head_init(&bfusb->pending_q);
++	skb_queue_head_init(&bfusb->completed_q);
++
++	snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum);
++
++	if (request_firmware(&firmware, "bfubase.frm", device) < 0) {
++		BT_ERR("Firmware request failed");
++		goto error;
++	}
++
++	if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
++		BT_ERR("Firmware loading failed");
++		goto release;
++	}
++
++	release_firmware(firmware);
++
++	/* Initialize and register HCI device */
++	hdev = &bfusb->hdev;
++
++	hdev->type = HCI_USB;
++	hdev->driver_data = bfusb;
++
++	hdev->open     = bfusb_open;
++	hdev->close    = bfusb_close;
++	hdev->flush    = bfusb_flush;
++	hdev->send     = bfusb_send_frame;
++	hdev->destruct = bfusb_destruct;
++	hdev->ioctl    = bfusb_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		BT_ERR("Can't register HCI device");
++		goto error;
++	}
++
++	return bfusb;
++
++release:
++	release_firmware(firmware);
++
++error:
++	kfree(bfusb);
++
++done:
++	return NULL;
++}
++
++static void bfusb_disconnect(struct usb_device *udev, void *ptr)
++{
++	struct bfusb *bfusb = (struct bfusb *) ptr;
++	struct hci_dev *hdev = &bfusb->hdev;
++
++	BT_DBG("udev %p ptr %p", udev, ptr);
++
++	if (!hdev)
++		return;
++
++	bfusb_close(hdev);
++
++	if (hci_unregister_dev(hdev) < 0)
++		BT_ERR("Can't unregister HCI device %s", hdev->name);
++}
++
++static struct usb_driver bfusb_driver = {
++	name:		"bfusb",
++	probe:		bfusb_probe,
++	disconnect:	bfusb_disconnect,
++	id_table:	bfusb_table,
++};
++
++static int __init bfusb_init(void)
++{
++	int err;
++
++	BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
++	BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>");
++
++	if ((err = usb_register(&bfusb_driver)) < 0)
++		BT_ERR("Failed to register BlueFRITZ! USB driver");
++
++	return err;
++}
++
++static void __exit bfusb_cleanup(void)
++{
++	usb_deregister(&bfusb_driver);
++}
++
++module_init(bfusb_init);
++module_exit(bfusb_cleanup);
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
++MODULE_LICENSE("GPL");
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/bluecard_cs.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,1113 @@
++/*
++ *
++ *  Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0x86bc;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct bluecard_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;		/* For serializing operations */
++	struct timer_list timer;	/* For LED control */
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++
++	unsigned char ctrl_reg;
++	unsigned long hw_state;		/* Status of the hardware and LED control */
++} bluecard_info_t;
++
++
++void bluecard_config(dev_link_t *link);
++void bluecard_release(u_long arg);
++int bluecard_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "bluecard_cs";
++
++dev_link_t *bluecard_attach(void);
++void bluecard_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Default baud rate: 57600, 115200, 230400 or 460800 */
++#define DEFAULT_BAUD_RATE  230400
++
++
++/* Hardware states */
++#define CARD_READY             1
++#define CARD_HAS_PCCARD_ID     4
++#define CARD_HAS_POWER_LED     5
++#define CARD_HAS_ACTIVITY_LED  6
++
++/* Transmit states  */
++#define XMIT_SENDING         1
++#define XMIT_WAKEUP          2
++#define XMIT_BUFFER_NUMBER   5	/* unset = buffer one, set = buffer two */
++#define XMIT_BUF_ONE_READY   6
++#define XMIT_BUF_TWO_READY   7
++#define XMIT_SENDING_READY   8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE   0
++#define RECV_WAIT_EVENT_HEADER  1
++#define RECV_WAIT_ACL_HEADER    2
++#define RECV_WAIT_SCO_HEADER    3
++#define RECV_WAIT_DATA          4
++
++/* Special packet types */
++#define PKT_BAUD_RATE_57600   0x80
++#define PKT_BAUD_RATE_115200  0x81
++#define PKT_BAUD_RATE_230400  0x82
++#define PKT_BAUD_RATE_460800  0x83
++
++
++/* These are the register offsets */
++#define REG_COMMAND     0x20
++#define REG_INTERRUPT   0x21
++#define REG_CONTROL     0x22
++#define REG_RX_CONTROL  0x24
++#define REG_CARD_RESET  0x30
++#define REG_LED_CTRL    0x30
++
++/* REG_COMMAND */
++#define REG_COMMAND_TX_BUF_ONE  0x01
++#define REG_COMMAND_TX_BUF_TWO  0x02
++#define REG_COMMAND_RX_BUF_ONE  0x04
++#define REG_COMMAND_RX_BUF_TWO  0x08
++#define REG_COMMAND_RX_WIN_ONE  0x00
++#define REG_COMMAND_RX_WIN_TWO  0x10
++
++/* REG_CONTROL */
++#define REG_CONTROL_BAUD_RATE_57600   0x00
++#define REG_CONTROL_BAUD_RATE_115200  0x01
++#define REG_CONTROL_BAUD_RATE_230400  0x02
++#define REG_CONTROL_BAUD_RATE_460800  0x03
++#define REG_CONTROL_RTS               0x04
++#define REG_CONTROL_BT_ON             0x08
++#define REG_CONTROL_BT_RESET          0x10
++#define REG_CONTROL_BT_RES_PU         0x20
++#define REG_CONTROL_INTERRUPT         0x40
++#define REG_CONTROL_CARD_RESET        0x80
++
++/* REG_RX_CONTROL */
++#define RTS_LEVEL_SHIFT_BITS  0x02
++
++
++
++/* ======================== LED handling routines ======================== */
++
++
++void bluecard_activity_led_timeout(u_long arg)
++{
++	bluecard_info_t *info = (bluecard_info_t *)arg;
++	unsigned int iobase = info->link.io.BasePort1;
++
++	if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
++		/* Disable activity LED */
++		outb(0x08 | 0x20, iobase + 0x30);
++	} else {
++		/* Disable power LED */
++		outb(0x00, iobase + 0x30);
++	}
++}
++
++
++static void bluecard_enable_activity_led(bluecard_info_t *info)
++{
++	unsigned int iobase = info->link.io.BasePort1;
++
++	if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
++		/* Enable activity LED */
++		outb(0x10 | 0x40, iobase + 0x30);
++
++		/* Stop the LED after HZ/4 */
++		mod_timer(&(info->timer), jiffies + HZ / 4);
++	} else {
++		/* Enable power LED */
++		outb(0x08 | 0x20, iobase + 0x30);
++
++		/* Stop the LED after HZ/2 */
++		mod_timer(&(info->timer), jiffies + HZ / 2);
++	}
++}
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
++{
++	int i, actual;
++
++	actual = (len > 15) ? 15 : len;
++
++	outb_p(actual, iobase + offset);
++
++	for (i = 0; i < actual; i++)
++		outb_p(buf[i], iobase + offset + i + 1);
++
++	return actual;
++}
++
++
++static void bluecard_write_wakeup(bluecard_info_t *info)
++{
++	if (!info) {
++		printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
++		return;
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register unsigned int offset;
++		register unsigned char command;
++		register unsigned long ready_bit;
++		register struct sk_buff *skb;
++		register int len;
++
++		clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (!(info->link.state & DEV_PRESENT))
++			return;
++
++		if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
++			if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
++				break;
++			offset = 0x10;
++			command = REG_COMMAND_TX_BUF_TWO;
++			ready_bit = XMIT_BUF_TWO_READY;
++		} else {
++			if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
++				break;
++			offset = 0x00;
++			command = REG_COMMAND_TX_BUF_ONE;
++			ready_bit = XMIT_BUF_ONE_READY;
++		}
++
++		if (!(skb = skb_dequeue(&(info->txq))))
++			break;
++
++		if (skb->pkt_type & 0x80) {
++			/* Disable RTS */
++			info->ctrl_reg |= REG_CONTROL_RTS;
++			outb(info->ctrl_reg, iobase + REG_CONTROL);
++		}
++
++		/* Activate LED */
++		bluecard_enable_activity_led(info);
++
++		/* Send frame */
++		len = bluecard_write(iobase, offset, skb->data, skb->len);
++
++		/* Tell the FPGA to send the data */
++		outb_p(command, iobase + REG_COMMAND);
++
++		/* Mark the buffer as dirty */
++		clear_bit(ready_bit, &(info->tx_state));
++
++		if (skb->pkt_type & 0x80) {
++
++			wait_queue_head_t wait;
++			unsigned char baud_reg;
++
++			switch (skb->pkt_type) {
++			case PKT_BAUD_RATE_460800:
++				baud_reg = REG_CONTROL_BAUD_RATE_460800;
++				break;
++			case PKT_BAUD_RATE_230400:
++				baud_reg = REG_CONTROL_BAUD_RATE_230400;
++				break;
++			case PKT_BAUD_RATE_115200:
++				baud_reg = REG_CONTROL_BAUD_RATE_115200;
++				break;
++			case PKT_BAUD_RATE_57600:
++				/* Fall through... */
++			default:
++				baud_reg = REG_CONTROL_BAUD_RATE_57600;
++				break;
++			}
++
++			/* Wait until the command reaches the baseband */
++			init_waitqueue_head(&wait);
++			interruptible_sleep_on_timeout(&wait, HZ / 10);
++
++			/* Set baud on baseband */
++			info->ctrl_reg &= ~0x03;
++			info->ctrl_reg |= baud_reg;
++			outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++			/* Enable RTS */
++			info->ctrl_reg &= ~REG_CONTROL_RTS;
++			outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++			/* Wait before the next HCI packet can be send */
++			interruptible_sleep_on_timeout(&wait, HZ);
++
++		}
++
++		if (len == skb->len) {
++			kfree_skb(skb);
++		} else {
++			skb_pull(skb, len);
++			skb_queue_head(&(info->txq), skb);
++		}
++
++		info->hdev.stat.byte_tx += len;
++
++		/* Change buffer */
++		change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
++
++	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++	clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
++{
++	int i, n, len;
++
++	outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
++
++	len = inb(iobase + offset);
++	n = 0;
++	i = 1;
++
++	while (n < len) {
++
++		if (i == 16) {
++			outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
++			i = 0;
++		}
++
++		buf[n] = inb(iobase + offset + i);
++
++		n++;
++		i++;
++
++	}
++
++	return len;
++}
++
++
++static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
++{
++	unsigned int iobase;
++	unsigned char buf[31];
++	int i, len;
++
++	if (!info) {
++		printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
++		bluecard_enable_activity_led(info);
++
++	len = bluecard_read(iobase, offset, buf, sizeof(buf));
++
++	for (i = 0; i < len; i++) {
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL) {
++			info->rx_state = RECV_WAIT_PACKET_TYPE;
++			info->rx_count = 0;
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
++				return;
++			}
++		}
++
++		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++			info->rx_skb->dev = (void *)&(info->hdev);
++			info->rx_skb->pkt_type = buf[i];
++
++			switch (info->rx_skb->pkt_type) {
++
++			case 0x00:
++				/* init packet */
++				if (offset != 0x00) {
++					set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
++					set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
++					set_bit(XMIT_SENDING_READY, &(info->tx_state));
++					bluecard_write_wakeup(info);
++				}
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			case HCI_EVENT_PKT:
++				info->rx_state = RECV_WAIT_EVENT_HEADER;
++				info->rx_count = HCI_EVENT_HDR_SIZE;
++				break;
++
++			case HCI_ACLDATA_PKT:
++				info->rx_state = RECV_WAIT_ACL_HEADER;
++				info->rx_count = HCI_ACL_HDR_SIZE;
++				break;
++
++			case HCI_SCODATA_PKT:
++				info->rx_state = RECV_WAIT_SCO_HEADER;
++				info->rx_count = HCI_SCO_HDR_SIZE;
++				break;
++
++			default:
++				/* unknown packet */
++				printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++				info->hdev.stat.err_rx++;
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			}
++
++		} else {
++
++			*skb_put(info->rx_skb, 1) = buf[i];
++			info->rx_count--;
++
++			if (info->rx_count == 0) {
++
++				int dlen;
++				hci_event_hdr *eh;
++				hci_acl_hdr *ah;
++				hci_sco_hdr *sh;
++
++				switch (info->rx_state) {
++
++				case RECV_WAIT_EVENT_HEADER:
++					eh = (hci_event_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = eh->plen;
++					break;
++
++				case RECV_WAIT_ACL_HEADER:
++					ah = (hci_acl_hdr *)(info->rx_skb->data);
++					dlen = __le16_to_cpu(ah->dlen);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = dlen;
++					break;
++
++				case RECV_WAIT_SCO_HEADER:
++					sh = (hci_sco_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = sh->dlen;
++					break;
++
++				case RECV_WAIT_DATA:
++					hci_recv_frame(info->rx_skb);
++					info->rx_skb = NULL;
++					break;
++
++				}
++
++			}
++
++		}
++
++
++	}
++
++	info->hdev.stat.byte_rx += len;
++}
++
++
++void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	bluecard_info_t *info = dev_inst;
++	unsigned int iobase;
++	unsigned char reg;
++
++	if (!info) {
++		printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	if (!test_bit(CARD_READY, &(info->hw_state)))
++		return;
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	/* Disable interrupt */
++	info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	reg = inb(iobase + REG_INTERRUPT);
++
++	if ((reg != 0x00) && (reg != 0xff)) {
++
++		if (reg & 0x04) {
++			bluecard_receive(info, 0x00);
++			outb(0x04, iobase + REG_INTERRUPT);
++			outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
++		}
++
++		if (reg & 0x08) {
++			bluecard_receive(info, 0x10);
++			outb(0x08, iobase + REG_INTERRUPT);
++			outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
++		}
++
++		if (reg & 0x01) {
++			set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
++			outb(0x01, iobase + REG_INTERRUPT);
++			bluecard_write_wakeup(info);
++		}
++
++		if (reg & 0x02) {
++			set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
++			outb(0x02, iobase + REG_INTERRUPT);
++			bluecard_write_wakeup(info);
++		}
++
++	}
++
++	/* Enable interrupt */
++	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	spin_unlock(&(info->lock));
++}
++
++
++
++/* ======================== Device specific HCI commands ======================== */
++
++
++static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++	struct sk_buff *skb;
++
++	/* Ericsson baud rate command */
++	unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
++
++	if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++		printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
++		return -1;
++	}
++
++	switch (baud) {
++	case 460800:
++		cmd[4] = 0x00;
++		skb->pkt_type = PKT_BAUD_RATE_460800;
++		break;
++	case 230400:
++		cmd[4] = 0x01;
++		skb->pkt_type = PKT_BAUD_RATE_230400;
++		break;
++	case 115200:
++		cmd[4] = 0x02;
++		skb->pkt_type = PKT_BAUD_RATE_115200;
++		break;
++	case 57600:
++		/* Fall through... */
++	default:
++		cmd[4] = 0x03;
++		skb->pkt_type = PKT_BAUD_RATE_57600;
++		break;
++	}
++
++	memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
++
++	skb_queue_tail(&(info->txq), skb);
++
++	bluecard_write_wakeup(info);
++
++	return 0;
++}
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int bluecard_hci_flush(struct hci_dev *hdev)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int bluecard_hci_open(struct hci_dev *hdev)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++	unsigned int iobase = info->link.io.BasePort1;
++
++	bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
++
++	if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	/* Enable LED */
++	outb(0x08 | 0x20, iobase + 0x30);
++
++	return 0;
++}
++
++
++static int bluecard_hci_close(struct hci_dev *hdev)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++	unsigned int iobase = info->link.io.BasePort1;
++
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	bluecard_hci_flush(hdev);
++
++	/* Disable LED */
++	outb(0x00, iobase + 0x30);
++
++	return 0;
++}
++
++
++static int bluecard_hci_send_frame(struct sk_buff *skb)
++{
++	bluecard_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++	if (!hdev) {
++		printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (bluecard_info_t *)(hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++	skb_queue_tail(&(info->txq), skb);
++
++	bluecard_write_wakeup(info);
++
++	return 0;
++}
++
++
++static void bluecard_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int bluecard_open(bluecard_info_t *info)
++{
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev;
++	unsigned char id;
++
++	spin_lock_init(&(info->lock));
++
++	init_timer(&(info->timer));
++	info->timer.function = &bluecard_activity_led_timeout;
++	info->timer.data = (u_long)info;
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_PACKET_TYPE;
++	info->rx_count = 0;
++	info->rx_skb = NULL;
++
++	id = inb(iobase + 0x30);
++
++	if ((id & 0x0f) == 0x02)
++		set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
++
++	if (id & 0x10)
++		set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
++
++	if (id & 0x20)
++		set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
++
++	/* Reset card */
++	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Turn FPGA off */
++	outb(0x80, iobase + 0x30);
++
++	/* Wait some time */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ / 100);
++
++	/* Turn FPGA on */
++	outb(0x00, iobase + 0x30);
++
++	/* Activate card */
++	info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Enable interrupt */
++	outb(0xff, iobase + REG_INTERRUPT);
++	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Start the RX buffers */
++	outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
++	outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
++
++	/* Signal that the hardware is ready */
++	set_bit(CARD_READY, &(info->hw_state));
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	/* Control the point at which RTS is enabled */
++	outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
++
++	/* Timeout before it is safe to send the first HCI packet */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout((HZ * 5) / 4);		// or set it to 3/2
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = bluecard_hci_open;
++	hdev->close = bluecard_hci_close;
++	hdev->flush = bluecard_hci_flush;
++	hdev->send = bluecard_hci_send_frame;
++	hdev->destruct = bluecard_hci_destruct;
++	hdev->ioctl = bluecard_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int bluecard_close(bluecard_info_t *info)
++{
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev = &(info->hdev);
++
++	bluecard_hci_close(hdev);
++
++	clear_bit(CARD_READY, &(info->hw_state));
++
++	/* Reset card */
++	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Turn FPGA off */
++	outb(0x80, iobase + 0x30);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *bluecard_attach(void)
++{
++	bluecard_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &bluecard_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = bluecard_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &bluecard_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		bluecard_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void bluecard_detach(dev_link_t *link)
++{
++	bluecard_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG)
++		bluecard_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void bluecard_config(dev_link_t *link)
++{
++	client_handle_t handle = link->handle;
++	bluecard_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	config_info_t config;
++	int i, n, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	link->conf.ConfigIndex = 0x20;
++	link->io.NumPorts1 = 64;
++	link->io.IOAddrLines = 6;
++
++	for (n = 0; n < 0x400; n += 0x40) {
++		link->io.BasePort1 = n ^ 0x300;
++		i = CardServices(RequestIO, link->handle, &link->io);
++		if (i == CS_SUCCESS)
++			break;
++	}
++
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (bluecard_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	bluecard_release((u_long)link);
++}
++
++
++void bluecard_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	bluecard_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		bluecard_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int bluecard_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	bluecard_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			bluecard_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		bluecard_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_bluecard_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach);
++
++	return err;
++}
++
++
++void __exit exit_bluecard_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		bluecard_detach(dev_list);
++}
++
++
++module_init(init_bluecard_cs);
++module_exit(exit_bluecard_cs);
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/bt3c_cs.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,946 @@
++/*
++ *
++ *  Driver for the 3Com Bluetooth PCMCIA card
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *                           Jose Orlando Pereira <jop@di.uminho.pt>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#define __KERNEL_SYSCALLS__
++
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0xffff;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
++MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct bt3c_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;		/* For serializing operations */
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++} bt3c_info_t;
++
++
++void bt3c_config(dev_link_t *link);
++void bt3c_release(u_long arg);
++int bt3c_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "bt3c_cs";
++
++dev_link_t *bt3c_attach(void);
++void bt3c_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Transmit states  */
++#define XMIT_SENDING  1
++#define XMIT_WAKEUP   2
++#define XMIT_WAITING  8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE   0
++#define RECV_WAIT_EVENT_HEADER  1
++#define RECV_WAIT_ACL_HEADER    2
++#define RECV_WAIT_SCO_HEADER    3
++#define RECV_WAIT_DATA          4
++
++
++
++/* ======================== Special I/O functions ======================== */
++
++
++#define DATA_L   0
++#define DATA_H   1
++#define ADDR_L   2
++#define ADDR_H   3
++#define CONTROL  4
++
++
++inline void bt3c_address(unsigned int iobase, unsigned short addr)
++{
++	outb(addr & 0xff, iobase + ADDR_L);
++	outb((addr >> 8) & 0xff, iobase + ADDR_H);
++}
++
++
++inline void bt3c_put(unsigned int iobase, unsigned short value)
++{
++	outb(value & 0xff, iobase + DATA_L);
++	outb((value >> 8) & 0xff, iobase + DATA_H);
++}
++
++
++inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
++{
++	bt3c_address(iobase, addr);
++	bt3c_put(iobase, value);
++}
++
++
++inline unsigned short bt3c_get(unsigned int iobase)
++{
++	unsigned short value = inb(iobase + DATA_L);
++
++	value |= inb(iobase + DATA_H) << 8;
++
++	return value;
++}
++
++
++inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
++{
++	bt3c_address(iobase, addr);
++
++	return bt3c_get(iobase);
++}
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
++{
++	int actual = 0;
++
++	bt3c_address(iobase, 0x7080);
++
++	/* Fill FIFO with current frame */
++	while (actual < len) {
++		/* Transmit next byte */
++		bt3c_put(iobase, buf[actual]);
++		actual++;
++	}
++
++	bt3c_io_write(iobase, 0x7005, actual);
++
++	return actual;
++}
++
++
++static void bt3c_write_wakeup(bt3c_info_t *info, int from)
++{
++	unsigned long flags;
++
++	if (!info) {
++		printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
++		return;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register struct sk_buff *skb;
++		register int len;
++
++		if (!(info->link.state & DEV_PRESENT))
++			break;
++
++
++		if (!(skb = skb_dequeue(&(info->txq)))) {
++			clear_bit(XMIT_SENDING, &(info->tx_state));
++			break;
++		}
++
++		/* Send frame */
++		len = bt3c_write(iobase, 256, skb->data, skb->len);
++
++		if (len != skb->len) {
++			printk(KERN_WARNING "bt3c_cs: very strange\n");
++		}
++
++		kfree_skb(skb);
++
++		info->hdev.stat.byte_tx += len;
++
++	} while (0);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++}
++
++
++static void bt3c_receive(bt3c_info_t *info)
++{
++	unsigned int iobase;
++	int size = 0, avail;
++
++	if (!info) {
++		printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	avail = bt3c_read(iobase, 0x7006);
++	//printk("bt3c_cs: receiving %d bytes\n", avail);
++
++	bt3c_address(iobase, 0x7480);
++	while (size < avail) {
++		size++;
++		info->hdev.stat.byte_rx++;
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL) {
++			info->rx_state = RECV_WAIT_PACKET_TYPE;
++			info->rx_count = 0;
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
++				return;
++			}
++		}
++
++
++		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++			info->rx_skb->dev = (void *)&(info->hdev);
++			info->rx_skb->pkt_type = inb(iobase + DATA_L);
++			inb(iobase + DATA_H);
++			//printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);
++
++			switch (info->rx_skb->pkt_type) {
++
++			case HCI_EVENT_PKT:
++				info->rx_state = RECV_WAIT_EVENT_HEADER;
++				info->rx_count = HCI_EVENT_HDR_SIZE;
++				break;
++
++			case HCI_ACLDATA_PKT:
++				info->rx_state = RECV_WAIT_ACL_HEADER;
++				info->rx_count = HCI_ACL_HDR_SIZE;
++				break;
++
++			case HCI_SCODATA_PKT:
++				info->rx_state = RECV_WAIT_SCO_HEADER;
++				info->rx_count = HCI_SCO_HDR_SIZE;
++				break;
++
++			default:
++				/* Unknown packet */
++				printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++				info->hdev.stat.err_rx++;
++				clear_bit(HCI_RUNNING, &(info->hdev.flags));
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			}
++
++		} else {
++
++			__u8 x = inb(iobase + DATA_L);
++
++			*skb_put(info->rx_skb, 1) = x;
++			inb(iobase + DATA_H);
++			info->rx_count--;
++
++			if (info->rx_count == 0) {
++
++				int dlen;
++				hci_event_hdr *eh;
++				hci_acl_hdr *ah;
++				hci_sco_hdr *sh;
++
++				switch (info->rx_state) {
++
++				case RECV_WAIT_EVENT_HEADER:
++					eh = (hci_event_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = eh->plen;
++					break;
++
++				case RECV_WAIT_ACL_HEADER:
++					ah = (hci_acl_hdr *)(info->rx_skb->data);
++					dlen = __le16_to_cpu(ah->dlen);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = dlen;
++					break;
++
++				case RECV_WAIT_SCO_HEADER:
++					sh = (hci_sco_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = sh->dlen;
++					break;
++
++				case RECV_WAIT_DATA:
++					hci_recv_frame(info->rx_skb);
++					info->rx_skb = NULL;
++					break;
++
++				}
++
++			}
++
++		}
++
++	}
++
++	bt3c_io_write(iobase, 0x7006, 0x0000);
++}
++
++
++void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	bt3c_info_t *info = dev_inst;
++	unsigned int iobase;
++	int iir;
++
++	if (!info) {
++		printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	iir = inb(iobase + CONTROL);
++	if (iir & 0x80) {
++		int stat = bt3c_read(iobase, 0x7001);
++
++		if ((stat & 0xff) == 0x7f) {
++			printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat);
++		} else if ((stat & 0xff) != 0xff) {
++			if (stat & 0x0020) {
++				int stat = bt3c_read(iobase, 0x7002) & 0x10;
++				printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN");
++			}
++			if (stat & 0x0001)
++				bt3c_receive(info);
++			if (stat & 0x0002) {
++				//printk("bt3c_cs: ACK %04x\n", stat);
++				clear_bit(XMIT_SENDING, &(info->tx_state));
++				bt3c_write_wakeup(info, 1);
++			}
++
++			bt3c_io_write(iobase, 0x7001, 0x0000);
++
++			outb(iir, iobase + CONTROL);
++		}
++	}
++
++	spin_unlock(&(info->lock));
++}
++
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int bt3c_hci_flush(struct hci_dev *hdev)
++{
++	bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int bt3c_hci_open(struct hci_dev *hdev)
++{
++	set_bit(HCI_RUNNING, &(hdev->flags));
++
++	return 0;
++}
++
++
++static int bt3c_hci_close(struct hci_dev *hdev)
++{
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	bt3c_hci_flush(hdev);
++
++	return 0;
++}
++
++
++static int bt3c_hci_send_frame(struct sk_buff *skb)
++{
++	bt3c_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++	if (!hdev) {
++		printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (bt3c_info_t *) (hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++	skb_queue_tail(&(info->txq), skb);
++
++	bt3c_write_wakeup(info, 0);
++
++	return 0;
++}
++
++
++static void bt3c_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== User mode firmware loader ======================== */
++
++
++#define FW_LOADER  "/sbin/bluefw"
++static int errno;
++
++
++static int bt3c_fw_loader_exec(void *dev)
++{
++	char *argv[] = { FW_LOADER, "pccard", dev, NULL };
++	char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
++	int err;
++
++	err = exec_usermodehelper(FW_LOADER, argv, envp);
++	if (err)
++		printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev);
++
++	return err;
++}
++
++
++static int bt3c_firmware_load(bt3c_info_t *info)
++{
++	sigset_t tmpsig;
++	char dev[16];
++	pid_t pid;
++	int result;
++
++	/* Check if root fs is mounted */
++	if (!current->fs->root) {
++		printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n");
++		return -EPERM;
++	}
++
++	sprintf(dev, "%04x", info->link.io.BasePort1);
++
++	pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0);
++	if (pid < 0) {
++		printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid);
++		return pid;
++	}
++
++	/* Block signals, everything but SIGKILL/SIGSTOP */
++	spin_lock_irq(&current->sigmask_lock);
++	tmpsig = current->blocked;
++	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
++	recalc_sigpending(current);
++	spin_unlock_irq(&current->sigmask_lock);
++
++	result = waitpid(pid, NULL, __WCLONE);
++
++	/* Allow signals again */
++	spin_lock_irq(&current->sigmask_lock);
++	current->blocked = tmpsig;
++	recalc_sigpending(current);
++	spin_unlock_irq(&current->sigmask_lock);
++
++	if (result != pid) {
++		printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
++		return -result;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int bt3c_open(bt3c_info_t *info)
++{
++	struct hci_dev *hdev;
++	int err;
++
++	spin_lock_init(&(info->lock));
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_PACKET_TYPE;
++	info->rx_count = 0;
++	info->rx_skb = NULL;
++
++	/* Load firmware */
++
++	if ((err = bt3c_firmware_load(info)) < 0)
++		return err;
++
++	/* Timeout before it is safe to send the first HCI packet */
++
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ);
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = bt3c_hci_open;
++	hdev->close = bt3c_hci_close;
++	hdev->flush = bt3c_hci_flush;
++	hdev->send = bt3c_hci_send_frame;
++	hdev->destruct = bt3c_hci_destruct;
++	hdev->ioctl = bt3c_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int bt3c_close(bt3c_info_t *info)
++{
++	struct hci_dev *hdev = &(info->hdev);
++
++	bt3c_hci_close(hdev);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *bt3c_attach(void)
++{
++	bt3c_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &bt3c_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = bt3c_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &bt3c_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		bt3c_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void bt3c_detach(dev_link_t *link)
++{
++	bt3c_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++
++	if (link->state & DEV_CONFIG)
++		bt3c_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void bt3c_config(dev_link_t *link)
++{
++	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
++	client_handle_t handle = link->handle;
++	bt3c_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++	config_info_t config;
++	int i, j, try, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	/* First pass: look for a config entry that looks normal. */
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++	/* Two tries: without IO aliases, then with aliases */
++	for (try = 0; try < 2; try++) {
++		i = first_tuple(handle, &tuple, &parse);
++		while (i != CS_NO_MORE_ITEMS) {
++			if (i != CS_SUCCESS)
++				goto next_entry;
++			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
++				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
++			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
++				link->conf.ConfigIndex = cf->index;
++				link->io.BasePort1 = cf->io.win[0].base;
++				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++next_entry:
++			i = next_tuple(handle, &tuple, &parse);
++		}
++	}
++
++	/* Second pass: try to find an entry that isn't picky about
++	   its base address, then try to grab any standard serial port
++	   address, and finally try to get any free port. */
++	i = first_tuple(handle, &tuple, &parse);
++	while (i != CS_NO_MORE_ITEMS) {
++		if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
++			link->conf.ConfigIndex = cf->index;
++			for (j = 0; j < 5; j++) {
++				link->io.BasePort1 = base[j];
++				link->io.IOAddrLines = base[j] ? 16 : 3;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++		}
++		i = next_tuple(handle, &tuple, &parse);
++	}
++
++found_port:
++	if (i != CS_SUCCESS) {
++		printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n");
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (bt3c_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	bt3c_release((u_long)link);
++}
++
++
++void bt3c_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	bt3c_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		bt3c_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int bt3c_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	bt3c_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			bt3c_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		bt3c_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_bt3c_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach);
++
++	return err;
++}
++
++
++void __exit exit_bt3c_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		bt3c_detach(dev_list);
++}
++
++
++module_init(init_bt3c_cs);
++module_exit(exit_bt3c_cs);
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/btuart_cs.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,906 @@
++/*
++ *
++ *  Driver for Bluetooth PCMCIA cards with HCI UART interface
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0xffff;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct btuart_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;	/* For serializing operations */
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++} btuart_info_t;
++
++
++void btuart_config(dev_link_t *link);
++void btuart_release(u_long arg);
++int btuart_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "btuart_cs";
++
++dev_link_t *btuart_attach(void);
++void btuart_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Maximum baud rate */
++#define SPEED_MAX  115200
++
++/* Default baud rate: 57600, 115200, 230400 or 460800 */
++#define DEFAULT_BAUD_RATE  115200
++
++
++/* Transmit states  */
++#define XMIT_SENDING	1
++#define XMIT_WAKEUP	2
++#define XMIT_WAITING	8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE	0
++#define RECV_WAIT_EVENT_HEADER	1
++#define RECV_WAIT_ACL_HEADER	2
++#define RECV_WAIT_SCO_HEADER	3
++#define RECV_WAIT_DATA		4
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
++{
++	int actual = 0;
++
++	/* Tx FIFO should be empty */
++	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
++		return 0;
++
++	/* Fill FIFO with current frame */
++	while ((fifo_size-- > 0) && (actual < len)) {
++		/* Transmit next byte */
++		outb(buf[actual], iobase + UART_TX);
++		actual++;
++	}
++
++	return actual;
++}
++
++
++static void btuart_write_wakeup(btuart_info_t *info)
++{
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register struct sk_buff *skb;
++		register int len;
++
++		clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (!(info->link.state & DEV_PRESENT))
++			return;
++
++		if (!(skb = skb_dequeue(&(info->txq))))
++			break;
++
++		/* Send frame */
++		len = btuart_write(iobase, 16, skb->data, skb->len);
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (len == skb->len) {
++			kfree_skb(skb);
++		} else {
++			skb_pull(skb, len);
++			skb_queue_head(&(info->txq), skb);
++		}
++
++		info->hdev.stat.byte_tx += len;
++
++	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++	clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static void btuart_receive(btuart_info_t *info)
++{
++	unsigned int iobase;
++	int boguscount = 0;
++
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	do {
++		info->hdev.stat.byte_rx++;
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL) {
++			info->rx_state = RECV_WAIT_PACKET_TYPE;
++			info->rx_count = 0;
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
++				return;
++			}
++		}
++
++		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++			info->rx_skb->dev = (void *)&(info->hdev);
++			info->rx_skb->pkt_type = inb(iobase + UART_RX);
++
++			switch (info->rx_skb->pkt_type) {
++
++			case HCI_EVENT_PKT:
++				info->rx_state = RECV_WAIT_EVENT_HEADER;
++				info->rx_count = HCI_EVENT_HDR_SIZE;
++				break;
++
++			case HCI_ACLDATA_PKT:
++				info->rx_state = RECV_WAIT_ACL_HEADER;
++				info->rx_count = HCI_ACL_HDR_SIZE;
++				break;
++
++			case HCI_SCODATA_PKT:
++				info->rx_state = RECV_WAIT_SCO_HEADER;
++				info->rx_count = HCI_SCO_HDR_SIZE;
++				break;
++
++			default:
++				/* Unknown packet */
++				printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++				info->hdev.stat.err_rx++;
++				clear_bit(HCI_RUNNING, &(info->hdev.flags));
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			}
++
++		} else {
++
++			*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
++			info->rx_count--;
++
++			if (info->rx_count == 0) {
++
++				int dlen;
++				hci_event_hdr *eh;
++				hci_acl_hdr *ah;
++				hci_sco_hdr *sh;
++
++
++				switch (info->rx_state) {
++
++				case RECV_WAIT_EVENT_HEADER:
++					eh = (hci_event_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = eh->plen;
++					break;
++
++				case RECV_WAIT_ACL_HEADER:
++					ah = (hci_acl_hdr *)(info->rx_skb->data);
++					dlen = __le16_to_cpu(ah->dlen);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = dlen;
++					break;
++
++				case RECV_WAIT_SCO_HEADER:
++					sh = (hci_sco_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = sh->dlen;
++					break;
++
++				case RECV_WAIT_DATA:
++					hci_recv_frame(info->rx_skb);
++					info->rx_skb = NULL;
++					break;
++
++				}
++
++			}
++
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 16)
++			break;
++
++	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
++}
++
++
++void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	btuart_info_t *info = dev_inst;
++	unsigned int iobase;
++	int boguscount = 0;
++	int iir, lsr;
++
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++	while (iir) {
++
++		/* Clear interrupt */
++		lsr = inb(iobase + UART_LSR);
++
++		switch (iir) {
++		case UART_IIR_RLSI:
++			printk(KERN_NOTICE "btuart_cs: RLSI\n");
++			break;
++		case UART_IIR_RDI:
++			/* Receive interrupt */
++			btuart_receive(info);
++			break;
++		case UART_IIR_THRI:
++			if (lsr & UART_LSR_THRE) {
++				/* Transmitter ready for data */
++				btuart_write_wakeup(info);
++			}
++			break;
++		default:
++			printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
++			break;
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 100)
++			break;
++
++		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++
++	}
++
++	spin_unlock(&(info->lock));
++}
++
++
++static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
++{
++	unsigned long flags;
++	unsigned int iobase;
++	int fcr;		/* FIFO control reg */
++	int lcr;		/* Line control reg */
++	int divisor;
++
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	divisor = SPEED_MAX / speed;
++
++	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
++
++	/* 
++	 * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
++	 * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
++	 * about this timeout since it will always be fast enough. 
++	 */
++
++	if (speed < 38400)
++		fcr |= UART_FCR_TRIGGER_1;
++	else
++		fcr |= UART_FCR_TRIGGER_14;
++
++	/* Bluetooth cards use 8N1 */
++	lcr = UART_LCR_WLEN8;
++
++	outb(UART_LCR_DLAB | lcr, iobase + UART_LCR);	/* Set DLAB */
++	outb(divisor & 0xff, iobase + UART_DLL);	/* Set speed */
++	outb(divisor >> 8, iobase + UART_DLM);
++	outb(lcr, iobase + UART_LCR);	/* Set 8N1  */
++	outb(fcr, iobase + UART_FCR);	/* Enable FIFO's */
++
++	/* Turn on interrups */
++	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++}
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int btuart_hci_flush(struct hci_dev *hdev)
++{
++	btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int btuart_hci_open(struct hci_dev *hdev)
++{
++	set_bit(HCI_RUNNING, &(hdev->flags));
++
++	return 0;
++}
++
++
++static int btuart_hci_close(struct hci_dev *hdev)
++{
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	btuart_hci_flush(hdev);
++
++	return 0;
++}
++
++
++static int btuart_hci_send_frame(struct sk_buff *skb)
++{
++	btuart_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++	if (!hdev) {
++		printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (btuart_info_t *)(hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++	skb_queue_tail(&(info->txq), skb);
++
++	btuart_write_wakeup(info);
++
++	return 0;
++}
++
++
++static void btuart_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int btuart_open(btuart_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev;
++
++	spin_lock_init(&(info->lock));
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_PACKET_TYPE;
++	info->rx_count = 0;
++	info->rx_skb = NULL;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	/* Initialize UART */
++	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
++	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
++
++	/* Turn on interrupts */
++	// outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	btuart_change_speed(info, DEFAULT_BAUD_RATE);
++
++	/* Timeout before it is safe to send the first HCI packet */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ);
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = btuart_hci_open;
++	hdev->close = btuart_hci_close;
++	hdev->flush = btuart_hci_flush;
++	hdev->send = btuart_hci_send_frame;
++	hdev->destruct = btuart_hci_destruct;
++	hdev->ioctl = btuart_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int btuart_close(btuart_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev = &(info->hdev);
++
++	btuart_hci_close(hdev);
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *btuart_attach(void)
++{
++	btuart_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &btuart_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = btuart_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &btuart_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		btuart_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void btuart_detach(dev_link_t *link)
++{
++	btuart_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG)
++		btuart_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void btuart_config(dev_link_t *link)
++{
++	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
++	client_handle_t handle = link->handle;
++	btuart_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++	config_info_t config;
++	int i, j, try, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	/* First pass: look for a config entry that looks normal. */
++	tuple.TupleData = (cisdata_t *) buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++	/* Two tries: without IO aliases, then with aliases */
++	for (try = 0; try < 2; try++) {
++		i = first_tuple(handle, &tuple, &parse);
++		while (i != CS_NO_MORE_ITEMS) {
++			if (i != CS_SUCCESS)
++				goto next_entry;
++			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
++				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
++			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
++				link->conf.ConfigIndex = cf->index;
++				link->io.BasePort1 = cf->io.win[0].base;
++				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++next_entry:
++			i = next_tuple(handle, &tuple, &parse);
++		}
++	}
++
++	/* Second pass: try to find an entry that isn't picky about
++	   its base address, then try to grab any standard serial port
++	   address, and finally try to get any free port. */
++	i = first_tuple(handle, &tuple, &parse);
++	while (i != CS_NO_MORE_ITEMS) {
++		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
++		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
++			link->conf.ConfigIndex = cf->index;
++			for (j = 0; j < 5; j++) {
++				link->io.BasePort1 = base[j];
++				link->io.IOAddrLines = base[j] ? 16 : 3;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++		}
++		i = next_tuple(handle, &tuple, &parse);
++	}
++
++found_port:
++	if (i != CS_SUCCESS) {
++		printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (btuart_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	btuart_release((u_long) link);
++}
++
++
++void btuart_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	btuart_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		btuart_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int btuart_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	btuart_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			btuart_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		btuart_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_btuart_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
++
++	return err;
++}
++
++
++void __exit exit_btuart_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		btuart_detach(dev_list);
++}
++
++
++module_init(init_btuart_cs);
++module_exit(exit_btuart_cs);
++
++EXPORT_NO_SYMBOLS;
+--- linux/drivers/bluetooth/Config.in~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/drivers/bluetooth/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -1,8 +1,33 @@
++#
++# Bluetooth HCI device drivers configuration
++#
++
+ mainmenu_option next_comment
+ comment 'Bluetooth device drivers'
+ 
+ dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
++if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
++   bool '  SCO (voice) support'  CONFIG_BLUEZ_HCIUSB_SCO
++fi
++
+ dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
+-dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
++if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
++   bool '  UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
++   bool '  BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
++   dep_bool '  Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
++fi
++
++dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB
++
++dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
+ 
+ endmenu
++
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/dtl1_cs.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,858 @@
++/*
++ *
++ *  A driver for Nokia Connectivity Card DTL-1 devices
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0xffff;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct dtl1_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;		/* For serializing operations */
++
++	unsigned long flowmask;		/* HCI flow mask */
++	int ri_latch;
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++} dtl1_info_t;
++
++
++void dtl1_config(dev_link_t *link);
++void dtl1_release(u_long arg);
++int dtl1_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "dtl1_cs";
++
++dev_link_t *dtl1_attach(void);
++void dtl1_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Transmit states  */
++#define XMIT_SENDING  1
++#define XMIT_WAKEUP   2
++#define XMIT_WAITING  8
++
++/* Receiver States */
++#define RECV_WAIT_NSH   0
++#define RECV_WAIT_DATA  1
++
++
++typedef struct {
++	u8 type;
++	u8 zero;
++	u16 len;
++} __attribute__ ((packed)) nsh_t;	/* Nokia Specific Header */
++
++#define NSHL  4				/* Nokia Specific Header Length */
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
++{
++	int actual = 0;
++
++	/* Tx FIFO should be empty */
++	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
++		return 0;
++
++	/* Fill FIFO with current frame */
++	while ((fifo_size-- > 0) && (actual < len)) {
++		/* Transmit next byte */
++		outb(buf[actual], iobase + UART_TX);
++		actual++;
++	}
++
++	return actual;
++}
++
++
++static void dtl1_write_wakeup(dtl1_info_t *info)
++{
++	if (!info) {
++		printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (test_bit(XMIT_WAITING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register struct sk_buff *skb;
++		register int len;
++
++		clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (!(info->link.state & DEV_PRESENT))
++			return;
++
++		if (!(skb = skb_dequeue(&(info->txq))))
++			break;
++
++		/* Send frame */
++		len = dtl1_write(iobase, 32, skb->data, skb->len);
++
++		if (len == skb->len) {
++			set_bit(XMIT_WAITING, &(info->tx_state));
++			kfree_skb(skb);
++		} else {
++			skb_pull(skb, len);
++			skb_queue_head(&(info->txq), skb);
++		}
++
++		info->hdev.stat.byte_tx += len;
++
++	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++	clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
++{
++	u8 flowmask = *(u8 *)skb->data;
++	int i;
++
++	printk(KERN_INFO "dtl1_cs: Nokia control data = ");
++	for (i = 0; i < skb->len; i++) {
++		printk("%02x ", skb->data[i]);
++	}
++	printk("\n");
++
++	/* transition to active state */
++	if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
++		clear_bit(XMIT_WAITING, &(info->tx_state));
++		dtl1_write_wakeup(info);
++	}
++
++	info->flowmask = flowmask;
++
++	kfree_skb(skb);
++}
++
++
++static void dtl1_receive(dtl1_info_t *info)
++{
++	unsigned int iobase;
++	nsh_t *nsh;
++	int boguscount = 0;
++
++	if (!info) {
++		printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	do {
++		info->hdev.stat.byte_rx++;
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL)
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
++				info->rx_state = RECV_WAIT_NSH;
++				info->rx_count = NSHL;
++				return;
++			}
++
++		*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
++		nsh = (nsh_t *)info->rx_skb->data;
++
++		info->rx_count--;
++
++		if (info->rx_count == 0) {
++
++			switch (info->rx_state) {
++			case RECV_WAIT_NSH:
++				info->rx_state = RECV_WAIT_DATA;
++				info->rx_count = nsh->len + (nsh->len & 0x0001);
++				break;
++			case RECV_WAIT_DATA:
++				info->rx_skb->pkt_type = nsh->type;
++
++				/* remove PAD byte if it exists */
++				if (nsh->len & 0x0001) {
++					info->rx_skb->tail--;
++					info->rx_skb->len--;
++				}
++
++				/* remove NSH */
++				skb_pull(info->rx_skb, NSHL);
++
++				switch (info->rx_skb->pkt_type) {
++				case 0x80:
++					/* control data for the Nokia Card */
++					dtl1_control(info, info->rx_skb);
++					break;
++				case 0x82:
++				case 0x83:
++				case 0x84:
++					/* send frame to the HCI layer */
++					info->rx_skb->dev = (void *)&(info->hdev);
++					info->rx_skb->pkt_type &= 0x0f;
++					hci_recv_frame(info->rx_skb);
++					break;
++				default:
++					/* unknown packet */
++					printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++					kfree_skb(info->rx_skb);
++					break;
++				}
++
++				info->rx_state = RECV_WAIT_NSH;
++				info->rx_count = NSHL;
++				info->rx_skb = NULL;
++				break;
++			}
++
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 32)
++			break;
++
++	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
++}
++
++
++void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	dtl1_info_t *info = dev_inst;
++	unsigned int iobase;
++	unsigned char msr;
++	int boguscount = 0;
++	int iir, lsr;
++
++	if (!info) {
++		printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++	while (iir) {
++
++		/* Clear interrupt */
++		lsr = inb(iobase + UART_LSR);
++
++		switch (iir) {
++		case UART_IIR_RLSI:
++			printk(KERN_NOTICE "dtl1_cs: RLSI\n");
++			break;
++		case UART_IIR_RDI:
++			/* Receive interrupt */
++			dtl1_receive(info);
++			break;
++		case UART_IIR_THRI:
++			if (lsr & UART_LSR_THRE) {
++				/* Transmitter ready for data */
++				dtl1_write_wakeup(info);
++			}
++			break;
++		default:
++			printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
++			break;
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 100)
++			break;
++
++		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++
++	}
++
++	msr = inb(iobase + UART_MSR);
++
++	if (info->ri_latch ^ (msr & UART_MSR_RI)) {
++		info->ri_latch = msr & UART_MSR_RI;
++		clear_bit(XMIT_WAITING, &(info->tx_state));
++		dtl1_write_wakeup(info);
++	}
++
++	spin_unlock(&(info->lock));
++}
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int dtl1_hci_open(struct hci_dev *hdev)
++{
++	set_bit(HCI_RUNNING, &(hdev->flags));
++
++	return 0;
++}
++
++
++static int dtl1_hci_flush(struct hci_dev *hdev)
++{
++	dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int dtl1_hci_close(struct hci_dev *hdev)
++{
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	dtl1_hci_flush(hdev);
++
++	return 0;
++}
++
++
++static int dtl1_hci_send_frame(struct sk_buff *skb)
++{
++	dtl1_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++	struct sk_buff *s;
++	nsh_t nsh;
++
++	if (!hdev) {
++		printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (dtl1_info_t *)(hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		nsh.type = 0x81;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		nsh.type = 0x82;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		nsh.type = 0x83;
++		break;
++	};
++
++	nsh.zero = 0;
++	nsh.len = skb->len;
++
++	s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
++	skb_reserve(s, NSHL);
++	memcpy(skb_put(s, skb->len), skb->data, skb->len);
++	if (skb->len & 0x0001)
++		*skb_put(s, 1) = 0;	/* PAD */
++
++	/* Prepend skb with Nokia frame header and queue */
++	memcpy(skb_push(s, NSHL), &nsh, NSHL);
++	skb_queue_tail(&(info->txq), s);
++
++	dtl1_write_wakeup(info);
++
++	kfree_skb(skb);
++
++	return 0;
++}
++
++
++static void dtl1_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int dtl1_open(dtl1_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev;
++
++	spin_lock_init(&(info->lock));
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_NSH;
++	info->rx_count = NSHL;
++	info->rx_skb = NULL;
++
++	set_bit(XMIT_WAITING, &(info->tx_state));
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	/* Initialize UART */
++	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
++	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
++
++	info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
++
++	/* Turn on interrupts */
++	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	/* Timeout before it is safe to send the first HCI packet */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ * 2);
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = dtl1_hci_open;
++	hdev->close = dtl1_hci_close;
++	hdev->flush = dtl1_hci_flush;
++	hdev->send = dtl1_hci_send_frame;
++	hdev->destruct = dtl1_hci_destruct;
++	hdev->ioctl = dtl1_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int dtl1_close(dtl1_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev = &(info->hdev);
++
++	dtl1_hci_close(hdev);
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *dtl1_attach(void)
++{
++	dtl1_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &dtl1_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = dtl1_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &dtl1_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		dtl1_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void dtl1_detach(dev_link_t *link)
++{
++	dtl1_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG)
++		dtl1_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void dtl1_config(dev_link_t *link)
++{
++	client_handle_t handle = link->handle;
++	dtl1_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++	config_info_t config;
++	int i, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++
++	/* Look for a generic full-sized window */
++	link->io.NumPorts1 = 8;
++	i = first_tuple(handle, &tuple, &parse);
++	while (i != CS_NO_MORE_ITEMS) {
++		if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
++			link->conf.ConfigIndex = cf->index;
++			link->io.BasePort1 = cf->io.win[0].base;
++			link->io.NumPorts1 = cf->io.win[0].len;	/*yo */
++			link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
++			i = CardServices(RequestIO, link->handle, &link->io);
++			if (i == CS_SUCCESS)
++				break;
++		}
++		i = next_tuple(handle, &tuple, &parse);
++	}
++
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (dtl1_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	dtl1_release((u_long)link);
++}
++
++
++void dtl1_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	dtl1_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		dtl1_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int dtl1_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	dtl1_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			dtl1_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		dtl1_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_dtl1_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
++
++	return err;
++}
++
++
++void __exit exit_dtl1_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		dtl1_detach(dev_list);
++}
++
++
++module_init(init_dtl1_cs);
++module_exit(exit_dtl1_cs);
++
++EXPORT_NO_SYMBOLS;
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_bcsp.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,710 @@
++/* 
++   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
++   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
++
++   Based on
++       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
++       ABCSP     by Carl Orsborn <cjo@csr.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#define VERSION "0.1"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/poll.h>
++
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/signal.h>
++#include <linux/ioctl.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include "hci_uart.h"
++#include "hci_bcsp.h"
++
++#ifndef HCI_UART_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
++#endif
++
++/* ---- BCSP CRC calculation ---- */
++
++/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
++initial value 0xffff, bits shifted in reverse order. */
++
++static const u16 crc_table[] = {
++	0x0000, 0x1081, 0x2102, 0x3183,
++	0x4204, 0x5285, 0x6306, 0x7387,
++	0x8408, 0x9489, 0xa50a, 0xb58b,
++	0xc60c, 0xd68d, 0xe70e, 0xf78f
++};
++
++/* Initialise the crc calculator */
++#define BCSP_CRC_INIT(x) x = 0xffff
++
++/*
++   Update crc with next data byte
++
++   Implementation note
++        The data byte is treated as two nibbles.  The crc is generated
++        in reverse, i.e., bits are fed into the register from the top.
++*/
++static void bcsp_crc_update(u16 *crc, u8 d)
++{
++	u16 reg = *crc;
++
++	reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
++	reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
++
++	*crc = reg;
++}
++
++/*
++   Get reverse of generated crc
++
++   Implementation note
++        The crc generator (bcsp_crc_init() and bcsp_crc_update())
++        creates a reversed crc, so it needs to be swapped back before
++        being passed on.
++*/
++static u16 bcsp_crc_reverse(u16 crc)
++{
++	u16 b, rev;
++
++	for (b = 0, rev = 0; b < 16; b++) {
++		rev = rev << 1;
++		rev |= (crc & 1);
++		crc = crc >> 1;
++	}
++	return (rev);
++}
++
++/* ---- BCSP core ---- */
++
++static void bcsp_slip_msgdelim(struct sk_buff *skb)
++{
++	const char pkt_delim = 0xc0;
++	memcpy(skb_put(skb, 1), &pkt_delim, 1);
++}
++
++static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
++{
++	const char esc_c0[2] = { 0xdb, 0xdc };
++	const char esc_db[2] = { 0xdb, 0xdd };
++
++	switch (c) {
++	case 0xc0:
++		memcpy(skb_put(skb, 2), &esc_c0, 2);
++		break;
++	case 0xdb:
++		memcpy(skb_put(skb, 2), &esc_db, 2);
++		break;
++	default:
++		memcpy(skb_put(skb, 1), &c, 1);
++	}
++}
++
++static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++
++	if (skb->len > 0xFFF) {
++		BT_ERR("Packet too long");
++		kfree_skb(skb);
++		return 0;
++	}
++
++	switch (skb->pkt_type) {
++	case HCI_ACLDATA_PKT:
++	case HCI_COMMAND_PKT:
++		skb_queue_tail(&bcsp->rel, skb);
++		break;
++
++	case HCI_SCODATA_PKT:
++		skb_queue_tail(&bcsp->unrel, skb);
++		break;
++		
++	default:
++		BT_ERR("Unknown packet type");
++		kfree_skb(skb);
++		break;
++	}
++	return 0;
++}
++
++static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
++		int len, int pkt_type)
++{
++	struct sk_buff *nskb;
++	u8  hdr[4], chan;
++	int rel, i;
++
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++	u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
++#endif
++
++	switch (pkt_type) {
++	case HCI_ACLDATA_PKT:
++		chan = 6;	/* BCSP ACL channel */
++		rel = 1;	/* reliable channel */
++		break;
++	case HCI_COMMAND_PKT:
++		chan = 5;	/* BCSP cmd/evt channel */
++		rel = 1;	/* reliable channel */
++		break;
++	case HCI_SCODATA_PKT:
++		chan = 7;	/* BCSP SCO channel */
++		rel = 0;	/* unreliable channel */
++		break;
++	case BCSP_LE_PKT:
++		chan = 1;	/* BCSP LE channel */
++		rel = 0;	/* unreliable channel */
++		break;
++	case BCSP_ACK_PKT:
++		chan = 0;	/* BCSP internal channel */
++		rel = 0;	/* unreliable channel */
++		break;
++	default:
++		BT_ERR("Unknown packet type");
++		return NULL;
++	}
++
++	/* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
++	   (because bytes 0xc0 and 0xdb are escaped, worst case is
++	   when the packet is all made of 0xc0 and 0xdb :) )
++	   + 2 (0xc0 delimiters at start and end). */
++
++	nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
++	if (!nskb)
++		return NULL;
++
++	nskb->pkt_type = pkt_type;
++
++	bcsp_slip_msgdelim(nskb);
++
++	hdr[0] = bcsp->rxseq_txack << 3;
++	bcsp->txack_req = 0;
++	BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
++
++	if (rel) {
++		hdr[0] |= 0x80 + bcsp->msgq_txseq;
++		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
++		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
++	}
++#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++	hdr[0] |= 0x40;
++#endif
++
++	hdr[1]  = (len << 4) & 0xFF;
++	hdr[1] |= chan;
++	hdr[2]  = len >> 4;
++	hdr[3]  = ~(hdr[0] + hdr[1] + hdr[2]);
++
++	/* Put BCSP header */
++	for (i = 0; i < 4; i++) {
++		bcsp_slip_one_byte(nskb, hdr[i]);
++#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++		bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
++#endif
++	}
++
++	/* Put payload */
++	for (i = 0; i < len; i++) {
++		bcsp_slip_one_byte(nskb, data[i]);
++#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++		bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
++#endif
++	}
++
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++	/* Put CRC */
++	bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
++	bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
++	bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
++#endif
++
++	bcsp_slip_msgdelim(nskb);
++	return nskb;
++}
++
++/* This is a rewrite of pkt_avail in ABCSP */
++static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
++	unsigned long flags;
++	struct sk_buff *skb;
++	
++	/* First of all, check for unreliable messages in the queue,
++	   since they have priority */
++
++	if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
++		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
++		if (nskb) {
++			kfree_skb(skb);
++			return nskb;
++		} else {
++			skb_queue_head(&bcsp->unrel, skb);
++			BT_ERR("Could not dequeue pkt because alloc_skb failed");
++		}
++	}
++
++	/* Now, try to send a reliable pkt. We can only send a
++	   reliable packet if the number of packets sent but not yet ack'ed
++	   is < than the winsize */
++
++	spin_lock_irqsave(&bcsp->unack.lock, flags);
++
++	if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
++		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
++		if (nskb) {
++			__skb_queue_tail(&bcsp->unack, skb);
++			mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
++			spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++			return nskb;
++		} else {
++			skb_queue_head(&bcsp->rel, skb);
++			BT_ERR("Could not dequeue pkt because alloc_skb failed");
++		}
++	}
++
++	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++
++
++	/* We could not send a reliable packet, either because there are
++	   none or because there are too many unack'ed pkts. Did we receive
++	   any packets we have not acknowledged yet ? */
++
++	if (bcsp->txack_req) {
++		/* if so, craft an empty ACK pkt and send it on BCSP unreliable
++		   channel 0 */
++		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
++		return nskb;
++	}
++
++	/* We have nothing to send */
++	return NULL;
++}
++
++static int bcsp_flush(struct hci_uart *hu)
++{
++	BT_DBG("hu %p", hu);
++	return 0;
++}
++
++/* Remove ack'ed packets */
++static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
++{
++	unsigned long flags;
++	struct sk_buff *skb;
++	int i, pkts_to_be_removed;
++	u8 seqno;
++
++	spin_lock_irqsave(&bcsp->unack.lock, flags);
++
++	pkts_to_be_removed = bcsp->unack.qlen;
++	seqno = bcsp->msgq_txseq;
++
++	while (pkts_to_be_removed) {
++		if (bcsp->rxack == seqno)
++			break;
++		pkts_to_be_removed--;
++		seqno = (seqno - 1) & 0x07;
++	}
++
++	if (bcsp->rxack != seqno)
++		BT_ERR("Peer acked invalid packet");
++
++	BT_DBG("Removing %u pkts out of %u, up to seqno %u",
++	       pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
++
++	for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
++			&& skb != (struct sk_buff *) &bcsp->unack; i++) {
++		struct sk_buff *nskb;
++
++		nskb = skb->next;
++		__skb_unlink(skb, &bcsp->unack);
++		kfree_skb(skb);
++		skb = nskb;
++	}
++	if (bcsp->unack.qlen == 0)
++		del_timer(&bcsp->tbcsp);
++	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++
++	if (i != pkts_to_be_removed)
++		BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
++}
++
++/* Handle BCSP link-establishment packets. When we
++   detect a "sync" packet, symptom that the BT module has reset,
++   we do nothing :) (yet) */
++static void bcsp_handle_le_pkt(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	u8 conf_pkt[4]     = { 0xad, 0xef, 0xac, 0xed };
++	u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
++	u8 sync_pkt[4]     = { 0xda, 0xdc, 0xed, 0xed };
++
++	/* spot "conf" pkts and reply with a "conf rsp" pkt */
++	if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
++			!memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
++		struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
++
++		BT_DBG("Found a LE conf pkt");
++		if (!nskb)
++			return;
++		memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
++		nskb->pkt_type = BCSP_LE_PKT;
++
++		skb_queue_head(&bcsp->unrel, nskb);
++		hci_uart_tx_wakeup(hu);
++	}
++	/* Spot "sync" pkts. If we find one...disaster! */
++	else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
++			!memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
++		BT_ERR("Found a LE sync pkt, card has reset");
++	}
++}
++
++static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
++{
++	const u8 c0 = 0xc0, db = 0xdb;
++
++	switch (bcsp->rx_esc_state) {
++	case BCSP_ESCSTATE_NOESC:
++		switch (byte) {
++		case 0xdb:
++			bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
++			break;
++		default:
++			memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
++			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
++					bcsp->rx_state != BCSP_W4_CRC)
++				bcsp_crc_update(&bcsp->message_crc, byte);
++			bcsp->rx_count--;
++		}
++		break;
++
++	case BCSP_ESCSTATE_ESC:
++		switch (byte) {
++		case 0xdc:
++			memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
++			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
++					bcsp->rx_state != BCSP_W4_CRC)
++				bcsp_crc_update(&bcsp-> message_crc, 0xc0);
++			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
++			bcsp->rx_count--;
++			break;
++
++		case 0xdd:
++			memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
++			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
++					bcsp->rx_state != BCSP_W4_CRC) 
++				bcsp_crc_update(&bcsp-> message_crc, 0xdb);
++			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
++			bcsp->rx_count--;
++			break;
++
++		default:
++			BT_ERR ("Invalid byte %02x after esc byte", byte);
++			kfree_skb(bcsp->rx_skb);
++			bcsp->rx_skb = NULL;
++			bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++			bcsp->rx_count = 0;
++		}
++	}
++}
++
++static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	int pass_up;
++
++	if (bcsp->rx_skb->data[0] & 0x80) {	/* reliable pkt */
++		BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
++		bcsp->rxseq_txack++;
++		bcsp->rxseq_txack %= 0x8;
++		bcsp->txack_req    = 1;
++
++		/* If needed, transmit an ack pkt */
++		hci_uart_tx_wakeup(hu);
++	}
++
++	bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
++	BT_DBG("Request for pkt %u from card", bcsp->rxack);
++
++	bcsp_pkt_cull(bcsp);
++	if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
++			bcsp->rx_skb->data[0] & 0x80) {
++		bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
++		pass_up = 1;
++	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
++			bcsp->rx_skb->data[0] & 0x80) {
++		bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
++		pass_up = 1;
++	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
++		bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
++		pass_up = 1;
++	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
++			!(bcsp->rx_skb->data[0] & 0x80)) {
++		bcsp_handle_le_pkt(hu);
++		pass_up = 0;
++	} else
++		pass_up = 0;
++
++	if (!pass_up) {
++		if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
++	    		(bcsp->rx_skb->data[1] & 0x0f) != 1) {
++			BT_ERR ("Packet for unknown channel (%u %s)",
++				bcsp->rx_skb->data[1] & 0x0f,
++				bcsp->rx_skb->data[0] & 0x80 ? 
++				"reliable" : "unreliable");
++		}
++		kfree_skb(bcsp->rx_skb);
++	} else {
++		/* Pull out BCSP hdr */
++		skb_pull(bcsp->rx_skb, 4);
++
++		hci_recv_frame(bcsp->rx_skb);
++	}
++	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++	bcsp->rx_skb = NULL;
++}
++
++/* Recv data */
++static int bcsp_recv(struct hci_uart *hu, void *data, int count)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	register unsigned char *ptr;
++
++	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
++		hu, count, bcsp->rx_state, bcsp->rx_count);
++
++	ptr = data;
++	while (count) {
++		if (bcsp->rx_count) {
++			if (*ptr == 0xc0) {
++				BT_ERR("Short BCSP packet");
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_START;
++				bcsp->rx_count = 0;
++			} else
++				bcsp_unslip_one_byte(bcsp, *ptr);
++
++			ptr++; count--;
++			continue;
++		}
++
++		switch (bcsp->rx_state) {
++		case BCSP_W4_BCSP_HDR:
++			if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
++					bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
++				BT_ERR("Error in BCSP hdr checksum");
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++				bcsp->rx_count = 0;
++				continue;
++			}
++			if (bcsp->rx_skb->data[0] & 0x80	/* reliable pkt */
++			    		&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
++				BT_ERR ("Out-of-order packet arrived, got %u expected %u",
++					bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
++
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++				bcsp->rx_count = 0;
++				continue;
++			}
++			bcsp->rx_state = BCSP_W4_DATA;
++			bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + 
++					(bcsp->rx_skb->data[2] << 4);	/* May be 0 */
++			continue;
++
++		case BCSP_W4_DATA:
++			if (bcsp->rx_skb->data[0] & 0x40) {	/* pkt with crc */
++				bcsp->rx_state = BCSP_W4_CRC;
++				bcsp->rx_count = 2;
++			} else
++				bcsp_complete_rx_pkt(hu);
++			continue;
++
++		case BCSP_W4_CRC:
++			if (bcsp_crc_reverse(bcsp->message_crc) !=
++					(bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
++					bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
++
++				BT_ERR ("Checksum failed: computed %04x received %04x",
++					bcsp_crc_reverse(bcsp->message_crc),
++				     	(bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
++				     	bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
++
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++				bcsp->rx_count = 0;
++				continue;
++			}
++			skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
++			bcsp_complete_rx_pkt(hu);
++			continue;
++
++		case BCSP_W4_PKT_DELIMITER:
++			switch (*ptr) {
++			case 0xc0:
++				bcsp->rx_state = BCSP_W4_PKT_START;
++				break;
++			default:
++				/*BT_ERR("Ignoring byte %02x", *ptr);*/
++				break;
++			}
++			ptr++; count--;
++			break;
++
++		case BCSP_W4_PKT_START:
++			switch (*ptr) {
++			case 0xc0:
++				ptr++; count--;
++				break;
++
++			default:
++				bcsp->rx_state = BCSP_W4_BCSP_HDR;
++				bcsp->rx_count = 4;
++				bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
++				BCSP_CRC_INIT(bcsp->message_crc);
++				
++				/* Do not increment ptr or decrement count
++				 * Allocate packet. Max len of a BCSP pkt= 
++				 * 0xFFF (payload) +4 (header) +2 (crc) */
++
++				bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
++				if (!bcsp->rx_skb) {
++					BT_ERR("Can't allocate mem for new packet");
++					bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++					bcsp->rx_count = 0;
++					return 0;
++				}
++				bcsp->rx_skb->dev = (void *) &hu->hdev;
++				break;
++			}
++			break;
++		}
++	}
++	return count;
++}
++
++	/* Arrange to retransmit all messages in the relq. */
++static void bcsp_timed_event(unsigned long arg)
++{
++	struct hci_uart *hu = (struct hci_uart *) arg;
++	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
++	struct sk_buff *skb;
++	unsigned long flags;
++
++	BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
++	spin_lock_irqsave(&bcsp->unack.lock, flags);
++
++	while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
++		bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
++		skb_queue_head(&bcsp->rel, skb);
++	}
++
++	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++
++	hci_uart_tx_wakeup(hu);
++}
++
++static int bcsp_open(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp;
++
++	BT_DBG("hu %p", hu);
++
++	bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
++	if (!bcsp)
++		return -ENOMEM;
++	memset(bcsp, 0, sizeof(*bcsp));
++
++	hu->priv = bcsp;
++	skb_queue_head_init(&bcsp->unack);
++	skb_queue_head_init(&bcsp->rel);
++	skb_queue_head_init(&bcsp->unrel);
++
++	init_timer(&bcsp->tbcsp);
++	bcsp->tbcsp.function = bcsp_timed_event;
++	bcsp->tbcsp.data     = (u_long) hu;
++
++	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++
++	return 0;
++}
++
++static int bcsp_close(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	hu->priv = NULL;
++
++	BT_DBG("hu %p", hu);
++
++	skb_queue_purge(&bcsp->unack);
++	skb_queue_purge(&bcsp->rel);
++	skb_queue_purge(&bcsp->unrel);
++	del_timer(&bcsp->tbcsp);
++
++	kfree(bcsp);
++	return 0;
++}
++
++static struct hci_uart_proto bcsp = {
++	id:      HCI_UART_BCSP,
++	open:    bcsp_open,
++	close:   bcsp_close,
++	enqueue: bcsp_enqueue,
++	dequeue: bcsp_dequeue,
++	recv:    bcsp_recv,
++	flush:   bcsp_flush
++};
++
++int bcsp_init(void)
++{
++	return hci_uart_register_proto(&bcsp);
++}
++
++int bcsp_deinit(void)
++{
++	return hci_uart_unregister_proto(&bcsp);
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_bcsp.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,70 @@
++/* 
++   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
++   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
++
++   Based on
++       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
++       ABCSP     by Carl Orsborn <cjo@csr.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/* 
++ * $Id$
++ */
++
++#ifndef __HCI_BCSP_H__
++#define __HCI_BCSP_H__
++
++#define BCSP_TXWINSIZE  4
++
++#define BCSP_ACK_PKT    0x05
++#define BCSP_LE_PKT     0x06
++
++struct bcsp_struct {
++	struct sk_buff_head unack;	/* Unack'ed packets queue */
++	struct sk_buff_head rel;	/* Reliable packets queue */
++	struct sk_buff_head unrel;	/* Unreliable packets queue */
++
++	unsigned long rx_count;
++	struct  sk_buff *rx_skb;
++	u8      rxseq_txack;		/* rxseq == txack. */
++	u8      rxack;			/* Last packet sent by us that the peer ack'ed */
++	struct  timer_list tbcsp;
++	
++	enum {
++		BCSP_W4_PKT_DELIMITER,
++		BCSP_W4_PKT_START,
++		BCSP_W4_BCSP_HDR,
++		BCSP_W4_DATA,
++		BCSP_W4_CRC
++	} rx_state;
++
++	enum {
++		BCSP_ESCSTATE_NOESC,
++		BCSP_ESCSTATE_ESC
++	} rx_esc_state;
++
++	u16     message_crc;
++	u8      txack_req;		/* Do we need to send ack's to the peer? */
++
++	/* Reliable packet sequence number - used to assign seq to each rel pkt. */
++	u8      msgq_txseq;
++};
++
++#endif	/* __HCI_BCSP_H__ */
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_h4.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,277 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ HCI UART(H4) protocol.
++ *
++ * $Id$    
++ */
++#define VERSION "1.2"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/poll.h>
++
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/signal.h>
++#include <linux/ioctl.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include "hci_uart.h"
++#include "hci_h4.h"
++
++#ifndef HCI_UART_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
++#endif
++
++/* Initialize protocol */
++static int h4_open(struct hci_uart *hu)
++{
++	struct h4_struct *h4;
++	
++	BT_DBG("hu %p", hu);
++	
++	h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
++	if (!h4)
++		return -ENOMEM;
++	memset(h4, 0, sizeof(*h4));
++
++	skb_queue_head_init(&h4->txq);
++
++	hu->priv = h4;
++	return 0;
++}
++
++/* Flush protocol data */
++static int h4_flush(struct hci_uart *hu)
++{
++	struct h4_struct *h4 = hu->priv;
++
++	BT_DBG("hu %p", hu);
++	skb_queue_purge(&h4->txq);
++	return 0;
++}
++
++/* Close protocol */
++static int h4_close(struct hci_uart *hu)
++{
++	struct h4_struct *h4 = hu->priv;
++	hu->priv = NULL;
++
++	BT_DBG("hu %p", hu);
++
++	skb_queue_purge(&h4->txq);
++	if (h4->rx_skb)
++		kfree_skb(h4->rx_skb);
++
++	hu->priv = NULL;
++	kfree(h4);
++	return 0;
++}
++
++/* Enqueue frame for transmittion (padding, crc, etc) */
++static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
++{
++	struct h4_struct *h4 = hu->priv;
++
++	BT_DBG("hu %p skb %p", hu, skb);
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
++	skb_queue_tail(&h4->txq, skb);
++	return 0;
++}
++
++static inline int h4_check_data_len(struct h4_struct *h4, int len)
++{
++	register int room = skb_tailroom(h4->rx_skb);
++
++	BT_DBG("len %d room %d", len, room);
++	if (!len) {
++		BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
++		hci_recv_frame(h4->rx_skb);
++	} else if (len > room) {
++		BT_ERR("Data length is too large");
++		kfree_skb(h4->rx_skb);
++	} else {
++		h4->rx_state = H4_W4_DATA;
++		h4->rx_count = len;
++		return len;
++	}
++
++	h4->rx_state = H4_W4_PACKET_TYPE;
++	h4->rx_skb   = NULL;
++	h4->rx_count = 0;
++	return 0;
++}
++
++/* Recv data */
++static int h4_recv(struct hci_uart *hu, void *data, int count)
++{
++	struct h4_struct *h4 = hu->priv;
++	register char *ptr;
++	hci_event_hdr *eh;
++	hci_acl_hdr   *ah;
++	hci_sco_hdr   *sh;
++	register int len, type, dlen;
++
++	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
++			hu, count, h4->rx_state, h4->rx_count);
++
++	ptr = data;
++	while (count) {
++		if (h4->rx_count) {
++			len = MIN(h4->rx_count, count);
++			memcpy(skb_put(h4->rx_skb, len), ptr, len);
++			h4->rx_count -= len; count -= len; ptr += len;
++
++			if (h4->rx_count)
++				continue;
++
++			switch (h4->rx_state) {
++			case H4_W4_DATA:
++				BT_DBG("Complete data");
++
++				BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
++
++				hci_recv_frame(h4->rx_skb);
++
++				h4->rx_state = H4_W4_PACKET_TYPE;
++				h4->rx_skb = NULL;
++				continue;
++
++			case H4_W4_EVENT_HDR:
++				eh = (hci_event_hdr *) h4->rx_skb->data;
++
++				BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
++
++				h4_check_data_len(h4, eh->plen);
++				continue;
++
++			case H4_W4_ACL_HDR:
++				ah = (hci_acl_hdr *) h4->rx_skb->data;
++				dlen = __le16_to_cpu(ah->dlen);
++
++				BT_DBG("ACL header: dlen %d", dlen);
++
++				h4_check_data_len(h4, dlen);
++				continue;
++
++			case H4_W4_SCO_HDR:
++				sh = (hci_sco_hdr *) h4->rx_skb->data;
++
++				BT_DBG("SCO header: dlen %d", sh->dlen);
++
++				h4_check_data_len(h4, sh->dlen);
++				continue;
++			}
++		}
++
++		/* H4_W4_PACKET_TYPE */
++		switch (*ptr) {
++		case HCI_EVENT_PKT:
++			BT_DBG("Event packet");
++			h4->rx_state = H4_W4_EVENT_HDR;
++			h4->rx_count = HCI_EVENT_HDR_SIZE;
++			type = HCI_EVENT_PKT;
++			break;
++
++		case HCI_ACLDATA_PKT:
++			BT_DBG("ACL packet");
++			h4->rx_state = H4_W4_ACL_HDR;
++			h4->rx_count = HCI_ACL_HDR_SIZE;
++			type = HCI_ACLDATA_PKT;
++			break;
++
++		case HCI_SCODATA_PKT:
++			BT_DBG("SCO packet");
++			h4->rx_state = H4_W4_SCO_HDR;
++			h4->rx_count = HCI_SCO_HDR_SIZE;
++			type = HCI_SCODATA_PKT;
++			break;
++
++		default:
++			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
++			hu->hdev.stat.err_rx++;
++			ptr++; count--;
++			continue;
++		};
++		ptr++; count--;
++
++		/* Allocate packet */
++		h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
++		if (!h4->rx_skb) {
++			BT_ERR("Can't allocate mem for new packet");
++			h4->rx_state = H4_W4_PACKET_TYPE;
++			h4->rx_count = 0;
++			return 0;
++		}
++		h4->rx_skb->dev = (void *) &hu->hdev;
++		h4->rx_skb->pkt_type = type;
++	}
++	return count;
++}
++
++static struct sk_buff *h4_dequeue(struct hci_uart *hu)
++{
++	struct h4_struct *h4 = hu->priv;
++	return skb_dequeue(&h4->txq);
++}
++
++static struct hci_uart_proto h4p = {
++	id:      HCI_UART_H4,
++	open:    h4_open,
++	close:   h4_close,
++	recv:    h4_recv,
++	enqueue: h4_enqueue,
++	dequeue: h4_dequeue,
++	flush:   h4_flush,
++};
++	      
++int h4_init(void)
++{
++	return hci_uart_register_proto(&h4p);
++}
++
++int h4_deinit(void)
++{
++	return hci_uart_unregister_proto(&h4p);
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_h4.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,44 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifdef __KERNEL__
++struct h4_struct {
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++	struct sk_buff_head txq;
++};
++
++/* H4 receiver States */
++#define H4_W4_PACKET_TYPE 0
++#define H4_W4_EVENT_HDR	  1
++#define H4_W4_ACL_HDR     2
++#define H4_W4_SCO_HDR     3
++#define H4_W4_DATA        4
++
++#endif /* __KERNEL__ */
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_ldisc.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,580 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ HCI UART driver.
++ *
++ * $Id$    
++ */
++#define VERSION "2.1"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/poll.h>
++
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/signal.h>
++#include <linux/ioctl.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include "hci_uart.h"
++
++#ifndef HCI_UART_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
++#endif
++
++static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
++
++int hci_uart_register_proto(struct hci_uart_proto *p)
++{
++	if (p->id >= HCI_UART_MAX_PROTO)
++		return -EINVAL;
++
++	if (hup[p->id])
++		return -EEXIST;
++
++	hup[p->id] = p;
++	return 0;
++}
++
++int hci_uart_unregister_proto(struct hci_uart_proto *p)
++{
++	if (p->id >= HCI_UART_MAX_PROTO)
++		return -EINVAL;
++
++	if (!hup[p->id])
++		return -EINVAL;
++
++	hup[p->id] = NULL;
++	return 0;
++}
++
++static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
++{
++	if (id >= HCI_UART_MAX_PROTO)
++		return NULL;
++	return hup[id];
++}
++
++static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
++{
++	struct hci_dev *hdev = &hu->hdev;
++	
++	/* Update HCI stat counters */
++	switch (pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++
++	case HCI_SCODATA_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	}
++}
++
++static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
++{
++	struct sk_buff *skb = hu->tx_skb;
++	if (!skb)
++		skb = hu->proto->dequeue(hu);
++	else
++		hu->tx_skb = NULL;
++	return skb;
++}
++
++int hci_uart_tx_wakeup(struct hci_uart *hu)
++{
++	struct tty_struct *tty = hu->tty;
++	struct hci_dev *hdev = &hu->hdev;
++	struct sk_buff *skb;
++	
++	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
++		set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
++		return 0;
++	}
++
++	BT_DBG("");
++
++restart:
++	clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
++
++	while ((skb = hci_uart_dequeue(hu))) {
++		int len;
++	
++		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
++		len = tty->driver.write(tty, 0, skb->data, skb->len);
++		hdev->stat.byte_tx += len;
++
++		skb_pull(skb, len);
++		if (skb->len) {
++			hu->tx_skb = skb;
++			break;
++		}
++	
++		hci_uart_tx_complete(hu, skb->pkt_type);
++		kfree_skb(skb);
++	} 
++	
++	if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
++		goto restart;
++
++	clear_bit(HCI_UART_SENDING, &hu->tx_state);
++	return 0;
++}
++
++/* ------- Interface to HCI layer ------ */
++/* Initialize device */
++static int hci_uart_open(struct hci_dev *hdev)
++{
++	BT_DBG("%s %p", hdev->name, hdev);
++
++	/* Nothing to do for UART driver */
++
++	set_bit(HCI_RUNNING, &hdev->flags);
++	return 0;
++}
++
++/* Reset device */
++static int hci_uart_flush(struct hci_dev *hdev)
++{
++	struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
++	struct tty_struct *tty = hu->tty;
++
++	BT_DBG("hdev %p tty %p", hdev, tty);
++
++	if (hu->tx_skb) {
++		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
++	}
++
++	/* Flush any pending characters in the driver and discipline. */
++	if (tty->ldisc.flush_buffer)
++		tty->ldisc.flush_buffer(tty);
++
++	if (tty->driver.flush_buffer)
++		tty->driver.flush_buffer(tty);
++
++	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
++		hu->proto->flush(hu);
++
++	return 0;
++}
++
++/* Close device */
++static int hci_uart_close(struct hci_dev *hdev)
++{
++	BT_DBG("hdev %p", hdev);
++
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
++	hci_uart_flush(hdev);
++	return 0;
++}
++
++/* Send frames from HCI layer */
++static int hci_uart_send_frame(struct sk_buff *skb)
++{
++	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
++	struct tty_struct *tty;
++	struct hci_uart *hu;
++
++	if (!hdev) {
++		BT_ERR("Frame for uknown device (hdev=NULL)");
++		return -ENODEV;
++	}
++
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return -EBUSY;
++
++	hu = (struct hci_uart *) hdev->driver_data;
++	tty = hu->tty;
++
++	BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
++
++	hu->proto->enqueue(hu, skb);
++
++	hci_uart_tx_wakeup(hu);
++	return 0;
++}
++
++static void hci_uart_destruct(struct hci_dev *hdev)
++{
++	struct hci_uart *hu;
++
++	if (!hdev) return;
++
++	BT_DBG("%s", hdev->name);
++
++	hu = (struct hci_uart *) hdev->driver_data;
++	kfree(hu);
++
++	MOD_DEC_USE_COUNT;
++}
++
++/* ------ LDISC part ------ */
++/* hci_uart_tty_open
++ * 
++ *     Called when line discipline changed to HCI_UART.
++ *
++ * Arguments:
++ *     tty    pointer to tty info structure
++ * Return Value:    
++ *     0 if success, otherwise error code
++ */
++static int hci_uart_tty_open(struct tty_struct *tty)
++{
++	struct hci_uart *hu = (void *) tty->disc_data;
++
++	BT_DBG("tty %p", tty);
++
++	if (hu)
++		return -EEXIST;
++
++	if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
++		BT_ERR("Can't allocate controll structure");
++		return -ENFILE;
++	}
++	memset(hu, 0, sizeof(struct hci_uart));
++
++	tty->disc_data = hu;
++	hu->tty = tty;
++
++	spin_lock_init(&hu->rx_lock);
++
++	/* Flush any pending characters in the driver and line discipline */
++	if (tty->ldisc.flush_buffer)
++		tty->ldisc.flush_buffer(tty);
++
++	if (tty->driver.flush_buffer)
++		tty->driver.flush_buffer(tty);
++	
++	MOD_INC_USE_COUNT;
++	return 0;
++}
++
++/* hci_uart_tty_close()
++ *
++ *    Called when the line discipline is changed to something
++ *    else, the tty is closed, or the tty detects a hangup.
++ */
++static void hci_uart_tty_close(struct tty_struct *tty)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++
++	BT_DBG("tty %p", tty);
++
++	/* Detach from the tty */
++	tty->disc_data = NULL;
++
++	if (hu) {
++		struct hci_dev *hdev = &hu->hdev;
++		hci_uart_close(hdev);
++
++		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
++			hu->proto->close(hu);
++			hci_unregister_dev(hdev);
++		}
++
++		MOD_DEC_USE_COUNT;
++	}
++}
++
++/* hci_uart_tty_wakeup()
++ *
++ *    Callback for transmit wakeup. Called when low level
++ *    device driver can accept more send data.
++ *
++ * Arguments:        tty    pointer to associated tty instance data
++ * Return Value:    None
++ */
++static void hci_uart_tty_wakeup(struct tty_struct *tty)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++
++	BT_DBG("");
++
++	if (!hu)
++		return;
++
++	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
++
++	if (tty != hu->tty)
++		return;
++
++	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
++		hci_uart_tx_wakeup(hu);
++}
++
++/* hci_uart_tty_room()
++ * 
++ *    Callback function from tty driver. Return the amount of 
++ *    space left in the receiver's buffer to decide if remote
++ *    transmitter is to be throttled.
++ *
++ * Arguments:        tty    pointer to associated tty instance data
++ * Return Value:    number of bytes left in receive buffer
++ */
++static int hci_uart_tty_room (struct tty_struct *tty)
++{
++	return 65536;
++}
++
++/* hci_uart_tty_receive()
++ * 
++ *     Called by tty low level driver when receive data is
++ *     available.
++ *     
++ * Arguments:  tty          pointer to tty isntance data
++ *             data         pointer to received data
++ *             flags        pointer to flags for data
++ *             count        count of received data in bytes
++ *     
++ * Return Value:    None
++ */
++static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++	
++	if (!hu || tty != hu->tty)
++		return;
++
++	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
++		return;
++	
++	spin_lock(&hu->rx_lock);
++	hu->proto->recv(hu, (void *) data, count);
++	hu->hdev.stat.byte_rx += count;
++	spin_unlock(&hu->rx_lock);
++
++	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
++		tty->driver.unthrottle(tty);
++}
++
++static int hci_uart_register_dev(struct hci_uart *hu)
++{
++	struct hci_dev *hdev;
++
++	BT_DBG("");
++
++	/* Initialize and register HCI device */
++	hdev = &hu->hdev;
++
++	hdev->type = HCI_UART;
++	hdev->driver_data = hu;
++
++	hdev->open  = hci_uart_open;
++	hdev->close = hci_uart_close;
++	hdev->flush = hci_uart_flush;
++	hdev->send  = hci_uart_send_frame;
++	hdev->destruct = hci_uart_destruct;
++
++	if (hci_register_dev(hdev) < 0) {
++		BT_ERR("Can't register HCI device %s", hdev->name);
++		return -ENODEV;
++	}
++	MOD_INC_USE_COUNT;
++	return 0;
++}
++
++static int hci_uart_set_proto(struct hci_uart *hu, int id)
++{
++	struct hci_uart_proto *p;
++	int err;	
++	
++	p = hci_uart_get_proto(id);
++	if (!p)
++		return -EPROTONOSUPPORT;
++
++	err = p->open(hu);
++	if (err)
++		return err;
++
++	hu->proto = p;
++
++	err = hci_uart_register_dev(hu);
++	if (err) {
++		p->close(hu);
++		return err;
++	}
++	return 0;
++}
++
++/* hci_uart_tty_ioctl()
++ *
++ *    Process IOCTL system call for the tty device.
++ *
++ * Arguments:
++ *
++ *    tty        pointer to tty instance data
++ *    file       pointer to open file object for device
++ *    cmd        IOCTL command code
++ *    arg        argument for IOCTL call (cmd dependent)
++ *
++ * Return Value:    Command dependent
++ */
++static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
++                            unsigned int cmd, unsigned long arg)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++	int err = 0;
++
++	BT_DBG("");
++
++	/* Verify the status of the device */
++	if (!hu)
++		return -EBADF;
++
++	switch (cmd) {
++	case HCIUARTSETPROTO:
++		if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
++			err = hci_uart_set_proto(hu, arg);
++			if (err) {
++				clear_bit(HCI_UART_PROTO_SET, &hu->flags);
++				return err;
++			}
++			tty->low_latency = 1;
++		} else	
++			return -EBUSY;
++
++	case HCIUARTGETPROTO:
++		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
++			return hu->proto->id;
++		return -EUNATCH;
++		
++	default:
++		err = n_tty_ioctl(tty, file, cmd, arg);
++		break;
++	};
++
++	return err;
++}
++
++/*
++ * We don't provide read/write/poll interface for user space.
++ */
++static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
++{
++	return 0;
++}
++static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
++{
++	return 0;
++}
++static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
++{
++	return 0;
++}
++
++#ifdef CONFIG_BLUEZ_HCIUART_H4
++int h4_init(void);
++int h4_deinit(void);
++#endif
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP
++int bcsp_init(void);
++int bcsp_deinit(void);
++#endif
++
++int __init hci_uart_init(void)
++{
++	static struct tty_ldisc hci_uart_ldisc;
++	int err;
++
++	BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
++		VERSION);
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++
++	/* Register the tty discipline */
++
++	memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
++	hci_uart_ldisc.magic       = TTY_LDISC_MAGIC;
++	hci_uart_ldisc.name        = "n_hci";
++	hci_uart_ldisc.open        = hci_uart_tty_open;
++	hci_uart_ldisc.close       = hci_uart_tty_close;
++	hci_uart_ldisc.read        = hci_uart_tty_read;
++	hci_uart_ldisc.write       = hci_uart_tty_write;
++	hci_uart_ldisc.ioctl       = hci_uart_tty_ioctl;
++	hci_uart_ldisc.poll        = hci_uart_tty_poll;
++	hci_uart_ldisc.receive_room= hci_uart_tty_room;
++	hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
++	hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
++
++	if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
++		BT_ERR("Can't register HCI line discipline (%d)", err);
++		return err;
++	}
++
++#ifdef CONFIG_BLUEZ_HCIUART_H4
++	h4_init();
++#endif
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP
++	bcsp_init();
++#endif
++	
++	return 0;
++}
++
++void hci_uart_cleanup(void)
++{
++	int err;
++
++#ifdef CONFIG_BLUEZ_HCIUART_H4
++	h4_deinit();
++#endif
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP
++	bcsp_deinit();
++#endif
++
++	/* Release tty registration of line discipline */
++	if ((err = tty_register_ldisc(N_HCI, NULL)))
++		BT_ERR("Can't unregister HCI line discipline (%d)", err);
++}
++
++module_init(hci_uart_init);
++module_exit(hci_uart_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
++MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
++MODULE_LICENSE("GPL");
+--- linux/drivers/bluetooth/hci_uart.c~bluetooth-2.4.18-mh11
++++ linux/drivers/bluetooth/hci_uart.c
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * BlueZ HCI UART driver.
+- *
+- * $Id$    
+- */
+-#define VERSION "1.0"
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-
+-#include <linux/version.h>
+-#include <linux/config.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/sched.h>
+-#include <linux/types.h>
+-#include <linux/fcntl.h>
+-#include <linux/interrupt.h>
+-#include <linux/ptrace.h>
+-#include <linux/poll.h>
+-
+-#include <linux/slab.h>
+-#include <linux/tty.h>
+-#include <linux/errno.h>
+-#include <linux/string.h>
+-#include <linux/signal.h>
+-#include <linux/ioctl.h>
+-#include <linux/skbuff.h>
+-
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci_uart.h>
+-
+-#ifndef HCI_UART_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#undef  DMP
+-#define DMP( A... )
+-#endif
+-
+-/* ------- Interface to HCI layer ------ */
+-/* Initialize device */
+-int n_hci_open(struct hci_dev *hdev)
+-{
+-	DBG("%s %p", hdev->name, hdev);
+-
+-	/* Nothing to do for UART driver */
+-
+-	hdev->flags |= HCI_RUNNING;
+-
+-	return 0;
+-}
+-
+-/* Reset device */
+-int n_hci_flush(struct hci_dev *hdev)
+-{
+-	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
+-	struct tty_struct *tty = n_hci->tty;
+-
+-	DBG("hdev %p tty %p", hdev, tty);
+-
+-	/* Drop TX queue */
+-	skb_queue_purge(&n_hci->txq);
+-
+-	/* Flush any pending characters in the driver and discipline. */
+-	if (tty->ldisc.flush_buffer)
+-		tty->ldisc.flush_buffer(tty);
+-
+-	if (tty->driver.flush_buffer)
+-		tty->driver.flush_buffer(tty);
+-
+-	return 0;
+-}
+-
+-/* Close device */
+-int n_hci_close(struct hci_dev *hdev)
+-{
+-	DBG("hdev %p", hdev);
+-
+-	hdev->flags &= ~HCI_RUNNING;
+-
+-	n_hci_flush(hdev);
+-
+-	return 0;
+-}
+-
+-int n_hci_tx_wakeup(struct n_hci *n_hci)
+-{
+-	register struct tty_struct *tty = n_hci->tty;
+-
+-	if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) {
+-		set_bit(TRANS_WAKEUP, &n_hci->tx_state);
+-		return 0;
+-	}
+-
+-	DBG("");
+-	do {
+-		register struct sk_buff *skb;
+-		register int len;
+-
+-		clear_bit(TRANS_WAKEUP, &n_hci->tx_state);
+-
+-		if (!(skb = skb_dequeue(&n_hci->txq)))
+-			break;
+-
+-		DMP(skb->data, skb->len);
+-
+-		/* Send frame to TTY driver */
+-		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+-		len = tty->driver.write(tty, 0, skb->data, skb->len);
+-
+-		n_hci->hdev.stat.byte_tx += len;
+-
+-		DBG("sent %d", len);
+-
+-		if (len == skb->len) {
+-			/* Full frame was sent */
+-			kfree_skb(skb);
+-		} else {
+-			/* Subtract sent part and requeue  */
+-			skb_pull(skb, len);
+-			skb_queue_head(&n_hci->txq, skb);
+-		}
+-	} while (test_bit(TRANS_WAKEUP, &n_hci->tx_state));
+-	clear_bit(TRANS_SENDING, &n_hci->tx_state);
+-
+-	return 0;
+-}
+-
+-/* Send frames from HCI layer */
+-int n_hci_send_frame(struct sk_buff *skb)
+-{
+-	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+-	struct tty_struct *tty;
+-	struct n_hci *n_hci;
+-
+-	if (!hdev) {
+-		ERR("Frame for uknown device (hdev=NULL)");
+-		return -ENODEV;
+-	}
+-
+-	if (!(hdev->flags & HCI_RUNNING))
+-		return -EBUSY;
+-
+-	n_hci = (struct n_hci *) hdev->driver_data;
+-	tty = n_hci2tty(n_hci);
+-
+-	DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
+-
+-	switch (skb->pkt_type) {
+-		case HCI_COMMAND_PKT:
+-			hdev->stat.cmd_tx++;
+-			break;
+-
+-                case HCI_ACLDATA_PKT:
+-			hdev->stat.acl_tx++;
+-                        break;
+-
+-		case HCI_SCODATA_PKT:
+-			hdev->stat.cmd_tx++;
+-                        break;
+-	};
+-
+-	/* Prepend skb with frame type and queue */
+-	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
+-	skb_queue_tail(&n_hci->txq, skb);
+-
+-	n_hci_tx_wakeup(n_hci);
+-
+-	return 0;
+-}
+-
+-/* ------ LDISC part ------ */
+-
+-/* n_hci_tty_open
+- * 
+- *     Called when line discipline changed to N_HCI.
+- *     
+- * Arguments:    
+- *     tty    pointer to tty info structure
+- * Return Value:    
+- *     0 if success, otherwise error code
+- */
+-static int n_hci_tty_open(struct tty_struct *tty)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-	struct hci_dev *hdev;
+-
+-	DBG("tty %p", tty);
+-
+-	if (n_hci)
+-		return -EEXIST;
+-
+-	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
+-		ERR("Can't allocate controll structure");
+-		return -ENFILE;
+-	}
+-	memset(n_hci, 0, sizeof(struct n_hci));
+-
+-	/* Initialize and register HCI device */
+-	hdev = &n_hci->hdev;
+-
+-	hdev->type = HCI_UART;
+-	hdev->driver_data = n_hci;
+-
+-	hdev->open  = n_hci_open;
+-	hdev->close = n_hci_close;
+-	hdev->flush = n_hci_flush;
+-	hdev->send  = n_hci_send_frame;
+-
+-	if (hci_register_dev(hdev) < 0) {
+-		ERR("Can't register HCI device %s", hdev->name);
+-		kfree(n_hci);
+-		return -ENODEV;
+-	}
+-
+-	tty->disc_data = n_hci;
+-	n_hci->tty = tty;
+-
+-	spin_lock_init(&n_hci->rx_lock);
+-	n_hci->rx_state = WAIT_PACKET_TYPE;
+-
+-	skb_queue_head_init(&n_hci->txq);
+-
+-	MOD_INC_USE_COUNT;
+-
+-	/* Flush any pending characters in the driver and discipline. */
+-	if (tty->ldisc.flush_buffer)
+-		tty->ldisc.flush_buffer(tty);
+-
+-	if (tty->driver.flush_buffer)
+-		tty->driver.flush_buffer(tty);
+-
+-	return 0;
+-}
+-
+-/* n_hci_tty_close()
+- *
+- *    Called when the line discipline is changed to something
+- *    else, the tty is closed, or the tty detects a hangup.
+- */
+-static void n_hci_tty_close(struct tty_struct *tty)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-	struct hci_dev *hdev = &n_hci->hdev;
+-
+-	DBG("tty %p hdev %p", tty, hdev);
+-
+-	if (n_hci != NULL) {
+-		n_hci_close(hdev);
+-
+-		if (hci_unregister_dev(hdev) < 0) {
+-			ERR("Can't unregister HCI device %s",hdev->name);
+-		}
+-
+-		hdev->driver_data = NULL;
+-		tty->disc_data = NULL;
+-		kfree(n_hci);
+-
+-		MOD_DEC_USE_COUNT;
+-	}
+-}
+-
+-/* n_hci_tty_wakeup()
+- *
+- *    Callback for transmit wakeup. Called when low level
+- *    device driver can accept more send data.
+- *
+- * Arguments:        tty    pointer to associated tty instance data
+- * Return Value:    None
+- */
+-static void n_hci_tty_wakeup( struct tty_struct *tty )
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-
+-	DBG("");
+-
+-	if (!n_hci)
+-		return;
+-
+-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+-
+-	if (tty != n_hci->tty)
+-		return;
+-
+-	n_hci_tx_wakeup(n_hci);
+-}
+-
+-/* n_hci_tty_room()
+- * 
+- *    Callback function from tty driver. Return the amount of 
+- *    space left in the receiver's buffer to decide if remote
+- *    transmitter is to be throttled.
+- *
+- * Arguments:        tty    pointer to associated tty instance data
+- * Return Value:    number of bytes left in receive buffer
+- */
+-static int n_hci_tty_room (struct tty_struct *tty)
+-{
+-	return 65536;
+-}
+-
+-static inline int n_hci_check_data_len(struct n_hci *n_hci, int len)
+-{
+-	register int room = skb_tailroom(n_hci->rx_skb);
+-
+-	DBG("len %d room %d", len, room);
+-	if (!len) {
+-		DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
+-		hci_recv_frame(n_hci->rx_skb);
+-	} else if (len > room) {
+-		ERR("Data length is to large");
+-		kfree_skb(n_hci->rx_skb);
+-		n_hci->hdev.stat.err_rx++;
+-	} else {
+-		n_hci->rx_state = WAIT_DATA;
+-		n_hci->rx_count = len;
+-		return len;
+-	}
+-
+-	n_hci->rx_state = WAIT_PACKET_TYPE;
+-	n_hci->rx_skb   = NULL;
+-	n_hci->rx_count = 0;
+-	return 0;
+-}
+-
+-static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
+-{
+-	register const char *ptr;
+-	hci_event_hdr *eh;
+-	hci_acl_hdr   *ah;
+-	hci_sco_hdr   *sh;
+-	register int len, type, dlen;
+-
+-	DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count);
+-
+-	n_hci->hdev.stat.byte_rx += count;
+-
+-	ptr = data;
+-	while (count) {
+-		if (n_hci->rx_count) {
+-			len = MIN(n_hci->rx_count, count);
+-			memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
+-			n_hci->rx_count -= len; count -= len; ptr += len;
+-
+-			if (n_hci->rx_count)
+-				continue;
+-
+-			switch (n_hci->rx_state) {
+-				case WAIT_DATA:
+-					DBG("Complete data");
+-
+-					DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
+-
+-					hci_recv_frame(n_hci->rx_skb);
+-
+-					n_hci->rx_state = WAIT_PACKET_TYPE;
+-					n_hci->rx_skb = NULL;
+-					continue;
+-
+-				case WAIT_EVENT_HDR:
+-					eh = (hci_event_hdr *) n_hci->rx_skb->data;
+-
+-					DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+-
+-					n_hci_check_data_len(n_hci, eh->plen);
+-					continue;
+-
+-				case WAIT_ACL_HDR:
+-					ah = (hci_acl_hdr *) n_hci->rx_skb->data;
+-					dlen = __le16_to_cpu(ah->dlen);
+-
+-					DBG("ACL header: dlen %d", dlen);
+-
+-					n_hci_check_data_len(n_hci, dlen);
+-					continue;
+-
+-				case WAIT_SCO_HDR:
+-					sh = (hci_sco_hdr *) n_hci->rx_skb->data;
+-
+-					DBG("SCO header: dlen %d", sh->dlen);
+-
+-					n_hci_check_data_len(n_hci, sh->dlen);
+-					continue;
+-			};
+-		}
+-
+-		/* WAIT_PACKET_TYPE */
+-		switch (*ptr) {
+-			case HCI_EVENT_PKT:
+-				DBG("Event packet");
+-				n_hci->rx_state = WAIT_EVENT_HDR;
+-				n_hci->rx_count = HCI_EVENT_HDR_SIZE;
+-				type = HCI_EVENT_PKT;
+-				break;
+-
+-			case HCI_ACLDATA_PKT:
+-				DBG("ACL packet");
+-				n_hci->rx_state = WAIT_ACL_HDR;
+-				n_hci->rx_count = HCI_ACL_HDR_SIZE;
+-				type = HCI_ACLDATA_PKT;
+-				break;
+-
+-			case HCI_SCODATA_PKT:
+-				DBG("SCO packet");
+-				n_hci->rx_state = WAIT_SCO_HDR;
+-				n_hci->rx_count = HCI_SCO_HDR_SIZE;
+-				type = HCI_SCODATA_PKT;
+-				break;
+-
+-			default:
+-				ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+-				n_hci->hdev.stat.err_rx++;
+-				ptr++; count--;
+-				continue;
+-		};
+-		ptr++; count--;
+-
+-		/* Allocate packet */
+-		if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+-			ERR("Can't allocate mem for new packet");
+-
+-			n_hci->rx_state = WAIT_PACKET_TYPE;
+-			n_hci->rx_count = 0;
+-			return;
+-		}
+-		n_hci->rx_skb->dev = (void *) &n_hci->hdev;
+-		n_hci->rx_skb->pkt_type = type;
+-	}
+-}
+-
+-/* n_hci_tty_receive()
+- * 
+- *     Called by tty low level driver when receive data is
+- *     available.
+- *     
+- * Arguments:  tty          pointer to tty isntance data
+- *             data         pointer to received data
+- *             flags        pointer to flags for data
+- *             count        count of received data in bytes
+- *     
+- * Return Value:    None
+- */
+-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-
+-	if (!n_hci || tty != n_hci->tty)
+-		return;
+-
+-	spin_lock(&n_hci->rx_lock);
+-	n_hci_rx(n_hci, data, flags, count);
+-	spin_unlock(&n_hci->rx_lock);
+-
+-	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
+-		tty->driver.unthrottle(tty);
+-}
+-
+-/* n_hci_tty_ioctl()
+- *
+- *    Process IOCTL system call for the tty device.
+- *
+- * Arguments:
+- *
+- *    tty        pointer to tty instance data
+- *    file       pointer to open file object for device
+- *    cmd        IOCTL command code
+- *    arg        argument for IOCTL call (cmd dependent)
+- *
+- * Return Value:    Command dependent
+- */
+-static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file,
+-                            unsigned int cmd, unsigned long arg)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-	int error = 0;
+-
+-	DBG("");
+-
+-	/* Verify the status of the device */
+-	if (!n_hci)
+-		return -EBADF;
+-
+-	switch (cmd) {
+-		default:
+-			error = n_tty_ioctl(tty, file, cmd, arg);
+-			break;
+-	};
+-
+-	return error;
+-}
+-
+-/*
+- * We don't provide read/write/poll interface for user space.
+- */
+-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
+-{
+-	return 0;
+-}
+-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
+-{
+-	return 0;
+-}
+-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
+-{
+-	return 0;
+-}
+-
+-int __init n_hci_init(void)
+-{
+-	static struct tty_ldisc n_hci_ldisc;
+-	int err;
+-
+-	INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
+-		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+-
+-	/* Register the tty discipline */
+-
+-	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
+-	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
+-	n_hci_ldisc.name        = "n_hci";
+-	n_hci_ldisc.open        = n_hci_tty_open;
+-	n_hci_ldisc.close       = n_hci_tty_close;
+-	n_hci_ldisc.read        = n_hci_tty_read;
+-	n_hci_ldisc.write       = n_hci_tty_write;
+-	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
+-	n_hci_ldisc.poll        = n_hci_tty_poll;
+-	n_hci_ldisc.receive_room= n_hci_tty_room;
+-	n_hci_ldisc.receive_buf = n_hci_tty_receive;
+-	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
+-
+-	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
+-		ERR("Can't register HCI line discipline (%d)", err);
+-		return err;
+-	}
+-
+-	return 0;
+-}
+-
+-void n_hci_cleanup(void)
+-{
+-	int err;
+-
+-	/* Release tty registration of line discipline */
+-	if ((err = tty_register_ldisc(N_HCI, NULL)))
+-		ERR("Can't unregister HCI line discipline (%d)", err);
+-}
+-
+-module_init(n_hci_init);
+-module_exit(n_hci_cleanup);
+-
+-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+-MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
+-MODULE_LICENSE("GPL");
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_uart.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,81 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef N_HCI 
++#define N_HCI	15
++#endif
++
++/* Ioctls */
++#define HCIUARTSETPROTO	_IOW('U', 200, int)
++#define HCIUARTGETPROTO	_IOR('U', 201, int)
++
++/* UART protocols */
++#define HCI_UART_MAX_PROTO	3
++
++#define HCI_UART_H4	0
++#define HCI_UART_BCSP	1
++#define HCI_UART_NCSP	2
++
++#ifdef __KERNEL__
++struct hci_uart;
++
++struct hci_uart_proto {
++	unsigned int id;
++	int (*open)(struct hci_uart *hu);
++	int (*close)(struct hci_uart *hu);
++	int (*flush)(struct hci_uart *hu);
++	int (*recv)(struct hci_uart *hu, void *data, int len);
++	int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
++	struct sk_buff *(*dequeue)(struct hci_uart *hu);
++};
++
++struct hci_uart {
++	struct tty_struct  *tty;
++	struct hci_dev     hdev;
++	unsigned long      flags;
++
++	struct hci_uart_proto *proto;
++	void               *priv;
++	
++	struct sk_buff     *tx_skb;
++	unsigned long      tx_state;
++	spinlock_t         rx_lock;
++};
++
++/* HCI_UART flag bits */
++#define HCI_UART_PROTO_SET		0
++
++/* TX states  */
++#define HCI_UART_SENDING		1
++#define HCI_UART_TX_WAKEUP		2
++
++int hci_uart_register_proto(struct hci_uart_proto *p);
++int hci_uart_unregister_proto(struct hci_uart_proto *p);
++int hci_uart_tx_wakeup(struct hci_uart *hu);
++
++#endif /* __KERNEL__ */
+--- linux/drivers/bluetooth/hci_usb.c~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/drivers/bluetooth/hci_usb.c	2004-01-25 23:37:39.000000000 +0100
+@@ -1,9 +1,10 @@
+ /* 
+-   BlueZ - Bluetooth protocol stack for Linux
++   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
+    Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+ 
++   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
++
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as
+    published by the Free Software Foundation;
+@@ -23,598 +24,914 @@
+ */
+ 
+ /*
+- * BlueZ HCI USB driver.
+  * Based on original USB Bluetooth driver for Linux kernel
+  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
+  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
+  *
+- * $Id$    
++ * $Id$    
+  */
+-#define VERSION "1.0"
++#define VERSION "2.4"
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
+ 
+ #include <linux/version.h>
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/sched.h>
++#include <linux/unistd.h>
+ #include <linux/types.h>
+-#include <linux/fcntl.h>
+ #include <linux/interrupt.h>
+-#include <linux/ptrace.h>
+-#include <linux/poll.h>
+ 
+ #include <linux/slab.h>
+-#include <linux/tty.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+-#include <linux/signal.h>
+-#include <linux/ioctl.h>
+ #include <linux/skbuff.h>
+ 
+ #include <linux/usb.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci_usb.h>
++
++#include "hci_usb.h"
+ 
+ #ifndef HCI_USB_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#undef  DMP
+-#define DMP( A... )
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
+ #endif
+ 
+-static struct usb_device_id usb_bluetooth_ids [] = {
++#ifndef CONFIG_BLUEZ_HCIUSB_ZERO_PACKET
++#undef  USB_ZERO_PACKET
++#define USB_ZERO_PACKET 0
++#endif
++
++static struct usb_driver hci_usb_driver; 
++
++static struct usb_device_id bluetooth_ids[] = {
++	/* Digianswer device */
++	{ USB_DEVICE(0x08fd, 0x0001), driver_info: HCI_DIGIANSWER },
++
++	/* Generic Bluetooth USB device */
+ 	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
++
++	/* Ericsson with non-standard id */
++	{ USB_DEVICE(0x0bdb, 0x1002) },
++
++	/* ALPS Module with non-standard id */
++	{ USB_DEVICE(0x044e, 0x3002) },
++
++	/* Bluetooth Ultraport Module from IBM */
++	{ USB_DEVICE(0x04bf, 0x030a) },
++
+ 	{ }	/* Terminating entry */
+ };
+ 
+-MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
++MODULE_DEVICE_TABLE (usb, bluetooth_ids);
+ 
+-static int hci_usb_ctrl_msg(struct hci_usb *husb,  struct sk_buff *skb);
+-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb);
++static struct usb_device_id ignore_ids[] = {
++	/* Broadcom BCM2033 without firmware */
++	{ USB_DEVICE(0x0a5c, 0x2033) },
+ 
+-static void hci_usb_unlink_urbs(struct hci_usb *husb)
+-{
+-	usb_unlink_urb(husb->read_urb);
+-	usb_unlink_urb(husb->intr_urb);
+-	usb_unlink_urb(husb->ctrl_urb);
+-	usb_unlink_urb(husb->write_urb);
+-}
++	{ }	/* Terminating entry */
++};
+ 
+-static void hci_usb_free_bufs(struct hci_usb *husb)
++struct _urb *_urb_alloc(int isoc, int gfp)
+ {
+-	if (husb->read_urb) {
+-		if (husb->read_urb->transfer_buffer)
+-			kfree(husb->read_urb->transfer_buffer);
+-		usb_free_urb(husb->read_urb);
++	struct _urb *_urb = kmalloc(sizeof(struct _urb) +
++				sizeof(iso_packet_descriptor_t) * isoc, gfp);
++	if (_urb) {
++		memset(_urb, 0, sizeof(*_urb));
++		spin_lock_init(&_urb->urb.lock);
+ 	}
++	return _urb;
++}
+ 
+-	if (husb->intr_urb) {
+-		if (husb->intr_urb->transfer_buffer)
+-			kfree(husb->intr_urb->transfer_buffer);
+-		usb_free_urb(husb->intr_urb);
++struct _urb *_urb_dequeue(struct _urb_queue *q)
++{
++	struct _urb *_urb = NULL;
++        unsigned long flags;
++        spin_lock_irqsave(&q->lock, flags);
++	{
++		struct list_head *head = &q->head;
++		struct list_head *next = head->next;
++		if (next != head) {
++			_urb = list_entry(next, struct _urb, list);
++			list_del(next); _urb->queue = NULL;
++		}
+ 	}
++	spin_unlock_irqrestore(&q->lock, flags);
++	return _urb;
++}
+ 
+-	if (husb->ctrl_urb)
+-		usb_free_urb(husb->ctrl_urb);
++static void hci_usb_rx_complete(struct urb *urb);
++static void hci_usb_tx_complete(struct urb *urb);
+ 
+-	if (husb->write_urb)
+-		usb_free_urb(husb->write_urb);
++#define __pending_tx(husb, type)  (&husb->pending_tx[type-1])
++#define __pending_q(husb, type)   (&husb->pending_q[type-1])
++#define __completed_q(husb, type) (&husb->completed_q[type-1])
++#define __transmit_q(husb, type)  (&husb->transmit_q[type-1])
++#define __reassembly(husb, type)  (husb->reassembly[type-1])
+ 
+-	if (husb->intr_skb)
+-		kfree_skb(husb->intr_skb);
++static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
++{
++	return _urb_dequeue(__completed_q(husb, type)); 
+ }
+ 
+-/* ------- Interface to HCI layer ------ */
+-/* Initialize device */
+-int hci_usb_open(struct hci_dev *hdev)
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+-	int status;
+-
+-	DBG("%s", hdev->name);
+-
+-	husb->read_urb->dev = husb->udev;
+-	if ((status = usb_submit_urb(husb->read_urb)))
+-		DBG("read submit failed. %d", status);
+-
+-	husb->intr_urb->dev = husb->udev;
+-	if ((status = usb_submit_urb(husb->intr_urb)))
+-		DBG("interrupt submit failed. %d", status);
++	int offset = 0, i;
+ 
+-	hdev->flags |= HCI_RUNNING;
++	BT_DBG("len %d mtu %d", len, mtu);
+ 
+-	return 0;
++	for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) {
++		urb->iso_frame_desc[i].offset = offset;
++		urb->iso_frame_desc[i].length = mtu;
++		BT_DBG("desc %d offset %d len %d", i, offset, mtu);
++	}
++	if (len && i < HCI_MAX_ISOC_FRAMES) {
++		urb->iso_frame_desc[i].offset = offset;
++		urb->iso_frame_desc[i].length = len;
++		BT_DBG("desc %d offset %d len %d", i, offset, len);
++		i++;
++	}
++	urb->number_of_packets = i;
+ }
++#endif
+ 
+-/* Reset device */
+-int hci_usb_flush(struct hci_dev *hdev)
++static int hci_usb_intr_rx_submit(struct hci_usb *husb)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	struct _urb *_urb;
++	struct urb *urb;
++	int err, pipe, interval, size;
++	void *buf;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", husb->hdev.name);
+ 
+-	/* Drop TX queues */
+-	skb_queue_purge(&husb->tx_ctrl_q);
+-	skb_queue_purge(&husb->tx_write_q);
++        size = husb->intr_in_ep->wMaxPacketSize;
+ 
+-	return 0;
++	buf = kmalloc(size, GFP_ATOMIC);
++	if (!buf)
++		return -ENOMEM;
++
++	_urb = _urb_alloc(0, GFP_ATOMIC);
++	if (!_urb) {
++		kfree(buf);
++		return -ENOMEM;
++	}
++	_urb->type = HCI_EVENT_PKT;
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
++
++	urb = &_urb->urb;
++	pipe     = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress);
++	interval = husb->intr_in_ep->bInterval;
++	FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval);
++	
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s intr rx submit failed urb %p err %d",
++				husb->hdev.name, urb, err);
++		_urb_unlink(_urb);
++		_urb_free(_urb);
++		kfree(buf);
++	}
++	return err;
+ }
+ 
+-/* Close device */
+-int hci_usb_close(struct hci_dev *hdev)
++static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	struct _urb *_urb;
++	struct urb *urb;
++	int err, pipe, size = HCI_MAX_FRAME_SIZE;
++	void *buf;
+ 
+-	DBG("%s", hdev->name);
++	buf = kmalloc(size, GFP_ATOMIC);
++	if (!buf)
++		return -ENOMEM;
+ 
+-	hdev->flags &= ~HCI_RUNNING;
+-	hci_usb_unlink_urbs(husb);
++	_urb = _urb_alloc(0, GFP_ATOMIC);
++	if (!_urb) {
++		kfree(buf);
++		return -ENOMEM;
++	}
++	_urb->type = HCI_ACLDATA_PKT;
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
+ 
+-	hci_usb_flush(hdev);
++	urb  = &_urb->urb;
++	pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress);
++        FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb);
++        urb->transfer_flags = USB_QUEUE_BULK;
+ 
+-	return 0;
++	BT_DBG("%s urb %p", husb->hdev.name, urb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk rx submit failed urb %p err %d",
++				husb->hdev.name, urb, err);
++		_urb_unlink(_urb);
++		_urb_free(_urb);
++		kfree(buf);
++	}
++	return err;
+ }
+ 
+-void hci_usb_ctrl_wakeup(struct hci_usb *husb)
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
+ {
+-	struct sk_buff *skb;
+-
+-	if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state))
+-		return;
++	struct _urb *_urb;
++	struct urb *urb;
++	int err, mtu, size;
++	void *buf;
+ 
+-	DBG("%s", husb->hdev.name);
++	mtu  = husb->isoc_in_ep->wMaxPacketSize;
++        size = mtu * HCI_MAX_ISOC_FRAMES;
+ 
+-	if (!(skb = skb_dequeue(&husb->tx_ctrl_q)))
+-		goto done;
++	buf = kmalloc(size, GFP_ATOMIC);
++	if (!buf)
++		return -ENOMEM;
+ 
+-	if (hci_usb_ctrl_msg(husb, skb)){
+-		kfree_skb(skb);
+-		goto done;
++	_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
++	if (!_urb) {
++		kfree(buf);
++		return -ENOMEM;
+ 	}
++	_urb->type = HCI_SCODATA_PKT;
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
+ 
+-	DMP(skb->data, skb->len);
++	urb = &_urb->urb;
+ 
+-	husb->hdev.stat.byte_tx += skb->len;
+-	return;
++	urb->context  = husb;
++	urb->dev      = husb->udev;
++	urb->pipe     = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress);
++	urb->complete = hci_usb_rx_complete;
+ 
+-done:
+-	clear_bit(HCI_TX_CTRL, &husb->tx_state);
+-	return;
++	urb->transfer_buffer_length = size;
++	urb->transfer_buffer = buf;
++	urb->transfer_flags  = USB_ISO_ASAP;
++
++	__fill_isoc_desc(urb, size, mtu);
++
++	BT_DBG("%s urb %p", husb->hdev.name, urb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s isoc rx submit failed urb %p err %d",
++				husb->hdev.name, urb, err);
++		_urb_unlink(_urb);
++		_urb_free(_urb);
++		kfree(buf);
++	}
++	return err;
+ }
++#endif
+ 
+-void hci_usb_write_wakeup(struct hci_usb *husb)
++/* Initialize device */
++static int hci_usb_open(struct hci_dev *hdev)
+ {
+-	struct sk_buff *skb;
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	int i, err;
++	unsigned long flags;
+ 
+-	if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state))
+-		return;
++	BT_DBG("%s", hdev->name);
+ 
+-	DBG("%s", husb->hdev.name);
++	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
+ 
+-	if (!(skb = skb_dequeue(&husb->tx_write_q)))
+-		goto done;
++	MOD_INC_USE_COUNT;
+ 
+-	if (hci_usb_write_msg(husb, skb)) {
+-		skb_queue_head(&husb->tx_write_q, skb);
+-		goto done;
++	write_lock_irqsave(&husb->completion_lock, flags);
++
++	err = hci_usb_intr_rx_submit(husb);
++	if (!err) {
++		for (i = 0; i < HCI_MAX_BULK_RX; i++)
++			hci_usb_bulk_rx_submit(husb);
++
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++		if (husb->isoc_iface)
++			for (i = 0; i < HCI_MAX_ISOC_RX; i++)
++				hci_usb_isoc_rx_submit(husb);
++#endif
++	} else {
++		clear_bit(HCI_RUNNING, &hdev->flags);
++		MOD_DEC_USE_COUNT;
+ 	}
+ 
+-	DMP(skb->data, skb->len);
++	write_unlock_irqrestore(&husb->completion_lock, flags);
++	return err;
++}
+ 
+-	husb->hdev.stat.byte_tx += skb->len;
+-	return;
++/* Reset device */
++static int hci_usb_flush(struct hci_dev *hdev)
++{
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	int i;
+ 
+-done:
+-	clear_bit(HCI_TX_WRITE, &husb->tx_state);
+-	return;
++	BT_DBG("%s", hdev->name);
++
++	for (i=0; i < 4; i++)
++		skb_queue_purge(&husb->transmit_q[i]);
++	return 0;
+ }
+ 
+-/* Send frames from HCI layer */
+-int hci_usb_send_frame(struct sk_buff *skb)
++static void hci_usb_unlink_urbs(struct hci_usb *husb)
+ {
+-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+-	struct hci_usb *husb;
++	int i;
+ 
+-	if (!hdev) {
+-		ERR("frame for uknown device (hdev=NULL)");
+-		return -ENODEV;
+-	}
++	BT_DBG("%s", husb->hdev.name);
+ 
+-	if (!(hdev->flags & HCI_RUNNING))
+-		return 0;
++	for (i=0; i < 4; i++) {
++		struct _urb *_urb;
++		struct urb *urb;
+ 
+-	husb = (struct hci_usb *) hdev->driver_data;
++		/* Kill pending requests */
++		while ((_urb = _urb_dequeue(&husb->pending_q[i]))) {
++			urb = &_urb->urb;
++			BT_DBG("%s unlinking _urb %p type %d urb %p", 
++					husb->hdev.name, _urb, _urb->type, urb);
++			usb_unlink_urb(urb);
++			_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
++		}
+ 
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
++		/* Release completed requests */
++		while ((_urb = _urb_dequeue(&husb->completed_q[i]))) {
++			urb = &_urb->urb;
++			BT_DBG("%s freeing _urb %p type %d urb %p",
++					husb->hdev.name, _urb, _urb->type, urb);
++			if (urb->setup_packet)
++				kfree(urb->setup_packet);
++			if (urb->transfer_buffer)
++				kfree(urb->transfer_buffer);
++			_urb_free(_urb);
++		}
+ 
+-	switch (skb->pkt_type) {
+-		case HCI_COMMAND_PKT:
+-			skb_queue_tail(&husb->tx_ctrl_q, skb);
+-			hci_usb_ctrl_wakeup(husb);
+-			hdev->stat.cmd_tx++;
+-			return 0;
++		/* Release reassembly buffers */
++		if (husb->reassembly[i]) {
++			kfree_skb(husb->reassembly[i]);
++			husb->reassembly[i] = NULL;
++		}
++	}
++}
+ 
+-		case HCI_ACLDATA_PKT:
+-			skb_queue_tail(&husb->tx_write_q, skb);
+-			hci_usb_write_wakeup(husb);
+-			hdev->stat.acl_tx++;
+-			return 0;
++/* Close device */
++static int hci_usb_close(struct hci_dev *hdev)
++{
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	unsigned long flags;
++	
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
+ 
+-		case HCI_SCODATA_PKT:
+-			return -EOPNOTSUPP;
+-	};
++	BT_DBG("%s", hdev->name);
++
++	write_lock_irqsave(&husb->completion_lock, flags);
++	
++	hci_usb_unlink_urbs(husb);
++	hci_usb_flush(hdev);
++
++	write_unlock_irqrestore(&husb->completion_lock, flags);
+ 
++	MOD_DEC_USE_COUNT;
+ 	return 0;
+ }
+ 
+-/* ---------- USB ------------- */
++static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
++{
++	struct urb *urb = &_urb->urb;
++	int err;
+ 
+-static void hci_usb_ctrl(struct urb *urb)
++	BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type);
++	
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s tx submit failed urb %p type %d err %d",
++				husb->hdev.name, urb, _urb->type, err);
++		_urb_unlink(_urb);
++		_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
++	} else
++		atomic_inc(__pending_tx(husb, _urb->type));
++
++	return err;
++}
++
++static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
+ {
+-	struct sk_buff *skb = (struct sk_buff *) urb->context;
+-	struct hci_dev *hdev;
+-	struct hci_usb *husb;
++	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
++	devrequest *dr;
++	struct urb *urb;
+ 
+-	if (!skb)
+-		return;
+-	hdev = (struct hci_dev *) skb->dev;
+-	husb = (struct hci_usb *) hdev->driver_data;
++	if (!_urb) {
++	       	_urb = _urb_alloc(0, GFP_ATOMIC);
++	       	if (!_urb)
++			return -ENOMEM;
++		_urb->type = skb->pkt_type;
+ 
+-	DBG("%s", hdev->name);
++		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
++		if (!dr) {
++			_urb_free(_urb);
++			return -ENOMEM;
++		}
++	} else
++		dr = (void *) _urb->urb.setup_packet;
+ 
+-	if (urb->status)
+-		DBG("%s ctrl status: %d", hdev->name, urb->status);
++	dr->requesttype = husb->ctrl_req;
++	dr->request = 0;
++	dr->index   = 0;
++	dr->value   = 0;
++	dr->length  = __cpu_to_le16(skb->len);
+ 
+-	clear_bit(HCI_TX_CTRL, &husb->tx_state);
+-	kfree_skb(skb);
++	urb = &_urb->urb;
++	FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0),
++		(void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb);
+ 
+-	/* Wake up device */
+-	hci_usb_ctrl_wakeup(husb);
++	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
++	
++	_urb->priv = skb;
++	return __tx_submit(husb, _urb);
+ }
+ 
+-static void hci_usb_bulk_write(struct urb *urb)
++static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
+ {
+-	struct sk_buff *skb = (struct sk_buff *) urb->context;
+-	struct hci_dev *hdev;
+-	struct hci_usb *husb;
+-
+-	if (!skb)
+-		return;
+-	hdev = (struct hci_dev *) skb->dev;
+-	husb = (struct hci_usb *) hdev->driver_data;
+-
+-	DBG("%s", hdev->name);
++	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
++	struct urb *urb;
++	int pipe;
+ 
+-	if (urb->status)
+-		DBG("%s bulk write status: %d", hdev->name, urb->status);
++	if (!_urb) {
++	       	_urb = _urb_alloc(0, GFP_ATOMIC);
++	       	if (!_urb)
++			return -ENOMEM;
++		_urb->type = skb->pkt_type;
++	}
+ 
+-	clear_bit(HCI_TX_WRITE, &husb->tx_state);
+-	kfree_skb(skb);
++	urb  = &_urb->urb;
++	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress);
++	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, 
++			hci_usb_tx_complete, husb);
++	urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
+ 
+-	/* Wake up device */
+-	hci_usb_write_wakeup(husb);
++	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
+ 
+-	return;
++	_urb->priv = skb;
++	return __tx_submit(husb, _urb);
+ }
+ 
+-static void hci_usb_intr(struct urb *urb)
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) urb->context;
+-	unsigned char *data = urb->transfer_buffer;
+-	register int count  = urb->actual_length;
+-	register struct sk_buff *skb = husb->intr_skb;
+-	hci_event_hdr *eh;
+-	register int len;
++	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
++	struct urb *urb;
++	
++	if (!_urb) {
++	       	_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
++	       	if (!_urb)
++			return -ENOMEM;
++		_urb->type = skb->pkt_type;
++	}
+ 
+-	if (!husb)
+-		return;
++	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
+ 
+-	DBG("%s count %d", husb->hdev.name, count);
++	urb = &_urb->urb;
++	
++	urb->context  = husb;
++	urb->dev      = husb->udev;
++	urb->pipe     = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress);
++	urb->complete = hci_usb_tx_complete;
++	urb->transfer_flags = USB_ISO_ASAP;
+ 
+-	if (urb->status || !count) {
+-		DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count);
+-		return;
+-	}
++	urb->transfer_buffer = skb->data;
++	urb->transfer_buffer_length = skb->len;
++	
++	__fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize);
+ 
+-	/* Do we really have to handle continuations here ? */
+-	if (!skb) {
+-		/* New frame */
+-		if (count < HCI_EVENT_HDR_SIZE) {
+-			DBG("%s bad frame len %d", husb->hdev.name, count);
+-			return;
+-		}
++	_urb->priv = skb;
++	return __tx_submit(husb, _urb);
++}
++#endif
+ 
+-		eh = (hci_event_hdr *) data;
+-		len = eh->plen + HCI_EVENT_HDR_SIZE;
++static void hci_usb_tx_process(struct hci_usb *husb)
++{
++	struct sk_buff_head *q;
++	struct sk_buff *skb;
+ 
+-		if (count > len) {
+-			DBG("%s corrupted frame, len %d", husb->hdev.name, count);
+-			return;
++	BT_DBG("%s", husb->hdev.name);
++
++	do {
++		clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
++
++		/* Process command queue */
++		q = __transmit_q(husb, HCI_COMMAND_PKT);
++		if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&
++				(skb = skb_dequeue(q))) {
++			if (hci_usb_send_ctrl(husb, skb) < 0)
++				skb_queue_head(q, skb);
+ 		}
+ 
+-		/* Allocate skb */
+-		if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
+-			ERR("Can't allocate mem for new packet");
+-			return;
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++		/* Process SCO queue */
++		q = __transmit_q(husb, HCI_SCODATA_PKT);
++		if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
++				(skb = skb_dequeue(q))) {
++			if (hci_usb_send_isoc(husb, skb) < 0)
++				skb_queue_head(q, skb);
+ 		}
+-		skb->dev = (void *) &husb->hdev;
+-		skb->pkt_type = HCI_EVENT_PKT;
++#endif
++		
++		/* Process ACL queue */
++		q = __transmit_q(husb, HCI_ACLDATA_PKT);
++		while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
++				(skb = skb_dequeue(q))) {
++			if (hci_usb_send_bulk(husb, skb) < 0) {
++				skb_queue_head(q, skb);
++				break;
++			}
++		}
++	} while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
++}
+ 
+-		husb->intr_skb = skb;
+-		husb->intr_count = len;
+-	} else {
+-		/* Continuation */
+-		if (count > husb->intr_count) {
+-			ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count);
++static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
++{
++	/* Serialize TX queue processing to avoid data reordering */
++	if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {
++		hci_usb_tx_process(husb);
++		clear_bit(HCI_USB_TX_PROCESS, &husb->state);
++	} else
++		set_bit(HCI_USB_TX_WAKEUP, &husb->state);
++}
+ 
+-			kfree_skb(skb);
+-			husb->intr_skb = NULL;
+-			husb->intr_count = 0;
+-			return;
+-		}
++/* Send frames from HCI layer */
++static int hci_usb_send_frame(struct sk_buff *skb)
++{
++	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
++	struct hci_usb *husb;
++
++	if (!hdev) {
++		BT_ERR("frame for uknown device (hdev=NULL)");
++		return -ENODEV;
+ 	}
+ 
+-	memcpy(skb_put(skb, count), data, count);
+-	husb->intr_count -= count;
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return -EBUSY;
+ 
+-	DMP(data, count);
++	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+ 
+-	if (!husb->intr_count) {
+-		/* Got complete frame */
++	husb = (struct hci_usb *) hdev->driver_data;
+ 
+-		husb->hdev.stat.byte_rx += skb->len;
+-		hci_recv_frame(skb);
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
+ 
+-		husb->intr_skb = NULL;
+-	}
+-}
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
+ 
+-static void hci_usb_bulk_read(struct urb *urb)
+-{
+-	struct hci_usb *husb = (struct hci_usb *) urb->context;
+-	unsigned char *data = urb->transfer_buffer;
+-	int count = urb->actual_length, status;
+-	struct sk_buff *skb;
+-	hci_acl_hdr *ah;
+-	register __u16 dlen;
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++#endif
+ 
+-	if (!husb)
+-		return;
++	default:
++		kfree_skb(skb);
++		return 0;
++	}
+ 
+-	DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags);
++	read_lock(&husb->completion_lock);
+ 
+-	if (urb->status) {
+-		/* Do not re-submit URB on critical errors */
+-		switch (urb->status) {
+-			case -ENOENT:
+-				return;
+-			default:
+-				goto resubmit;
+-		};
+-	}
+-	if (!count)
+-		goto resubmit;
++	skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
++	hci_usb_tx_wakeup(husb);
+ 
+-	DMP(data, count);
++	read_unlock(&husb->completion_lock);
++	return 0;
++}
+ 
+-	ah = (hci_acl_hdr *) data;
+-	dlen = le16_to_cpu(ah->dlen);
++static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
++{
++	BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count);
+ 
+-	/* Verify frame len and completeness */
+-	if ((count - HCI_ACL_HDR_SIZE) != dlen) {
+-		ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen);
+-		goto resubmit;
+-	}
++	husb->hdev.stat.byte_rx += count;
+ 
+-	/* Allocate packet */
+-	if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) {
+-		ERR("Can't allocate mem for new packet");
+-		goto resubmit;
+-	}
++	while (count) {
++		struct sk_buff *skb = __reassembly(husb, type);
++		struct { int expect; } *scb;
++		int len = 0;
++	
++		if (!skb) {
++			/* Start of the frame */
+ 
+-	memcpy(skb_put(skb, count), data, count);
+-	skb->dev = (void *) &husb->hdev;
+-	skb->pkt_type = HCI_ACLDATA_PKT;
++			switch (type) {
++			case HCI_EVENT_PKT:
++				if (count >= HCI_EVENT_HDR_SIZE) {
++					hci_event_hdr *h = data;
++					len = HCI_EVENT_HDR_SIZE + h->plen;
++				} else
++					return -EILSEQ;
++				break;
+ 
+-	husb->hdev.stat.byte_rx += skb->len;
++			case HCI_ACLDATA_PKT:
++				if (count >= HCI_ACL_HDR_SIZE) {
++					hci_acl_hdr *h = data;
++					len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
++				} else
++					return -EILSEQ;
++				break;
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++			case HCI_SCODATA_PKT:
++				if (count >= HCI_SCO_HDR_SIZE) {
++					hci_sco_hdr *h = data;
++					len = HCI_SCO_HDR_SIZE + h->dlen;
++				} else 
++					return -EILSEQ;
++				break;
++#endif
++			}
++			BT_DBG("new packet len %d", len);
++				
++			skb = bluez_skb_alloc(len, GFP_ATOMIC);
++			if (!skb) {
++				BT_ERR("%s no memory for the packet", husb->hdev.name);
++				return -ENOMEM;
++			}
++			skb->dev = (void *) &husb->hdev;
++			skb->pkt_type = type;
++	
++			__reassembly(husb, type) = skb;
+ 
+-	hci_recv_frame(skb);
++			scb = (void *) skb->cb;
++			scb->expect = len;
++		} else {
++			/* Continuation */
++			scb = (void *) skb->cb;
++			len = scb->expect;
++		}
+ 
+-resubmit:
+-	husb->read_urb->dev = husb->udev;
+-	if ((status = usb_submit_urb(husb->read_urb)))
+-		DBG("%s read URB submit failed %d", husb->hdev.name, status);
++		len = min(len, count);
++		
++		memcpy(skb_put(skb, len), data, len);
+ 
+-	DBG("%s read URB re-submited", husb->hdev.name);
++		scb->expect -= len;
++		if (!scb->expect) {
++			/* Complete frame */
++			__reassembly(husb, type) = NULL;
++			hci_recv_frame(skb);
++		}
++
++		count -= len; data += len;
++	}
++	return 0;
+ }
+ 
+-static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb)
++static void hci_usb_rx_complete(struct urb *urb)
+ {
+-	struct urb *urb = husb->ctrl_urb;
+-	devrequest *dr  = &husb->dev_req;
+-	int pipe, status;
++	struct _urb *_urb = container_of(urb, struct _urb, urb);
++	struct hci_usb *husb = (void *) urb->context;
++	struct hci_dev *hdev = &husb->hdev;
++	int    err, count = urb->actual_length;
+ 
+-	DBG("%s len %d", husb->hdev.name, skb->len);
++	BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
++			_urb->type, urb->status, count, urb->transfer_flags);
+ 
+-	pipe = usb_sndctrlpipe(husb->udev, 0);
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return;
+ 
+-	dr->requesttype = HCI_CTRL_REQ;
+-	dr->request = 0;
+-	dr->index   = 0;
+-	dr->value   = 0;
+-	dr->length  = cpu_to_le16(skb->len);
++	read_lock(&husb->completion_lock);
+ 
+-	FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
+-	                 hci_usb_ctrl, skb);
++	if (urb->status || !count)
++		goto resubmit;
+ 
+-	if ((status = usb_submit_urb(urb))) {
+-		DBG("%s control URB submit failed %d", husb->hdev.name, status);
+-		return status;
++	if (_urb->type == HCI_SCODATA_PKT) {
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++		int i;
++		for (i=0; i < urb->number_of_packets; i++) {
++			BT_DBG("desc %d status %d offset %d len %d", i,
++					urb->iso_frame_desc[i].status,
++					urb->iso_frame_desc[i].offset,
++					urb->iso_frame_desc[i].actual_length);
++	
++			if (!urb->iso_frame_desc[i].status)
++				__recv_frame(husb, _urb->type, 
++					urb->transfer_buffer + urb->iso_frame_desc[i].offset,
++					urb->iso_frame_desc[i].actual_length);
++		}
++#else
++		;
++#endif
++	} else {
++		err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
++		if (err < 0) { 
++			BT_ERR("%s corrupted packet: type %d count %d",
++					husb->hdev.name, _urb->type, count);
++			hdev->stat.err_rx++;
++		}
+ 	}
+ 
+-	return 0;
++resubmit:
++	if (_urb->type != HCI_EVENT_PKT) {
++		urb->dev = husb->udev;
++		err      = usb_submit_urb(urb);
++		BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
++				_urb->type, err);
++	}
++	read_unlock(&husb->completion_lock);
+ }
+ 
+-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb)
++static void hci_usb_tx_complete(struct urb *urb)
+ {
+-	struct urb *urb = husb->write_urb;
+-	int pipe, status;
++	struct _urb *_urb = container_of(urb, struct _urb, urb);
++	struct hci_usb *husb = (void *) urb->context;
++	struct hci_dev *hdev = &husb->hdev;
+ 
+-	DBG("%s len %d", husb->hdev.name, skb->len);
++	BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,
++			urb->status, urb->transfer_flags);
+ 
+-	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr);
++	atomic_dec(__pending_tx(husb, _urb->type));
+ 
+-	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
+-	              hci_usb_bulk_write, skb);
+-	urb->transfer_flags |= USB_QUEUE_BULK;
++	urb->transfer_buffer = NULL;
++	kfree_skb((struct sk_buff *) _urb->priv);
+ 
+-	if ((status = usb_submit_urb(urb))) {
+-		DBG("%s write URB submit failed %d", husb->hdev.name, status);
+-		return status;
+-	}
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return;
+ 
+-	return 0;
++	if (!urb->status)
++		hdev->stat.byte_tx += urb->transfer_buffer_length;
++	else
++		hdev->stat.err_tx++;
++
++	read_lock(&husb->completion_lock);
++
++	_urb_unlink(_urb);
++	_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
++
++	hci_usb_tx_wakeup(husb);
++	
++	read_unlock(&husb->completion_lock);
+ }
+ 
+-static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
++static void hci_usb_destruct(struct hci_dev *hdev)
+ {
+-	struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep;
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++
++	BT_DBG("%s", hdev->name);
++
++	kfree(husb);
++}
++
++static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
++{
++	struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM];
+ 	struct usb_interface_descriptor *uif;
+ 	struct usb_endpoint_descriptor *ep;
++	struct usb_interface *iface, *isoc_iface;
+ 	struct hci_usb *husb;
+ 	struct hci_dev *hdev;
+-	int i, size, pipe;
+-	__u8 * buf;
+-
+-	DBG("udev %p ifnum %d", udev, ifnum);
++	int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
+ 
+-	/* Check device signature */
+-	if ((udev->descriptor.bDeviceClass    != HCI_DEV_CLASS)   ||
+-	    (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)||
+-	    (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) )
+-		return NULL;
++	BT_DBG("udev %p ifnum %d", udev, ifnum);
+ 
+-	MOD_INC_USE_COUNT;
++	iface = &udev->actconfig->interface[0];
+ 
+-	uif = &udev->actconfig->interface[ifnum].altsetting[0];
++	/* Check our black list */
++	if (usb_match_id(udev, iface, ignore_ids))
++		return NULL;
+ 
+-	if (uif->bNumEndpoints != 3) {
+-		DBG("Wrong number of endpoints %d", uif->bNumEndpoints);
+-		MOD_DEC_USE_COUNT;
++	/* Check number of endpoints */
++	if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)
+ 		return NULL;
+-	}
+ 
+-	bulk_out_ep = intr_in_ep = bulk_in_ep = NULL;
++	memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
++	memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
++	memset(bulk_in_ep,  0, sizeof(bulk_in_ep));
++	memset(isoc_in_ep,  0, sizeof(isoc_in_ep));
++	memset(intr_in_ep,  0, sizeof(intr_in_ep));
+ 
++	size = 0; 
++	isoc_iface = NULL;
++	isoc_alts  = isoc_ifnum = 0;
++	
+ 	/* Find endpoints that we need */
+-	for ( i = 0; i < uif->bNumEndpoints; ++i) {
+-		ep = &uif->endpoint[i];
+ 
+-		switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+-			case USB_ENDPOINT_XFER_BULK:
+-				if (ep->bEndpointAddress & USB_DIR_IN)
+-					bulk_in_ep  = ep;
+-				else
+-					bulk_out_ep = ep;
+-				break;
+-
+-			case USB_ENDPOINT_XFER_INT:
+-				intr_in_ep = ep;
+-				break;
+-		};
+-	}
++	ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
++	for (i = 0; i < ifn; i++) {
++		iface = &udev->actconfig->interface[i];
++		for (a = 0; a < iface->num_altsetting; a++) {
++			uif = &iface->altsetting[a];
++			for (e = 0; e < uif->bNumEndpoints; e++) {
++				ep = &uif->endpoint[e];
+ 
+-	if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
+-		DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep);
+-		MOD_DEC_USE_COUNT;
+-		return NULL;
+-	}
++				switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
++				case USB_ENDPOINT_XFER_INT:
++					if (ep->bEndpointAddress & USB_DIR_IN)
++						intr_in_ep[i] = ep;
++					break;
+ 
+-	if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
+-		ERR("Can't allocate: control structure");
+-		MOD_DEC_USE_COUNT;
+-		return NULL;
+-	}
++				case USB_ENDPOINT_XFER_BULK:
++					if (ep->bEndpointAddress & USB_DIR_IN)
++						bulk_in_ep[i]  = ep;
++					else
++						bulk_out_ep[i] = ep;
++					break;
+ 
+-	memset(husb, 0, sizeof(struct hci_usb));
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++				case USB_ENDPOINT_XFER_ISOC:
++					if (ep->wMaxPacketSize < size || a > 2)
++						break;
++					size = ep->wMaxPacketSize;
+ 
+-	husb->udev = udev;
+-	husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress;
++					isoc_iface = iface;
++					isoc_alts  = a;
++					isoc_ifnum = i;
+ 
+-	if (!(husb->ctrl_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: control URB");
+-		goto probe_error;
++					if (ep->bEndpointAddress & USB_DIR_IN)
++						isoc_in_ep[i]  = ep;
++					else
++						isoc_out_ep[i] = ep;
++					break;
++#endif
++				}
++			}
++		}
+ 	}
+ 
+-	if (!(husb->write_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: write URB");
+-		goto probe_error;
++	if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {
++		BT_DBG("Bulk endpoints not found");
++		goto done;
+ 	}
+ 
+-	if (!(husb->read_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: read URB");
+-		goto probe_error;
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++	if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
++		BT_DBG("Isoc endpoints not found");
++		isoc_iface = NULL;
+ 	}
++#endif
+ 
+-	ep = bulk_in_ep;
+-	pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress);
+-	size = HCI_MAX_FRAME_SIZE;
+-
+-	if (!(buf = kmalloc(size, GFP_KERNEL))) {
+-		ERR("Can't allocate: read buffer");
+-		goto probe_error;
++	if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
++		BT_ERR("Can't allocate: control structure");
++		goto done;
+ 	}
+ 
+-	FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb);
+-	husb->read_urb->transfer_flags |= USB_QUEUE_BULK;
++	memset(husb, 0, sizeof(struct hci_usb));
+ 
+-	ep = intr_in_ep;
+-	pipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
+-	size = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
++	husb->udev = udev;
++	husb->bulk_out_ep = bulk_out_ep[0];
++	husb->bulk_in_ep  = bulk_in_ep[0];
++	husb->intr_in_ep  = intr_in_ep[0];
+ 
+-	if (!(husb->intr_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: interrupt URB");
+-		goto probe_error;
+-	}
++	if (id->driver_info & HCI_DIGIANSWER)
++		husb->ctrl_req = HCI_DIGI_REQ;
++	else
++		husb->ctrl_req = HCI_CTRL_REQ;
+ 
+-	if (!(buf = kmalloc(size, GFP_KERNEL))) {
+-		ERR("Can't allocate: interrupt buffer");
+-		goto probe_error;
++#ifdef CONFIG_BLUEZ_HCIUSB_SCO
++	if (isoc_iface) {
++		BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
++		if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
++			BT_ERR("Can't set isoc interface settings");
++			isoc_iface = NULL;
++		}
++		usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
++		husb->isoc_iface  = isoc_iface;
++		husb->isoc_in_ep  = isoc_in_ep[isoc_ifnum];
++		husb->isoc_out_ep = isoc_out_ep[isoc_ifnum];
+ 	}
++#endif
++	
++	husb->completion_lock = RW_LOCK_UNLOCKED;
+ 
+-	FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval);
+-
+-	skb_queue_head_init(&husb->tx_ctrl_q);
+-	skb_queue_head_init(&husb->tx_write_q);
++	for (i = 0; i < 4; i++) {	
++		skb_queue_head_init(&husb->transmit_q[i]);
++		_urb_queue_init(&husb->pending_q[i]);
++		_urb_queue_init(&husb->completed_q[i]);
++	}
+ 
+ 	/* Initialize and register HCI device */
+ 	hdev = &husb->hdev;
+ 
+-	hdev->type = HCI_USB;
++	hdev->type  = HCI_USB;
+ 	hdev->driver_data = husb;
+ 
+ 	hdev->open  = hci_usb_open;
+ 	hdev->close = hci_usb_close;
+ 	hdev->flush = hci_usb_flush;
+-	hdev->send	= hci_usb_send_frame;
++	hdev->send  = hci_usb_send_frame;
++	hdev->destruct = hci_usb_destruct;
+ 
+ 	if (hci_register_dev(hdev) < 0) {
+-		ERR("Can't register HCI device %s", hdev->name);
++		BT_ERR("Can't register HCI device");
+ 		goto probe_error;
+ 	}
+ 
+ 	return husb;
+ 
+ probe_error:
+-	hci_usb_free_bufs(husb);
+ 	kfree(husb);
+-	MOD_DEC_USE_COUNT;
++
++done:
+ 	return NULL;
+ }
+ 
+@@ -626,38 +943,34 @@
+ 	if (!husb)
+ 		return;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", hdev->name);
+ 
+ 	hci_usb_close(hdev);
+ 
+-	if (hci_unregister_dev(hdev) < 0) {
+-		ERR("Can't unregister HCI device %s", hdev->name);
+-	}
+-
+-	hci_usb_free_bufs(husb);
+-	kfree(husb);
++	if (husb->isoc_iface)
++		usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
+ 
+-	MOD_DEC_USE_COUNT;
++	if (hci_unregister_dev(hdev) < 0)
++		BT_ERR("Can't unregister HCI device %s", hdev->name);
+ }
+ 
+-static struct usb_driver hci_usb_driver =
+-{
++static struct usb_driver hci_usb_driver = {
+ 	name:           "hci_usb",
+ 	probe:          hci_usb_probe,
+ 	disconnect:     hci_usb_disconnect,
+-	id_table:       usb_bluetooth_ids,
++	id_table:       bluetooth_ids,
+ };
+ 
+ int hci_usb_init(void)
+ {
+ 	int err;
+ 
+-	INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
++	BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+ 		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+ 
+ 	if ((err = usb_register(&hci_usb_driver)) < 0)
+-		ERR("Failed to register HCI USB driver");
++		BT_ERR("Failed to register HCI USB driver");
+ 
+ 	return err;
+ }
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_usb.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,144 @@
++/* 
++   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifdef __KERNEL__
++
++/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
++#define HCI_DEV_CLASS        0xe0	/* Wireless class */
++#define HCI_DEV_SUBCLASS     0x01	/* RF subclass */
++#define HCI_DEV_PROTOCOL     0x01	/* Bluetooth programming protocol */
++
++#define HCI_CTRL_REQ	     0x20
++#define HCI_DIGI_REQ	     0x40
++
++#define HCI_DIGIANSWER       0x01
++
++#define HCI_MAX_IFACE_NUM	3 
++
++#define HCI_MAX_BULK_TX     	4
++#define HCI_MAX_BULK_RX     	1
++
++#define HCI_MAX_ISOC_RX		2
++#define HCI_MAX_ISOC_TX		2
++
++#define HCI_MAX_ISOC_FRAMES     10
++
++struct _urb_queue {
++	struct list_head head;
++	spinlock_t       lock;
++};
++
++struct _urb {
++	struct list_head  list;
++	struct _urb_queue *queue;
++	int               type;
++	void              *priv;
++	struct urb        urb;
++};
++
++struct _urb *_urb_alloc(int isoc, int gfp);
++
++static inline void _urb_free(struct _urb *_urb)
++{
++	kfree(_urb);
++}
++
++static inline void _urb_queue_init(struct _urb_queue *q)
++{
++	INIT_LIST_HEAD(&q->head);
++	spin_lock_init(&q->lock);
++}
++
++static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
++{
++        unsigned long flags;
++        spin_lock_irqsave(&q->lock, flags);
++	list_add(&_urb->list, &q->head); _urb->queue = q;
++	spin_unlock_irqrestore(&q->lock, flags);
++}
++
++static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
++{
++        unsigned long flags;
++        spin_lock_irqsave(&q->lock, flags);
++	list_add_tail(&_urb->list, &q->head); _urb->queue = q;
++	spin_unlock_irqrestore(&q->lock, flags);
++}
++
++static inline void _urb_unlink(struct _urb *_urb)
++{
++	struct _urb_queue *q = _urb->queue;
++        unsigned long flags;
++	if (q) {
++        	spin_lock_irqsave(&q->lock, flags);
++		list_del(&_urb->list); _urb->queue = NULL;
++		spin_unlock_irqrestore(&q->lock, flags);
++	}
++}
++
++struct _urb *_urb_dequeue(struct _urb_queue *q);
++
++#ifndef container_of
++#define container_of(ptr, type, member) ({                      \
++		        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
++			        (type *)( (char *)__mptr - offsetof(type,member) );})
++#endif
++
++struct hci_usb {
++	struct hci_dev		hdev;
++
++	unsigned long		state;
++	
++	struct usb_device 	*udev;
++	
++	struct usb_endpoint_descriptor	*bulk_in_ep;
++	struct usb_endpoint_descriptor	*bulk_out_ep;
++	struct usb_endpoint_descriptor	*intr_in_ep;
++
++	struct usb_interface            *isoc_iface;
++	struct usb_endpoint_descriptor	*isoc_out_ep;
++	struct usb_endpoint_descriptor	*isoc_in_ep;
++
++	__u8			ctrl_req;
++
++	struct sk_buff_head	transmit_q[4];
++	struct sk_buff		*reassembly[4]; // Reassembly buffers
++
++	rwlock_t		completion_lock;
++
++	atomic_t		pending_tx[4];  // Number of pending requests 
++	struct _urb_queue	pending_q[4];   // Pending requests
++	struct _urb_queue	completed_q[4]; // Completed requests
++};
++
++/* States  */
++#define HCI_USB_TX_PROCESS	1
++#define HCI_USB_TX_WAKEUP	2
++
++#endif /* __KERNEL__ */
+--- linux/drivers/bluetooth/hci_vhci.c~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/drivers/bluetooth/hci_vhci.c	2004-01-25 23:37:39.000000000 +0100
+@@ -25,9 +25,9 @@
+ /*
+  * BlueZ HCI virtual device driver.
+  *
+- * $Id$ 
++ * $Id$ 
+  */
+-#define VERSION "1.0"
++#define VERSION "1.1"
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
+@@ -49,43 +49,56 @@
+ #include <asm/uaccess.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci_vhci.h>
++#include "hci_vhci.h"
+ 
+ /* HCI device part */
+ 
+-int hci_vhci_open(struct hci_dev *hdev)
++static int hci_vhci_open(struct hci_dev *hdev)
+ {
+-	hdev->flags |= HCI_RUNNING;
++	set_bit(HCI_RUNNING, &hdev->flags);
+ 	return 0;
+ }
+ 
+-int hci_vhci_flush(struct hci_dev *hdev)
++static int hci_vhci_flush(struct hci_dev *hdev)
+ {
+ 	struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
+ 	skb_queue_purge(&hci_vhci->readq);
+ 	return 0;
+ }
+ 
+-int hci_vhci_close(struct hci_dev *hdev)
++static int hci_vhci_close(struct hci_dev *hdev)
+ {
+-	hdev->flags &= ~HCI_RUNNING;
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
+ 	hci_vhci_flush(hdev);
+ 	return 0;
+ }
+ 
+-int hci_vhci_send_frame(struct sk_buff *skb)
++static void hci_vhci_destruct(struct hci_dev *hdev)
++{
++	struct hci_vhci_struct *vhci;
++
++	if (!hdev) return;
++
++	vhci = (struct hci_vhci_struct *) hdev->driver_data;
++	kfree(vhci);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static int hci_vhci_send_frame(struct sk_buff *skb)
+ {
+ 	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+ 	struct hci_vhci_struct *hci_vhci;
+ 
+ 	if (!hdev) {
+-		ERR("Frame for uknown device (hdev=NULL)");
++		BT_ERR("Frame for uknown device (hdev=NULL)");
+ 		return -ENODEV;
+ 	}
+ 
+-	if (!(hdev->flags & HCI_RUNNING))
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
+ 		return -EBUSY;
+ 
+ 	hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
+@@ -188,7 +201,7 @@
+ 
+ 	add_wait_queue(&hci_vhci->read_wait, &wait);
+ 	while (count) {
+-		current->state = TASK_INTERRUPTIBLE;
++		set_current_state(TASK_INTERRUPTIBLE);
+ 
+ 		/* Read frames from device queue */
+ 		if (!(skb = skb_dequeue(&hci_vhci->readq))) {
+@@ -214,8 +227,7 @@
+ 		kfree_skb(skb);
+ 		break;
+ 	}
+-
+-	current->state = TASK_RUNNING;
++	set_current_state(TASK_RUNNING);
+ 	remove_wait_queue(&hci_vhci->read_wait, &wait);
+ 
+ 	return ret;
+@@ -270,11 +282,13 @@
+ 	hdev->close = hci_vhci_close;
+ 	hdev->flush = hci_vhci_flush;
+ 	hdev->send  = hci_vhci_send_frame;
++	hdev->destruct = hci_vhci_destruct;
+ 
+ 	if (hci_register_dev(hdev) < 0) {
+ 		kfree(hci_vhci);
+ 		return -EBUSY;
+ 	}
++	MOD_INC_USE_COUNT;
+ 
+ 	file->private_data = hci_vhci;
+ 	return 0;   
+@@ -285,12 +299,10 @@
+ 	struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
+ 
+ 	if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
+-		ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
++		BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
+ 	}
+ 
+-	kfree(hci_vhci);
+ 	file->private_data = NULL;
+-
+ 	return 0;
+ }
+ 
+@@ -315,12 +327,12 @@
+ 
+ int __init hci_vhci_init(void)
+ {
+-	INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
++	BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+ 		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+ 
+ 	if (misc_register(&hci_vhci_miscdev)) {
+-		ERR("Can't register misc device %d\n", VHCI_MINOR);
++		BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
+ 		return -EIO;
+ 	}
+ 
+@@ -337,4 +349,4 @@
+ 
+ MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+ MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
+-MODULE_LICENSE("GPL");
++MODULE_LICENSE("GPL"); 
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/hci_vhci.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,50 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef __HCI_VHCI_H
++#define __HCI_VHCI_H
++
++#ifdef __KERNEL__
++
++struct hci_vhci_struct {
++	struct hci_dev       hdev;
++	__u32                flags;
++	wait_queue_head_t    read_wait;
++	struct sk_buff_head  readq;
++	struct fasync_struct *fasync;
++};
++
++/* VHCI device flags */
++#define VHCI_FASYNC		0x0010
++
++#endif /* __KERNEL__ */
++
++#define VHCI_DEV	"/dev/vhci"
++#define VHCI_MINOR	250
++
++#endif /* __HCI_VHCI_H */
+--- linux/drivers/bluetooth/Makefile~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/drivers/bluetooth/Makefile	2004-01-25 23:37:39.000000000 +0100
+@@ -1,11 +1,27 @@
+ #
+-# Makefile for Bluetooth HCI device drivers.
++# Makefile for the Linux Bluetooth HCI device drivers
+ #
+ 
+ O_TARGET	:= bluetooth.o
+ 
++list-multi	:= hci_uart.o
++
+ obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
+-obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
+ obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
+ 
++obj-$(CONFIG_BLUEZ_HCIUART)		+= hci_uart.o
++uart-y					:= hci_ldisc.o
++uart-$(CONFIG_BLUEZ_HCIUART_H4)		+= hci_h4.o
++uart-$(CONFIG_BLUEZ_HCIUART_BCSP)	+= hci_bcsp.o
++
++obj-$(CONFIG_BLUEZ_HCIBFUSB)	+= bfusb.o
++
++obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
++obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
++obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
++obj-$(CONFIG_BLUEZ_HCIBTUART)	+= btuart_cs.o
++
+ include $(TOPDIR)/Rules.make
++
++hci_uart.o: $(uart-y)
++	$(LD) -r -o $@ $(uart-y)
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/bluetooth/Makefile.lib	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1 @@
++obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o
+--- linux/drivers/char/pcmcia/serial_cs.c~bluetooth-2.4.18-mh11	2004-01-25 23:28:22.000000000 +0100
++++ linux/drivers/char/pcmcia/serial_cs.c	2004-01-25 23:37:39.000000000 +0100
+@@ -72,14 +72,14 @@
+ static int irq_list[4] = { -1 };
+ MODULE_PARM(irq_list, "1-4i");
+ 
+-/* Enable the speaker? */
+-INT_MODULE_PARM(do_sound, 1);
++INT_MODULE_PARM(do_sound, 1);		/* Enable the speaker? */
++INT_MODULE_PARM(buggy_uart, 0);		/* Skip strict UART tests? */
+ 
+ #ifdef PCMCIA_DEBUG
+ INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+ #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+ static char *version =
+-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
++"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
+ #else
+ #define DEBUG(n, args...)
+ #endif
+@@ -98,6 +98,7 @@
+     { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
+     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
+     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
++    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
+     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
+     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
+     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
+@@ -151,7 +152,7 @@
+     client_reg_t client_reg;
+     dev_link_t *link;
+     int i, ret;
+-    
++
+     DEBUG(0, "serial_attach()\n");
+ 
+     /* Create new serial device */
+@@ -163,7 +164,7 @@
+     link->release.function = &serial_release;
+     link->release.data = (u_long)link;
+     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+-    link->io.NumPorts1 = 8;
++    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+     if (irq_list[0] == -1)
+@@ -172,13 +173,12 @@
+ 	for (i = 0; i < 4; i++)
+ 	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+     link->conf.Attributes = CONF_ENABLE_IRQ;
+-    link->conf.Vcc = 50;
+     if (do_sound) {
+ 	link->conf.Attributes |= CONF_ENABLE_SPKR;
+ 	link->conf.Status = CCSR_AUDIO_ENA;
+     }
+     link->conf.IntType = INT_MEMORY_AND_IO;
+-    
++
+     /* Register with Card Services */
+     link->next = dev_list;
+     dev_list = link;
+@@ -197,7 +197,7 @@
+ 	serial_detach(link);
+ 	return NULL;
+     }
+-    
++
+     return link;
+ } /* serial_attach */
+ 
+@@ -217,7 +217,7 @@
+     int ret;
+ 
+     DEBUG(0, "serial_detach(0x%p)\n", link);
+-    
++
+     /* Locate device structure */
+     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ 	if (*linkp == link) break;
+@@ -227,17 +227,17 @@
+     del_timer(&link->release);
+     if (link->state & DEV_CONFIG)
+ 	serial_release((u_long)link);
+-    
++
+     if (link->handle) {
+ 	ret = CardServices(DeregisterClient, link->handle);
+ 	if (ret != CS_SUCCESS)
+ 	    cs_error(link->handle, DeregisterClient, ret);
+     }
+-    
++
+     /* Unlink device structure, free bits */
+     *linkp = link->next;
+     kfree(info);
+-    
++
+ } /* serial_detach */
+ 
+ /*====================================================================*/
+@@ -246,18 +246,20 @@
+ {
+     struct serial_struct serial;
+     int line;
+-    
++
+     memset(&serial, 0, sizeof(serial));
+     serial.port = port;
+     serial.irq = irq;
+     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
++    if (buggy_uart)
++	serial.flags |= ASYNC_BUGGY_UART;
+     line = register_serial(&serial);
+     if (line < 0) {
+ 	printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
+ 	       " irq %d failed\n", (u_long)serial.port, serial.irq);
+ 	return -1;
+     }
+-    
++
+     info->line[info->ndev] = line;
+     sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
+     info->node[info->ndev].major = TTY_MAJOR;
+@@ -265,7 +267,7 @@
+     if (info->ndev > 0)
+ 	info->node[info->ndev-1].next = &info->node[info->ndev];
+     info->ndev++;
+-    
++
+     return 0;
+ }
+ 
+@@ -316,7 +318,10 @@
+ 	    return setup_serial(info, port, config.AssignedIRQ);
+     }
+     link->conf.Vcc = config.Vcc;
+-    
++
++    link->io.NumPorts1 = 8;
++    link->io.NumPorts2 = 0;
++
+     /* First pass: look for a config entry that looks normal. */
+     tuple.TupleData = (cisdata_t *)buf;
+     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+@@ -343,7 +348,7 @@
+ 	    i = next_tuple(handle, &tuple, &parse);
+ 	}
+     }
+-    
++
+     /* Second pass: try to find an entry that isn't picky about
+        its base address, then try to grab any standard serial port
+        address, and finally try to get any free port. */
+@@ -355,8 +360,7 @@
+ 	    for (j = 0; j < 5; j++) {
+ 		link->io.BasePort1 = base[j];
+ 		link->io.IOAddrLines = base[j] ? 16 : 3;
+-		i = CardServices(RequestIO, link->handle,
+-				 &link->io);
++		i = CardServices(RequestIO, link->handle, &link->io);
+ 		if (i == CS_SUCCESS) goto found_port;
+ 	    }
+ 	}
+@@ -368,7 +372,7 @@
+ 	cs_error(link->handle, RequestIO, i);
+ 	return -1;
+     }
+-    
++
+     i = CardServices(RequestIRQ, link->handle, &link->irq);
+     if (i != CS_SUCCESS) {
+ 	cs_error(link->handle, RequestIRQ, i);
+@@ -393,8 +397,12 @@
+     u_char buf[256];
+     cisparse_t parse;
+     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++    config_info_t config;
+     int i, base2 = 0;
+ 
++    CardServices(GetConfigurationInfo, handle, &config);
++    link->conf.Vcc = config.Vcc;
++
+     tuple.TupleData = (cisdata_t *)buf;
+     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+     tuple.Attributes = 0;
+@@ -436,12 +444,12 @@
+ 	    i = next_tuple(handle, &tuple, &parse);
+ 	}
+     }
+-    
++
+     if (i != CS_SUCCESS) {
+-	cs_error(link->handle, RequestIO, i);
+-	return -1;
++	/* At worst, try to configure as a single port */
++	return simple_config(link);
+     }
+-    
++
+     i = CardServices(RequestIRQ, link->handle, &link->irq);
+     if (i != CS_SUCCESS) {
+ 	cs_error(link->handle, RequestIRQ, i);
+@@ -457,14 +465,27 @@
+ 	cs_error(link->handle, RequestConfiguration, i);
+ 	return -1;
+     }
+-    
++
++    /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
++       8 registers are for the UART, the others are extra registers */
++    if (info->manfid == MANFID_OXSEMI) {
++	if (cf->index == 1 || cf->index == 3) {
++	    setup_serial(info, base2, link->irq.AssignedIRQ);
++	    outb(12,link->io.BasePort1+1);
++	} else {
++	    setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
++	    outb(12,base2+1);
++	}
++	return 0;
++    }
++
+     setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+     /* The Nokia cards are not really multiport cards */
+     if (info->manfid == MANFID_NOKIA)
+ 	return 0;
+     for (i = 0; i < info->multi-1; i++)
+ 	setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
+-    
++
+     return 0;
+ }
+ 
+@@ -490,7 +511,7 @@
+     int i, last_ret, last_fn;
+ 
+     DEBUG(0, "serial_config(0x%p)\n", link);
+-	
++
+     tuple.TupleData = (cisdata_t *)buf;
+     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+     tuple.Attributes = 0;
+@@ -525,7 +546,7 @@
+     }
+     link->conf.ConfigBase = parse.config.base;
+     link->conf.Present = parse.config.rmask[0];
+-    
++
+     /* Configure card */
+     link->state |= DEV_CONFIG;
+ 
+@@ -533,8 +554,8 @@
+     tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+     tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
+     info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
+-    
+-    /* Is this a multiport card? */
++
++    /* Scan list of known multiport card ID's */
+     tuple.DesiredTuple = CISTPL_MANFID;
+     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+ 	info->manfid = le16_to_cpu(buf[0]);
+@@ -589,15 +610,15 @@
+ 	}
+ #endif
+     }
+-    
++
+     if (info->multi > 1)
+ 	multi_config(link);
+     else
+ 	simple_config(link);
+-    
++
+     if (info->ndev == 0)
+ 	goto failed;
+-    
++
+     if (info->manfid == MANFID_IBM) {
+ 	conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
+ 	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
+@@ -614,6 +635,7 @@
+     cs_error(link->handle, last_fn, last_ret);
+ failed:
+     serial_release((u_long)link);
++    link->state &= ~DEV_CONFIG_PENDING;
+ 
+ } /* serial_config */
+ 
+@@ -621,7 +643,7 @@
+ 
+     After a card is removed, serial_release() will unregister the net
+     device, and release the PCMCIA configuration.
+-    
++
+ ======================================================================*/
+ 
+ void serial_release(u_long arg)
+@@ -629,7 +651,7 @@
+     dev_link_t *link = (dev_link_t *)arg;
+     serial_info_t *info = link->priv;
+     int i;
+-    
++
+     DEBUG(0, "serial_release(0x%p)\n", link);
+ 
+     for (i = 0; i < info->ndev; i++) {
+@@ -642,7 +664,7 @@
+ 	CardServices(ReleaseIO, link->handle, &link->io);
+ 	CardServices(ReleaseIRQ, link->handle, &link->irq);
+     }
+-    
++
+     link->state &= ~DEV_CONFIG;
+ 
+ } /* serial_release */
+@@ -653,7 +675,7 @@
+     stuff to run after an event is received.  A CARD_REMOVAL event
+     also sets some flags to discourage the serial drivers from
+     talking to the ports.
+-    
++
+ ======================================================================*/
+ 
+ static int serial_event(event_t event, int priority,
+@@ -661,9 +683,9 @@
+ {
+     dev_link_t *link = args->client_data;
+     serial_info_t *info = link->priv;
+-    
++
+     DEBUG(1, "serial_event(0x%06x)\n", event);
+-    
++
+     switch (event) {
+     case CS_EVENT_CARD_REMOVAL:
+ 	link->state &= ~DEV_PRESENT;
+@@ -702,7 +724,7 @@
+     if (serv.Revision != CS_RELEASE_CODE) {
+ 	printk(KERN_NOTICE "serial_cs: Card Services release "
+ 	       "does not match!\n");
+-	return -1;
++	return -EINVAL;
+     }
+     register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
+     return 0;
+--- linux/drivers/input/Config.in~bluetooth-2.4.18-mh11	2001-09-13 00:34:06.000000000 +0200
++++ linux/drivers/input/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -14,5 +14,6 @@
+ fi
+ dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+ dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
++dep_tristate '  User level driver support' CONFIG_INPUT_UINPUT $CONFIG_INPUT
+ 
+ endmenu
+--- linux/drivers/input/keybdev.c~bluetooth-2.4.18-mh11	2001-10-11 18:14:32.000000000 +0200
++++ linux/drivers/input/keybdev.c	2004-01-25 23:37:39.000000000 +0100
+@@ -154,16 +154,18 @@
+ 
+ static struct input_handler keybdev_handler;
+ 
++static unsigned int ledstate = 0xff;
++
+ void keybdev_ledfunc(unsigned int led)
+ {
+ 	struct input_handle *handle;	
+ 
+-	for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
++	ledstate = led;
+ 
++	for (handle = keybdev_handler.handle; handle; handle = handle->hnext) {
+ 		input_event(handle->dev, EV_LED, LED_SCROLLL, !!(led & 0x01));
+ 		input_event(handle->dev, EV_LED, LED_NUML,    !!(led & 0x02));
+ 		input_event(handle->dev, EV_LED, LED_CAPSL,   !!(led & 0x04));
+-
+ 	}
+ }
+ 
+@@ -202,6 +204,12 @@
+ 
+ //	printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
+ 
++	if (ledstate != 0xff) {
++		input_event(dev, EV_LED, LED_SCROLLL, !!(ledstate & 0x01));
++		input_event(dev, EV_LED, LED_NUML,    !!(ledstate & 0x02));
++		input_event(dev, EV_LED, LED_CAPSL,   !!(ledstate & 0x04));
++	}
++
+ 	return handle;
+ }
+ 
+--- linux/drivers/input/Makefile~bluetooth-2.4.18-mh11	2000-12-29 23:07:22.000000000 +0100
++++ linux/drivers/input/Makefile	2004-01-25 23:37:39.000000000 +0100
+@@ -24,6 +24,7 @@
+ obj-$(CONFIG_INPUT_MOUSEDEV)	+= mousedev.o
+ obj-$(CONFIG_INPUT_JOYDEV)	+= joydev.o
+ obj-$(CONFIG_INPUT_EVDEV)	+= evdev.o
++obj-$(CONFIG_INPUT_UINPUT)	+= uinput.o
+ 
+ # The global Rules.make.
+ 
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/drivers/input/uinput.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,428 @@
++/*
++ *  User level driver support for input subsystem
++ *
++ * Heavily based on evdev.c by Vojtech Pavlik
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
++ * 
++ * Changes/Revisions:
++ *	0.1	20/06/2002
++ *		- first public version
++ */
++
++#include <linux/poll.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/smp_lock.h>
++#include <linux/fs.h>
++#include <linux/miscdevice.h>
++#include <linux/uinput.h>
++
++static int uinput_dev_open(struct input_dev *dev)
++{
++	return 0;
++}
++
++static void uinput_dev_close(struct input_dev *dev)
++{
++}
++
++static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
++{
++	struct uinput_device	*udev;
++
++	udev = (struct uinput_device *)dev->private;
++
++	udev->buff[udev->head].type = type;
++	udev->buff[udev->head].code = code;
++	udev->buff[udev->head].value = value;
++	do_gettimeofday(&udev->buff[udev->head].time);
++	udev->head = (udev->head + 1) % UINPUT_BUFFER_SIZE;
++
++	wake_up_interruptible(&udev->waitq);
++
++	return 0;
++}
++
++static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
++{
++	return 0;
++}
++
++static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id)
++{
++	return 0;
++}					
++
++static int uinput_create_device(struct uinput_device *udev)
++{
++	if (!udev->dev->name) {
++		printk(KERN_DEBUG "%s: write device info first\n", UINPUT_NAME);
++		return -EINVAL;
++	}
++
++	udev->dev->open = uinput_dev_open;
++	udev->dev->close = uinput_dev_close;
++	udev->dev->event = uinput_dev_event;
++	udev->dev->upload_effect = uinput_dev_upload_effect;
++	udev->dev->erase_effect = uinput_dev_erase_effect;
++	udev->dev->private = udev;
++
++	init_waitqueue_head(&(udev->waitq));
++
++	input_register_device(udev->dev);
++
++	set_bit(UIST_CREATED, &(udev->state));
++
++	return 0;
++}
++
++static int uinput_destroy_device(struct uinput_device *udev)
++{
++	if (!test_bit(UIST_CREATED, &(udev->state))) {
++		printk(KERN_WARNING "%s: create the device first\n", UINPUT_NAME);
++		return -EINVAL;
++	}
++
++	input_unregister_device(udev->dev);
++
++	clear_bit(UIST_CREATED, &(udev->state));
++
++	return 0;
++}
++
++static int uinput_open(struct inode *inode, struct file *file)
++{
++	struct uinput_device	*newdev;
++	struct input_dev	*newinput;
++
++	newdev = kmalloc(sizeof(struct uinput_device), GFP_KERNEL);
++	if (!newdev)
++		goto error;
++	memset(newdev, 0, sizeof(struct uinput_device));
++
++	newinput = kmalloc(sizeof(struct input_dev), GFP_KERNEL);
++	if (!newinput)
++		goto cleanup;
++	memset(newinput, 0, sizeof(struct input_dev));
++
++	newdev->dev = newinput;
++	
++	file->private_data = newdev;
++
++	return 0;
++cleanup:
++	kfree(newdev);
++error:
++	return -ENOMEM;
++}
++
++static int uinput_validate_absbits(struct input_dev *dev)
++{
++	unsigned int cnt;
++	int retval = 0;
++	
++	for (cnt = 0; cnt < ABS_MAX; cnt++) {
++		if (!test_bit(cnt, dev->absbit)) 
++			continue;
++		
++		if (/*!dev->absmin[cnt] || !dev->absmax[cnt] || */
++		    (dev->absmax[cnt] <= dev->absmin[cnt])) {
++			printk(KERN_DEBUG 
++				"%s: invalid abs[%02x] min:%d max:%d\n",
++				UINPUT_NAME, cnt, 
++				dev->absmin[cnt], dev->absmax[cnt]);
++			retval = -EINVAL;
++			break;
++		}
++
++		if ((dev->absflat[cnt] < dev->absmin[cnt]) ||
++		    (dev->absflat[cnt] > dev->absmax[cnt])) {
++			printk(KERN_DEBUG 
++				"%s: absflat[%02x] out of range: %d "
++				"(min:%d/max:%d)\n",
++				UINPUT_NAME, cnt, dev->absflat[cnt],
++				dev->absmin[cnt], dev->absmax[cnt]);
++			retval = -EINVAL;
++			break;
++		}
++	}
++	return retval;
++}
++
++static int uinput_alloc_device(struct file *file, const char *buffer, size_t count)
++{
++	struct uinput_user_dev	*user_dev;
++	struct input_dev	*dev;
++	struct uinput_device	*udev;
++	int			size,
++				retval;
++
++	retval = count;
++
++	udev = (struct uinput_device *)file->private_data;
++	dev = udev->dev;
++
++	user_dev = kmalloc(sizeof(*user_dev), GFP_KERNEL);
++	if (!user_dev) {
++		retval = -ENOMEM;
++		goto exit;
++	}
++
++	if (copy_from_user(user_dev, buffer, sizeof(struct uinput_user_dev))) {
++		retval = -EFAULT;
++		goto exit;
++	}
++
++	if (NULL != dev->name) 
++		kfree(dev->name);
++
++	size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
++	dev->name = kmalloc(size, GFP_KERNEL);
++	if (!dev->name) {
++		retval = -ENOMEM;
++		goto exit;
++	}
++
++	strncpy(dev->name, user_dev->name, size);
++	dev->idbus	= user_dev->idbus;
++	dev->idvendor	= user_dev->idvendor;
++	dev->idproduct	= user_dev->idproduct;
++	dev->idversion	= user_dev->idversion;
++	dev->ff_effects_max = user_dev->ff_effects_max;
++
++	size = sizeof(int) * (ABS_MAX + 1);
++	memcpy(dev->absmax, user_dev->absmax, size);
++	memcpy(dev->absmin, user_dev->absmin, size);
++	memcpy(dev->absfuzz, user_dev->absfuzz, size);
++	memcpy(dev->absflat, user_dev->absflat, size);
++
++	/* check if absmin/absmax/absfuzz/absflat are filled as
++	 * told in Documentation/input/input-programming.txt */
++	if (test_bit(EV_ABS, dev->evbit)) {
++		retval = uinput_validate_absbits(dev);
++		if (retval < 0)
++			kfree(dev->name);
++	}
++
++exit:
++	kfree(user_dev);
++	return retval;
++}
++
++static ssize_t uinput_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
++{
++	struct uinput_device	*udev = file->private_data;
++	
++	if (test_bit(UIST_CREATED, &(udev->state))) {
++		struct input_event	ev;
++
++		if (copy_from_user(&ev, buffer, sizeof(struct input_event)))
++			return -EFAULT;
++		input_event(udev->dev, ev.type, ev.code, ev.value);
++	}
++	else
++		count = uinput_alloc_device(file, buffer, count);
++
++	return count;
++}
++
++static ssize_t uinput_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
++{
++	struct uinput_device *udev = file->private_data;
++	int retval = 0;
++	
++	if (!test_bit(UIST_CREATED, &(udev->state)))
++		return -ENODEV;
++
++	if ((udev->head == udev->tail) && (file->f_flags & O_NONBLOCK))
++		return -EAGAIN;
++
++	retval = wait_event_interruptible(udev->waitq,
++			(udev->head != udev->tail) || 
++			!test_bit(UIST_CREATED, &(udev->state)));
++	
++	if (retval)
++		return retval;
++
++	if (!test_bit(UIST_CREATED, &(udev->state)))
++		return -ENODEV;
++
++	while ((udev->head != udev->tail) && 
++	    (retval + sizeof(struct input_event) <= count)) {
++		if (copy_to_user(buffer + retval, &(udev->buff[udev->tail]),
++		    sizeof(struct input_event))) return -EFAULT;
++		udev->tail = (udev->tail + 1) % UINPUT_BUFFER_SIZE;
++		retval += sizeof(struct input_event);
++	}
++
++	return retval;
++}
++
++static unsigned int uinput_poll(struct file *file, poll_table *wait)
++{
++	struct uinput_device *udev = file->private_data;
++
++	poll_wait(file, &udev->waitq, wait);
++
++	if (udev->head != udev->tail)
++		return POLLIN | POLLRDNORM;
++
++	return 0;			
++}
++
++static int uinput_burn_device(struct uinput_device *udev)
++{
++	if (test_bit(UIST_CREATED, &(udev->state)))
++		uinput_destroy_device(udev);
++
++	kfree(udev->dev);
++	kfree(udev);
++
++	return 0;
++}
++
++static int uinput_close(struct inode *inode, struct file *file)
++{
++	return uinput_burn_device((struct uinput_device *)file->private_data);
++}
++
++static int uinput_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
++{
++	int			retval = 0;
++	struct uinput_device	*udev;
++
++	udev = (struct uinput_device *)file->private_data;
++
++	/* device attributes can not be changed after the device is created */
++	if (cmd >= UI_SET_EVBIT && test_bit(UIST_CREATED, &(udev->state)))
++		return -EINVAL;
++
++	switch (cmd) {
++		case UI_DEV_CREATE:
++			retval = uinput_create_device(udev);
++			break;
++			
++		case UI_DEV_DESTROY:
++			retval = uinput_destroy_device(udev);
++			break;
++
++		case UI_SET_EVBIT:
++			if (arg > EV_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->evbit);
++			break;
++			
++		case UI_SET_KEYBIT:
++			if (arg > KEY_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->keybit);
++			break;
++			
++		case UI_SET_RELBIT:
++			if (arg > REL_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->relbit);
++			break;
++			
++		case UI_SET_ABSBIT:
++			if (arg > ABS_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->absbit);
++			break;
++			
++		case UI_SET_MSCBIT:
++			if (arg > MSC_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->mscbit);
++			break;
++			
++		case UI_SET_LEDBIT:
++			if (arg > LED_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->ledbit);
++			break;
++			
++		case UI_SET_SNDBIT:
++			if (arg > SND_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->sndbit);
++			break;
++			
++		case UI_SET_FFBIT:
++			if (arg > FF_MAX) {
++				retval = -EINVAL;
++				break;
++			}
++			set_bit(arg, udev->dev->ffbit);
++			break;
++			
++		default:
++			retval = -EFAULT;
++	}
++	return retval;
++}
++
++struct file_operations uinput_fops = {
++	owner:		THIS_MODULE,
++	open:		uinput_open,
++	release:	uinput_close,
++	read:		uinput_read,
++	write:		uinput_write,
++	poll:		uinput_poll,
++	ioctl:		uinput_ioctl,
++};
++
++static struct miscdevice uinput_misc = {
++	fops:		&uinput_fops,
++	minor:		UINPUT_MINOR,
++	name:		UINPUT_NAME,
++};
++
++static int __init uinput_init(void)
++{
++	return misc_register(&uinput_misc);
++}
++
++static void __exit uinput_exit(void)
++{
++	misc_deregister(&uinput_misc);
++}
++
++MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
++MODULE_DESCRIPTION("User level driver support for input subsystem");
++MODULE_LICENSE("GPL");
++
++module_init(uinput_init);
++module_exit(uinput_exit);
++
+--- linux/drivers/isdn/avmb1/capidrv.c~bluetooth-2.4.18-mh11	2001-12-21 18:41:54.000000000 +0100
++++ linux/drivers/isdn/avmb1/capidrv.c	2004-01-25 23:37:39.000000000 +0100
+@@ -514,13 +514,25 @@
+ 
+ static void send_message(capidrv_contr * card, _cmsg * cmsg)
+ {
+-	struct sk_buff *skb;
+-	size_t len;
++	struct sk_buff	*skb;
++	size_t		len;
++	u16		err;
++
+ 	capi_cmsg2message(cmsg, cmsg->buf);
+ 	len = CAPIMSG_LEN(cmsg->buf);
+ 	skb = alloc_skb(len, GFP_ATOMIC);
++	if(!skb) {
++		printk(KERN_ERR "no skb len(%d) memory\n", len);
++		return;
++	}
+ 	memcpy(skb_put(skb, len), cmsg->buf, len);
+-	(*capifuncs->capi_put_message) (global.appid, skb);
++	err = (*capifuncs->capi_put_message) (global.appid, skb);
++	if (err) {
++		printk(KERN_WARNING "%s: capi_put_message error: %04x\n",
++			__FUNCTION__, err);
++		kfree_skb(skb);
++		return;
++	}
+ 	global.nsentctlpkt++;
+ }
+ 
+@@ -2179,10 +2191,10 @@
+ 			free_ncci(card, card->bchans[card->nbchan-1].nccip);
+ 		if (card->bchans[card->nbchan-1].plcip)
+ 			free_plci(card, card->bchans[card->nbchan-1].plcip);
+-		if (card->plci_list)
+-			printk(KERN_ERR "capidrv: bug in free_plci()\n");
+ 		card->nbchan--;
+ 	}
++	if (card->plci_list)
++		printk(KERN_ERR "capidrv: bug in free_plci()\n");
+ 	kfree(card->bchans);
+ 	card->bchans = 0;
+ 
+--- linux/drivers/isdn/avmb1/kcapi.c~bluetooth-2.4.18-mh11	2001-12-21 18:41:54.000000000 +0100
++++ linux/drivers/isdn/avmb1/kcapi.c	2004-01-25 23:37:39.000000000 +0100
+@@ -545,7 +545,13 @@
+ static void notify_up(__u32 contr)
+ {
+ 	struct capi_interface_user *p;
++	__u16 appl;
+ 
++	for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
++		if (!VALID_APPLID(appl)) continue;
++		if (APPL(appl)->releasing) continue;
++		CARD(contr)->driver->register_appl(CARD(contr), appl, &APPL(appl)->rparam);
++	}
+         printk(KERN_NOTICE "kcapi: notify up contr %d\n", contr);
+ 	spin_lock(&capi_users_lock);
+ 	for (p = capi_users; p; p = p->next) {
+@@ -705,12 +711,16 @@
+ 			nextpp = &(*pp)->next;
+ 		}
+ 	}
+-	APPL(appl)->releasing--;
+-	if (APPL(appl)->releasing <= 0) {
+-		APPL(appl)->signal = 0;
+-		APPL_MARK_FREE(appl);
+-		printk(KERN_INFO "kcapi: appl %d down\n", appl);
+-	}
++	if (APPL(appl)->releasing) { /* only release if the application was marked for release */
++		printk(KERN_DEBUG "kcapi: appl %d releasing(%d)\n", appl, APPL(appl)->releasing);
++		APPL(appl)->releasing--;
++		if (APPL(appl)->releasing <= 0) {
++			APPL(appl)->signal = 0;
++			APPL_MARK_FREE(appl);
++			printk(KERN_INFO "kcapi: appl %d down\n", appl);
++		}
++	} else
++		printk(KERN_WARNING "kcapi: appl %d card%d released without request\n", appl, card->cnr);
+ }
+ /*
+  * ncci management
+@@ -863,16 +873,7 @@
+ 
+ static void controllercb_ready(struct capi_ctr * card)
+ {
+-	__u16 appl;
+-
+ 	card->cardstate = CARD_RUNNING;
+-
+-	for (appl = 1; appl <= CAPI_MAXAPPL; appl++) {
+-		if (!VALID_APPLID(appl)) continue;
+-		if (APPL(appl)->releasing) continue;
+-		card->driver->register_appl(card, appl, &APPL(appl)->rparam);
+-	}
+-
+         printk(KERN_NOTICE "kcapi: card %d \"%s\" ready.\n",
+ 		CARDNR(card), card->name);
+ 
+--- linux/drivers/usb/Config.in~bluetooth-2.4.18-mh11	2004-01-25 23:28:22.000000000 +0100
++++ linux/drivers/usb/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -39,7 +39,13 @@
+ 
+ comment 'USB Device Class drivers'
+ dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
+-dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++   if [ "$CONFIG_BLUEZ" = "n" ]; then
++      dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
++   else
++      comment '  USB Bluetooth can only be used with disabled Bluetooth subsystem'
++   fi
++fi
+ if [ "$CONFIG_SCSI" = "n" ]; then
+    comment '  SCSI support is needed for USB Storage'
+ fi
+--- linux/drivers/usb/hid-core.c~bluetooth-2.4.18-mh11	2001-12-21 18:41:55.000000000 +0100
++++ linux/drivers/usb/hid-core.c	2004-01-25 23:37:39.000000000 +0100
+@@ -217,6 +217,8 @@
+ 
+ 	offset = report->size;
+ 	report->size += parser->global.report_size * parser->global.report_count;
++	if (usages < parser->global.report_count)
++		usages = parser->global.report_count;
+ 
+ 	if (usages == 0)
+ 		return 0; /* ignore padding fields */
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/firmware.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,20 @@
++#ifndef _LINUX_FIRMWARE_H
++#define _LINUX_FIRMWARE_H
++#include <linux/module.h>
++#include <linux/types.h>
++#define FIRMWARE_NAME_MAX 30 
++struct firmware {
++	size_t size;
++	u8 *data;
++};
++int request_firmware (const struct firmware **fw, const char *name,
++		      const char *device);
++int request_firmware_nowait (
++	struct module *module,
++	const char *name, const char *device, void *context,
++	void (*cont)(const struct firmware *fw, void *context));
++/* On 2.5 'device' is 'struct device *' */
++
++void release_firmware (const struct firmware *fw);
++void register_firmware (const char *name, const u8 *data, size_t size);
++#endif
+--- linux/include/linux/input.h~bluetooth-2.4.18-mh11	2001-09-13 00:34:06.000000000 +0200
++++ linux/include/linux/input.h	2004-01-25 23:37:39.000000000 +0100
+@@ -468,6 +468,8 @@
+ #define BUS_PCI			0x01
+ #define BUS_ISAPNP		0x02
+ #define BUS_USB			0x03
++#define BUS_HIL			0x04
++#define BUS_BLUETOOTH		0x05
+ 
+ #define BUS_ISA			0x10
+ #define BUS_I8042		0x11
+--- linux/include/linux/kernel.h~bluetooth-2.4.18-mh11	2002-02-25 20:38:13.000000000 +0100
++++ linux/include/linux/kernel.h	2004-01-25 23:37:39.000000000 +0100
+@@ -11,6 +11,7 @@
+ #include <linux/linkage.h>
+ #include <linux/stddef.h>
+ #include <linux/types.h>
++#include <linux/compiler.h>
+ 
+ /* Optimization barrier */
+ /* The "volatile" is due to gcc bugs */
+@@ -181,4 +182,6 @@
+ 	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
+ };
+ 
+-#endif
++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
++
++#endif /* _LINUX_KERNEL_H */
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/include/linux/uinput.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,79 @@
++/*
++ *  User level driver support for input subsystem
++ *
++ * Heavily based on evdev.c by Vojtech Pavlik
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
++ * 
++ * Changes/Revisions:
++ *	0.1	20/06/2002
++ *		- first public version
++ */
++
++#ifndef __UINPUT_H_
++#define __UINPUT_H_
++
++#ifdef __KERNEL__
++#define UINPUT_MINOR		223
++#define UINPUT_NAME		"uinput"
++#define UINPUT_BUFFER_SIZE	16
++
++/* state flags => bit index for {set|clear|test}_bit ops */
++#define UIST_CREATED		0
++
++struct uinput_device {
++	struct input_dev	*dev;
++	unsigned long		state;
++	wait_queue_head_t	waitq;
++	unsigned char		ready,
++				head,
++				tail;
++	struct input_event	buff[UINPUT_BUFFER_SIZE];
++};
++#endif	/* __KERNEL__ */
++
++/* ioctl */
++#define UINPUT_IOCTL_BASE	'U'
++#define UI_DEV_CREATE		_IO(UINPUT_IOCTL_BASE, 1)
++#define UI_DEV_DESTROY		_IO(UINPUT_IOCTL_BASE, 2)
++#define UI_SET_EVBIT		_IOW(UINPUT_IOCTL_BASE, 100, int)
++#define UI_SET_KEYBIT		_IOW(UINPUT_IOCTL_BASE, 101, int)
++#define UI_SET_RELBIT		_IOW(UINPUT_IOCTL_BASE, 102, int)
++#define UI_SET_ABSBIT		_IOW(UINPUT_IOCTL_BASE, 103, int)
++#define UI_SET_MSCBIT		_IOW(UINPUT_IOCTL_BASE, 104, int)
++#define UI_SET_LEDBIT		_IOW(UINPUT_IOCTL_BASE, 105, int)
++#define UI_SET_SNDBIT		_IOW(UINPUT_IOCTL_BASE, 106, int)
++#define UI_SET_FFBIT		_IOW(UINPUT_IOCTL_BASE, 107, int)
++
++#ifndef NBITS
++#define NBITS(x) ((((x)-1)/(sizeof(long)*8))+1)
++#endif	/* NBITS */
++
++#define UINPUT_MAX_NAME_SIZE	80
++struct uinput_user_dev {
++	char name[UINPUT_MAX_NAME_SIZE];
++	unsigned short idbus;
++	unsigned short idvendor;
++	unsigned short idproduct;
++	unsigned short idversion;
++	int ff_effects_max;
++	int absmax[ABS_MAX + 1];
++	int absmin[ABS_MAX + 1];
++	int absfuzz[ABS_MAX + 1];
++	int absflat[ABS_MAX + 1];
++};
++#endif	/* __UINPUT_H_ */
+--- linux/include/net/bluetooth/bluetooth.h~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/include/net/bluetooth/bluetooth.h	2004-01-25 23:37:39.000000000 +0100
+@@ -23,7 +23,7 @@
+ */
+ 
+ /*
+- *  $Id$
++ *  $Id$
+  */
+ 
+ #ifndef __BLUETOOTH_H
+@@ -31,17 +31,63 @@
+ 
+ #include <asm/types.h>
+ #include <asm/byteorder.h>
++#include <linux/poll.h>
++#include <net/sock.h>
+ 
+ #ifndef AF_BLUETOOTH
+ #define AF_BLUETOOTH	31
+ #define PF_BLUETOOTH	AF_BLUETOOTH
+ #endif
+ 
++/* Reserv for core and drivers use */
++#define BLUEZ_SKB_RESERVE       8
++
++#ifndef MIN
++#define MIN(a,b) ((a) < (b) ? (a) : (b))
++#endif
++
+ #define BTPROTO_L2CAP   0
+ #define BTPROTO_HCI     1
++#define BTPROTO_SCO   	2
++#define BTPROTO_RFCOMM	3
++#define BTPROTO_BNEP	4
++#define BTPROTO_CMTP	5
+ 
+ #define SOL_HCI     0
+ #define SOL_L2CAP   6
++#define SOL_SCO     17
++#define SOL_RFCOMM  18
++
++/* Debugging */
++#ifdef CONFIG_BLUEZ_DEBUG
++
++#define HCI_CORE_DEBUG		1
++#define HCI_SOCK_DEBUG		1
++#define HCI_UART_DEBUG		1
++#define HCI_USB_DEBUG		1
++//#define HCI_DATA_DUMP		1
++
++#define L2CAP_DEBUG		1
++#define SCO_DEBUG		1
++#define AF_BLUETOOTH_DEBUG	1
++
++#endif /* CONFIG_BLUEZ_DEBUG */
++
++extern void bluez_dump(char *pref, __u8 *buf, int count);
++
++#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95
++#define __func__ __FUNCTION__
++#endif
++
++#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
++#define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
++#define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __func__ , ## arg)
++
++#ifdef HCI_DATA_DUMP
++#define BT_DMP(buf, len)    bluez_dump(__func__, buf, len)
++#else
++#define BT_DMP(D...)
++#endif
+ 
+ /* Connection and socket states */
+ enum {
+@@ -50,6 +96,7 @@
+ 	BT_BOUND,
+ 	BT_LISTEN,
+ 	BT_CONNECT,
++	BT_CONNECT2,
+ 	BT_CONFIG,
+ 	BT_DISCONN,
+ 	BT_CLOSED
+@@ -66,7 +113,8 @@
+ 	__u8 b[6];
+ } __attribute__((packed)) bdaddr_t;
+ 
+-#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000")
++#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
++#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+ 
+ /* Copy, swap, convert BD Address */
+ static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
+@@ -82,6 +130,91 @@
+ char *batostr(bdaddr_t *ba);
+ bdaddr_t *strtoba(char *str);
+ 
++/* Common socket structures and functions */
++
++#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo)
++#define bluez_sk(pi) ((struct sock *) \
++	((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo)))
++
++struct bluez_pinfo {
++	bdaddr_t	src;
++	bdaddr_t	dst;
++
++	struct list_head accept_q;
++	struct sock *parent;
++};
++
++struct bluez_sock_list {
++	struct sock *head;
++	rwlock_t     lock;
++};
++
++int  bluez_sock_register(int proto, struct net_proto_family *ops);
++int  bluez_sock_unregister(int proto);
++void bluez_sock_init(struct socket *sock, struct sock *sk);
++void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
++void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
++int  bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
++uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
++int  bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
++
++void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
++struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
++
++/* Skb helpers */
++struct bluez_skb_cb {
++	int    incomming;
++};
++#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
++
++static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
++{
++	struct sk_buff *skb;
++
++	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
++		skb_reserve(skb, BLUEZ_SKB_RESERVE);
++		bluez_cb(skb)->incomming  = 0;
++	}
++	return skb;
++}
++
++static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
++						       int nb, int *err)
++{
++	struct sk_buff *skb;
++
++	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
++		skb_reserve(skb, BLUEZ_SKB_RESERVE);
++		bluez_cb(skb)->incomming  = 0;
++	}
++
++	return skb;
++}
++
++static inline int skb_frags_no(struct sk_buff *skb)
++{
++	register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
++	register int n = 1;
++
++	for (; frag; frag=frag->next, n++);
++	return n;
++}
++
++int hci_core_init(void);
++int hci_core_cleanup(void);
++int hci_sock_init(void);
++int hci_sock_cleanup(void);
++
+ int bterr(__u16 code);
+ 
++#ifndef MODULE_LICENSE
++#define MODULE_LICENSE(x)
++#endif
++
++#ifndef list_for_each_safe
++#define list_for_each_safe(pos, n, head) \
++	for (pos = (head)->next, n = pos->next; pos != (head); \
++		pos = n, n = pos->next)
++#endif
++
+ #endif /* __BLUETOOTH_H */
+--- linux/include/net/bluetooth/bluez.h~bluetooth-2.4.18-mh11
++++ linux/include/net/bluetooth/bluez.h
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- *  $Id$
+- */
+-
+-#ifndef __IF_BLUEZ_H
+-#define __IF_BLUEZ_H
+-
+-#include <net/sock.h>
+-
+-#define BLUEZ_MAX_PROTO 	2
+-
+-/* Reserv for core and drivers use */
+-#define BLUEZ_SKB_RESERVE	8
+-
+-#ifndef MIN
+-#define MIN(a,b) ((a) < (b) ? (a) : (b))
+-#endif
+-
+-/* Debugging */
+-#ifdef BLUEZ_DEBUG
+-
+-#define HCI_CORE_DEBUG		1
+-#define HCI_SOCK_DEBUG		1
+-#define HCI_UART_DEBUG		1
+-#define HCI_USB_DEBUG		1
+-//#define HCI_DATA_DUMP		1
+-
+-#define L2CAP_DEBUG			1
+-
+-#endif /* BLUEZ_DEBUG */
+-
+-extern void bluez_dump(char *pref, __u8 *buf, int count);
+-
+-#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
+-#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg)
+-#define ERR(fmt, arg...) printk(KERN_ERR  __FUNCTION__ ": " fmt "\n" , ## arg)
+-
+-#ifdef HCI_DATA_DUMP
+-#define DMP(buf, len)    bluez_dump(__FUNCTION__, buf, len)
+-#else
+-#define DMP(D...)
+-#endif
+-
+-/* ----- Sockets ------ */
+-struct bluez_sock_list {
+-	struct sock *head;
+-	rwlock_t     lock;
+-};
+-
+-extern int  bluez_sock_register(int proto, struct net_proto_family *ops);
+-extern int  bluez_sock_unregister(int proto);
+-
+-extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
+-extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
+-
+-/* ----- SKB helpers ----- */
+-struct bluez_skb_cb {
+-	int    incomming;
+-};
+-#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
+-
+-static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
+-{
+-	struct sk_buff *skb;
+-
+-	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
+-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+-		bluez_cb(skb)->incomming  = 0;
+-	}
+-	return skb;
+-}
+-
+-static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
+-						       int nb, int *err)
+-{
+-	struct sk_buff *skb;
+-
+-	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
+-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+-		bluez_cb(skb)->incomming  = 0;
+-	}
+-
+-	return skb;
+-}
+-
+-static inline int skb_frags_no(struct sk_buff *skb)
+-{
+-	register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
+-	register int n = 1;
+-
+-	for (; frag; frag=frag->next, n++);
+-	return n;
+-}
+-
+-extern int hci_core_init(void);
+-extern int hci_core_cleanup(void);
+-extern int hci_sock_init(void);
+-extern int hci_sock_cleanup(void);
+-
+-#endif /* __IF_BLUEZ_H */
+--- linux/include/net/bluetooth/hci_core.h~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/include/net/bluetooth/hci_core.h	2004-01-25 23:37:39.000000000 +0100
+@@ -23,7 +23,7 @@
+ */
+ 
+ /* 
+- * $Id$ 
++ * $Id$ 
+  */
+ 
+ #ifndef __HCI_CORE_H
+@@ -32,14 +32,12 @@
+ #include <net/bluetooth/hci.h>
+ 
+ /* HCI upper protocols */
+-#define HCI_MAX_PROTO 	1
+ #define HCI_PROTO_L2CAP	0
++#define HCI_PROTO_SCO	1
+ 
+ #define HCI_INIT_TIMEOUT (HZ * 10)
+ 
+-/* ----- Inquiry cache ----- */
+-#define INQUIRY_CACHE_AGE_MAX   (HZ*5)    // 5 seconds
+-#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
++/* HCI Core structures */
+ 
+ struct inquiry_entry {
+ 	struct inquiry_entry 	*next;
+@@ -53,111 +51,186 @@
+ 	struct inquiry_entry 	*list;
+ };
+ 
+-static inline void inquiry_cache_init(struct inquiry_cache *cache)
+-{
+-	spin_lock_init(&cache->lock);
+-	cache->list = NULL;
+-}
++struct conn_hash {
++	struct list_head list;
++	spinlock_t       lock;
++	unsigned int     num;
++};
+ 
+-static inline void inquiry_cache_lock(struct inquiry_cache *cache)
+-{
+-	spin_lock(&cache->lock);
+-}
++struct hci_dev {
++	struct list_head list;
++	spinlock_t	lock;
++	atomic_t 	refcnt;
+ 
+-static inline void inquiry_cache_unlock(struct inquiry_cache *cache)
+-{
+-	spin_unlock(&cache->lock);
+-}
++	char		name[8];
++	unsigned long	flags;
++	__u16		id;
++	__u8	 	type;
++	bdaddr_t	bdaddr;
++	__u8		features[8];
+ 
+-static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache)
+-{
+-	spin_lock_bh(&cache->lock);
+-}
++	__u16		pkt_type;
++	__u16		link_policy;
++	__u16		link_mode;
++	
++	atomic_t 	cmd_cnt;
++	unsigned int 	acl_cnt;
++	unsigned int 	sco_cnt;
+ 
+-static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache)
+-{
+-	spin_unlock_bh(&cache->lock);
+-}
++	unsigned int	acl_mtu;
++	unsigned int 	sco_mtu;
++	unsigned int	acl_pkts;
++	unsigned int	sco_pkts;
+ 
+-static inline long inquiry_cache_age(struct inquiry_cache *cache)
+-{
+-	return jiffies - cache->timestamp;
+-}
++	unsigned long   cmd_last_tx;
++	unsigned long   acl_last_tx;
++	unsigned long   sco_last_tx;
++	
++	struct tasklet_struct 	cmd_task;
++	struct tasklet_struct	rx_task;
++	struct tasklet_struct 	tx_task;
+ 
+-static inline long inquiry_entry_age(struct inquiry_entry *e)
+-{
+-	return jiffies - e->timestamp;
+-}
+-extern void inquiry_cache_flush(struct inquiry_cache *cache);
++	struct sk_buff_head	rx_q;
++	struct sk_buff_head 	raw_q;
++	struct sk_buff_head 	cmd_q;
+ 
+-struct hci_dev;
++	struct sk_buff     	*sent_cmd;
++
++	struct semaphore	req_lock;
++	wait_queue_head_t	req_wait_q;
++	__u32			req_status;
++	__u32			req_result;
++
++	struct inquiry_cache 	inq_cache;
++	struct conn_hash 	conn_hash;
++
++	struct hci_dev_stats 	stat;
++
++	void			*driver_data;
++	void			*core_data;
++
++	atomic_t 		promisc;
++
++	int (*open)(struct hci_dev *hdev);
++	int (*close)(struct hci_dev *hdev);
++	int (*flush)(struct hci_dev *hdev);
++	int (*send)(struct sk_buff *skb);
++	void (*destruct)(struct hci_dev *hdev);
++	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
++};
+ 
+-/* ----- HCI Connections ----- */
+ struct hci_conn {
+ 	struct list_head list;
++
++	atomic_t	 refcnt;
++	spinlock_t	 lock;
++
+ 	bdaddr_t         dst;
+ 	__u16            handle;
++	__u16            state;
+ 	__u8		 type;
+-	unsigned int     sent;
++	__u8		 out;
++	__u32		 link_mode;
++	unsigned long	 pend;
++	
++	unsigned int	 sent;
++	
++	struct sk_buff_head data_q;
+ 
++	struct timer_list timer;
++	
+ 	struct hci_dev 	*hdev;
+ 	void		*l2cap_data;
++	void		*sco_data;
+ 	void		*priv;
+ 
+-	struct sk_buff_head data_q;
++	struct hci_conn *link;
+ };
+ 
+-struct conn_hash {
+-	struct list_head list;
+-	spinlock_t       lock;
+-	unsigned int     num;
+-};
++extern struct hci_proto *hci_proto[];
++extern struct list_head hdev_list;
++extern rwlock_t hdev_list_lock;
+ 
+-static inline void conn_hash_init(struct conn_hash *h)
++/* ----- Inquiry cache ----- */
++#define INQUIRY_CACHE_AGE_MAX   (HZ*30)   // 30 seconds
++#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
++
++#define inquiry_cache_lock(c)		spin_lock(&c->lock)
++#define inquiry_cache_unlock(c)		spin_unlock(&c->lock)
++#define inquiry_cache_lock_bh(c)	spin_lock_bh(&c->lock)
++#define inquiry_cache_unlock_bh(c)	spin_unlock_bh(&c->lock)
++
++static inline void inquiry_cache_init(struct hci_dev *hdev)
+ {
+-	INIT_LIST_HEAD(&h->list);
+-	spin_lock_init(&h->lock);
+-	h->num = 0;	
++	struct inquiry_cache *c = &hdev->inq_cache;
++	spin_lock_init(&c->lock);
++	c->list = NULL;
+ }
+ 
+-static inline void conn_hash_lock(struct conn_hash *h)
++static inline int inquiry_cache_empty(struct hci_dev *hdev)
+ {
+-	spin_lock(&h->lock);
++	struct inquiry_cache *c = &hdev->inq_cache;
++	return (c->list == NULL);
+ }
+ 
+-static inline void conn_hash_unlock(struct conn_hash *h)
++static inline long inquiry_cache_age(struct hci_dev *hdev)
+ {
+-	spin_unlock(&h->lock);
++	struct inquiry_cache *c = &hdev->inq_cache;
++	return jiffies - c->timestamp;
+ }
+ 
+-static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
++static inline long inquiry_entry_age(struct inquiry_entry *e)
+ {
+-	list_add(&c->list, &h->list);
+-	h->num++;
++	return jiffies - e->timestamp;
+ }
+ 
+-static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info);
++void inquiry_cache_flush(struct hci_dev *hdev);
++int  inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf);
++
++/* ----- HCI Connections ----- */
++enum {
++	HCI_CONN_AUTH_PEND,
++	HCI_CONN_ENCRYPT_PEND
++};
++
++#define hci_conn_lock(c)	spin_lock(&c->lock)
++#define hci_conn_unlock(c)	spin_unlock(&c->lock)
++#define hci_conn_lock_bh(c)	spin_lock_bh(&c->lock)
++#define hci_conn_unlock_bh(c)	spin_unlock_bh(&c->lock)
++
++#define conn_hash_lock(d)	spin_lock(&d->conn_hash->lock)
++#define conn_hash_unlock(d)	spin_unlock(&d->conn_hash->lock)
++#define conn_hash_lock_bh(d)	spin_lock_bh(&d->conn_hash->lock)
++#define conn_hash_unlock_bh(d)	spin_unlock_bh(&d->conn_hash->lock)
++
++static inline void conn_hash_init(struct hci_dev *hdev)
+ {
+-	conn_hash_lock(h);
+-	__conn_hash_add(h, handle, c);
+-	conn_hash_unlock(h);
++	struct conn_hash *h = &hdev->conn_hash;
++	INIT_LIST_HEAD(&h->list);
++	spin_lock_init(&h->lock);
++	h->num = 0;	
+ }
+ 
+-static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c)
++static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
+ {
+-	list_del(&c->list);
+-	h->num--;
++	struct conn_hash *h = &hdev->conn_hash;
++	list_add(&c->list, &h->list);
++	h->num++;
+ }
+ 
+-static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c)
++static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
+ {
+-	conn_hash_lock(h);
+-	__conn_hash_del(h, c);
+-	conn_hash_unlock(h);
++	struct conn_hash *h = &hdev->conn_hash;
++	list_del(&c->list);
++	h->num--;
+ }
+ 
+-static inline  struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle)
++static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev,
++	       				__u16 handle)
+ {
++	register struct conn_hash *h = &hdev->conn_hash;
+ 	register struct list_head *p;
+ 	register struct hci_conn  *c;
+ 
+@@ -169,101 +242,97 @@
+         return NULL;
+ }
+ 
+-static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle)
++static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev,
++					__u8 type, bdaddr_t *ba)
+ {
+-	struct hci_conn *conn;
++	register struct conn_hash *h = &hdev->conn_hash;
++	register struct list_head *p;
++	register struct hci_conn  *c;
+ 
+-	conn_hash_lock(h);
+-	conn = __conn_hash_lookup(h, handle);
+-	conn_hash_unlock(h);
+-	return conn;
++	list_for_each(p, &h->list) {
++		c = list_entry(p, struct hci_conn, list);
++		if (c->type == type && !bacmp(&c->dst, ba))
++			return c;
++	}
++        return NULL;
+ }
+ 
+-/* ----- HCI Devices ----- */
+-struct hci_dev {
+-	atomic_t 	refcnt;
+-
+-	char		name[8];
+-	__u32	 	flags;
+-	__u16		id;
+-	__u8	 	type;
+-	bdaddr_t	bdaddr;
+-	__u8		features[8];
+-
+-	__u16		pkt_type;
+-
+-	atomic_t 	cmd_cnt;
+-	unsigned int 	acl_cnt;
+-	unsigned int 	sco_cnt;
+-
+-	unsigned int	acl_mtu;
+-	unsigned int 	sco_mtu;
+-	unsigned int	acl_max;
+-	unsigned int	sco_max;
+-
+-	void		*driver_data;
+-	void		*l2cap_data;
+-	void		*priv;
+-
+-	struct tasklet_struct 	cmd_task;
+-	struct tasklet_struct	rx_task;
+-	struct tasklet_struct 	tx_task;
+-
+-	struct sk_buff_head	rx_q;
+-	struct sk_buff_head 	raw_q;
+-	struct sk_buff_head 	cmd_q;
+-
+-	struct sk_buff     	*sent_cmd;
+-
+-	struct semaphore	req_lock;
+-	wait_queue_head_t	req_wait_q;
+-	__u32			req_status;
+-	__u32			req_result;
++void hci_acl_connect(struct hci_conn *conn);
++void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
++void hci_add_sco(struct hci_conn *conn, __u16 handle);
+ 
+-	struct inquiry_cache 	inq_cache;
++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
++int    hci_conn_del(struct hci_conn *conn);
++void   hci_conn_hash_flush(struct hci_dev *hdev);
+ 
+-	struct conn_hash 	conn_hash;
++struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
++int hci_conn_auth(struct hci_conn *conn);
++int hci_conn_encrypt(struct hci_conn *conn);
+ 
+-	struct hci_dev_stats 	stat;
++static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout)
++{
++	mod_timer(&conn->timer, jiffies + timeout);
++}
+ 
+-	int (*open)(struct hci_dev *hdev);
+-	int (*close)(struct hci_dev *hdev);
+-	int (*flush)(struct hci_dev *hdev);
+-	int (*send)(struct sk_buff *skb);
+-};
++static inline void hci_conn_del_timer(struct hci_conn *conn)
++{
++	del_timer(&conn->timer);
++}
+ 
+-static inline void hci_dev_hold(struct hci_dev *hdev)
++static inline void hci_conn_hold(struct hci_conn *conn)
+ {
+-	atomic_inc(&hdev->refcnt);
++	atomic_inc(&conn->refcnt);
++	hci_conn_del_timer(conn);
+ }
+ 
+-static inline void hci_dev_put(struct hci_dev *hdev)
++static inline void hci_conn_put(struct hci_conn *conn)
+ {
+-	atomic_dec(&hdev->refcnt);
++	if (atomic_dec_and_test(&conn->refcnt)) {
++		if (conn->type == ACL_LINK) {
++			unsigned long timeo = (conn->out) ?
++				HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2;
++			hci_conn_set_timer(conn, timeo);
++		} else
++			hci_conn_set_timer(conn, HZ / 100);
++	}
+ }
+ 
+-extern struct hci_dev *hci_dev_get(int index);
+-extern int hci_register_dev(struct hci_dev *hdev);
+-extern int hci_unregister_dev(struct hci_dev *hdev);
+-extern int hci_dev_open(__u16 dev);
+-extern int hci_dev_close(__u16 dev);
+-extern int hci_dev_reset(__u16 dev);
+-extern int hci_dev_reset_stat(__u16 dev);
+-extern int hci_dev_info(unsigned long arg);
+-extern int hci_dev_list(unsigned long arg);
+-extern int hci_dev_setscan(unsigned long arg);
+-extern int hci_dev_setauth(unsigned long arg);
+-extern int hci_dev_setptype(unsigned long arg);
+-extern int hci_conn_list(unsigned long arg);
+-extern int hci_inquiry(unsigned long arg);
++/* ----- HCI Devices ----- */
++static inline void hci_dev_put(struct hci_dev *d)
++{ 
++	if (atomic_dec_and_test(&d->refcnt))
++		d->destruct(d);
++}
++#define hci_dev_hold(d)		atomic_inc(&d->refcnt)
+ 
+-extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode);
+-extern __u32 hci_dev_getmode(struct hci_dev *hdev);
++#define hci_dev_lock(d)		spin_lock(&d->lock)
++#define hci_dev_unlock(d)	spin_unlock(&d->lock)
++#define hci_dev_lock_bh(d)	spin_lock_bh(&d->lock)
++#define hci_dev_unlock_bh(d)	spin_unlock_bh(&d->lock)
+ 
+-extern int hci_recv_frame(struct sk_buff *skb);
++struct hci_dev *hci_dev_get(int index);
++struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
++int hci_register_dev(struct hci_dev *hdev);
++int hci_unregister_dev(struct hci_dev *hdev);
++int hci_suspend_dev(struct hci_dev *hdev);
++int hci_resume_dev(struct hci_dev *hdev);
++int hci_dev_open(__u16 dev);
++int hci_dev_close(__u16 dev);
++int hci_dev_reset(__u16 dev);
++int hci_dev_reset_stat(__u16 dev);
++int hci_dev_cmd(unsigned int cmd, unsigned long arg);
++int hci_get_dev_list(unsigned long arg);
++int hci_get_dev_info(unsigned long arg);
++int hci_get_conn_list(unsigned long arg);
++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg);
++int hci_inquiry(unsigned long arg);
++
++int  hci_recv_frame(struct sk_buff *skb);
++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
+ 
+ /* ----- LMP capabilities ----- */
+ #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
++#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
+ 
+ /* ----- HCI tasks ----- */
+ static inline void hci_sched_cmd(struct hci_dev *hdev)
+@@ -284,43 +353,130 @@
+ /* ----- HCI protocols ----- */
+ struct hci_proto {
+ 	char 		*name;
+-	__u32		id;
+-	__u32		flags;
++	unsigned int 	id;
++	unsigned long	flags;
+ 
+ 	void		*priv;
+ 
+-	int (*connect_ind) 	(struct hci_dev *hdev, bdaddr_t *bdaddr);
+-	int (*connect_cfm)	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn);
++	int (*connect_ind) 	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
++	int (*connect_cfm)	(struct hci_conn *conn, __u8 status);
+ 	int (*disconn_ind)	(struct hci_conn *conn, __u8 reason);
+-	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb , __u16 flags);
++	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+ 	int (*recv_scodata)	(struct hci_conn *conn, struct sk_buff *skb);
++	int (*auth_cfm)		(struct hci_conn *conn, __u8 status);
++	int (*encrypt_cfm)	(struct hci_conn *conn, __u8 status);
+ };
+ 
+-extern int hci_register_proto(struct hci_proto *hproto);
+-extern int hci_unregister_proto(struct hci_proto *hproto);
+-extern int hci_register_notifier(struct notifier_block *nb);
+-extern int hci_unregister_notifier(struct notifier_block *nb);
+-extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr);
+-extern int hci_disconnect(struct hci_conn *conn, __u8 reason);
+-extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param);
+-extern int hci_send_raw(struct sk_buff *skb);
+-extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+-extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
++static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
++{
++	register struct hci_proto *hp;
++	int mask = 0;
++	
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->connect_ind)
++		mask |= hp->connect_ind(hdev, bdaddr, type);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->connect_ind)
++		mask |= hp->connect_ind(hdev, bdaddr, type);
++
++	return mask;
++}
++
++static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->connect_cfm)
++		hp->connect_cfm(conn, status);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->connect_cfm)
++		hp->connect_cfm(conn, status);
++}
++
++static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->disconn_ind)
++		hp->disconn_ind(conn, reason);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->disconn_ind)
++		hp->disconn_ind(conn, reason);
++}
++
++static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->auth_cfm)
++		hp->auth_cfm(conn, status);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->auth_cfm)
++		hp->auth_cfm(conn, status);
++}
++
++static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->encrypt_cfm)
++		hp->encrypt_cfm(conn, status);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->encrypt_cfm)
++		hp->encrypt_cfm(conn, status);
++}
++
++int hci_register_proto(struct hci_proto *hproto);
++int hci_unregister_proto(struct hci_proto *hproto);
++int hci_register_notifier(struct notifier_block *nb);
++int hci_unregister_notifier(struct notifier_block *nb);
++
++int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
++int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
++int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
++
++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
++
++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
+ 
+ /* ----- HCI Sockets ----- */
+-extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
++void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+ 
+ /* HCI info for socket */
+-#define hci_pi(sk)	((struct hci_pinfo *) &sk->protinfo)
++#define hci_pi(sk)	((struct hci_pinfo *) &sk->tp_pinfo)
+ struct hci_pinfo {
+ 	struct hci_dev 	  *hdev;
+ 	struct hci_filter filter;
+ 	__u32             cmsg_mask;
+ };
+ 
++/* HCI security filter */
++#define HCI_SFLT_MAX_OGF  5
++
++struct hci_sec_filter {
++	__u32 type_mask;
++	__u32 event_mask[2];
++	__u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
++};
++
+ /* ----- HCI requests ----- */
+ #define HCI_REQ_DONE	  0
+ #define HCI_REQ_PEND	  1
+ #define HCI_REQ_CANCELED  2
+ 
++#define hci_req_lock(d)		down(&d->req_lock)
++#define hci_req_unlock(d)	up(&d->req_lock)
++
++void hci_req_complete(struct hci_dev *hdev, int result);
++void hci_req_cancel(struct hci_dev *hdev, int err);
++
+ #endif /* __HCI_CORE_H */
+--- linux/include/net/bluetooth/hci.h~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/include/net/bluetooth/hci.h	2004-01-25 23:37:39.000000000 +0100
+@@ -23,59 +23,75 @@
+ */
+ 
+ /*
+- *  $Id$
++ *  $Id$
+  */
+ 
+ #ifndef __HCI_H
+ #define __HCI_H
+ 
+-#include <asm/byteorder.h>
+-
+-#define HCI_MAX_DEV 	8
+-#define HCI_MAX_FRAME_SIZE	2048
++#define HCI_MAX_ACL_SIZE	1024
++#define HCI_MAX_SCO_SIZE	255
++#define HCI_MAX_EVENT_SIZE	260
++#define HCI_MAX_FRAME_SIZE	(HCI_MAX_ACL_SIZE + 4)
+ 
+ /* HCI dev events */
+ #define HCI_DEV_REG	1
+ #define HCI_DEV_UNREG   2
+ #define HCI_DEV_UP	3
+ #define HCI_DEV_DOWN	4
++#define HCI_DEV_SUSPEND	5
++#define HCI_DEV_RESUME	6
+ 
+ /* HCI device types */
+-#define HCI_UART 	0
++#define HCI_VHCI	0
+ #define HCI_USB		1
+-#define HCI_VHCI	2
++#define HCI_PCCARD	2
++#define HCI_UART 	3
++#define HCI_RS232 	4
++#define HCI_PCI		5
+ 
+-/* HCI device modes */
+-#define HCI_NORMAL 	0x0001
+-#define HCI_RAW		0x0002
+-#define HCI_MODE_MASK   (HCI_NORMAL | HCI_RAW)
+-#define HCI_SOCK	0x1000
++/* HCI device flags */
++enum {
++	HCI_UP,
++	HCI_INIT,
++	HCI_RUNNING,
+ 
+-/* HCI device states */
+-#define HCI_INIT	0x0010
+-#define HCI_UP 		0x0020
+-#define HCI_RUNNING	0x0040
++	HCI_PSCAN,
++	HCI_ISCAN,
++	HCI_AUTH,
++	HCI_ENCRYPT,
++	HCI_INQUIRY,
+ 
+-/* HCI device flags */
+-#define HCI_PSCAN	0x0100
+-#define HCI_ISCAN	0x0200
+-#define HCI_AUTH	0x0400
++	HCI_RAW
++};
+ 
+-/* HCI Ioctl defines */
++/* HCI ioctl defines */
+ #define HCIDEVUP        _IOW('H', 201, int)
+ #define HCIDEVDOWN      _IOW('H', 202, int)
+ #define HCIDEVRESET     _IOW('H', 203, int)
+-#define HCIRESETSTAT    _IOW('H', 204, int)
+-#define HCIGETINFO      _IOR('H', 205, int)
+-#define HCIGETDEVLIST   _IOR('H', 206, int)
+-#define HCISETRAW       _IOW('H', 207, int)
+-#define HCISETSCAN      _IOW('H', 208, int)
+-#define HCISETAUTH      _IOW('H', 209, int)
+-#define HCIINQUIRY      _IOR('H', 210, int)
+-#define HCISETPTYPE     _IOW('H', 211, int)
++#define HCIDEVRESTAT    _IOW('H', 204, int)
++
++#define HCIGETDEVLIST   _IOR('H', 210, int)
++#define HCIGETDEVINFO   _IOR('H', 211, int)
+ #define HCIGETCONNLIST  _IOR('H', 212, int)
++#define HCIGETCONNINFO  _IOR('H', 213, int)
+ 
+-#ifndef __NO_HCI_DEFS
++#define HCISETRAW       _IOW('H', 220, int)
++#define HCISETSCAN      _IOW('H', 221, int)
++#define HCISETAUTH      _IOW('H', 222, int)
++#define HCISETENCRYPT   _IOW('H', 223, int)
++#define HCISETPTYPE     _IOW('H', 224, int)
++#define HCISETLINKPOL   _IOW('H', 225, int)
++#define HCISETLINKMODE  _IOW('H', 226, int)
++#define HCISETACLMTU    _IOW('H', 227, int)
++#define HCISETSCOMTU    _IOW('H', 228, int)
++
++#define HCIINQUIRY      _IOR('H', 240, int)
++
++/* HCI timeouts */
++#define HCI_CONN_TIMEOUT 	(HZ * 40)
++#define HCI_DISCONN_TIMEOUT 	(HZ * 2)
++#define HCI_CONN_IDLE_TIMEOUT	(HZ * 60)
+ 
+ /* HCI Packet types */
+ #define HCI_COMMAND_PKT		0x01
+@@ -92,11 +108,18 @@
+ #define HCI_DH3 	0x0800
+ #define HCI_DH5 	0x8000
+ 
++#define HCI_HV1		0x0020
++#define HCI_HV2		0x0040
++#define HCI_HV3		0x0080
++
++#define SCO_PTYPE_MASK	(HCI_HV1 | HCI_HV2 | HCI_HV3)
++#define ACL_PTYPE_MASK	(~SCO_PTYPE_MASK)
++
+ /* ACL flags */
+-#define ACL_CONT		0x0001
+-#define ACL_START		0x0002
+-#define ACL_ACTIVE_BCAST	0x0010
+-#define ACL_PICO_BCAST		0x0020
++#define ACL_CONT		0x01
++#define ACL_START		0x02
++#define ACL_ACTIVE_BCAST	0x04
++#define ACL_PICO_BCAST		0x08
+ 
+ /* Baseband links */
+ #define SCO_LINK	0x00
+@@ -125,6 +148,20 @@
+ #define LMP_PSCHEME	0x02
+ #define LMP_PCONTROL	0x04
+ 
++/* Link policies */
++#define HCI_LP_RSWITCH	0x0001
++#define HCI_LP_HOLD	0x0002
++#define HCI_LP_SNIFF	0x0004
++#define HCI_LP_PARK	0x0008
++
++/* Link mode */
++#define HCI_LM_ACCEPT	0x8000
++#define HCI_LM_MASTER	0x0001
++#define HCI_LM_AUTH	0x0002
++#define HCI_LM_ENCRYPT	0x0004
++#define HCI_LM_TRUSTED	0x0008
++#define HCI_LM_RELIABLE	0x0010
++
+ /* -----  HCI Commands ----- */
+ /* OGF & OCF values */
+ 
+@@ -137,9 +174,10 @@
+ 	__u8  hci_ver;
+ 	__u16 hci_rev;
+ 	__u8  lmp_ver;
+-	__u16 man_name;
+-	__u16 lmp_sub;
++	__u16 manufacturer;
++	__u16 lmp_subver;
+ } __attribute__ ((packed)) read_local_version_rp;
++#define READ_LOCAL_VERSION_RP_SIZE 9
+ 
+ #define OCF_READ_LOCAL_FEATURES	0x0003
+ typedef struct {
+@@ -165,18 +203,24 @@
+ /* Host Controller and Baseband */
+ #define OGF_HOST_CTL	0x03
+ #define OCF_RESET		0x0003
++#define OCF_READ_AUTH_ENABLE	0x001F
+ #define OCF_WRITE_AUTH_ENABLE	0x0020
+-	#define AUTH_DISABLED			0x00
+-	#define AUTH_ENABLED			0x01
++	#define AUTH_DISABLED		0x00
++	#define AUTH_ENABLED		0x01
++
++#define OCF_READ_ENCRYPT_MODE	0x0021
++#define OCF_WRITE_ENCRYPT_MODE	0x0022
++	#define ENCRYPT_DISABLED	0x00
++	#define ENCRYPT_P2P		0x01
++	#define ENCRYPT_BOTH		0x02
+ 
+ #define OCF_WRITE_CA_TIMEOUT  	0x0016	
+ #define OCF_WRITE_PG_TIMEOUT  	0x0018
+ 
+ #define OCF_WRITE_SCAN_ENABLE 	0x001A
+-	#define SCANS_DISABLED		0x00
+-	#define IS_ENA_PS_DIS		0x01
+-	#define IS_DIS_PS_ENA		0x02
+-	#define IS_ENA_PS_ENA		0x03
++	#define SCAN_DISABLED		0x00
++	#define SCAN_INQUIRY		0x01
++	#define SCAN_PAGE		0x02
+ 
+ #define OCF_SET_EVENT_FLT	0x0005
+ typedef struct {
+@@ -226,9 +270,18 @@
+ } __attribute__ ((packed)) write_class_of_dev_cp;
+ #define WRITE_CLASS_OF_DEV_CP_SIZE 3
+ 
++#define OCF_HOST_BUFFER_SIZE	0x0033
++typedef struct {
++	__u16 	acl_mtu;
++	__u8 	sco_mtu;
++	__u16 	acl_max_pkt;
++	__u16	sco_max_pkt;
++} __attribute__ ((packed)) host_buffer_size_cp;
++#define HOST_BUFFER_SIZE_CP_SIZE 7
++
+ /* Link Control */
+ #define OGF_LINK_CTL	0x01 
+-#define OCF_CREATE_CONN	0x0005
++#define OCF_CREATE_CONN		0x0005
+ typedef struct {
+ 	bdaddr_t bdaddr;
+ 	__u16 	pkt_type;
+@@ -246,6 +299,13 @@
+ } __attribute__ ((packed)) accept_conn_req_cp;
+ #define ACCEPT_CONN_REQ_CP_SIZE	7
+ 
++#define OCF_REJECT_CONN_REQ	0x000a
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8 	reason;
++} __attribute__ ((packed)) reject_conn_req_cp;
++#define REJECT_CONN_REQ_CP_SIZE	7
++
+ #define OCF_DISCONNECT	0x0006
+ typedef struct {
+ 	__u16 	handle;
+@@ -253,17 +313,142 @@
+ } __attribute__ ((packed)) disconnect_cp;
+ #define DISCONNECT_CP_SIZE 3
+ 
++#define OCF_ADD_SCO	0x0007
++typedef struct {
++	__u16 	handle;
++	__u16 	pkt_type;
++} __attribute__ ((packed)) add_sco_cp;
++#define ADD_SCO_CP_SIZE 4
++
+ #define OCF_INQUIRY		0x0001
+ typedef struct {
+ 	__u8 	lap[3];
+-	__u8 	lenght;
++	__u8 	length;
+ 	__u8	num_rsp;
+ } __attribute__ ((packed)) inquiry_cp;
+ #define INQUIRY_CP_SIZE 5
+ 
+-#define OGF_LINK_POLICY	 	0x02   /* Link Policy */
++typedef struct {
++	__u8     status;
++	bdaddr_t bdaddr;
++} __attribute__ ((packed)) status_bdaddr_rp;
++#define STATUS_BDADDR_RP_SIZE 7
+ 
+-/* --------- HCI Events --------- */
++#define OCF_INQUIRY_CANCEL	0x0002
++
++#define OCF_LINK_KEY_REPLY	0x000B
++#define OCF_LINK_KEY_NEG_REPLY	0x000C
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8     link_key[16];
++} __attribute__ ((packed)) link_key_reply_cp;
++#define LINK_KEY_REPLY_CP_SIZE 22
++
++#define OCF_PIN_CODE_REPLY	0x000D
++#define OCF_PIN_CODE_NEG_REPLY	0x000E
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8	 pin_len;
++	__u8	 pin_code[16];
++} __attribute__ ((packed)) pin_code_reply_cp;
++#define PIN_CODE_REPLY_CP_SIZE 23
++
++#define OCF_CHANGE_CONN_PTYPE	0x000F
++typedef struct {
++	__u16	 handle;
++	__u16	 pkt_type;
++} __attribute__ ((packed)) change_conn_ptype_cp;
++#define CHANGE_CONN_PTYPE_CP_SIZE 4
++
++#define OCF_AUTH_REQUESTED	0x0011
++typedef struct {
++	__u16	 handle;
++} __attribute__ ((packed)) auth_requested_cp;
++#define AUTH_REQUESTED_CP_SIZE 2
++
++#define OCF_SET_CONN_ENCRYPT	0x0013
++typedef struct {
++	__u16	 handle;
++	__u8	 encrypt;
++} __attribute__ ((packed)) set_conn_encrypt_cp;
++#define SET_CONN_ENCRYPT_CP_SIZE 3
++
++#define OCF_REMOTE_NAME_REQ	0x0019
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8     pscan_rep_mode;
++	__u8     pscan_mode;
++	__u16    clock_offset;
++} __attribute__ ((packed)) remote_name_req_cp;
++#define REMOTE_NAME_REQ_CP_SIZE 10
++
++#define OCF_READ_REMOTE_FEATURES 0x001B
++typedef struct {
++	__u16   handle;
++} __attribute__ ((packed)) read_remote_features_cp;
++#define READ_REMOTE_FEATURES_CP_SIZE 2
++
++#define OCF_READ_REMOTE_VERSION 0x001D
++typedef struct {
++	__u16   handle;
++} __attribute__ ((packed)) read_remote_version_cp;
++#define READ_REMOTE_VERSION_CP_SIZE 2
++
++/* Link Policy */
++#define OGF_LINK_POLICY	 0x02   
++#define OCF_ROLE_DISCOVERY	0x0009
++typedef struct {
++	__u16	handle;
++} __attribute__ ((packed)) role_discovery_cp;
++#define ROLE_DISCOVERY_CP_SIZE 2
++typedef struct {
++	__u8    status;
++	__u16	handle;
++	__u8    role;
++} __attribute__ ((packed)) role_discovery_rp;
++#define ROLE_DISCOVERY_RP_SIZE 4
++
++#define OCF_READ_LINK_POLICY	0x000C
++typedef struct {
++	__u16	handle;
++} __attribute__ ((packed)) read_link_policy_cp;
++#define READ_LINK_POLICY_CP_SIZE 2
++typedef struct {
++	__u8    status;
++	__u16	handle;
++	__u16   policy;
++} __attribute__ ((packed)) read_link_policy_rp;
++#define READ_LINK_POLICY_RP_SIZE 5
++
++#define OCF_SWITCH_ROLE	0x000B
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8     role;
++} __attribute__ ((packed)) switch_role_cp;
++#define SWITCH_ROLE_CP_SIZE 7
++
++#define OCF_WRITE_LINK_POLICY	0x000D
++typedef struct {
++	__u16	handle;
++	__u16   policy;
++} __attribute__ ((packed)) write_link_policy_cp;
++#define WRITE_LINK_POLICY_CP_SIZE 4
++typedef struct {
++	__u8    status;
++	__u16	handle;
++} __attribute__ ((packed)) write_link_policy_rp;
++#define WRITE_LINK_POLICY_RP_SIZE 3
++
++/* Status params */
++#define OGF_STATUS_PARAM 	0x05
++
++/* Testing commands */
++#define OGF_TESTING_CMD 	0x3e
++
++/* Vendor specific commands */
++#define OGF_VENDOR_CMD  	0x3f
++
++/* ---- HCI Events ---- */
+ #define EVT_INQUIRY_COMPLETE 	0x01
+ 
+ #define EVT_INQUIRY_RESULT 	0x02
+@@ -272,11 +457,22 @@
+ 	__u8	pscan_rep_mode;
+ 	__u8	pscan_period_mode;
+ 	__u8	pscan_mode;
+-	__u8	class[3];
++	__u8	dev_class[3];
+ 	__u16	clock_offset;
+ } __attribute__ ((packed)) inquiry_info;
+ #define INQUIRY_INFO_SIZE 14
+ 
++#define EVT_INQUIRY_RESULT_WITH_RSSI	0x22
++typedef struct {
++	bdaddr_t	bdaddr;
++	__u8	pscan_rep_mode;
++	__u8	pscan_period_mode;
++	__u8	dev_class[3];
++	__u16	clock_offset;
++	__u8	rssi;
++} __attribute__ ((packed)) inquiry_info_with_rssi;
++#define INQUIRY_INFO_WITH_RSSI_SIZE 14
++
+ #define EVT_CONN_COMPLETE 	0x03
+ typedef struct {
+ 	__u8	status;
+@@ -303,6 +499,44 @@
+ } __attribute__ ((packed)) evt_disconn_complete;
+ #define EVT_DISCONN_COMPLETE_SIZE 4
+ 
++#define EVT_AUTH_COMPLETE	0x06
++typedef struct {
++	__u8 	status;
++	__u16 	handle;
++} __attribute__ ((packed)) evt_auth_complete;
++#define EVT_AUTH_COMPLETE_SIZE 3
++
++#define EVT_REMOTE_NAME_REQ_COMPLETE	0x07
++typedef struct {
++	__u8 	 status;
++	bdaddr_t bdaddr;
++	__u8 	 name[248];
++} __attribute__ ((packed)) evt_remote_name_req_complete;
++#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
++
++#define EVT_ENCRYPT_CHANGE	0x08
++typedef struct {
++	__u8 	status;
++	__u16 	handle;
++	__u8	encrypt;
++} __attribute__ ((packed)) evt_encrypt_change;
++#define EVT_ENCRYPT_CHANGE_SIZE 5
++
++#define EVT_QOS_SETUP_COMPLETE 0x0D
++typedef struct {
++	__u8	service_type;
++	__u32	token_rate;
++	__u32	peak_bandwidth;
++	__u32	latency;
++	__u32	delay_variation;
++} __attribute__ ((packed)) hci_qos;
++typedef struct {
++	__u8	status;
++	__u16	handle;
++	hci_qos qos;
++} __attribute__ ((packed)) evt_qos_setup_complete;
++#define EVT_QOS_SETUP_COMPLETE_SIZE 20
++
+ #define EVT_CMD_COMPLETE 	0x0e
+ typedef struct {
+ 	__u8 	ncmd;
+@@ -321,16 +555,78 @@
+ #define EVT_NUM_COMP_PKTS	0x13
+ typedef struct {
+ 	__u8 	num_hndl;
+-	/* variable lenght part */
++	/* variable length part */
+ } __attribute__ ((packed)) evt_num_comp_pkts;
+ #define EVT_NUM_COMP_PKTS_SIZE 1
+ 
+-#define EVT_HCI_DEV_EVENT	0xfd
++#define EVT_ROLE_CHANGE		0x12
++typedef struct {
++	__u8 	 status;
++	bdaddr_t bdaddr;
++	__u8     role;
++} __attribute__ ((packed)) evt_role_change;
++#define EVT_ROLE_CHANGE_SIZE 8
++
++#define EVT_PIN_CODE_REQ        0x16
++typedef struct {
++	bdaddr_t bdaddr;
++} __attribute__ ((packed)) evt_pin_code_req;
++#define EVT_PIN_CODE_REQ_SIZE 6
++
++#define EVT_LINK_KEY_REQ        0x17
++typedef struct {
++	bdaddr_t bdaddr;
++} __attribute__ ((packed)) evt_link_key_req;
++#define EVT_LINK_KEY_REQ_SIZE 6
++
++#define EVT_LINK_KEY_NOTIFY	0x18
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8	 link_key[16];
++	__u8	 key_type;
++} __attribute__ ((packed)) evt_link_key_notify;
++#define EVT_LINK_KEY_NOTIFY_SIZE 23
++
++#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B
++typedef struct {
++	__u8    status;
++	__u16   handle;
++	__u8    features[8];
++} __attribute__ ((packed)) evt_read_remote_features_complete;
++#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
++
++#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C
++typedef struct {
++	__u8    status;
++	__u16   handle;
++	__u8    lmp_ver;
++	__u16   manufacturer;
++	__u16   lmp_subver;
++} __attribute__ ((packed)) evt_read_remote_version_complete;
++#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
++
++/* Internal events generated by BlueZ stack */
++#define EVT_STACK_INTERNAL	0xfd
++typedef struct {
++	__u16   type;
++	__u8 	data[0];
++} __attribute__ ((packed)) evt_stack_internal;
++#define EVT_STACK_INTERNAL_SIZE 2
++
++#define EVT_SI_DEVICE  	0x01
++typedef struct {
++	__u16   event;
++	__u16 	dev_id;
++} __attribute__ ((packed)) evt_si_device;
++#define EVT_SI_DEVICE_SIZE 4
++
++#define EVT_SI_SECURITY	0x02
+ typedef struct {
+ 	__u16 	event;
+-	__u16 	param;
+-} __attribute__ ((packed)) evt_hci_dev_event;
+-#define EVT_HCI_DEV_EVENT_SIZE 4
++	__u16   proto;
++	__u16   subproto;
++	__u8    incomming;
++} __attribute__ ((packed)) evt_si_security;
+ 
+ /* --------  HCI Packet structures  -------- */
+ #define HCI_TYPE_LEN	1
+@@ -369,14 +665,14 @@
+ #define acl_handle(h)		(h & 0x0fff)
+ #define acl_flags(h)		(h >> 12)
+ 
+-#endif /* _NO_HCI_DEFS */
+-
+ /* HCI Socket options */
+-#define HCI_DATA_DIR	0x0001
+-#define HCI_FILTER	0x0002
++#define HCI_DATA_DIR	1
++#define HCI_FILTER	2
++#define HCI_TIME_STAMP	3
+ 
+ /* HCI CMSG flags */
+ #define HCI_CMSG_DIR	0x0001
++#define HCI_CMSG_TSTAMP	0x0002
+ 
+ struct sockaddr_hci {
+ 	sa_family_t    hci_family;
+@@ -387,27 +683,29 @@
+ struct hci_filter {
+ 	__u32 type_mask;
+ 	__u32 event_mask[2];
++	__u16 opcode;
+ };
+ 
+-struct hci_dev_req {
+-	__u16 dev_id;
+-	__u32 dev_opt;
+-};
+-
+-struct hci_dev_list_req {
+-	__u16  dev_num;
+-	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */
+-};
++#define HCI_FLT_TYPE_BITS	31
++#define HCI_FLT_EVENT_BITS	63
++#define HCI_FLT_OGF_BITS	63
++#define HCI_FLT_OCF_BITS	127
+ 
+-struct hci_inquiry_req {
+-	__u16 dev_id;
+-	__u16 flags;
+-	__u8  lap[3];
+-	__u8  length;
+-	__u8  num_rsp;
+-};
+-#define IREQ_CACHE_FLUSH 0x0001
++#if BITS_PER_LONG == 64
++static inline void hci_set_bit(int nr, void *addr)
++{
++	*((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31));
++}
++static inline int hci_test_bit(int nr, void *addr)
++{
++	return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
++}
++#else
++#define hci_set_bit	set_bit
++#define hci_test_bit	test_bit
++#endif
+ 
++/* Ioctl requests structures */
+ struct hci_dev_stats {
+ 	__u32 err_rx;
+ 	__u32 err_tx;
+@@ -433,11 +731,13 @@
+ 	__u8  features[8];
+ 
+ 	__u32 pkt_type;
++	__u32 link_policy;
++	__u32 link_mode;
+ 
+ 	__u16 acl_mtu;
+-	__u16 acl_max;
++	__u16 acl_pkts;
+ 	__u16 sco_mtu;
+-	__u16 sco_max;
++	__u16 sco_pkts;
+ 
+ 	struct hci_dev_stats stat;
+ };
+@@ -445,6 +745,20 @@
+ struct hci_conn_info {
+ 	__u16    handle;
+ 	bdaddr_t bdaddr;
++	__u8	 type;
++	__u8	 out;
++	__u16	 state;
++	__u32	 link_mode;
++};
++
++struct hci_dev_req {
++	__u16 dev_id;
++	__u32 dev_opt;
++};
++
++struct hci_dev_list_req {
++	__u16  dev_num;
++	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */
+ };
+ 
+ struct hci_conn_list_req {
+@@ -453,4 +767,26 @@
+ 	struct hci_conn_info conn_info[0];
+ };
+ 
++struct hci_conn_info_req {
++	bdaddr_t bdaddr;
++	__u8     type;
++	struct   hci_conn_info conn_info[0];
++};
++
++struct hci_inquiry_req {
++	__u16 dev_id;
++	__u16 flags;
++	__u8  lap[3];
++	__u8  length;
++	__u8  num_rsp;
++};
++#define IREQ_CACHE_FLUSH 0x0001
++
++struct hci_remotename_req {
++	__u16 dev_id;
++	__u16 flags;
++	bdaddr_t bdaddr;
++	__u8  name[248];
++};
++
+ #endif /* __HCI_H */
+--- linux/include/net/bluetooth/hci_uart.h~bluetooth-2.4.18-mh11
++++ linux/include/net/bluetooth/hci_uart.h
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * $Id$
+- */
+-
+-#ifndef N_HCI
+-#define N_HCI	15
+-#endif
+-
+-#ifdef __KERNEL__
+-
+-#define tty2n_hci(tty)  ((struct n_hci *)((tty)->disc_data))
+-#define n_hci2tty(n_hci) ((n_hci)->tty)
+-
+-struct n_hci {
+-	struct tty_struct *tty;
+-	struct hci_dev hdev;
+-
+-	struct sk_buff_head txq;
+-	unsigned long tx_state;
+-
+-	spinlock_t rx_lock;
+-	unsigned long rx_state;
+-	unsigned long rx_count;
+-	struct sk_buff *rx_skb;
+-};
+-
+-/* Transmit states  */
+-#define TRANS_SENDING		1
+-#define TRANS_WAKEUP		2
+-
+-/* Receiver States */
+-#define WAIT_PACKET_TYPE	0
+-#define WAIT_EVENT_HDR	 	1
+-#define WAIT_ACL_HDR		2
+-#define WAIT_SCO_HDR		3
+-#define WAIT_DATA	        4
+-
+-#endif /* __KERNEL__ */
+--- linux/include/net/bluetooth/hci_usb.h~bluetooth-2.4.18-mh11
++++ linux/include/net/bluetooth/hci_usb.h
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * $Id$
+- */
+-
+-#ifdef __KERNEL__
+-
+-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
+-#define HCI_DEV_CLASS        0xe0	/* Wireless class */
+-#define HCI_DEV_SUBCLASS     0x01	/* RF subclass */
+-#define HCI_DEV_PROTOCOL     0x01	/* Bluetooth programming protocol */
+-
+-#define HCI_CTRL_REQ	     0x20
+-
+-struct hci_usb {
+-	struct usb_device 	*udev;
+-
+-	devrequest		dev_req;
+-	struct urb 		*ctrl_urb;
+-	struct urb		*intr_urb;
+-	struct urb		*read_urb;
+-	struct urb		*write_urb;
+-
+-	__u8			*read_buf;
+-	__u8			*intr_buf;
+-	struct sk_buff		*intr_skb;
+-	int			intr_count;
+-
+-	__u8			bulk_out_ep_addr;
+-	__u8			bulk_in_ep_addr;
+-	__u8			intr_in_ep_addr;
+-	__u8			intr_in_interval;
+-
+-	struct hci_dev		hdev;
+-
+-	unsigned long		tx_state;
+-	struct sk_buff_head	tx_ctrl_q;
+-	struct sk_buff_head	tx_write_q;
+-};
+-
+-/* Transmit states  */
+-#define HCI_TX_CTRL	1
+-#define HCI_TX_WRITE	2
+-
+-#endif /* __KERNEL__ */
+--- linux/include/net/bluetooth/hci_vhci.h~bluetooth-2.4.18-mh11
++++ linux/include/net/bluetooth/hci_vhci.h
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * $Id$
+- */
+-
+-#ifndef __HCI_VHCI_H
+-#define __HCI_VHCI_H
+-
+-#ifdef __KERNEL__
+-
+-struct hci_vhci_struct {
+-	struct hci_dev       hdev;
+-	__u32                flags;
+-	wait_queue_head_t    read_wait;
+-	struct sk_buff_head  readq;
+-	struct fasync_struct *fasync;
+-};
+-
+-/* VHCI device flags */
+-#define VHCI_FASYNC		0x0010
+-
+-#endif /* __KERNEL__ */
+-
+-#define VHCI_DEV	"/dev/vhci"
+-#define VHCI_MINOR	250
+-
+-#endif /* __HCI_VHCI_H */
+--- linux/include/net/bluetooth/l2cap_core.h~bluetooth-2.4.18-mh11
++++ linux/include/net/bluetooth/l2cap_core.h
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- *  $Id$
+- */
+-
+-#ifndef __L2CAP_CORE_H
+-#define __L2CAP_CORE_H
+-
+-#ifdef __KERNEL__
+-
+-/* ----- L2CAP interface ----- */
+-struct l2cap_iff {
+-	struct list_head list;
+-	struct hci_dev   *hdev;
+-	bdaddr_t         *bdaddr;
+-	__u16            mtu;
+-	spinlock_t       lock;
+-	struct list_head conn_list;
+-};
+-
+-static inline void l2cap_iff_lock(struct l2cap_iff *iff)
+-{
+-	spin_lock(&iff->lock);
+-}
+-
+-static inline void l2cap_iff_unlock(struct l2cap_iff *iff)
+-{
+-	spin_unlock(&iff->lock);
+-}
+-
+-/* ----- L2CAP connections ----- */
+-struct l2cap_chan_list {
+-	struct sock	*head;
+-	rwlock_t	lock;
+-	long		num;
+-};
+-
+-struct l2cap_conn {
+-	struct l2cap_iff *iff;
+-	struct list_head list;
+-
+-	struct hci_conn	 *hconn;
+-
+-	__u16		state;
+-	__u8		out;
+-	bdaddr_t	src;
+-	bdaddr_t	dst;
+-
+-	spinlock_t	lock;
+-	atomic_t	refcnt;
+-
+-	struct sk_buff *rx_skb;
+-	__u32		rx_len;
+-	__u8		rx_ident;
+-	__u8		tx_ident;
+-
+-	struct l2cap_chan_list chan_list;
+-
+-	struct timer_list timer;
+-};
+-
+-static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c)
+-{
+-	list_add(&c->list, &iff->conn_list);
+-}
+-
+-static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c)
+-{
+-	list_del(&c->list);
+-}
+-
+-/* ----- L2CAP channel and socket info ----- */
+-#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->protinfo)
+-
+-struct l2cap_accept_q {
+-	struct sock 	*head;
+-	struct sock 	*tail;
+-};
+-
+-struct l2cap_pinfo {
+-	bdaddr_t	src;
+-	bdaddr_t	dst;
+-	__u16		psm;
+-	__u16		dcid;
+-	__u16		scid;
+-	__u32		flags;
+-
+-	__u16		imtu;
+-	__u16		omtu;
+-	__u16		flush_to;
+-
+-	__u8		conf_state;
+-	__u16		conf_mtu;
+-
+-	__u8		ident;
+-
+-	struct l2cap_conn 	*conn;
+-	struct sock 		*next_c;
+-	struct sock 		*prev_c;
+-
+-	struct sock *parent;
+-	struct sock *next_q;
+-	struct sock *prev_q;
+-
+-	struct l2cap_accept_q accept_q;
+-};
+-
+-#define CONF_REQ_SENT    0x01
+-#define CONF_INPUT_DONE  0x02
+-#define CONF_OUTPUT_DONE 0x04
+-
+-extern struct bluez_sock_list l2cap_sk_list;
+-extern struct list_head  l2cap_iff_list;
+-extern rwlock_t l2cap_rt_lock;
+-
+-extern void l2cap_register_proc(void);
+-extern void l2cap_unregister_proc(void);
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __L2CAP_CORE_H */
+--- linux/include/net/bluetooth/l2cap.h~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/include/net/bluetooth/l2cap.h	2004-01-25 23:37:39.000000000 +0100
+@@ -23,22 +23,17 @@
+ */
+ 
+ /*
+- *  $Id$
++ *  $Id$
+  */
+ 
+ #ifndef __L2CAP_H
+ #define __L2CAP_H
+ 
+-#include <asm/types.h>
+-#include <asm/byteorder.h>
+-
+ /* L2CAP defaults */
+ #define L2CAP_DEFAULT_MTU 	672
+ #define L2CAP_DEFAULT_FLUSH_TO	0xFFFF
+ 
+ #define L2CAP_CONN_TIMEOUT 	(HZ * 40)
+-#define L2CAP_DISCONN_TIMEOUT 	(HZ * 2)
+-#define L2CAP_CONN_IDLE_TIMEOUT	(HZ * 60)
+ 
+ /* L2CAP socket address */
+ struct sockaddr_l2 {
+@@ -47,17 +42,12 @@
+ 	bdaddr_t	l2_bdaddr;
+ };
+ 
+-/* set/get sockopt defines */
+-#define L2CAP_OPTIONS  0x01
++/* Socket options */
++#define L2CAP_OPTIONS	0x01
+ struct l2cap_options {
+ 	__u16 omtu;
+ 	__u16 imtu;
+ 	__u16 flush_to;
+-	__u32 token_rate;
+-	__u32 bucket_size;
+-	__u32 pick_band;
+-	__u32 latency;
+-	__u32 delay_var;
+ };
+ 
+ #define L2CAP_CONNINFO  0x02
+@@ -65,6 +55,27 @@
+ 	__u16 hci_handle;
+ };
+ 
++#define L2CAP_LM	0x03
++#define L2CAP_LM_MASTER		0x0001
++#define L2CAP_LM_AUTH		0x0002
++#define L2CAP_LM_ENCRYPT	0x0004
++#define L2CAP_LM_TRUSTED	0x0008
++#define L2CAP_LM_RELIABLE	0x0010
++
++#define L2CAP_QOS	0x04
++struct l2cap_qos {
++	__u16 service_type;
++	__u32 token_rate;
++	__u32 token_bucket_size;
++	__u32 peak_bandwidth;
++	__u32 latency;
++	__u32 delay_variation;
++};
++
++#define L2CAP_SERV_NO_TRAFFIC	0x00
++#define L2CAP_SERV_BEST_EFFORT	0x01
++#define L2CAP_SERV_GUARANTEED	0x02
++
+ /* L2CAP command codes */
+ #define L2CAP_COMMAND_REJ 0x01
+ #define L2CAP_CONN_REQ    0x02
+@@ -79,7 +90,6 @@
+ #define L2CAP_INFO_RSP    0x0b
+ 
+ /* L2CAP structures */
+-
+ typedef struct {
+ 	__u16      len;
+ 	__u16      cid;
+@@ -112,11 +122,17 @@
+ } __attribute__ ((packed))	l2cap_conn_rsp;
+ #define L2CAP_CONN_RSP_SIZE	8
+ 
+-#define L2CAP_CONN_SUCCESS    0x0000
+-#define L2CAP_CONN_PEND       0x0001
+-#define L2CAP_CONN_BAD_PSM    0x0002
+-#define L2CAP_CONN_SEC_BLOCK  0x0003
+-#define L2CAP_CONN_NO_MEM     0x0004
++/* connect result */
++#define L2CAP_CR_SUCCESS    0x0000
++#define L2CAP_CR_PEND       0x0001
++#define L2CAP_CR_BAD_PSM    0x0002
++#define L2CAP_CR_SEC_BLOCK  0x0003
++#define L2CAP_CR_NO_MEM     0x0004
++
++/* connect status */
++#define L2CAP_CS_NO_INFO      0x0000
++#define L2CAP_CS_AUTHEN_PEND  0x0001
++#define L2CAP_CS_AUTHOR_PEND  0x0002
+ 
+ typedef struct {
+ 	__u16      dcid;
+@@ -147,6 +163,8 @@
+ #define L2CAP_CONF_FLUSH_TO	0x02
+ #define L2CAP_CONF_QOS		0x03
+ 
++#define L2CAP_CONF_MAX_SIZE	22
++
+ typedef struct {
+ 	__u16      dcid;
+ 	__u16      scid;
+@@ -159,4 +177,74 @@
+ } __attribute__ ((packed)) 	l2cap_disconn_rsp;
+ #define L2CAP_DISCONN_RSP_SIZE	4
+ 
++typedef struct {
++	__u16       type;
++	__u8        data[0];
++} __attribute__ ((packed))	l2cap_info_req;
++#define L2CAP_INFO_REQ_SIZE	2
++
++typedef struct {
++	__u16       type;
++	__u16       result;
++	__u8        data[0];
++} __attribute__ ((packed))	l2cap_info_rsp;
++#define L2CAP_INFO_RSP_SIZE	4
++
++/* ----- L2CAP connections ----- */
++struct l2cap_chan_list {
++	struct sock	*head;
++	rwlock_t	lock;
++	long		num;
++};
++
++struct l2cap_conn {
++	struct hci_conn	*hcon;
++
++	bdaddr_t 	*dst;
++	bdaddr_t 	*src;
++	
++	unsigned int    mtu;
++
++	spinlock_t	lock;
++	
++	struct sk_buff *rx_skb;
++	__u32		rx_len;
++	__u8		rx_ident;
++	__u8		tx_ident;
++
++	struct l2cap_chan_list chan_list;
++};
++
++/* ----- L2CAP channel and socket info ----- */
++#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->tp_pinfo)
++
++struct l2cap_pinfo {
++	__u16		psm;
++	__u16		dcid;
++	__u16		scid;
++
++	__u16		imtu;
++	__u16		omtu;
++	__u16		flush_to;
++	
++	__u32		link_mode;
++
++	__u8		conf_state;
++	__u8		conf_retry;
++	__u16		conf_mtu;
++
++	__u8		ident;
++
++	struct l2cap_conn 	*conn;
++	struct sock 		*next_c;
++	struct sock 		*prev_c;
++};
++
++#define L2CAP_CONF_REQ_SENT    0x01
++#define L2CAP_CONF_INPUT_DONE  0x02
++#define L2CAP_CONF_OUTPUT_DONE 0x04
++#define L2CAP_CONF_MAX_RETRIES 2
++
++void l2cap_load(void);
++
+ #endif /* __L2CAP_H */
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/include/net/bluetooth/rfcomm.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,361 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/* 
++   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef __RFCOMM_H
++#define __RFCOMM_H
++
++#define RFCOMM_PSM 3
++
++#define RFCOMM_CONN_TIMEOUT (HZ * 30)
++#define RFCOMM_DISC_TIMEOUT (HZ * 20)
++
++#define RFCOMM_DEFAULT_MTU	127
++#define RFCOMM_DEFAULT_CREDITS	7
++
++#define RFCOMM_MAX_L2CAP_MTU	1024
++#define RFCOMM_MAX_CREDITS	40
++
++#define RFCOMM_SKB_HEAD_RESERVE	8
++#define RFCOMM_SKB_TAIL_RESERVE	2
++#define RFCOMM_SKB_RESERVE	(RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
++
++#define RFCOMM_SABM	0x2f
++#define RFCOMM_DISC	0x43
++#define RFCOMM_UA	0x63
++#define RFCOMM_DM	0x0f
++#define RFCOMM_UIH	0xef
++
++#define RFCOMM_TEST	0x08
++#define RFCOMM_FCON	0x28
++#define RFCOMM_FCOFF	0x18
++#define RFCOMM_MSC	0x38
++#define RFCOMM_RPN	0x24
++#define RFCOMM_RLS	0x14
++#define RFCOMM_PN	0x20
++#define RFCOMM_NSC	0x04
++
++#define RFCOMM_V24_FC	0x02
++#define RFCOMM_V24_RTC	0x04
++#define RFCOMM_V24_RTR	0x08
++#define RFCOMM_V24_IC	0x40
++#define RFCOMM_V24_DV	0x80
++
++#define RFCOMM_RPN_BR_2400	0x0
++#define RFCOMM_RPN_BR_4800	0x1
++#define RFCOMM_RPN_BR_7200	0x2
++#define RFCOMM_RPN_BR_9600	0x3
++#define RFCOMM_RPN_BR_19200	0x4
++#define RFCOMM_RPN_BR_38400	0x5
++#define RFCOMM_RPN_BR_57600	0x6
++#define RFCOMM_RPN_BR_115200	0x7
++#define RFCOMM_RPN_BR_230400	0x8
++
++#define RFCOMM_RPN_DATA_5	0x0
++#define RFCOMM_RPN_DATA_6	0x1
++#define RFCOMM_RPN_DATA_7	0x2
++#define RFCOMM_RPN_DATA_8	0x3
++
++#define RFCOMM_RPN_STOP_1	0
++#define RFCOMM_RPN_STOP_15	1
++
++#define RFCOMM_RPN_PARITY_NONE	0x0
++#define RFCOMM_RPN_PARITY_ODD	0x4
++#define RFCOMM_RPN_PARITY_EVEN	0x5
++#define RFCOMM_RPN_PARITY_MARK	0x6
++#define RFCOMM_RPN_PARITY_SPACE	0x7
++
++#define RFCOMM_RPN_FLOW_NONE	0x00
++
++#define RFCOMM_RPN_XON_CHAR	0x11
++#define RFCOMM_RPN_XOFF_CHAR	0x13
++
++#define RFCOMM_RPN_PM_BITRATE		0x0001
++#define RFCOMM_RPN_PM_DATA		0x0002
++#define RFCOMM_RPN_PM_STOP		0x0004
++#define RFCOMM_RPN_PM_PARITY		0x0008
++#define RFCOMM_RPN_PM_PARITY_TYPE	0x0010
++#define RFCOMM_RPN_PM_XON		0x0020
++#define RFCOMM_RPN_PM_XOFF		0x0040
++#define RFCOMM_RPN_PM_FLOW		0x3F00
++
++#define RFCOMM_RPN_PM_ALL		0x3F7F
++
++struct rfcomm_hdr {
++	u8 addr;
++	u8 ctrl;
++	u8 len;    // Actual size can be 2 bytes
++} __attribute__ ((packed));
++
++struct rfcomm_cmd {
++	u8 addr;
++	u8 ctrl;
++	u8 len;
++	u8 fcs;
++} __attribute__ ((packed));
++
++struct rfcomm_mcc {
++	u8 type;
++	u8 len;
++} __attribute__ ((packed));
++
++struct rfcomm_pn {
++	u8  dlci;
++	u8  flow_ctrl;
++	u8  priority;
++	u8  ack_timer;
++	u16 mtu;
++	u8  max_retrans;
++	u8  credits;
++} __attribute__ ((packed));
++
++struct rfcomm_rpn {
++	u8  dlci;
++	u8  bit_rate;
++	u8  line_settings;
++	u8  flow_ctrl;
++	u8  xon_char;
++	u8  xoff_char;
++	u16 param_mask;
++} __attribute__ ((packed));
++
++struct rfcomm_rls {
++	u8  dlci;
++	u8  status;
++} __attribute__ ((packed));
++
++struct rfcomm_msc {
++	u8  dlci;
++	u8  v24_sig;
++} __attribute__ ((packed));
++
++/* ---- Core structures, flags etc ---- */
++
++struct rfcomm_session {
++	struct list_head list;
++	struct socket   *sock;
++	unsigned long    state;
++	unsigned long    flags;
++	atomic_t         refcnt;
++	int              initiator;
++
++	/* Default DLC parameters */
++	int    cfc;
++	uint   mtu;
++
++	struct list_head dlcs;
++};
++
++struct rfcomm_dlc {
++	struct list_head      list;
++	struct rfcomm_session *session;
++	struct sk_buff_head   tx_queue;
++	struct timer_list     timer;
++
++	spinlock_t    lock;
++	unsigned long state;
++	unsigned long flags;
++	atomic_t      refcnt;
++	u8            dlci;
++	u8            addr;
++	u8            priority;
++	u8            v24_sig;
++	u8            mscex;
++
++	uint          mtu;
++	uint          cfc;
++	uint          rx_credits;
++	uint          tx_credits;
++
++	void          *owner;
++
++	void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
++	void (*state_change)(struct rfcomm_dlc *d, int err);
++	void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
++};
++
++/* DLC and session flags */
++#define RFCOMM_RX_THROTTLED 0
++#define RFCOMM_TX_THROTTLED 1
++#define RFCOMM_MSC_PENDING  2
++#define RFCOMM_TIMED_OUT    3
++
++/* Scheduling flags and events */
++#define RFCOMM_SCHED_STATE  0
++#define RFCOMM_SCHED_RX     1
++#define RFCOMM_SCHED_TX     2
++#define RFCOMM_SCHED_TIMEO  3
++#define RFCOMM_SCHED_WAKEUP 31
++
++/* MSC exchange flags */
++#define RFCOMM_MSCEX_TX     1
++#define RFCOMM_MSCEX_RX     2
++#define RFCOMM_MSCEX_OK     (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
++
++/* CFC states */
++#define RFCOMM_CFC_UNKNOWN  -1
++#define RFCOMM_CFC_DISABLED 0
++#define RFCOMM_CFC_ENABLED  RFCOMM_MAX_CREDITS
++
++extern struct task_struct *rfcomm_thread;
++extern unsigned long rfcomm_event;
++
++static inline void rfcomm_schedule(uint event)
++{
++	if (!rfcomm_thread)
++		return;
++	set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
++	wake_up_process(rfcomm_thread);
++}
++
++extern struct semaphore rfcomm_sem;
++#define rfcomm_lock()	down(&rfcomm_sem);
++#define rfcomm_unlock()	up(&rfcomm_sem);
++
++/* ---- RFCOMM DLCs (channels) ---- */
++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
++void rfcomm_dlc_free(struct rfcomm_dlc *d);
++int  rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
++int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
++int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
++int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
++int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
++
++#define rfcomm_dlc_lock(d)	spin_lock(&d->lock)
++#define rfcomm_dlc_unlock(d)	spin_unlock(&d->lock)
++
++static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
++{
++	atomic_inc(&d->refcnt);
++}
++
++static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
++{
++	if (atomic_dec_and_test(&d->refcnt))
++		rfcomm_dlc_free(d);
++}
++
++extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
++extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
++
++static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
++{
++	if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
++		__rfcomm_dlc_throttle(d);
++}
++
++static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
++{
++	if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
++		__rfcomm_dlc_unthrottle(d);
++}
++
++/* ---- RFCOMM sessions ---- */
++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
++void   rfcomm_session_del(struct rfcomm_session *s);
++void   rfcomm_session_close(struct rfcomm_session *s, int err);
++void   rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
++
++static inline void rfcomm_session_hold(struct rfcomm_session *s)
++{
++	atomic_inc(&s->refcnt);
++}
++
++static inline void rfcomm_session_put(struct rfcomm_session *s)
++{
++	if (atomic_dec_and_test(&s->refcnt))
++		rfcomm_session_del(s);
++}
++
++/* ---- RFCOMM chechsum ---- */
++extern u8 rfcomm_crc_table[];
++
++/* ---- RFCOMM sockets ---- */
++struct sockaddr_rc {
++	sa_family_t rc_family;
++	bdaddr_t    rc_bdaddr;
++	u8          rc_channel;
++};
++
++#define rfcomm_pi(sk)	((struct rfcomm_pinfo *) &sk->tp_pinfo)
++
++struct rfcomm_pinfo {
++	struct rfcomm_dlc *dlc;
++	u8 channel;
++};
++
++int  rfcomm_init_sockets(void);
++void rfcomm_cleanup_sockets(void);
++
++int  rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
++
++/* ---- RFCOMM TTY ---- */
++#define RFCOMM_MAX_DEV  256
++
++#define RFCOMMCREATEDEV		_IOW('R', 200, int)
++#define RFCOMMRELEASEDEV	_IOW('R', 201, int)
++#define RFCOMMGETDEVLIST	_IOR('R', 210, int)
++#define RFCOMMGETDEVINFO	_IOR('R', 211, int)
++#define RFCOMMSTEALDLC		_IOW('R', 220, int)
++
++#define RFCOMM_REUSE_DLC	0
++#define RFCOMM_RELEASE_ONHUP	1
++#define RFCOMM_HANGUP_NOW	2
++#define RFCOMM_TTY_ATTACHED	3
++
++struct rfcomm_dev_req {
++	s16      dev_id;
++	u32      flags;
++	bdaddr_t src;
++	bdaddr_t dst;
++	u8       channel;
++};
++
++struct rfcomm_dev_info {
++	s16      id;
++	u32      flags;
++	u16      state;
++	bdaddr_t src;
++	bdaddr_t dst;
++	u8       channel;
++};
++
++struct rfcomm_dev_list_req {
++	u16      dev_num;
++	struct   rfcomm_dev_info dev_info[0];
++};
++
++int  rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
++int  rfcomm_init_ttys(void);
++void rfcomm_cleanup_ttys(void);
++
++#endif /* __RFCOMM_H */
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/include/net/bluetooth/sco.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,81 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ *  $Id$
++ */
++
++#ifndef __SCO_H
++#define __SCO_H
++
++/* SCO defaults */
++#define SCO_DEFAULT_MTU 	500
++#define SCO_DEFAULT_FLUSH_TO	0xFFFF
++
++#define SCO_CONN_TIMEOUT 	(HZ * 40)
++#define SCO_DISCONN_TIMEOUT 	(HZ * 2)
++#define SCO_CONN_IDLE_TIMEOUT	(HZ * 60)
++
++/* SCO socket address */
++struct sockaddr_sco {
++	sa_family_t	sco_family;
++	bdaddr_t	sco_bdaddr;
++};
++
++/* set/get sockopt defines */
++#define SCO_OPTIONS  0x01
++struct sco_options {
++	__u16 mtu;
++};
++
++#define SCO_CONNINFO  0x02
++struct sco_conninfo {
++	__u16 hci_handle;
++};
++
++/* ---- SCO connections ---- */
++struct sco_conn {
++	struct hci_conn	*hcon;
++
++	bdaddr_t 	*dst;
++	bdaddr_t 	*src;
++	
++	spinlock_t	lock;
++	struct sock 	*sk;
++
++	unsigned int    mtu;
++};
++
++#define sco_conn_lock(c)	spin_lock(&c->lock);
++#define sco_conn_unlock(c)	spin_unlock(&c->lock);
++
++/* ----- SCO socket info ----- */
++#define sco_pi(sk)   ((struct sco_pinfo *) &sk->tp_pinfo)
++
++struct sco_pinfo {
++	__u32		flags;
++	struct sco_conn	*conn;
++};
++
++#endif /* __SCO_H */
+--- linux/include/pcmcia/ciscode.h~bluetooth-2.4.18-mh11	2001-12-21 18:42:04.000000000 +0100
++++ linux/include/pcmcia/ciscode.h	2004-01-25 23:37:39.000000000 +0100
+@@ -1,5 +1,5 @@
+ /*
+- * ciscode.h 1.48 2001/08/24 12:16:12
++ * ciscode.h 1.57 2002/11/03 20:38:14
+  *
+  * The contents of this file are subject to the Mozilla Public License
+  * Version 1.1 (the "License"); you may not use this file except in
+@@ -60,6 +60,10 @@
+ #define PRODID_INTEL_DUAL_RS232		0x0301
+ #define PRODID_INTEL_2PLUS		0x8422
+ 
++#define MANFID_KME			0x0032
++#define PRODID_KME_KXLC005_A		0x0704
++#define PRODID_KME_KXLC005_B		0x2904
++
+ #define MANFID_LINKSYS			0x0143
+ #define PRODID_LINKSYS_PCMLM28		0xc0ab
+ #define PRODID_LINKSYS_3400		0x3341
+@@ -94,6 +98,8 @@
+ #define PRODID_OSITECH_JACK_336		0x0007
+ #define PRODID_OSITECH_SEVEN		0x0008
+ 
++#define MANFID_OXSEMI			0x0279
++
+ #define MANFID_PIONEER			0x000b
+ 
+ #define MANFID_PSION			0x016c
+@@ -103,6 +109,7 @@
+ #define PRODID_QUATECH_SPP100		0x0003
+ #define PRODID_QUATECH_DUAL_RS232	0x0012
+ #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
++#define PRODID_QUATECH_DUAL_RS232_D2	0x0052
+ #define PRODID_QUATECH_QUAD_RS232	0x001b
+ #define PRODID_QUATECH_DUAL_RS422	0x000e
+ #define PRODID_QUATECH_QUAD_RS422	0x0045
+@@ -120,9 +127,12 @@
+ 
+ #define MANFID_TDK			0x0105
+ #define PRODID_TDK_CF010		0x0900
++#define PRODID_TDK_GN3410		0x4815
+ 
+ #define MANFID_TOSHIBA			0x0098
+ 
++#define MANFID_UNGERMANN		0x02c0
++
+ #define MANFID_XIRCOM			0x0105
+ 
+ #endif /* _LINUX_CISCODE_H */
+--- linux/kernel/ksyms.c~bluetooth-2.4.18-mh11	2004-01-25 23:28:30.000000000 +0100
++++ linux/kernel/ksyms.c	2004-01-25 23:37:39.000000000 +0100
+@@ -47,6 +47,7 @@
+ #include <linux/in6.h>
+ #include <linux/completion.h>
+ #include <linux/seq_file.h>
++#include <linux/firmware.h>
+ #include <asm/checksum.h>
+ 
+ #if defined(CONFIG_PROC_FS)
+@@ -543,6 +544,13 @@
+ EXPORT_SYMBOL(strspn);
+ EXPORT_SYMBOL(strsep);
+ 
++#ifdef CONFIG_FW_LOADER
++EXPORT_SYMBOL(release_firmware);
++EXPORT_SYMBOL(request_firmware);
++EXPORT_SYMBOL(request_firmware_nowait);
++EXPORT_SYMBOL(register_firmware);
++#endif
++
+ /* software interrupts */
+ EXPORT_SYMBOL(tasklet_hi_vec);
+ EXPORT_SYMBOL(tasklet_vec);
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/lib/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,12 @@
++#
++# Library configuration
++#
++mainmenu_option next_comment
++comment 'Library routines'
++
++if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
++     "$CONFIG_HOTPLUG" = "y" ]; then
++   tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER
++fi
++
++endmenu
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/lib/firmware_class.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,573 @@
++/*
++ * firmware_class.c - Multi purpose firmware loading support
++ *
++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
++ *
++ * Please see Documentation/firmware_class/ for more information.
++ *
++ */
++/*
++ * Based on kernel/kmod.c and drivers/usb/usb.c
++ */
++/*
++        kernel/kmod.c
++        Kirk Petersen
++
++        Reorganized not to be a daemon by Adam Richter, with guidance
++        from Greg Zornetzer.
++
++        Modified to avoid chroot and file sharing problems.
++        Mikael Pettersson
++
++        Limit the concurrent number of kmod modprobes to catch loops from
++        "modprobe needs a service that is in a module".
++        Keith Owens <kaos@ocs.com.au> December 1999
++
++        Unblock all signals when we exec a usermode process.
++        Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
++*/
++/*
++ * drivers/usb/usb.c
++ *
++ * (C) Copyright Linus Torvalds 1999
++ * (C) Copyright Johannes Erdfelt 1999-2001
++ * (C) Copyright Andreas Gal 1999
++ * (C) Copyright Gregory P. Smith 1999
++ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
++ * (C) Copyright Randy Dunlap 2000
++ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
++ * (C) Copyright Yggdrasil Computing, Inc. 2000
++ *     (usb_device_id matching changes by Adam J. Richter)
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/kmod.h>
++#include <linux/proc_fs.h>
++#include <linux/vmalloc.h>
++#include <asm/hardirq.h>
++
++#include "linux/firmware.h"
++
++MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
++MODULE_DESCRIPTION("Multi purpose firmware loading support");
++MODULE_LICENSE("GPL");
++
++#define err(format, arg...) \
++     printk(KERN_ERR  "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
++#define warn(format, arg...) \
++     printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
++#define dbg(format, arg...) \
++     printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
++
++static int loading_timeout = 10;	/* In seconds */
++static struct proc_dir_entry *proc_dir_timeout;
++static struct proc_dir_entry *proc_dir;
++
++#ifdef CONFIG_HOTPLUG
++
++static int
++call_helper(char *verb, const char *name, const char *device)
++{
++	char *argv[3], **envp, *buf, *scratch;
++	int i = 0;
++
++	int retval = 0;
++
++	if (!hotplug_path[0])
++		return -ENOENT;
++	if (in_interrupt()) {
++		err("in_interrupt");
++		return -EFAULT;
++	}
++	if (!current->fs->root) {
++		warn("call_policy %s -- no FS yet", verb);
++		return -EPERM;
++	}
++
++	if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
++		err("unable to allocate envp");
++		return -ENOMEM;
++	}
++	if (!(buf = kmalloc(256, GFP_KERNEL))) {
++		kfree(envp);
++		err("unable to allocate buf");
++		return -ENOMEM;
++	}
++
++	/* only one standardized param to hotplug command: type */
++	argv[0] = hotplug_path;
++	argv[1] = "firmware";
++	argv[2] = 0;
++
++	/* minimal command environment */
++	envp[i++] = "HOME=/";
++	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++
++#ifdef  DEBUG
++	/* hint that policy agent should enter no-stdout debug mode */
++	envp[i++] = "DEBUG=kernel";
++#endif
++	scratch = buf;
++
++	if (device) {
++		envp[i++] = scratch;
++		scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25,
++				    "DEVPATH=/driver/firmware/%s", device) + 1;
++	}
++
++	envp[i++] = scratch;
++	scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
++
++	envp[i++] = scratch;
++	scratch += snprintf(scratch, FIRMWARE_NAME_MAX,
++			    "FIRMWARE=%s", name) + 1;
++
++	envp[i++] = 0;
++
++#ifdef  DEBUG
++	dbg("firmware: %s %s %s", argv[0], argv[1], verb);
++#endif
++
++	retval = call_usermodehelper(argv[0], argv, envp);
++	if (retval) {
++		printk("call_usermodehelper return %d\n", retval);
++	}
++
++	kfree(buf);
++	kfree(envp);
++	return retval;
++}
++#else
++
++static inline int
++call_helper(char *verb, const char *name, const char *device)
++{
++	return -ENOENT;
++}
++
++#endif /* CONFIG_HOTPLUG */
++
++struct firmware_priv {
++	struct completion completion;
++	struct proc_dir_entry *proc_dir;
++	struct proc_dir_entry *attr_data;
++	struct proc_dir_entry *attr_loading;
++	struct firmware *fw;
++	int loading;
++	int abort;
++	int alloc_size;
++	struct timer_list timeout;
++};
++
++static int
++firmware_timeout_show(char *buf, char **start, off_t off,
++		      int count, int *eof, void *data)
++{
++	return sprintf(buf, "%d\n", loading_timeout);
++}
++
++/**
++ * firmware_timeout_store:
++ * Description:
++ *	Sets the number of seconds to wait for the firmware.  Once
++ *	this expires an error will be return to the driver and no
++ *	firmware will be provided.
++ *
++ *	Note: zero means 'wait for ever'
++ *  
++ **/
++static int
++firmware_timeout_store(struct file *file, const char *buf,
++		       unsigned long count, void *data)
++{
++	loading_timeout = simple_strtol(buf, NULL, 10);
++	return count;
++}
++
++static int
++firmware_loading_show(char *buf, char **start, off_t off,
++		      int count, int *eof, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	return sprintf(buf, "%d\n", fw_priv->loading);
++}
++
++/**
++ * firmware_loading_store: - loading control file
++ * Description:
++ *	The relevant values are: 
++ *
++ *	 1: Start a load, discarding any previous partial load.
++ *	 0: Conclude the load and handle the data to the driver code.
++ *	-1: Conclude the load with an error and discard any written data.
++ **/
++static int
++firmware_loading_store(struct file *file, const char *buf,
++		       unsigned long count, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	int prev_loading = fw_priv->loading;
++
++	fw_priv->loading = simple_strtol(buf, NULL, 10);
++
++	switch (fw_priv->loading) {
++	case -1:
++		fw_priv->abort = 1;
++		wmb();
++		complete(&fw_priv->completion);
++		break;
++	case 1:
++		kfree(fw_priv->fw->data);
++		fw_priv->fw->data = NULL;
++		fw_priv->fw->size = 0;
++		fw_priv->alloc_size = 0;
++		break;
++	case 0:
++		if (prev_loading == 1)
++			complete(&fw_priv->completion);
++		break;
++	}
++
++	return count;
++}
++
++static int
++firmware_data_read(char *buffer, char **start, off_t offset,
++		   int count, int *eof, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	struct firmware *fw = fw_priv->fw;
++
++	if (offset > fw->size)
++		return 0;
++	if (offset + count > fw->size)
++		count = fw->size - offset;
++
++	memcpy(buffer, fw->data + offset, count);
++	*start = (void *) ((long) count);
++	return count;
++}
++static int
++fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
++{
++	u8 *new_data;
++	int new_size;
++
++	if (min_size <= fw_priv->alloc_size)
++		return 0;
++	if((min_size % PAGE_SIZE) == 0)
++		new_size = min_size;
++	else
++		new_size = (min_size + PAGE_SIZE) & PAGE_MASK;
++	new_data = vmalloc(new_size);
++	if (!new_data) {
++		printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
++		/* Make sure that we don't keep incomplete data */
++		fw_priv->abort = 1;
++		return -ENOMEM;
++	}
++	fw_priv->alloc_size = new_size;
++	if (fw_priv->fw->data) {
++		memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
++		vfree(fw_priv->fw->data);
++	}
++	fw_priv->fw->data = new_data;
++	BUG_ON(min_size > fw_priv->alloc_size);
++	return 0;
++}
++
++/**
++ * firmware_data_write:
++ *
++ * Description:
++ *
++ *	Data written to the 'data' attribute will be later handled to
++ *	the driver as a firmware image.
++ **/
++static int
++firmware_data_write(struct file *file, const char *buffer,
++		    unsigned long count, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	struct firmware *fw = fw_priv->fw;
++	int offset = file->f_pos;
++	int retval;
++
++	retval = fw_realloc_buffer(fw_priv, offset + count);
++	if (retval) {
++		printk("%s: retval:%d\n", __FUNCTION__, retval);
++		return retval;
++	}
++
++	memcpy(fw->data + offset, buffer, count);
++
++	fw->size = max_t(size_t, offset + count, fw->size);
++	file->f_pos += count;
++	return count;
++}
++
++static void
++firmware_class_timeout(u_long data)
++{
++	struct firmware_priv *fw_priv = (struct firmware_priv *) data;
++	fw_priv->abort = 1;
++	wmb();
++	complete(&fw_priv->completion);
++}
++static int
++fw_setup_class_device(struct firmware_priv **fw_priv_p,
++		      const char *fw_name, const char *device)
++{
++	int retval;
++	struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
++						GFP_KERNEL);
++	*fw_priv_p = fw_priv;
++	if (!fw_priv) {
++		retval = -ENOMEM;
++		goto out;
++	}
++	memset(fw_priv, 0, sizeof (*fw_priv));
++
++	init_completion(&fw_priv->completion);
++
++	fw_priv->timeout.function = firmware_class_timeout;
++	fw_priv->timeout.data = (u_long) fw_priv;
++	init_timer(&fw_priv->timeout);
++
++	retval = -EAGAIN;
++	fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir);
++	if (!fw_priv->proc_dir)
++		goto err_free_fw_priv;
++
++	fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG,
++					       fw_priv->proc_dir);
++	if (!fw_priv->attr_data)
++		goto err_remove_dir;
++
++	fw_priv->attr_data->read_proc = firmware_data_read;
++	fw_priv->attr_data->write_proc = firmware_data_write;
++	fw_priv->attr_data->data = fw_priv;
++
++	fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG,
++						  fw_priv->proc_dir);
++	if (!fw_priv->attr_loading)
++		goto err_remove_data;
++
++	fw_priv->attr_loading->read_proc = firmware_loading_show;
++	fw_priv->attr_loading->write_proc = firmware_loading_store;
++	fw_priv->attr_loading->data = fw_priv;
++
++	retval = 0;
++	fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
++	if (!fw_priv->fw) {
++		printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
++		       __FUNCTION__);
++		retval = -ENOMEM;
++		goto err_remove_loading;
++	}
++	memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
++
++	goto out;
++
++err_remove_loading:
++	remove_proc_entry("loading", fw_priv->proc_dir);
++err_remove_data:
++	remove_proc_entry("data", fw_priv->proc_dir);
++err_remove_dir:
++	remove_proc_entry(device, proc_dir);
++err_free_fw_priv:
++	kfree(fw_priv);
++out:
++	return retval;
++}
++static void
++fw_remove_class_device(struct firmware_priv *fw_priv)
++{
++	remove_proc_entry("loading", fw_priv->proc_dir);
++	remove_proc_entry("data", fw_priv->proc_dir);
++	remove_proc_entry(fw_priv->proc_dir->name, proc_dir);
++}
++
++/** 
++ * request_firmware: - request firmware to hotplug and wait for it
++ * Description:
++ *	@firmware will be used to return a firmware image by the name
++ *	of @name for device @device.
++ *
++ *	Should be called from user context where sleeping is allowed.
++ *
++ *	@name will be use as $FIRMWARE in the hotplug environment and
++ *	should be distinctive enough not to be confused with any other
++ *	firmware image for this or any other device.
++ **/
++int
++request_firmware(const struct firmware **firmware, const char *name,
++		 const char *device)
++{
++	struct firmware_priv *fw_priv;
++	int retval;
++
++	if (!firmware) {
++		retval = -EINVAL;
++		goto out;
++	}
++	*firmware = NULL;
++
++	retval = fw_setup_class_device(&fw_priv, name, device);
++	if (retval)
++		goto out;
++
++	retval = call_helper("add", name, device);
++	if (retval)
++		goto out;
++	if (loading_timeout) {
++		fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
++		add_timer(&fw_priv->timeout);
++	}
++
++	wait_for_completion(&fw_priv->completion);
++
++	del_timer(&fw_priv->timeout);
++	fw_remove_class_device(fw_priv);
++
++	if (fw_priv->fw->size && !fw_priv->abort) {
++		*firmware = fw_priv->fw;
++	} else {
++		retval = -ENOENT;
++		vfree(fw_priv->fw->data);
++		kfree(fw_priv->fw);
++	}
++out:
++	kfree(fw_priv);
++	return retval;
++}
++
++void
++release_firmware(const struct firmware *fw)
++{
++	if (fw) {
++		vfree(fw->data);
++		kfree(fw);
++	}
++}
++
++/**
++ * register_firmware: - provide a firmware image for later usage
++ * 
++ * Description:
++ *	Make sure that @data will be available by requesting firmware @name.
++ *
++ *	Note: This will not be possible until some kind of persistence
++ *	is available.
++ **/
++void
++register_firmware(const char *name, const u8 *data, size_t size)
++{
++	/* This is meaningless without firmware caching, so until we
++	 * decide if firmware caching is reasonable just leave it as a
++	 * noop */
++}
++
++/* Async support */
++struct firmware_work {
++	struct tq_struct work;
++	struct module *module;
++	const char *name;
++	const char *device;
++	void *context;
++	void (*cont)(const struct firmware *fw, void *context);
++};
++
++static void
++request_firmware_work_func(void *arg)
++{
++	struct firmware_work *fw_work = arg;
++	const struct firmware *fw;
++	if (!arg)
++		return;
++	request_firmware(&fw, fw_work->name, fw_work->device);
++	fw_work->cont(fw, fw_work->context);
++	release_firmware(fw);
++	__MOD_DEC_USE_COUNT(fw_work->module);
++	kfree(fw_work);
++}
++
++/**
++ * request_firmware_nowait:
++ *
++ * Description:
++ *	Asynchronous variant of request_firmware() for contexts where
++ *	it is not possible to sleep.
++ *
++ *	@cont will be called asynchronously when the firmware request is over.
++ *
++ *	@context will be passed over to @cont.
++ *
++ *	@fw may be %NULL if firmware request fails.
++ *
++ **/
++int
++request_firmware_nowait(
++	struct module *module,
++	const char *name, const char *device, void *context,
++	void (*cont)(const struct firmware *fw, void *context))
++{
++	struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
++						GFP_ATOMIC);
++	if (!fw_work)
++		return -ENOMEM;
++	if (!try_inc_mod_count(module)) {
++		kfree(fw_work);
++		return -EFAULT;
++	}
++
++	*fw_work = (struct firmware_work) {
++		.module = module,
++		.name = name,
++		.device = device,
++		.context = context,
++		.cont = cont,
++	};
++	INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work);
++
++	schedule_task(&fw_work->work);
++	return 0;
++}
++
++static int __init
++firmware_class_init(void)
++{
++	proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL);
++	if (!proc_dir)
++		return -EAGAIN;
++	proc_dir_timeout = create_proc_entry("timeout",
++					     0644 | S_IFREG, proc_dir);
++	if (!proc_dir_timeout) {
++		remove_proc_entry("driver/firmware", NULL);
++		return -EAGAIN;
++	}
++	proc_dir_timeout->read_proc = firmware_timeout_show;
++	proc_dir_timeout->write_proc = firmware_timeout_store;
++	return 0;
++}
++static void __exit
++firmware_class_exit(void)
++{
++	remove_proc_entry("timeout", proc_dir);
++	remove_proc_entry("driver/firmware", NULL);
++}
++
++module_init(firmware_class_init);
++module_exit(firmware_class_exit);
++
++#ifndef CONFIG_FW_LOADER
++EXPORT_SYMBOL(release_firmware);
++EXPORT_SYMBOL(request_firmware);
++EXPORT_SYMBOL(request_firmware_nowait);
++EXPORT_SYMBOL(register_firmware);
++#endif
+--- linux/lib/Makefile~bluetooth-2.4.18-mh11	2001-09-18 00:31:15.000000000 +0200
++++ linux/lib/Makefile	2004-01-25 23:37:39.000000000 +0100
+@@ -8,13 +8,17 @@
+ 
+ L_TARGET := lib.a
+ 
+-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
++export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
++	       firmware_class.o
+ 
+ obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
+ 
++obj-$(CONFIG_FW_LOADER) += firmware_class.o
+ obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
+ obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
+ 
++include $(TOPDIR)/drivers/bluetooth/Makefile.lib
++
+ ifneq ($(CONFIG_HAVE_DEC_LOCK),y) 
+   obj-y += dec_and_lock.o
+ endif
+--- linux/MAINTAINERS~bluetooth-2.4.18-mh11	2004-01-25 23:28:29.000000000 +0100
++++ linux/MAINTAINERS	2004-01-25 23:37:39.000000000 +0100
+@@ -259,7 +259,84 @@
+ L:	linux-kernel@vger.kernel.org
+ S:	Maintained
+ 
+-BLUETOOTH SUBSYSTEM (BlueZ)
++BLUETOOTH SUBSYSTEM
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++L:	bluez-devel@lists.sf.net
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH RFCOMM LAYER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH BNEP LAYER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH CMTP LAYER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI USB DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH HCI UART DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH HCI BFUSB DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI DTL1 DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI BLUECARD DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI BT3C DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI BTUART DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI VHCI DRIVER
+ P:	Maxim Krasnyansky
+ M:	maxk@qualcomm.com
+ W:	http://bluez.sf.net
+--- linux/net/bluetooth/af_bluetooth.c~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/net/bluetooth/af_bluetooth.c	2004-01-25 23:37:39.000000000 +0100
+@@ -25,14 +25,15 @@
+ /*
+  * BlueZ Bluetooth address family and sockets.
+  *
+- * $Id$
++ * $Id$
+  */
+-#define VERSION "1.1"
++#define VERSION "2.3"
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
+ 
+ #include <linux/types.h>
++#include <linux/list.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/major.h>
+@@ -40,6 +41,7 @@
+ #include <linux/slab.h>
+ #include <linux/skbuff.h>
+ #include <linux/init.h>
++#include <linux/poll.h>
+ #include <linux/proc_fs.h>
+ #include <net/sock.h>
+ 
+@@ -48,70 +50,79 @@
+ #endif
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
++
++#ifndef AF_BLUETOOTH_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
+ 
+ /* Bluetooth sockets */
+-static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
++#define BLUEZ_MAX_PROTO	6
++static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
+ 
+ int bluez_sock_register(int proto, struct net_proto_family *ops)
+ {
+-	if (proto > BLUEZ_MAX_PROTO)
++	if (proto >= BLUEZ_MAX_PROTO)
+ 		return -EINVAL;
+ 
+-	if (bluez_sock[proto])
++	if (bluez_proto[proto])
+ 		return -EEXIST;
+ 
+-	bluez_sock[proto] = ops;
++	bluez_proto[proto] = ops;
+ 	return 0;
+ }
+ 
+ int bluez_sock_unregister(int proto)
+ {
+-	if (proto > BLUEZ_MAX_PROTO)
++	if (proto >= BLUEZ_MAX_PROTO)
+ 		return -EINVAL;
+ 
+-	if (!bluez_sock[proto])
++	if (!bluez_proto[proto])
+ 		return -ENOENT;
+ 
+-	bluez_sock[proto] = NULL;
++	bluez_proto[proto] = NULL;
+ 	return 0;
+ }
+ 
+ static int bluez_sock_create(struct socket *sock, int proto)
+ {
+-	if (proto > BLUEZ_MAX_PROTO)
++	if (proto >= BLUEZ_MAX_PROTO)
+ 		return -EINVAL;
+ 
+ #if defined(CONFIG_KMOD)
+-	if (!bluez_sock[proto]) {
++	if (!bluez_proto[proto]) {
+ 		char module_name[30];
+ 		sprintf(module_name, "bt-proto-%d", proto);
+ 		request_module(module_name);
+ 	}
+ #endif
+ 
+-	if (!bluez_sock[proto])
++	if (!bluez_proto[proto])
+ 		return -ENOENT;
+ 
+-	return bluez_sock[proto]->create(sock, proto);
++	return bluez_proto[proto]->create(sock, proto);
++}
++
++void bluez_sock_init(struct socket *sock, struct sock *sk)
++{ 
++	sock_init_data(sock, sk);
++	INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
+ }
+ 
+ void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
+ {
+-	write_lock(&l->lock);
+-
++	write_lock_bh(&l->lock);
+ 	sk->next = l->head;
+ 	l->head = sk;
+ 	sock_hold(sk);
+-
+-	write_unlock(&l->lock);
++	write_unlock_bh(&l->lock);
+ }
+ 
+ void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
+ {
+ 	struct sock **skp;
+ 
+-	write_lock(&l->lock);
++	write_lock_bh(&l->lock);
+ 	for (skp = &l->head; *skp; skp = &((*skp)->next)) {
+ 		if (*skp == sk) {
+ 			*skp = sk->next;
+@@ -119,7 +130,162 @@
+ 			break;
+ 		}
+ 	}
+-	write_unlock(&l->lock);
++	write_unlock_bh(&l->lock);
++}
++
++void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
++{
++	BT_DBG("parent %p, sk %p", parent, sk);
++
++	sock_hold(sk);
++	list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
++	bluez_pi(sk)->parent = parent;
++	parent->ack_backlog++;
++}
++
++static void bluez_accept_unlink(struct sock *sk)
++{
++	BT_DBG("sk %p state %d", sk, sk->state);
++
++	list_del_init(&bluez_pi(sk)->accept_q);
++	bluez_pi(sk)->parent->ack_backlog--;
++	bluez_pi(sk)->parent = NULL;
++	sock_put(sk);
++}
++
++struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
++{
++	struct list_head *p, *n;
++	struct bluez_pinfo *pi;
++	struct sock *sk;
++	
++	BT_DBG("parent %p", parent);
++
++	list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
++		pi = list_entry(p, struct bluez_pinfo, accept_q);
++		sk = bluez_sk(pi);
++		
++		lock_sock(sk);
++		if (sk->state == BT_CLOSED) {
++			release_sock(sk);
++			bluez_accept_unlink(sk);
++			continue;
++		}
++		
++		if (sk->state == BT_CONNECTED || !newsock) {
++			bluez_accept_unlink(sk);
++			if (newsock)
++				sock_graft(sk, newsock);
++			release_sock(sk);
++			return sk;
++		}
++		release_sock(sk);
++	}
++	return NULL;
++}
++
++int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
++{
++	int noblock = flags & MSG_DONTWAIT;
++	struct sock *sk = sock->sk;
++	struct sk_buff *skb;
++	int copied, err;
++
++	BT_DBG("sock %p sk %p len %d", sock, sk, len);
++
++	if (flags & (MSG_OOB))
++		return -EOPNOTSUPP;
++
++	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
++		if (sk->shutdown & RCV_SHUTDOWN)
++			return 0;
++		return err;
++	}
++
++	msg->msg_namelen = 0;
++
++	copied = skb->len;
++	if (len < copied) {
++		msg->msg_flags |= MSG_TRUNC;
++		copied = len;
++	}
++
++	skb->h.raw = skb->data;
++	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
++
++	skb_free_datagram(sk, skb);
++
++	return err ? : copied;
++}
++
++unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
++{
++	struct sock *sk = sock->sk;
++	unsigned int mask;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	poll_wait(file, sk->sleep, wait);
++	mask = 0;
++
++	if (sk->err || !skb_queue_empty(&sk->error_queue))
++		mask |= POLLERR;
++
++	if (sk->shutdown == SHUTDOWN_MASK)
++		mask |= POLLHUP;
++
++	if (!skb_queue_empty(&sk->receive_queue) || 
++			!list_empty(&bluez_pi(sk)->accept_q) ||
++			(sk->shutdown & RCV_SHUTDOWN))
++		mask |= POLLIN | POLLRDNORM;
++
++	if (sk->state == BT_CLOSED)
++		mask |= POLLHUP;
++
++	if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
++		return mask;
++	
++	if (sock_writeable(sk))
++		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
++	else
++		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
++
++	return mask;
++}
++
++int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	add_wait_queue(sk->sleep, &wait);
++	while (sk->state != state) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->err) {
++			err = sock_error(sk);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++	return err;
+ }
+ 
+ struct net_proto_family bluez_sock_family_ops =
+@@ -129,9 +295,9 @@
+ 
+ int bluez_init(void)
+ {
+-	INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
++	BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+ 		 VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+ 
+ 	proc_mkdir("bluetooth", NULL);
+ 
+@@ -164,5 +330,6 @@
+ module_exit(bluez_cleanup);
+ 
+ MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+-MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION);
++MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
++MODULE_LICENSE("GPL");
+ #endif
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/bnep.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,185 @@
++/*
++  BNEP protocol definition for Linux Bluetooth stack (BlueZ).
++  Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++	
++  This program is free software; you can redistribute it and/or modify
++  it under the terms of the GNU General Public License, version 2, as
++  published by the Free Software Foundation.
++
++  This program is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++  GNU General Public License for more details.
++
++  You should have received a copy of the GNU General Public License
++  along with this program; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef _BNEP_H
++#define _BNEP_H
++
++#include <linux/types.h>
++#include <net/bluetooth/bluetooth.h>
++
++#include "crc32.h"
++
++// Limits
++#define BNEP_MAX_PROTO_FILTERS     5
++#define BNEP_MAX_MULTICAST_FILTERS 20
++
++// UUIDs
++#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
++#define BNEP_UUID16    0x02
++#define BNEP_UUID32    0x04
++#define BNEP_UUID128   0x16
++
++#define BNEP_SVC_PANU  0x1115
++#define BNEP_SVC_NAP   0x1116
++#define BNEP_SVC_GN    0x1117
++
++// Packet types
++#define BNEP_GENERAL               0x00
++#define BNEP_CONTROL               0x01
++#define BNEP_COMPRESSED            0x02
++#define BNEP_COMPRESSED_SRC_ONLY   0x03
++#define BNEP_COMPRESSED_DST_ONLY   0x04
++
++// Control types
++#define BNEP_CMD_NOT_UNDERSTOOD    0x00
++#define BNEP_SETUP_CONN_REQ        0x01
++#define BNEP_SETUP_CONN_RSP        0x02
++#define BNEP_FILTER_NET_TYPE_SET   0x03
++#define BNEP_FILTER_NET_TYPE_RSP   0x04
++#define BNEP_FILTER_MULTI_ADDR_SET 0x05
++#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
++
++// Extension types
++#define BNEP_EXT_CONTROL           0x00
++
++// Response messages 
++#define BNEP_SUCCESS               0x00
++
++#define BNEP_CONN_INVALID_DST      0x01
++#define BNEP_CONN_INVALID_SRC      0x02
++#define BNEP_CONN_INVALID_SVC      0x03
++#define BNEP_CONN_NOT_ALLOWED      0x04
++
++#define BNEP_FILTER_UNSUPPORTED_REQ    0x01
++#define BNEP_FILTER_INVALID_RANGE      0x02
++#define BNEP_FILTER_INVALID_MCADDR     0x02
++#define BNEP_FILTER_LIMIT_REACHED      0x03
++#define BNEP_FILTER_DENIED_SECURITY    0x04
++
++// L2CAP settings
++#define BNEP_MTU         1691
++#define BNEP_PSM	 0x0f
++#define BNEP_FLUSH_TO    0xffff
++#define BNEP_CONNECT_TO  15
++#define BNEP_FILTER_TO   15
++
++// Headers 
++#define BNEP_TYPE_MASK	 0x7f
++#define BNEP_EXT_HEADER	 0x80
++
++struct bnep_setup_conn_req {
++	__u8  type;
++	__u8  ctrl;
++	__u8  uuid_size;
++	__u8  service[0];
++} __attribute__((packed));
++
++struct bnep_set_filter_req {
++	__u8  type;
++	__u8  ctrl;
++	__u16 len;
++	__u8  list[0];
++} __attribute__((packed));
++
++struct bnep_control_rsp {
++	__u8  type;
++	__u8  ctrl;
++	__u16 resp;
++} __attribute__((packed));
++
++struct bnep_ext_hdr {
++	__u8  type;
++	__u8  len;
++	__u8  data[0];
++} __attribute__((packed));
++
++/* BNEP ioctl defines */
++#define BNEPCONNADD	_IOW('B', 200, int)
++#define BNEPCONNDEL	_IOW('B', 201, int)
++#define BNEPGETCONNLIST	_IOR('B', 210, int)
++#define BNEPGETCONNINFO	_IOR('B', 211, int)
++
++struct bnep_connadd_req {
++	int   sock;       // Connected socket
++	__u32 flags;
++	__u16 role;
++	char  device[16]; // Name of the Ethernet device
++};
++
++struct bnep_conndel_req {
++	__u32 flags;
++	__u8  dst[ETH_ALEN];
++};
++
++struct bnep_conninfo {
++	__u32 flags;
++	__u16 role;
++	__u16 state;	
++	__u8  dst[ETH_ALEN];
++	char  device[16];
++};
++
++struct bnep_connlist_req {
++	__u32  cnum;
++	struct bnep_conninfo *ci;
++};
++
++struct bnep_proto_filter {
++	__u16 start;
++	__u16 end;
++};
++
++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
++int bnep_del_connection(struct bnep_conndel_req *req);
++int bnep_get_connlist(struct bnep_connlist_req *req);
++int bnep_get_conninfo(struct bnep_conninfo *ci);
++
++// BNEP sessions
++struct bnep_session {
++	struct list_head list;
++	
++	unsigned int  role;
++        unsigned long state;
++        unsigned long flags;
++	atomic_t      killed;
++
++	struct ethhdr eh;
++	struct msghdr msg;
++
++	struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
++	u64    mc_filter;
++	
++	struct socket    *sock;
++	struct net_device dev;
++	struct net_device_stats stats;
++};
++
++int bnep_net_init(struct net_device *dev);
++int bnep_sock_init(void);
++int bnep_sock_cleanup(void);
++
++static inline int bnep_mc_hash(__u8 *addr)
++{
++        return (bnep_crc32(~0, addr, ETH_ALEN) >> 26);
++}
++
++#endif
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,11 @@
++#
++# Bluetooth BNEP layer configuration
++#
++
++dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
++
++if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
++   bool '  Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
++   bool '  Protocol filter support'  CONFIG_BLUEZ_BNEP_PROTO_FILTER
++fi
++
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/core.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,708 @@
++/* 
++   BNEP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2001-2002 Inventel Systemes
++   Written 2001-2002 by
++	Cl�ment Moreau <clement.moreau@inventel.fr>
++	David Libault  <david.libault@inventel.fr>
++
++   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */ 
++
++#define __KERNEL_SYSCALLS__
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/init.h>
++#include <linux/wait.h>
++#include <linux/errno.h>
++#include <linux/smp_lock.h>
++#include <linux/net.h>
++#include <net/sock.h>
++
++#include <linux/socket.h>
++#include <linux/file.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/l2cap.h>
++
++#include "bnep.h"
++
++#ifndef CONFIG_BLUEZ_BNEP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define VERSION "1.1"
++
++static LIST_HEAD(bnep_session_list);
++static DECLARE_RWSEM(bnep_session_sem);
++
++static struct bnep_session *__bnep_get_session(u8 *dst)
++{
++	struct bnep_session *s;
++	struct list_head *p;
++
++	BT_DBG("");
++
++	list_for_each(p, &bnep_session_list) {
++		s = list_entry(p, struct bnep_session, list);	
++		if (!memcmp(dst, s->eh.h_source, ETH_ALEN))
++			return s;
++	}
++	return NULL;
++}
++
++static void __bnep_link_session(struct bnep_session *s)
++{
++	MOD_INC_USE_COUNT;
++	list_add(&s->list, &bnep_session_list);	
++}
++
++static void __bnep_unlink_session(struct bnep_session *s)
++{
++	list_del(&s->list);
++	MOD_DEC_USE_COUNT;
++}
++
++static int bnep_send(struct bnep_session *s, void *data, size_t len)
++{
++	struct socket *sock = s->sock;
++	struct iovec iv = { data, len };
++	s->msg.msg_iov    = &iv;
++	s->msg.msg_iovlen = 1;
++	return sock->ops->sendmsg(sock, &s->msg, len, NULL);
++}
++
++static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
++{
++	struct bnep_control_rsp rsp;
++	rsp.type = BNEP_CONTROL;
++	rsp.ctrl = ctrl;
++	rsp.resp = htons(resp);
++	return bnep_send(s, &rsp, sizeof(rsp));
++}
++
++static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
++{
++	int n;
++
++	if (len < 2)
++		return -EILSEQ;
++	
++	n = ntohs(get_unaligned(data));
++	data++; len -= 2;
++
++	if (len < n)
++		return -EILSEQ;
++
++	BT_DBG("filter len %d", n);
++
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++	n /= 4;
++	if (n <= BNEP_MAX_PROTO_FILTERS) {
++		struct bnep_proto_filter *f = s->proto_filter;
++		int i;
++
++		for (i = 0; i < n; i++) {
++			f[i].start = get_unaligned(data++);
++			f[i].end   = get_unaligned(data++);
++
++			BT_DBG("proto filter start %d end %d",
++				f[i].start, f[i].end);
++		}
++		if (i < BNEP_MAX_PROTO_FILTERS)
++			memset(f + i, 0, sizeof(*f));
++
++		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
++	} else {
++		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
++	}
++#else
++	bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
++#endif
++	return 0;
++}
++
++static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
++{
++	int n;
++
++	if (len < 2)
++		return -EILSEQ;
++	
++	n = ntohs(get_unaligned((u16 *) data)); 
++	data += 2; len -= 2;
++
++	if (len < n)
++		return -EILSEQ;
++
++	BT_DBG("filter len %d", n);
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	n /= (ETH_ALEN * 2);
++
++	if (n > 0) {
++		s->mc_filter = 0;
++
++		/* Always send broadcast */
++		set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter);
++
++		/* Add address ranges to the multicast hash */
++		for (; n > 0; n--) {
++			u8 a1[6], *a2;
++
++			memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
++			a2 = data; data += ETH_ALEN;
++	
++			BT_DBG("mc filter %s -> %s",
++				batostr((void *) a1), batostr((void *) a2));
++
++			#define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
++
++			/* Iterate from a1 to a2 */
++			set_bit(bnep_mc_hash(a1), &s->mc_filter);
++			while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
++				INCA(a1);
++				set_bit(bnep_mc_hash(a1), &s->mc_filter);
++			}
++		}
++	}
++
++	BT_DBG("mc filter hash 0x%llx", s->mc_filter);
++
++	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
++#else
++	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
++#endif
++	return 0;
++}
++
++static int bnep_rx_control(struct bnep_session *s, void *data, int len)
++{
++	u8  cmd = *(u8 *)data;
++	int err = 0;
++
++	data++; len--;
++	
++	switch (cmd) {
++	case BNEP_CMD_NOT_UNDERSTOOD:
++	case BNEP_SETUP_CONN_REQ:
++	case BNEP_SETUP_CONN_RSP:
++	case BNEP_FILTER_NET_TYPE_RSP:
++	case BNEP_FILTER_MULTI_ADDR_RSP:
++		/* Ignore these for now */
++		break;
++		
++	case BNEP_FILTER_NET_TYPE_SET:
++		err = bnep_ctrl_set_netfilter(s, data, len);
++		break;
++
++	case BNEP_FILTER_MULTI_ADDR_SET:
++		err = bnep_ctrl_set_mcfilter(s, data, len);
++		break;
++
++	default: {
++			u8 pkt[3];
++			pkt[0] = BNEP_CONTROL;
++			pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
++			pkt[2] = cmd;
++			bnep_send(s, pkt, sizeof(pkt));
++		}
++		break;
++	}
++
++	return err;
++}
++
++static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
++{
++	struct bnep_ext_hdr *h;
++	int err = 0;
++
++	do {
++		h = (void *) skb->data;
++		if (!skb_pull(skb, sizeof(*h))) {
++			err = -EILSEQ;
++			break;
++		}
++
++		BT_DBG("type 0x%x len %d", h->type, h->len);
++		
++		switch (h->type & BNEP_TYPE_MASK) {
++		case BNEP_EXT_CONTROL:
++			bnep_rx_control(s, skb->data, skb->len);
++			break;
++
++		default:
++			/* Unknown extension, skip it. */
++			break;
++		}
++	
++		if (!skb_pull(skb, h->len)) {
++			err = -EILSEQ;
++			break;
++		}
++	} while (!err && (h->type & BNEP_EXT_HEADER));
++	
++	return err;
++}
++
++static u8 __bnep_rx_hlen[] = {
++	ETH_HLEN,     /* BNEP_GENERAL */
++	0,            /* BNEP_CONTROL */
++	2,            /* BNEP_COMPRESSED */
++	ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
++	ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
++};
++#define BNEP_RX_TYPES	(sizeof(__bnep_rx_hlen) - 1)
++
++static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
++{
++	struct net_device *dev = &s->dev;
++	struct sk_buff *nskb;
++	u8 type;
++
++	dev->last_rx = jiffies;
++	s->stats.rx_bytes += skb->len;
++
++	type = *(u8 *) skb->data; skb_pull(skb, 1);
++
++	if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
++		goto badframe;
++	
++	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
++		bnep_rx_control(s, skb->data, skb->len);
++		kfree_skb(skb);
++		return 0;
++	}
++
++	skb->mac.raw = skb->data;
++
++	/* Verify and pull out header */
++	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
++		goto badframe;
++
++	s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
++
++	if (type & BNEP_EXT_HEADER) {
++		if (bnep_rx_extension(s, skb) < 0)
++			goto badframe;
++	}
++
++	/* Strip 802.1p header */
++	if (ntohs(s->eh.h_proto) == 0x8100) {
++		if (!skb_pull(skb, 4))
++			goto badframe;
++		s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
++	}
++	
++	/* We have to alloc new skb and copy data here :(. Because original skb
++	 * may not be modified and because of the alignment requirements. */
++	nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
++	if (!nskb) {
++		s->stats.rx_dropped++;
++		kfree_skb(skb);
++		return -ENOMEM;
++	}
++	skb_reserve(nskb, 2);
++
++	/* Decompress header and construct ether frame */
++	switch (type & BNEP_TYPE_MASK) {
++	case BNEP_COMPRESSED:
++		memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
++		break;
++	
++	case BNEP_COMPRESSED_SRC_ONLY:
++		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
++		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
++		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
++		break;
++
++	case BNEP_COMPRESSED_DST_ONLY:
++		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
++		memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
++		break;
++
++	case BNEP_GENERAL:
++		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
++		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
++		break;
++	}
++
++	memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
++	kfree_skb(skb);
++	
++	s->stats.rx_packets++;
++	nskb->dev       = dev;
++	nskb->ip_summed = CHECKSUM_UNNECESSARY;
++	nskb->protocol  = eth_type_trans(nskb, dev);
++	netif_rx_ni(nskb);
++	return 0;
++
++badframe:
++	s->stats.rx_errors++;
++	kfree_skb(skb);
++	return 0;
++}
++
++static u8 __bnep_tx_types[] = {
++	BNEP_GENERAL,
++	BNEP_COMPRESSED_SRC_ONLY,
++	BNEP_COMPRESSED_DST_ONLY,
++	BNEP_COMPRESSED
++};
++
++static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
++{
++	struct ethhdr *eh = (void *) skb->data;
++	struct socket *sock = s->sock;
++	struct iovec iv[3];
++	int len = 0, il = 0;
++	u8 type = 0;
++
++	BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
++
++	if (!skb->dev) {
++		/* Control frame sent by us */
++		goto send;
++	}
++
++	iv[il++] = (struct iovec) { &type, 1 };
++	len++;
++
++	if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN))
++		type |= 0x01;
++
++	if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN))
++		type |= 0x02;
++
++	if (type)
++		skb_pull(skb, ETH_ALEN * 2);
++
++	type = __bnep_tx_types[type];
++	switch (type) {
++	case BNEP_COMPRESSED_SRC_ONLY:
++		iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN };
++		len += ETH_ALEN;
++		break;
++		
++	case BNEP_COMPRESSED_DST_ONLY:
++		iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN };
++		len += ETH_ALEN;
++		break;
++	}
++
++send:
++	iv[il++] = (struct iovec) { skb->data, skb->len };
++	len += skb->len;
++	
++	/* FIXME: linearize skb */
++	
++	s->msg.msg_iov    = iv;
++	s->msg.msg_iovlen = il;
++	len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
++	kfree_skb(skb);
++
++	if (len > 0) {
++		s->stats.tx_bytes += len;
++		s->stats.tx_packets++;
++		return 0;
++	}
++
++	return len;
++}
++
++static int bnep_session(void *arg)
++{
++	struct bnep_session *s = arg;
++	struct net_device *dev = &s->dev;
++	struct sock *sk = s->sock->sk;
++	struct sk_buff *skb;
++	wait_queue_t wait;
++
++	BT_DBG("");
++
++        daemonize(); reparent_to_init();
++
++        sprintf(current->comm, "kbnepd %s", dev->name);
++	
++        sigfillset(&current->blocked);
++	flush_signals(current);
++
++	current->nice = -15;
++
++        set_fs(KERNEL_DS);
++
++	init_waitqueue_entry(&wait, current);
++	add_wait_queue(sk->sleep, &wait);
++	while (!atomic_read(&s->killed)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		// RX
++		while ((skb = skb_dequeue(&sk->receive_queue))) {
++			skb_orphan(skb);
++			bnep_rx_frame(s, skb);
++		}
++
++		if (sk->state != BT_CONNECTED)
++			break;
++	
++		// TX
++		while ((skb = skb_dequeue(&sk->write_queue)))
++			if (bnep_tx_frame(s, skb))
++				break;
++		netif_wake_queue(dev);
++	
++		schedule();
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	/* Cleanup session */
++	down_write(&bnep_session_sem);
++
++	/* Delete network device */
++	unregister_netdev(dev);
++
++	/* Release the socket */
++	fput(s->sock->file);
++
++	__bnep_unlink_session(s);
++
++	up_write(&bnep_session_sem);
++	kfree(s);
++	return 0;
++}
++
++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
++{
++	struct net_device *dev;
++	struct bnep_session *s, *ss;
++	u8 dst[ETH_ALEN], src[ETH_ALEN];
++	int err;
++
++	BT_DBG("");
++
++	baswap((void *) dst, &bluez_pi(sock->sk)->dst);
++	baswap((void *) src, &bluez_pi(sock->sk)->src);
++
++	s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
++	if (!s) 
++		return -ENOMEM;
++	memset(s, 0, sizeof(struct bnep_session));
++
++	down_write(&bnep_session_sem);
++
++	ss = __bnep_get_session(dst);
++	if (ss && ss->state == BT_CONNECTED) {
++		err = -EEXIST;
++		goto failed;
++	}
++
++	dev = &s->dev;
++	
++	if (*req->device)
++		strcpy(dev->name, req->device);
++	else
++		strcpy(dev->name, "bnep%d");
++
++	memset(dev->broadcast, 0xff, ETH_ALEN);
++
++	/* This is rx header therefor addresses are swaped.
++	 * ie eh.h_dest is our local address. */
++	memcpy(s->eh.h_dest,   &src, ETH_ALEN);
++	memcpy(s->eh.h_source, &dst, ETH_ALEN);
++
++	s->sock  = sock;
++	s->role  = req->role;
++	s->state = BT_CONNECTED;
++	
++	s->msg.msg_flags = MSG_NOSIGNAL;
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	/* Set default mc filter */
++	set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
++#endif
++	
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++	/* Set default protocol filter */
++
++	/* (IPv4, ARP)  */
++	s->proto_filter[0].start = htons(0x0800);
++	s->proto_filter[0].end   = htons(0x0806);
++	/* (RARP, AppleTalk) */
++	s->proto_filter[1].start = htons(0x8035);
++	s->proto_filter[1].end   = htons(0x80F3);
++	/* (IPX, IPv6) */
++	s->proto_filter[2].start = htons(0x8137);
++	s->proto_filter[2].end   = htons(0x86DD);
++#endif
++	
++	dev->init = bnep_net_init;
++	dev->priv = s;
++	err = register_netdev(dev);
++	if (err) {
++		goto failed;
++	}
++
++	__bnep_link_session(s);
++	
++	err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++	if (err < 0) {
++		/* Session thread start failed, gotta cleanup. */
++		unregister_netdev(dev);
++		__bnep_unlink_session(s);
++		goto failed;
++	}
++
++	up_write(&bnep_session_sem);
++	strcpy(req->device, dev->name);
++	return 0;
++
++failed:
++	up_write(&bnep_session_sem);
++	kfree(s);
++	return err;
++}
++
++int bnep_del_connection(struct bnep_conndel_req *req)
++{
++	struct bnep_session *s;
++	int  err = 0;
++
++	BT_DBG("");
++
++	down_read(&bnep_session_sem);
++
++	s = __bnep_get_session(req->dst);
++	if (s) {
++		/* Wakeup user-space which is polling for socket errors.
++		 * This is temporary hack untill we have shutdown in L2CAP */
++		s->sock->sk->err = EUNATCH;
++		
++		/* Kill session thread */
++		atomic_inc(&s->killed);
++		wake_up_interruptible(s->sock->sk->sleep);
++	} else
++		err = -ENOENT;
++
++	up_read(&bnep_session_sem);
++	return err;
++}
++
++static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
++{
++	memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
++	strcpy(ci->device, s->dev.name);
++	ci->flags = s->flags;
++	ci->state = s->state;
++	ci->role  = s->role;
++}
++
++int bnep_get_connlist(struct bnep_connlist_req *req)
++{
++	struct list_head *p;
++	int err = 0, n = 0;
++
++	down_read(&bnep_session_sem);
++
++	list_for_each(p, &bnep_session_list) {
++		struct bnep_session *s;
++		struct bnep_conninfo ci;
++
++		s = list_entry(p, struct bnep_session, list);
++
++		__bnep_copy_ci(&ci, s);
++		
++		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
++			err = -EFAULT;
++			break;
++		}
++
++		if (++n >= req->cnum)
++			break;
++
++		req->ci++;
++	}
++	req->cnum = n;
++
++	up_read(&bnep_session_sem);
++	return err;
++}
++
++int bnep_get_conninfo(struct bnep_conninfo *ci)
++{
++	struct bnep_session *s;
++	int err = 0;
++
++	down_read(&bnep_session_sem);
++
++	s = __bnep_get_session(ci->dst);
++	if (s)
++		__bnep_copy_ci(ci, s);
++	else
++		err = -ENOENT;
++
++	up_read(&bnep_session_sem);
++	return err;
++}
++
++static int __init bnep_init_module(void)
++{
++	l2cap_load();
++
++	bnep_crc32_init();
++	bnep_sock_init();
++
++	BT_INFO("BlueZ BNEP ver %s", VERSION);
++	BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
++	BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
++	BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
++	BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
++
++	return 0;
++}
++
++static void __exit bnep_cleanup_module(void)
++{
++	bnep_sock_cleanup();
++	bnep_crc32_cleanup();
++}
++
++module_init(bnep_init_module);
++module_exit(bnep_cleanup_module);
++
++MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
++MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
++MODULE_LICENSE("GPL");
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/crc32.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,59 @@
++/* 
++ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com>
++ *
++ * FIXME: Remove in 2.5  
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <asm/atomic.h>
++
++#include "crc32.h"
++
++#define CRCPOLY_BE 0x04c11db7
++#define CRC_BE_BITS 8
++
++static u32 *bnep_crc32_table;
++
++/*
++ * This code is in the public domain; copyright abandoned.
++ * Liability for non-performance of this code is limited to the amount
++ * you paid for it.  Since it is distributed for free, your refund will
++ * be very very small.  If it breaks, you get to keep both pieces.
++ */
++u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len)
++{
++	while (len--)
++		crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++];
++	
++	return crc;
++}
++
++int __init bnep_crc32_init(void)
++{
++	unsigned i, j;
++	u32 crc = 0x80000000;
++
++	bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
++	if (!bnep_crc32_table)
++		return -ENOMEM;
++
++	bnep_crc32_table[0] = 0;
++
++	for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
++		crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
++		for (j = 0; j < i; j++)
++			bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j];
++	}
++	return 0;
++}
++
++void __exit bnep_crc32_cleanup(void)
++{
++	if (bnep_crc32_table)
++		kfree(bnep_crc32_table);
++	bnep_crc32_table = NULL;
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/crc32.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,10 @@
++/*
++ * crc32.h
++ * See crc32.c for license and changes
++ *
++ * FIXME: Remove in 2.5
++ */
++
++int  bnep_crc32_init(void);
++void bnep_crc32_cleanup(void);
++u32  bnep_crc32(u32 crc, unsigned char const *p, size_t len);
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/Makefile	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,10 @@
++#
++# Makefile for the Linux Bluetooth BNEP layer
++#
++
++O_TARGET := bnep.o
++
++obj-y	 := core.o sock.o netdev.o crc32.o
++obj-m    += $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/netdev.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,254 @@
++/* 
++   BNEP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2001-2002 Inventel Systemes
++   Written 2001-2002 by
++	Cl�ment Moreau <clement.moreau@inventel.fr>
++	David Libault  <david.libault@inventel.fr>
++
++   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */ 
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/socket.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/wait.h>
++
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include <net/bluetooth/l2cap.h>
++
++#include "bnep.h"
++
++#ifndef CONFIG_BLUEZ_BNEP_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++#define BNEP_TX_QUEUE_LEN 20
++
++static int bnep_net_open(struct net_device *dev)
++{
++	netif_start_queue(dev);
++	return 0;
++}
++
++static int bnep_net_close(struct net_device *dev)
++{
++	netif_stop_queue(dev);
++	return 0;
++}
++
++static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
++{
++	struct bnep_session *s = dev->priv;
++	return &s->stats;
++}
++
++static void bnep_net_set_mc_list(struct net_device *dev)
++{
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	struct bnep_session *s = dev->priv;
++	struct sock *sk = s->sock->sk;
++	struct bnep_set_filter_req *r;
++	struct sk_buff *skb;
++	int size;
++
++	BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
++
++	size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
++	skb  = alloc_skb(size, GFP_ATOMIC);
++	if (!skb) {
++		BT_ERR("%s Multicast list allocation failed", dev->name);
++		return;
++	}
++
++	r = (void *) skb->data;
++	__skb_put(skb, sizeof(*r));
++
++	r->type = BNEP_CONTROL;
++	r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
++
++        if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
++		u8 start[ETH_ALEN] = { 0x01 };
++
++		/* Request all addresses */
++		memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
++		memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
++		r->len = htons(ETH_ALEN * 2);
++	} else {
++                struct dev_mc_list *dmi = dev->mc_list;
++		int i, len = skb->len;
++
++		if (dev->flags & IFF_BROADCAST) {
++			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
++			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
++		}	
++		
++		/* FIXME: We should group addresses here. */
++
++		for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
++			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
++			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
++			dmi = dmi->next;
++		}
++		r->len = htons(skb->len - len);
++	}
++
++	skb_queue_tail(&sk->write_queue, skb);
++	wake_up_interruptible(sk->sleep);
++#endif
++}
++
++static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
++{
++	BT_DBG("%s", dev->name);
++	return 0;
++}
++
++static void bnep_net_timeout(struct net_device *dev)
++{
++	BT_DBG("net_timeout");
++	netif_wake_queue(dev);
++}
++
++static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++	return -EINVAL;
++}
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
++{
++	struct ethhdr *eh = (void *) skb->data;
++
++	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) {
++		BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, 
++				eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
++				eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
++		return 1;
++	}
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++/* Determine ether protocol. Based on eth_type_trans. */
++static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
++{
++	struct ethhdr *eh = (void *) skb->data;
++	
++	if (ntohs(eh->h_proto) >= 1536)
++		return eh->h_proto;
++		
++	if (get_unaligned((u16 *) skb->data) == 0xFFFF)
++		return htons(ETH_P_802_3);
++		
++	return htons(ETH_P_802_2);
++}
++
++static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
++{
++	u16 proto = bnep_net_eth_proto(skb);
++	struct bnep_proto_filter *f = s->proto_filter;
++	int i;
++	
++	for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
++		if (proto >= f[i].start && proto <= f[i].end)
++			return 0;
++	}
++
++	BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
++	return 1;
++}
++#endif
++
++static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct bnep_session *s = dev->priv;
++	struct sock *sk = s->sock->sk;
++
++	BT_DBG("skb %p, dev %p", skb, dev);
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	if (bnep_net_mc_filter(skb, s)) {
++		kfree_skb(skb);
++		return 0;
++	}
++#endif
++	
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++	if (bnep_net_proto_filter(skb, s)) {
++		kfree_skb(skb);
++		return 0;
++	}
++#endif
++	
++	/*
++	 * We cannot send L2CAP packets from here as we are potentially in a bh.
++	 * So we have to queue them and wake up session thread which is sleeping
++	 * on the sk->sleep.
++	 */
++	dev->trans_start = jiffies;
++	skb_queue_tail(&sk->write_queue, skb);
++	wake_up_interruptible(sk->sleep);
++
++	if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) {
++		BT_DBG("tx queue is full");
++
++		/* Stop queuing.
++		 * Session thread will do netif_wake_queue() */
++		netif_stop_queue(dev);
++	}
++
++	return 0;
++}
++
++int bnep_net_init(struct net_device *dev)
++{
++	struct bnep_session *s = dev->priv;
++
++	memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
++	dev->addr_len = ETH_ALEN;
++
++	ether_setup(dev);
++
++	dev->open            = bnep_net_open;
++	dev->stop            = bnep_net_close;
++	dev->hard_start_xmit = bnep_net_xmit;
++	dev->get_stats       = bnep_net_get_stats;
++	dev->do_ioctl        = bnep_net_ioctl;
++	dev->set_mac_address = bnep_net_set_mac_addr;
++	dev->set_multicast_list = bnep_net_set_mc_list;
++
++	dev->watchdog_timeo  = HZ * 2;
++	dev->tx_timeout      = bnep_net_timeout;
++
++	return 0;
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/bnep/sock.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,238 @@
++/* 
++   BNEP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2001-2002 Inventel Systemes
++   Written 2001-2002 by
++	David Libault  <david.libault@inventel.fr>
++
++   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */ 
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include "bnep.h"
++
++#ifndef CONFIG_BLUEZ_BNEP_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++static inline struct socket *socki_lookup(struct inode *inode)
++{
++	return &inode->u.socket_i;
++}
++
++static struct socket *sockfd_lookup(int fd, int *err)
++{
++	struct file *file;
++	struct inode *inode;
++	struct socket *sock;
++
++	if (!(file = fget(fd))) {
++		*err = -EBADF;
++		return NULL;
++	}
++
++	inode = file->f_dentry->d_inode;
++	if (!inode->i_sock || !(sock = socki_lookup(inode))) {
++		*err = -ENOTSOCK;
++		fput(file);
++		return NULL;
++	}
++
++	if (sock->file != file) {
++		printk(KERN_ERR "socki_lookup: socket file changed!\n");
++		sock->file = file;
++	}
++	return sock;
++}
++ 
++static int bnep_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	sock_orphan(sk);
++	sock_put(sk);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct bnep_connlist_req cl;
++	struct bnep_connadd_req  ca;
++	struct bnep_conndel_req  cd;
++	struct bnep_conninfo ci;
++	struct socket *nsock;
++	int err;
++
++	BT_DBG("cmd %x arg %lx", cmd, arg);
++
++	switch (cmd) {
++	case BNEPCONNADD:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
++			return -EFAULT;
++	
++		nsock = sockfd_lookup(ca.sock, &err);
++		if (!nsock)
++			return err;
++
++		if (nsock->sk->state != BT_CONNECTED)
++			return -EBADFD;
++
++		err = bnep_add_connection(&ca, nsock);
++		if (!err) {
++    			if (copy_to_user((void *) arg, &ca, sizeof(ca)))
++				err = -EFAULT;
++		} else
++			fput(nsock->file);
++
++		return err;
++	
++	case BNEPCONNDEL:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
++			return -EFAULT;
++	
++		return bnep_del_connection(&cd);
++
++	case BNEPGETCONNLIST:
++		if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
++			return -EFAULT;
++
++		if (cl.cnum <= 0)
++			return -EINVAL;
++	
++		err = bnep_get_connlist(&cl);
++		if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
++			return -EFAULT;
++
++		return err;
++
++	case BNEPGETCONNINFO:
++		if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
++			return -EFAULT;
++
++		err = bnep_get_conninfo(&ci);
++		if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
++			return -EFAULT;
++
++		return err;
++
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static struct proto_ops bnep_sock_ops = {
++	family:     PF_BLUETOOTH,
++	release:    bnep_sock_release,
++	ioctl:      bnep_sock_ioctl,
++	bind:       sock_no_bind,
++	getname:    sock_no_getname,
++	sendmsg:    sock_no_sendmsg,
++	recvmsg:    sock_no_recvmsg,
++	poll:       sock_no_poll,
++	listen:     sock_no_listen,
++	shutdown:   sock_no_shutdown,
++	setsockopt: sock_no_setsockopt,
++	getsockopt: sock_no_getsockopt,
++	connect:    sock_no_connect,
++	socketpair: sock_no_socketpair,
++	accept:     sock_no_accept,
++	mmap:       sock_no_mmap
++};
++
++static int bnep_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	if (sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &bnep_sock_ops;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
++		return -ENOMEM;
++
++	MOD_INC_USE_COUNT;
++
++	sock->state = SS_UNCONNECTED;
++	sock_init_data(sock, sk);
++
++	sk->destruct = NULL;
++	sk->protocol = protocol;
++
++	return 0;
++}
++
++static struct net_proto_family bnep_sock_family_ops = {
++	family: PF_BLUETOOTH,
++	create: bnep_sock_create
++};
++
++int bnep_sock_init(void)
++{
++	bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
++	return 0;
++}
++
++int bnep_sock_cleanup(void)
++{
++	if (bluez_sock_unregister(BTPROTO_BNEP))
++		BT_ERR("Can't unregister BNEP socket");
++	return 0;
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/cmtp/capi.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,707 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <linux/capi.h>
++
++#include "../drivers/isdn/avmb1/capilli.h"
++#include "../drivers/isdn/avmb1/capicmd.h"
++#include "../drivers/isdn/avmb1/capiutil.h"
++
++#include "cmtp.h"
++
++#ifndef CONFIG_BLUEZ_CMTP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define REVISION "1.0"
++
++#define CAPI_INTEROPERABILITY		0x20
++
++#define CAPI_INTEROPERABILITY_REQ	CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
++#define CAPI_INTEROPERABILITY_CONF	CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
++#define CAPI_INTEROPERABILITY_IND	CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
++#define CAPI_INTEROPERABILITY_RESP	CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
++
++#define CAPI_INTEROPERABILITY_REQ_LEN	(CAPI_MSG_BASELEN + 2)
++#define CAPI_INTEROPERABILITY_CONF_LEN	(CAPI_MSG_BASELEN + 4)
++#define CAPI_INTEROPERABILITY_IND_LEN	(CAPI_MSG_BASELEN + 2)
++#define CAPI_INTEROPERABILITY_RESP_LEN	(CAPI_MSG_BASELEN + 2)
++
++#define CAPI_FUNCTION_REGISTER		0
++#define CAPI_FUNCTION_RELEASE		1
++#define CAPI_FUNCTION_GET_PROFILE	2
++#define CAPI_FUNCTION_GET_MANUFACTURER	3
++#define CAPI_FUNCTION_GET_VERSION	4
++#define CAPI_FUNCTION_GET_SERIAL_NUMBER	5
++#define CAPI_FUNCTION_MANUFACTURER	6
++#define CAPI_FUNCTION_LOOPBACK		7
++
++static struct capi_driver_interface *di;
++
++
++#define CMTP_MSGNUM	1
++#define CMTP_APPLID	2
++#define CMTP_MAPPING	3
++
++static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
++{
++	struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
++
++	BT_DBG("session %p application %p appl %d", session, app, appl);
++
++	if (!app)
++		return NULL;
++
++	memset(app, 0, sizeof(*app));
++
++	app->state = BT_OPEN;
++	app->appl = appl;
++
++	list_add_tail(&app->list, &session->applications);
++
++	return app;
++}
++
++static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
++{
++	BT_DBG("session %p application %p", session, app);
++
++	if (app) {
++		list_del(&app->list);
++		kfree(app);
++	}
++}
++
++static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
++{
++	struct cmtp_application *app;
++	struct list_head *p, *n;
++
++	list_for_each_safe(p, n, &session->applications) {
++		app = list_entry(p, struct cmtp_application, list);
++		switch (pattern) {
++		case CMTP_MSGNUM:
++			if (app->msgnum == value)
++				return app;
++			break;
++		case CMTP_APPLID:
++			if (app->appl == value)
++				return app;
++			break;
++		case CMTP_MAPPING:
++			if (app->mapping == value)
++				return app;
++			break;
++		}
++	}
++
++	return NULL;
++}
++
++static int cmtp_msgnum_get(struct cmtp_session *session)
++{
++	session->msgnum++;
++
++	if ((session->msgnum & 0xff) > 200)
++		session->msgnum = CMTP_INITIAL_MSGNUM + 1;
++
++	return session->msgnum;
++}
++
++
++static void cmtp_send_interopmsg(struct cmtp_session *session,
++					__u8 subcmd, __u16 appl, __u16 msgnum,
++					__u16 function, unsigned char *buf, int len)
++{
++	struct sk_buff *skb;
++	unsigned char *s;
++
++	BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
++
++	if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for interoperability packet");
++		return;
++	}
++
++	s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
++
++	capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
++	capimsg_setu16(s, 2, appl);
++	capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
++	capimsg_setu8 (s, 5, subcmd);
++	capimsg_setu16(s, 6, msgnum);
++
++	/* Interoperability selector (Bluetooth Device Management) */
++	capimsg_setu16(s, 8, 0x0001);
++
++	capimsg_setu8 (s, 10, 3 + len);
++	capimsg_setu16(s, 11, function);
++	capimsg_setu8 (s, 13, len);
++
++	if (len > 0)
++		memcpy(s + 14, buf, len);
++
++	cmtp_send_capimsg(session, skb);
++}
++
++static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
++{
++	struct capi_ctr *ctrl = session->ctrl;
++	struct cmtp_application *application;
++	__u16 appl, msgnum, func, info;
++	__u32 controller;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	switch (CAPIMSG_SUBCOMMAND(skb->data)) {
++	case CAPI_CONF:
++		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
++		info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
++
++		switch (func) {
++		case CAPI_FUNCTION_REGISTER:
++			msgnum = CAPIMSG_MSGID(skb->data);
++
++			application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
++			if (application) {
++				application->state = BT_CONNECTED;
++				application->msgnum = 0;
++				application->mapping = CAPIMSG_APPID(skb->data);
++				wake_up_interruptible(&session->wait);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_RELEASE:
++			appl = CAPIMSG_APPID(skb->data);
++
++			application = cmtp_application_get(session, CMTP_MAPPING, appl);
++			if (application) {
++				application->state = BT_CLOSED;
++				application->msgnum = 0;
++				wake_up_interruptible(&session->wait);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_PROFILE:
++			controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
++			msgnum = CAPIMSG_MSGID(skb->data);
++
++			if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
++				session->ncontroller = controller;
++				wake_up_interruptible(&session->wait);
++				break;
++			}
++
++			if (!info && ctrl) {
++				memcpy(&ctrl->profile,
++					skb->data + CAPI_MSG_BASELEN + 11,
++					sizeof(capi_profile));
++				session->state = BT_CONNECTED;
++				ctrl->ready(ctrl);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_MANUFACTURER:
++			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
++
++			if (!info && ctrl) {
++				strncpy(ctrl->manu,
++					skb->data + CAPI_MSG_BASELEN + 15,
++					skb->data[CAPI_MSG_BASELEN + 14]);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_VERSION:
++			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
++
++			if (!info && ctrl) {
++				ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
++				ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
++				ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
++				ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_SERIAL_NUMBER:
++			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
++
++			if (!info && ctrl) {
++				memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
++				strncpy(ctrl->serial,
++					skb->data + CAPI_MSG_BASELEN + 17,
++					skb->data[CAPI_MSG_BASELEN + 16]);
++			}
++
++			break;
++		}
++
++		break;
++
++	case CAPI_IND:
++		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
++
++		if (func == CAPI_FUNCTION_LOOPBACK) {
++			appl = CAPIMSG_APPID(skb->data);
++			msgnum = CAPIMSG_MSGID(skb->data);
++			cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
++						skb->data + CAPI_MSG_BASELEN + 6,
++						skb->data[CAPI_MSG_BASELEN + 5]);
++		}
++
++		break;
++	}
++
++	kfree_skb(skb);
++}
++
++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
++{
++	struct capi_ctr *ctrl = session->ctrl;
++	struct cmtp_application *application;
++	__u16 cmd, appl, info;
++	__u32 ncci, contr;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
++		cmtp_recv_interopmsg(session, skb);
++		return;
++	}
++
++	if (session->flags & (1 << CMTP_LOOPBACK)) {
++		kfree_skb(skb);
++		return;
++	}
++
++	cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
++	appl = CAPIMSG_APPID(skb->data);
++	contr = CAPIMSG_CONTROL(skb->data);
++
++	application = cmtp_application_get(session, CMTP_MAPPING, appl);
++	if (application) {
++		appl = application->appl;
++		CAPIMSG_SETAPPID(skb->data, appl);
++	} else {
++		BT_ERR("Can't find application with id %d", appl);
++		kfree_skb(skb);
++		return;
++	}
++
++	if ((contr & 0x7f) == 0x01) {
++		contr = (contr & 0xffffff80) | session->num;
++		CAPIMSG_SETCONTROL(skb->data, contr);
++	}
++
++	if (!ctrl) {
++		BT_ERR("Can't find controller %d for message", session->num);
++		kfree_skb(skb);
++		return;
++	}
++
++	switch (cmd) {
++	case CAPI_CONNECT_B3_CONF:
++		ncci = CAPIMSG_NCCI(skb->data);
++		info = CAPIMSG_U16(skb->data, 12);
++
++		BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info);
++
++		if (info == 0)
++			ctrl->new_ncci(ctrl, appl, ncci, 8);
++
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		break;
++
++	case CAPI_CONNECT_B3_IND:
++		ncci = CAPIMSG_NCCI(skb->data);
++
++		BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci);
++
++		ctrl->new_ncci(ctrl, appl, ncci, 8);
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		break;
++
++	case CAPI_DISCONNECT_B3_IND:
++		ncci = CAPIMSG_NCCI(skb->data);
++
++		BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci);
++
++		if (ncci == 0xffffffff)
++			BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff");
++
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		ctrl->free_ncci(ctrl, appl, ncci);
++		break;
++
++	default:
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		break;
++	}
++}
++
++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
++{
++	struct cmtp_scb *scb = (void *) skb->cb;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	scb->id = -1;
++	scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
++
++	skb_queue_tail(&session->transmit, skb);
++
++	cmtp_schedule(session);
++}
++
++
++static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
++{
++	BT_DBG("ctrl %p data %p", ctrl, data);
++
++	return -EIO;
++}
++
++static void cmtp_reset_ctr(struct capi_ctr *ctrl)
++{
++	BT_DBG("ctrl %p", ctrl);
++
++	ctrl->reseted(ctrl);
++}
++
++static void cmtp_remove_ctr(struct capi_ctr *ctrl)
++{
++	struct cmtp_session *session = ctrl->driverdata;
++
++	BT_DBG("ctrl %p", ctrl);
++
++	ctrl->suspend_output(ctrl);
++
++	atomic_inc(&session->terminate);
++	cmtp_schedule(session);
++}
++
++static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *application;
++	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
++	unsigned char buf[8];
++	int err = 0, nconn, want = rp->level3cnt;
++
++	BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
++		ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
++
++	application = cmtp_application_add(session, appl);
++	if (!application) {
++		BT_ERR("Can't allocate memory for new application");
++		ctrl->appl_released(ctrl, appl);
++		return;
++	}
++
++	if (want < 0)
++		nconn = ctrl->profile.nbchannel * -want;
++	else
++		nconn = want;
++
++	if (nconn == 0)
++		nconn = ctrl->profile.nbchannel;
++
++	capimsg_setu16(buf, 0, nconn);
++	capimsg_setu16(buf, 2, rp->datablkcnt);
++	capimsg_setu16(buf, 4, rp->datablklen);
++
++	application->state = BT_CONFIG;
++	application->msgnum = cmtp_msgnum_get(session);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
++				CAPI_FUNCTION_REGISTER, buf, 6);
++
++	add_wait_queue(&session->wait, &wait);
++	while (1) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		if (application->state == BT_CLOSED) {
++			err = -application->err;
++			break;
++		}
++
++		if (application->state == BT_CONNECTED)
++			break;
++
++		if (signal_pending(current)) {
++			err = -EINTR;
++			break;
++		}
++
++		timeo = schedule_timeout(timeo);
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&session->wait, &wait);
++
++	if (err) {
++		ctrl->appl_released(ctrl, appl);
++		cmtp_application_del(session, application);
++		return;
++	}
++
++	ctrl->appl_registered(ctrl, appl);
++}
++
++static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *application;
++	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
++
++	BT_DBG("ctrl %p appl %d", ctrl, appl);
++
++	application = cmtp_application_get(session, CMTP_APPLID, appl);
++	if (!application) {
++		BT_ERR("Can't find application");
++		return;
++	}
++
++	application->msgnum = cmtp_msgnum_get(session);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
++				CAPI_FUNCTION_RELEASE, NULL, 0);
++
++	add_wait_queue(&session->wait, &wait);
++	while (timeo) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (application->state == BT_CLOSED)
++			break;
++
++		if (signal_pending(current))
++			break;
++
++		timeo = schedule_timeout(timeo);
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&session->wait, &wait);
++
++	cmtp_application_del(session, application);
++	ctrl->appl_released(ctrl, appl);
++}
++
++static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
++{
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *application;
++	__u16 appl;
++	__u32 contr;
++
++	BT_DBG("ctrl %p skb %p", ctrl, skb);
++
++	appl = CAPIMSG_APPID(skb->data);
++	contr = CAPIMSG_CONTROL(skb->data);
++
++	application = cmtp_application_get(session, CMTP_APPLID, appl);
++	if ((!application) || (application->state != BT_CONNECTED)) {
++		BT_ERR("Can't find application with id %d", appl);
++		kfree_skb(skb);
++		return;
++	}
++
++	CAPIMSG_SETAPPID(skb->data, application->mapping);
++
++	if ((contr & 0x7f) == session->num) {
++		contr = (contr & 0xffffff80) | 0x01;
++		CAPIMSG_SETCONTROL(skb->data, contr);
++	}
++
++	cmtp_send_capimsg(session, skb);
++}
++
++static char *cmtp_procinfo(struct capi_ctr *ctrl)
++{
++	return "CAPI Message Transport Protocol";
++}
++
++static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
++{
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *app;
++	struct list_head *p, *n;
++	int len = 0;
++
++	len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION);
++	len += sprintf(page + len, "addr %s\n", session->name);
++	len += sprintf(page + len, "ctrl %d\n", session->num);
++
++	list_for_each_safe(p, n, &session->applications) {
++		app = list_entry(p, struct cmtp_application, list);
++		len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
++	}
++
++	if (off + count >= len)
++		*eof = 1;
++
++	if (len < off)
++		return 0;
++
++	*start = page + off;
++
++	return ((count < len - off) ? count : len - off);
++}
++
++static struct capi_driver cmtp_driver = {
++	name:		"cmtp",
++	revision:	REVISION,
++	load_firmware:	cmtp_load_firmware,
++	reset_ctr:	cmtp_reset_ctr,
++	remove_ctr:	cmtp_remove_ctr,
++	register_appl:	cmtp_register_appl,
++	release_appl:	cmtp_release_appl,
++	send_message:	cmtp_send_message,
++	procinfo:	cmtp_procinfo,
++	ctr_read_proc:	cmtp_ctr_read_proc,
++
++	driver_read_proc:	0,
++	add_card:		0,
++};
++
++
++int cmtp_attach_device(struct cmtp_session *session)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
++	unsigned char buf[4];
++
++	BT_DBG("session %p", session);
++
++	capimsg_setu32(buf, 0, 0);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
++				CAPI_FUNCTION_GET_PROFILE, buf, 4);
++
++	add_wait_queue(&session->wait, &wait);
++	while (timeo) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (session->ncontroller)
++			break;
++
++		if (signal_pending(current))
++			break;
++
++		timeo = schedule_timeout(timeo);
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&session->wait, &wait);
++
++	BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
++
++	if (!timeo)
++		return -ETIMEDOUT;
++
++	if (!session->ncontroller)
++		return -ENODEV;
++
++
++	if (session->ncontroller > 1)
++		BT_INFO("Setting up only CAPI controller 1");
++
++	if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) {
++		BT_ERR("Can't attach new controller");
++		return -EBUSY;
++	}
++
++	session->num = session->ctrl->cnr;
++
++	BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num);
++
++	capimsg_setu32(buf, 0, 1);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_VERSION, buf, 4);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_PROFILE, buf, 4);
++
++	return 0;
++}
++
++void cmtp_detach_device(struct cmtp_session *session)
++{
++	struct capi_ctr *ctrl = session->ctrl;
++
++	BT_DBG("session %p ctrl %p", session, ctrl);
++
++	if (!ctrl)
++		return;
++
++	ctrl->reseted(ctrl);
++
++	di->detach_ctr(ctrl);
++}
++
++int cmtp_init_capi(void)
++{
++	if (!(di = attach_capi_driver(&cmtp_driver))) {
++		BT_ERR("Can't attach CAPI driver");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++void cmtp_cleanup_capi(void)
++{
++	detach_capi_driver(&cmtp_driver);
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/cmtp/cmtp.h	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,138 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#ifndef __CMTP_H
++#define __CMTP_H
++
++#include <linux/types.h>
++#include <net/bluetooth/bluetooth.h>
++
++#define BTNAMSIZ 18
++
++/* CMTP ioctl defines */
++#define CMTPCONNADD	_IOW('C', 200, int)
++#define CMTPCONNDEL	_IOW('C', 201, int)
++#define CMTPGETCONNLIST	_IOR('C', 210, int)
++#define CMTPGETCONNINFO	_IOR('C', 211, int)
++
++#define CMTP_LOOPBACK	0
++
++struct cmtp_connadd_req {
++	int   sock;	// Connected socket
++	__u32 flags;
++};
++
++struct cmtp_conndel_req {
++	bdaddr_t bdaddr;
++	__u32    flags;
++};
++
++struct cmtp_conninfo {
++	bdaddr_t bdaddr;
++	__u32    flags;
++	__u16    state;
++	int      num;
++};
++
++struct cmtp_connlist_req {
++	__u32  cnum;
++	struct cmtp_conninfo *ci;
++};
++
++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
++int cmtp_del_connection(struct cmtp_conndel_req *req);
++int cmtp_get_connlist(struct cmtp_connlist_req *req);
++int cmtp_get_conninfo(struct cmtp_conninfo *ci);
++
++/* CMTP session defines */
++#define CMTP_INTEROP_TIMEOUT	(HZ * 5)
++#define CMTP_INITIAL_MSGNUM	0xff00
++
++struct cmtp_session {
++	struct list_head list;
++
++	struct socket *sock;
++
++	bdaddr_t bdaddr;
++
++	unsigned long state;
++	unsigned long flags;
++
++	uint mtu;
++
++	char name[BTNAMSIZ];
++
++	atomic_t terminate;
++
++	wait_queue_head_t wait;
++
++	int ncontroller;
++	int num;
++	struct capi_ctr *ctrl;
++
++	struct list_head applications;
++
++	unsigned long blockids;
++	int msgnum;
++
++	struct sk_buff_head transmit;
++
++	struct sk_buff *reassembly[16];
++};
++
++struct cmtp_application {
++	struct list_head list;
++
++	unsigned long state;
++	int err;
++
++	__u16 appl;
++	__u16 mapping;
++
++	__u16 msgnum;
++};
++
++struct cmtp_scb {
++	int id;
++	int data;
++};
++
++int  cmtp_attach_device(struct cmtp_session *session);
++void cmtp_detach_device(struct cmtp_session *session);
++
++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb);
++
++static inline void cmtp_schedule(struct cmtp_session *session)
++{
++	struct sock *sk = session->sock->sk;
++
++	wake_up_interruptible(sk->sleep);
++}
++
++/* CMTP init defines */
++int cmtp_init_capi(void);
++int cmtp_init_sockets(void);
++void cmtp_cleanup_capi(void);
++void cmtp_cleanup_sockets(void);
++
++#endif /* __CMTP_H */
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/cmtp/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,7 @@
++#
++# Bluetooth CMTP layer configuration
++#
++
++if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then 
++   dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP
++fi
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/cmtp/core.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,515 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <linux/init.h>
++#include <net/sock.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/l2cap.h>
++
++#include "cmtp.h"
++
++#ifndef CONFIG_BLUEZ_CMTP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define VERSION "1.0"
++
++static DECLARE_RWSEM(cmtp_session_sem);
++static LIST_HEAD(cmtp_session_list);
++
++static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
++{
++	struct cmtp_session *session;
++	struct list_head *p;
++
++	BT_DBG("");
++
++	list_for_each(p, &cmtp_session_list) {
++		session = list_entry(p, struct cmtp_session, list);
++		if (!bacmp(bdaddr, &session->bdaddr))
++			return session;
++	}
++	return NULL;
++}
++
++static void __cmtp_link_session(struct cmtp_session *session)
++{
++	MOD_INC_USE_COUNT;
++	list_add(&session->list, &cmtp_session_list);
++}
++
++static void __cmtp_unlink_session(struct cmtp_session *session)
++{
++	list_del(&session->list);
++	MOD_DEC_USE_COUNT;
++}
++
++static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
++{
++	bacpy(&ci->bdaddr, &session->bdaddr);
++
++	ci->flags = session->flags;
++	ci->state = session->state;
++
++	ci->num = session->num;
++}
++
++
++static inline int cmtp_alloc_block_id(struct cmtp_session *session)
++{
++	int i, id = -1;
++
++	for (i = 0; i < 16; i++)
++		if (!test_and_set_bit(i, &session->blockids)) {
++			id = i;
++			break;
++		}
++
++	return id;
++}
++
++static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
++{
++	clear_bit(id, &session->blockids);
++}
++
++static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
++{
++	struct sk_buff *skb = session->reassembly[id], *nskb;
++	int size;
++
++	BT_DBG("session %p buf %p count %d", session, buf, count);
++
++	size = (skb) ? skb->len + count : count;
++
++	if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for CAPI message");
++		return;
++	}
++
++	if (skb && (skb->len > 0))
++		memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
++
++	memcpy(skb_put(nskb, count), buf, count);
++
++	session->reassembly[id] = nskb;
++
++	if (skb)
++		kfree_skb(skb);
++}
++
++static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
++{
++	__u8 hdr, hdrlen, id;
++	__u16 len;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	while (skb->len > 0) {
++		hdr = skb->data[0];
++
++		switch (hdr & 0xc0) {
++		case 0x40:
++			hdrlen = 2;
++			len = skb->data[1];
++			break;
++		case 0x80:
++			hdrlen = 3;
++			len = skb->data[1] | (skb->data[2] << 8);
++			break;
++		default:
++			hdrlen = 1;
++			len = 0;
++			break;
++		}
++
++		id = (hdr & 0x3c) >> 2;
++
++		BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
++
++		if (hdrlen + len > skb->len) {
++			BT_ERR("Wrong size or header information in CMTP frame");
++			break;
++		}
++
++		if (len == 0) {
++			skb_pull(skb, hdrlen);
++			continue;
++		}
++
++		switch (hdr & 0x03) {
++		case 0x00:
++			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
++			cmtp_recv_capimsg(session, session->reassembly[id]);
++			session->reassembly[id] = NULL;
++			break;
++		case 0x01:
++			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
++			break;
++		default:
++			if (session->reassembly[id] != NULL)
++				kfree_skb(session->reassembly[id]);
++			session->reassembly[id] = NULL;
++			break;
++		}
++
++		skb_pull(skb, hdrlen + len);
++	}
++
++	kfree_skb(skb);
++	return 0;
++}
++
++static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
++{
++	struct socket *sock = session->sock;
++	struct iovec iv = { data, len };
++	struct msghdr msg;
++	int err;
++
++	BT_DBG("session %p data %p len %d", session, data, len);
++
++	if (!len)
++		return 0;
++
++	memset(&msg, 0, sizeof(msg));
++	msg.msg_iovlen = 1;
++	msg.msg_iov = &iv;
++
++	err = sock->ops->sendmsg(sock, &msg, len, 0);
++	return err;
++}
++
++static int cmtp_process_transmit(struct cmtp_session *session)
++{
++	struct sk_buff *skb, *nskb;
++	unsigned char *hdr;
++	unsigned int size, tail;
++
++	BT_DBG("session %p", session);
++
++	if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for new frame");
++		return -ENOMEM;
++	}
++
++	while ((skb = skb_dequeue(&session->transmit))) {
++		struct cmtp_scb *scb = (void *) skb->cb;
++
++		if ((tail = (session->mtu - nskb->len)) < 5) {
++			cmtp_send_frame(session, nskb->data, nskb->len);
++			skb_trim(nskb, 0);
++			tail = session->mtu;
++		}
++
++		size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
++
++		if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
++			skb_queue_head(&session->transmit, skb);
++			break;
++		}
++
++		if (size < 256) {
++			hdr = skb_put(nskb, 2);
++			hdr[0] = 0x40
++				| ((scb->id << 2) & 0x3c)
++				| ((skb->len == size) ? 0x00 : 0x01);
++			hdr[1] = size;
++		} else {
++			hdr = skb_put(nskb, 3);
++			hdr[0] = 0x80
++				| ((scb->id << 2) & 0x3c)
++				| ((skb->len == size) ? 0x00 : 0x01);
++			hdr[1] = size & 0xff;
++			hdr[2] = size >> 8;
++		}
++
++		memcpy(skb_put(nskb, size), skb->data, size);
++		skb_pull(skb, size);
++
++		if (skb->len > 0) {
++			skb_queue_head(&session->transmit, skb);
++		} else {
++			cmtp_free_block_id(session, scb->id);
++			if (scb->data) {
++				cmtp_send_frame(session, nskb->data, nskb->len);
++				skb_trim(nskb, 0);
++			}
++			kfree_skb(skb);
++		}
++	}
++
++	cmtp_send_frame(session, nskb->data, nskb->len);
++
++	kfree_skb(nskb);
++
++	return skb_queue_len(&session->transmit);
++}
++
++static int cmtp_session(void *arg)
++{
++	struct cmtp_session *session = arg;
++	struct sock *sk = session->sock->sk;
++	struct sk_buff *skb;
++	wait_queue_t wait;
++
++	BT_DBG("session %p", session);
++
++	daemonize(); reparent_to_init();
++
++	sprintf(current->comm, "kcmtpd_ctr_%d", session->num);
++
++	sigfillset(&current->blocked);
++	flush_signals(current);
++
++	current->nice = -15;
++
++	set_fs(KERNEL_DS);
++
++	init_waitqueue_entry(&wait, current);
++	add_wait_queue(sk->sleep, &wait);
++	while (!atomic_read(&session->terminate)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (sk->state != BT_CONNECTED)
++			break;
++
++		while ((skb = skb_dequeue(&sk->receive_queue))) {
++			skb_orphan(skb);
++			cmtp_recv_frame(session, skb);
++		}
++
++		cmtp_process_transmit(session);
++
++		schedule();
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	down_write(&cmtp_session_sem);
++
++	if (!(session->flags & (1 << CMTP_LOOPBACK)))
++		cmtp_detach_device(session);
++
++	fput(session->sock->file);
++
++	__cmtp_unlink_session(session);
++
++	up_write(&cmtp_session_sem);
++
++	kfree(session);
++	return 0;
++}
++
++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
++{
++	struct cmtp_session *session, *s;
++	bdaddr_t src, dst;
++	int i, err;
++
++	BT_DBG("");
++
++	baswap(&src, &bluez_pi(sock->sk)->src);
++	baswap(&dst, &bluez_pi(sock->sk)->dst);
++
++	session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL);
++	if (!session) 
++		return -ENOMEM;
++	memset(session, 0, sizeof(struct cmtp_session));
++
++	down_write(&cmtp_session_sem);
++
++	s = __cmtp_get_session(&bluez_pi(sock->sk)->dst);
++	if (s && s->state == BT_CONNECTED) {
++		err = -EEXIST;
++		goto failed;
++	}
++
++	bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst);
++
++	session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
++
++	BT_DBG("mtu %d", session->mtu);
++
++	sprintf(session->name, "%s", batostr(&dst));
++
++	session->sock  = sock;
++	session->state = BT_CONFIG;
++
++	init_waitqueue_head(&session->wait);
++
++	session->ctrl   = NULL;
++	session->msgnum = CMTP_INITIAL_MSGNUM;
++
++	INIT_LIST_HEAD(&session->applications);
++
++	skb_queue_head_init(&session->transmit);
++
++	for (i = 0; i < 16; i++)
++		session->reassembly[i] = NULL;
++
++	session->flags = req->flags;
++
++	__cmtp_link_session(session);
++
++	err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++	if (err < 0)
++		goto unlink;
++
++	if (!(session->flags & (1 << CMTP_LOOPBACK))) {
++		err = cmtp_attach_device(session);
++		if (err < 0)
++			goto detach;
++	}
++
++	up_write(&cmtp_session_sem);
++	return 0;
++
++detach:
++	cmtp_detach_device(session);
++
++unlink:
++	__cmtp_unlink_session(session);
++
++failed:
++	up_write(&cmtp_session_sem);
++	kfree(session);
++	return err;
++}
++
++int cmtp_del_connection(struct cmtp_conndel_req *req)
++{
++	struct cmtp_session *session;
++	int err = 0;
++
++	BT_DBG("");
++
++	down_read(&cmtp_session_sem);
++
++	session = __cmtp_get_session(&req->bdaddr);
++	if (session) {
++		/* Flush the transmit queue */
++		skb_queue_purge(&session->transmit);
++
++		/* Kill session thread */
++		atomic_inc(&session->terminate);
++		cmtp_schedule(session);
++	} else
++		err = -ENOENT;
++
++	up_read(&cmtp_session_sem);
++	return err;
++}
++
++int cmtp_get_connlist(struct cmtp_connlist_req *req)
++{
++	struct list_head *p;
++	int err = 0, n = 0;
++
++	BT_DBG("");
++
++	down_read(&cmtp_session_sem);
++
++	list_for_each(p, &cmtp_session_list) {
++		struct cmtp_session *session;
++		struct cmtp_conninfo ci;
++
++		session = list_entry(p, struct cmtp_session, list);
++
++		__cmtp_copy_session(session, &ci);
++
++		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
++			err = -EFAULT;
++			break;
++		}
++
++		if (++n >= req->cnum)
++			break;
++
++		req->ci++;
++	}
++	req->cnum = n;
++
++	up_read(&cmtp_session_sem);
++	return err;
++}
++
++int cmtp_get_conninfo(struct cmtp_conninfo *ci)
++{
++	struct cmtp_session *session;
++	int err = 0;
++
++	down_read(&cmtp_session_sem);
++
++	session = __cmtp_get_session(&ci->bdaddr);
++	if (session)
++		__cmtp_copy_session(session, ci);
++	else
++		err = -ENOENT;
++
++	up_read(&cmtp_session_sem);
++	return err;
++}
++
++
++int __init init_cmtp(void)
++{
++	l2cap_load();
++
++	cmtp_init_capi();
++	cmtp_init_sockets();
++
++	BT_INFO("BlueZ CMTP ver %s", VERSION);
++	BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>");
++
++	return 0;
++}
++
++void __exit exit_cmtp(void)
++{
++	cmtp_cleanup_sockets();
++	cmtp_cleanup_capi();
++}
++
++module_init(init_cmtp);
++module_exit(exit_cmtp);
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION);
++MODULE_LICENSE("GPL");
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/cmtp/Makefile	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,10 @@
++#
++# Makefile for the Linux Bluetooth CMTP layer
++#
++
++O_TARGET := cmtp.o
++
++obj-y	:= core.o sock.o capi.o
++obj-m	+= $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/cmtp/sock.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,236 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include "cmtp.h"
++
++#ifndef CONFIG_BLUEZ_CMTP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++static inline struct socket *socki_lookup(struct inode *inode)
++{
++	return &inode->u.socket_i;
++}
++
++static struct socket *sockfd_lookup(int fd, int *err)
++{
++	struct file *file;
++	struct inode *inode;
++	struct socket *sock;
++
++	if (!(file = fget(fd))) {
++		*err = -EBADF;
++		return NULL;
++	}
++
++	inode = file->f_dentry->d_inode;
++	if (!inode->i_sock || !(sock = socki_lookup(inode))) {
++		*err = -ENOTSOCK;
++		fput(file);
++		return NULL;
++	}
++
++	if (sock->file != file) {
++		printk(KERN_ERR "socki_lookup: socket file changed!\n");
++		sock->file = file;
++	}
++	return sock;
++}
++
++static int cmtp_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	sock_orphan(sk);
++	sock_put(sk);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct cmtp_connadd_req ca;
++	struct cmtp_conndel_req cd;
++	struct cmtp_connlist_req cl;
++	struct cmtp_conninfo ci;
++	struct socket *nsock;
++	int err;
++
++	BT_DBG("cmd %x arg %lx", cmd, arg);
++
++	switch (cmd) {
++	case CMTPCONNADD:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
++			return -EFAULT;
++
++		nsock = sockfd_lookup(ca.sock, &err);
++		if (!nsock)
++			return err;
++
++		if (nsock->sk->state != BT_CONNECTED)
++			return -EBADFD;
++
++		err = cmtp_add_connection(&ca, nsock);
++		if (!err) {
++			if (copy_to_user((void *) arg, &ca, sizeof(ca)))
++				err = -EFAULT;
++		} else
++			fput(nsock->file);
++
++		return err;
++
++	case CMTPCONNDEL:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
++			return -EFAULT;
++
++		return cmtp_del_connection(&cd);
++
++	case CMTPGETCONNLIST:
++		if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
++			return -EFAULT;
++
++		if (cl.cnum <= 0)
++			return -EINVAL;
++
++		err = cmtp_get_connlist(&cl);
++		if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
++			return -EFAULT;
++
++		return err;
++
++	case CMTPGETCONNINFO:
++		if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
++			return -EFAULT;
++
++		err = cmtp_get_conninfo(&ci);
++		if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
++			return -EFAULT;
++
++		return err;
++	}
++
++	return -EINVAL;
++}
++
++static struct proto_ops cmtp_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	cmtp_sock_release,
++	ioctl:		cmtp_sock_ioctl,
++	bind:		sock_no_bind,
++	getname:	sock_no_getname,
++	sendmsg:	sock_no_sendmsg,
++	recvmsg:	sock_no_recvmsg,
++	poll:		sock_no_poll,
++	listen:		sock_no_listen,
++	shutdown:	sock_no_shutdown,
++	setsockopt:	sock_no_setsockopt,
++	getsockopt:	sock_no_getsockopt,
++	connect:	sock_no_connect,
++	socketpair:	sock_no_socketpair,
++	accept:		sock_no_accept,
++	mmap:		sock_no_mmap
++};
++
++static int cmtp_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	if (sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &cmtp_sock_ops;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
++		return -ENOMEM;
++
++	MOD_INC_USE_COUNT;
++
++	sock->state = SS_UNCONNECTED;
++	sock_init_data(sock, sk);
++
++	sk->destruct = NULL;
++	sk->protocol = protocol;
++
++	return 0;
++}
++
++static struct net_proto_family cmtp_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		cmtp_sock_create
++};
++
++int cmtp_init_sockets(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) {
++		BT_ERR("Can't register CMTP socket layer (%d)", err);
++		return err;
++	}
++
++	return 0;
++}
++
++void cmtp_cleanup_sockets(void)
++{
++	int err;
++
++	if ((err = bluez_sock_unregister(BTPROTO_CMTP)))
++		BT_ERR("Can't unregister CMTP socket layer (%d)", err);
++
++	return;
++}
+--- linux/net/bluetooth/Config.in~bluetooth-2.4.18-mh11	2001-06-12 04:15:27.000000000 +0200
++++ linux/net/bluetooth/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -1,16 +1,22 @@
+ #
+-# Bluetooth configuration
++# Bluetooth subsystem configuration
+ #
+ 
+ if [ "$CONFIG_NET" != "n" ]; then
++
+    mainmenu_option next_comment
+    comment 'Bluetooth support'
+    dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
+ 
+    if [ "$CONFIG_BLUEZ" != "n" ]; then
+       dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
++      dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
++      source net/bluetooth/rfcomm/Config.in
++      source net/bluetooth/bnep/Config.in
++      source net/bluetooth/cmtp/Config.in
+       source drivers/bluetooth/Config.in
+    fi
++
+    endmenu
+ fi
+ 
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/hci_conn.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,435 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * HCI Connection handling.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/notifier.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++#ifndef HCI_CORE_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++void hci_acl_connect(struct hci_conn *conn)
++{
++	struct hci_dev *hdev = conn->hdev;
++	struct inquiry_entry *ie;
++	create_conn_cp cp;
++
++	BT_DBG("%p", conn);
++
++	conn->state = BT_CONNECT;
++	conn->out   = 1;
++	conn->link_mode = HCI_LM_MASTER;
++
++	memset(&cp, 0, sizeof(cp));
++	bacpy(&cp.bdaddr, &conn->dst);
++	cp.pscan_rep_mode = 0x02;
++
++	if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
++			inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
++		cp.pscan_rep_mode = ie->info.pscan_rep_mode;
++		cp.pscan_mode     = ie->info.pscan_mode;
++		cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
++	}
++
++	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
++	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
++		cp.role_switch	= 0x01;
++	else
++		cp.role_switch	= 0x00;
++		
++	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
++				CREATE_CONN_CP_SIZE, &cp);
++}
++
++void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
++{
++	disconnect_cp cp;
++
++	BT_DBG("%p", conn);
++
++	conn->state = BT_DISCONN;
++
++	cp.handle = __cpu_to_le16(conn->handle);
++	cp.reason = reason;
++	hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
++				DISCONNECT_CP_SIZE, &cp);
++}
++
++void hci_add_sco(struct hci_conn *conn, __u16 handle)
++{
++	struct hci_dev *hdev = conn->hdev;
++	add_sco_cp cp;
++
++	BT_DBG("%p", conn);
++
++	conn->state = BT_CONNECT;
++	conn->out = 1;
++
++	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
++	cp.handle   = __cpu_to_le16(handle);
++
++	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
++}
++
++static void hci_conn_timeout(unsigned long arg)
++{
++	struct hci_conn *conn = (void *)arg;
++	struct hci_dev  *hdev = conn->hdev;
++
++	BT_DBG("conn %p state %d", conn, conn->state);
++
++	if (atomic_read(&conn->refcnt))
++		return;
++
++	hci_dev_lock(hdev);
++ 	if (conn->state == BT_CONNECTED)
++		hci_acl_disconn(conn, 0x13);
++	else
++		conn->state = BT_CLOSED;
++	hci_dev_unlock(hdev);
++	return;
++}
++
++static void hci_conn_init_timer(struct hci_conn *conn)
++{
++	init_timer(&conn->timer);
++	conn->timer.function = hci_conn_timeout;
++	conn->timer.data = (unsigned long)conn;
++}
++
++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
++{
++	struct hci_conn *conn;
++
++	BT_DBG("%s dst %s", hdev->name, batostr(dst));
++
++	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
++		return NULL;
++	memset(conn, 0, sizeof(struct hci_conn));
++
++	bacpy(&conn->dst, dst);
++	conn->type   = type;
++	conn->hdev   = hdev;
++	conn->state  = BT_OPEN;
++
++	skb_queue_head_init(&conn->data_q);
++	hci_conn_init_timer(conn);
++
++	atomic_set(&conn->refcnt, 0);
++
++	hci_dev_hold(hdev);
++
++	tasklet_disable(&hdev->tx_task);
++	conn_hash_add(hdev, conn);
++	tasklet_enable(&hdev->tx_task);
++
++	return conn;
++}
++
++int hci_conn_del(struct hci_conn *conn)
++{
++	struct hci_dev  *hdev = conn->hdev;
++
++	BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
++	
++	hci_conn_del_timer(conn);
++
++	if (conn->type == SCO_LINK) {
++		struct hci_conn *acl = conn->link;
++		if (acl) {
++			acl->link = NULL;
++			hci_conn_put(acl);
++		}
++	} else {
++		struct hci_conn *sco = conn->link;
++		if (sco)
++			sco->link = NULL;
++
++		/* Unacked frames */
++		hdev->acl_cnt += conn->sent;
++	}
++
++	tasklet_disable(&hdev->tx_task);
++	conn_hash_del(hdev, conn);
++	tasklet_enable(&hdev->tx_task);
++
++	skb_queue_purge(&conn->data_q);
++
++	hci_dev_put(hdev);
++
++	kfree(conn);
++	return 0;
++}
++
++struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
++{
++	int use_src = bacmp(src, BDADDR_ANY);
++	struct hci_dev *hdev = NULL;
++	struct list_head *p;
++
++	BT_DBG("%s -> %s", batostr(src), batostr(dst));
++
++	read_lock_bh(&hdev_list_lock);
++
++	list_for_each(p, &hdev_list) {
++		struct hci_dev *d;
++		d = list_entry(p, struct hci_dev, list);
++		
++		if (!test_bit(HCI_UP, &d->flags))
++			continue;
++
++		/* Simple routing: 
++	 	 * 	No source address - find interface with bdaddr != dst 
++	 	 *	Source address 	  - find interface with bdaddr == src 
++	 	 */
++
++		if (use_src) {
++			if (!bacmp(&d->bdaddr, src)) {
++				hdev = d; break;
++			}
++		} else {
++			if (bacmp(&d->bdaddr, dst)) {
++				hdev = d; break;
++			}
++		}
++	}
++
++	if (hdev)
++		hci_dev_hold(hdev);
++
++	read_unlock_bh(&hdev_list_lock);
++	return hdev;
++}
++
++/* Create SCO or ACL connection.
++ * Device _must_ be locked */
++struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
++{
++	struct hci_conn *acl;
++
++	BT_DBG("%s dst %s", hdev->name, batostr(dst));
++
++	if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
++		if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
++			return NULL;
++	}
++
++	hci_conn_hold(acl);
++
++	if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
++		hci_acl_connect(acl);
++
++	if (type == SCO_LINK) {
++		struct hci_conn *sco;
++
++		if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
++			if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
++				hci_conn_put(acl);
++				return NULL;
++			}
++		}
++		acl->link = sco;
++		sco->link = acl;
++
++		hci_conn_hold(sco);
++
++		if (acl->state == BT_CONNECTED && 
++				(sco->state == BT_OPEN || sco->state == BT_CLOSED))
++			hci_add_sco(sco, acl->handle);
++
++		return sco;
++	} else {
++		return acl;
++	}
++}
++
++/* Authenticate remote device */
++int hci_conn_auth(struct hci_conn *conn)
++{
++	BT_DBG("conn %p", conn);
++	
++	if (conn->link_mode & HCI_LM_AUTH)
++		return 1;
++	
++	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
++		auth_requested_cp ar;
++		ar.handle = __cpu_to_le16(conn->handle);
++		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
++				AUTH_REQUESTED_CP_SIZE, &ar);
++	}
++	return 0;
++}
++
++/* Enable encryption */
++int hci_conn_encrypt(struct hci_conn *conn)
++{
++	BT_DBG("conn %p", conn);
++	
++	if (conn->link_mode & HCI_LM_ENCRYPT)
++		return 1;
++	
++	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
++		return 0;
++
++	if (hci_conn_auth(conn)) {
++		set_conn_encrypt_cp ce;
++		ce.handle  = __cpu_to_le16(conn->handle);
++		ce.encrypt = 1; 
++		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
++				SET_CONN_ENCRYPT_CP_SIZE, &ce);
++	}
++	return 0;
++}
++
++/* Drop all connection on the device */
++void hci_conn_hash_flush(struct hci_dev *hdev)
++{
++	struct conn_hash *h = &hdev->conn_hash;
++        struct list_head *p;
++
++	BT_DBG("hdev %s", hdev->name);
++
++	p = h->list.next;
++	while (p != &h->list) {
++		struct hci_conn *c;
++
++		c = list_entry(p, struct hci_conn, list);
++		p = p->next;
++
++		c->state = BT_CLOSED;
++
++		hci_proto_disconn_ind(c, 0x16);
++		hci_conn_del(c);
++	}
++}
++
++int hci_get_conn_list(unsigned long arg)
++{
++	struct hci_conn_list_req req, *cl;
++	struct hci_conn_info *ci;
++	struct hci_dev *hdev;
++	struct list_head *p;
++	int n = 0, size;
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	if (!(hdev = hci_dev_get(req.dev_id)))
++		return -ENODEV;
++
++	size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
++
++	if (verify_area(VERIFY_WRITE, (void *)arg, size))
++		return -EFAULT;
++
++	if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
++		return -ENOMEM;
++	ci = cl->conn_info;
++
++	hci_dev_lock_bh(hdev);
++	list_for_each(p, &hdev->conn_hash.list) {
++		register struct hci_conn *c;
++		c = list_entry(p, struct hci_conn, list);
++
++		bacpy(&(ci + n)->bdaddr, &c->dst);
++		(ci + n)->handle = c->handle;
++		(ci + n)->type  = c->type;
++		(ci + n)->out   = c->out;
++		(ci + n)->state = c->state;
++		(ci + n)->link_mode = c->link_mode;
++		n++;
++	}
++	hci_dev_unlock_bh(hdev);
++
++	cl->dev_id = hdev->id;
++	cl->conn_num = n;
++	size = n * sizeof(struct hci_conn_info) + sizeof(req);
++
++	hci_dev_put(hdev);
++
++	copy_to_user((void *) arg, cl, size);
++	kfree(cl);
++
++	return 0;
++}
++
++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
++{
++	struct hci_conn_info_req req;
++	struct hci_conn_info ci;
++	struct hci_conn *conn;
++	char *ptr = (void *) arg + sizeof(req);
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
++		return -EFAULT;
++
++	hci_dev_lock_bh(hdev);
++	conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
++	if (conn) {
++		bacpy(&ci.bdaddr, &conn->dst);
++		ci.handle = conn->handle;
++		ci.type  = conn->type;
++		ci.out   = conn->out;
++		ci.state = conn->state;
++		ci.link_mode = conn->link_mode;
++	}
++	hci_dev_unlock_bh(hdev);
++
++	if (!conn)
++		return -ENOENT;
++
++	copy_to_user(ptr, &ci, sizeof(ci));
++	return 0;
++}
+--- linux/net/bluetooth/hci_core.c~bluetooth-2.4.18-mh11	2001-11-09 23:21:21.000000000 +0100
++++ linux/net/bluetooth/hci_core.c	2004-01-25 23:37:39.000000000 +0100
+@@ -25,11 +25,12 @@
+ /*
+  * BlueZ HCI Core.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
++#include <linux/kmod.h>
+ 
+ #include <linux/types.h>
+ #include <linux/errno.h>
+@@ -50,12 +51,11 @@
+ #include <asm/unaligned.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+ 
+ #ifndef HCI_CORE_DEBUG
+-#undef  DBG
+-#define DBG( A... )
++#undef  BT_DBG
++#define BT_DBG( A... )
+ #endif
+ 
+ static void hci_cmd_task(unsigned long arg);
+@@ -63,279 +63,69 @@
+ static void hci_tx_task(unsigned long arg);
+ static void hci_notify(struct hci_dev *hdev, int event);
+ 
+-static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
++rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
+ 
+ /* HCI device list */
+-struct hci_dev *hdev_list[HCI_MAX_DEV];
+-spinlock_t hdev_list_lock;
+-#define GET_HDEV(a) (hdev_list[a])
++LIST_HEAD(hdev_list);
++rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
+ 
+-/* HCI protocol list */
+-struct hci_proto *hproto_list[HCI_MAX_PROTO];
+-#define GET_HPROTO(a) (hproto_list[a])
++/* HCI protocols */
++#define HCI_MAX_PROTO	2
++struct hci_proto *hci_proto[HCI_MAX_PROTO];
+ 
+ /* HCI notifiers list */
+-struct notifier_block *hci_dev_notifier;
+-
+-/* HCI device notifications */
+-int hci_register_notifier(struct notifier_block *nb)
+-{
+-	int err, i;
+-	struct hci_dev *hdev;
+-
+-	if ((err = notifier_chain_register(&hci_dev_notifier, nb)))
+-		return err;
+-
+-	/* Notify about already registered devices */
+-	spin_lock(&hdev_list_lock);
+-	for (i = 0; i < HCI_MAX_DEV; i++) {
+-		if (!(hdev = GET_HDEV(i)))
+-			continue;
+-		if (hdev->flags & HCI_UP)
+-			(*nb->notifier_call)(nb, HCI_DEV_UP, hdev);
+-	}
+-	spin_unlock(&hdev_list_lock);
+-
+-	return 0;
+-}
+-
+-int hci_unregister_notifier(struct notifier_block *nb)
+-{
+-	return notifier_chain_unregister(&hci_dev_notifier, nb);
+-}
+-
+-static inline void hci_notify(struct hci_dev *hdev, int event)
+-{
+-	notifier_call_chain(&hci_dev_notifier, event, hdev);
+-}
+-
+-/* Get HCI device by index (device is locked on return)*/
+-struct hci_dev *hci_dev_get(int index)
+-{
+-	struct hci_dev *hdev;
+-	DBG("%d", index);
+-
+-	if (index < 0 || index >= HCI_MAX_DEV)
+-		return NULL;
+-
+-	spin_lock(&hdev_list_lock);
+-	if ((hdev = GET_HDEV(index)))
+-		hci_dev_hold(hdev);
+-	spin_unlock(&hdev_list_lock);
+-
+-	return hdev;
+-}
+-
+-/* Flush inquiry cache */
+-void inquiry_cache_flush(struct inquiry_cache *cache)
+-{
+-	struct inquiry_entry *next = cache->list, *e;
+-
+-	DBG("cache %p", cache);
+-
+-	cache->list = NULL;
+-	while ((e = next)) {
+-		next = e->next;
+-		kfree(e);
+-	}
+-}
+-
+-/* Lookup by bdaddr.
+- * Cache must be locked. */
+-static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr)
+-{
+-	struct inquiry_entry *e;
+-
+-	DBG("cache %p, %s", cache, batostr(bdaddr));
+-
+-	for (e = cache->list; e; e = e->next)
+-		if (!bacmp(&e->info.bdaddr, bdaddr))
+-			break;
+-
+-	return e;
+-}
+-
+-static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info)
+-{
+-	struct inquiry_entry *e;
+-
+-	DBG("cache %p, %s", cache, batostr(&info->bdaddr));
+-
+-	inquiry_cache_lock(cache);
+-
+-	if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) {
+-		/* Entry not in the cache. Add new one. */
+-		if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
+-			goto unlock;
+-		memset(e, 0, sizeof(struct inquiry_entry));
+-		e->next     = cache->list;
+-		cache->list = e;
+-	}
+-
+-	memcpy(&e->info, info, sizeof(inquiry_info));
+-	e->timestamp = jiffies;
+-	cache->timestamp = jiffies;
+-unlock:
+-	inquiry_cache_unlock(cache);
+-}
+-
+-static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf)
+-{
+-	inquiry_info *info = (inquiry_info *) buf;
+-	struct inquiry_entry *e;
+-	int copied = 0;
+-
+-	inquiry_cache_lock(cache);
+-
+-	for (e = cache->list; e && copied < num; e = e->next, copied++)
+-		memcpy(info++, &e->info, sizeof(inquiry_info));
++static struct notifier_block *hci_notifier;
+ 
+-	inquiry_cache_unlock(cache);
+ 
+-	DBG("cache %p, copied %d", cache, copied);
+-	return copied;
+-}
++/* ---- HCI notifications ---- */
+ 
+-/* --------- BaseBand connections --------- */
+-static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst)
++int hci_register_notifier(struct notifier_block *nb)
+ {
+-	struct hci_conn *conn;
+-
+-	DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst));
+-
+-	if ( conn_hash_lookup(&hdev->conn_hash, handle)) {
+-		ERR("%s handle 0x%x already exists", hdev->name, handle);
+-		return NULL;
+-	}
+-
+-	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
+-		return NULL;
+-	memset(conn, 0, sizeof(struct hci_conn));
+-
+-	bacpy(&conn->dst, dst);
+-	conn->handle = handle;
+-	conn->type   = type;
+-	conn->hdev   = hdev;
+-
+-	skb_queue_head_init(&conn->data_q);
+-
+-	hci_dev_hold(hdev);
+-	conn_hash_add(&hdev->conn_hash, handle, conn);
+-
+-	return conn;
++	return notifier_chain_register(&hci_notifier, nb);
+ }
+ 
+-static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn)
++int hci_unregister_notifier(struct notifier_block *nb)
+ {
+-	DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
+-
+-	conn_hash_del(&hdev->conn_hash, conn);
+-	hci_dev_put(hdev);
+-
+-	/* Unacked frames */
+-	hdev->acl_cnt += conn->sent;
+-
+-	skb_queue_purge(&conn->data_q);
+-
+-	kfree(conn);
+-	return 0;
++	return notifier_chain_unregister(&hci_notifier, nb);
+ }
+ 
+-/* Drop all connection on the device */
+-static void hci_conn_hash_flush(struct hci_dev *hdev)
++void hci_notify(struct hci_dev *hdev, int event)
+ {
+-	struct conn_hash *h = &hdev->conn_hash;
+-	struct hci_proto *hp;
+-        struct list_head *p;
+-
+-	DBG("hdev %s", hdev->name);
+-
+-	p = h->list.next;
+-	while (p != &h->list) {
+-		struct hci_conn *c;
+-
+-		c = list_entry(p, struct hci_conn, list);
+-		p = p->next;
+-
+-		if (c->type == ACL_LINK) {
+-			/* ACL link notify L2CAP layer */
+-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
+-				hp->disconn_ind(c, 0x16);
+-		} else {
+-			/* SCO link (no notification) */
+-		}
+-
+-		hci_conn_del(hdev, c);
+-	}
++	notifier_call_chain(&hci_notifier, event, hdev);
+ }
+ 
+-int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr)
+-{
+-	struct inquiry_cache *cache = &hdev->inq_cache;
+-	struct inquiry_entry *e;
+-	create_conn_cp cc;
+-	__u16 clock_offset;
+-
+-	DBG("%s bdaddr %s", hdev->name, batostr(bdaddr));
+-
+-	if (!(hdev->flags & HCI_UP))
+-		return -ENODEV;
+-
+-	inquiry_cache_lock_bh(cache);
+-
+-	if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) {
+-		cc.pscan_rep_mode = 0;
+-		cc.pscan_mode     = 0;
+-		clock_offset      = 0;
+-	} else {
+-		cc.pscan_rep_mode = e->info.pscan_rep_mode;
+-		cc.pscan_mode     = e->info.pscan_mode;
+-		clock_offset      = __le16_to_cpu(e->info.clock_offset) & 0x8000;
+-	}
+-
+-	inquiry_cache_unlock_bh(cache);
+-
+-	bacpy(&cc.bdaddr, bdaddr);
+-	cc.pkt_type	= __cpu_to_le16(hdev->pkt_type);
+-	cc.clock_offset	= __cpu_to_le16(clock_offset);
+-
+-	if (lmp_rswitch_capable(hdev))
+-		cc.role_switch	= 0x01;
+-	else
+-		cc.role_switch	= 0x00;
+-		
+-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc);
++/* ---- HCI hotplug support ---- */
+ 
+-	return 0;
+-}
++#ifdef CONFIG_HOTPLUG
+ 
+-int hci_disconnect(struct hci_conn *conn, __u8 reason)
++static int hci_run_hotplug(char *dev, char *action)
+ {
+-	disconnect_cp dc;
+-
+-	DBG("conn %p handle %d", conn, conn->handle);
++	char *argv[3], *envp[5], dstr[20], astr[32];
+ 
+-	dc.handle = __cpu_to_le16(conn->handle);
+-	dc.reason = reason;
+-	hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc);
++	sprintf(dstr, "DEVICE=%s", dev);
++	sprintf(astr, "ACTION=%s", action);
+ 
+-	return 0;
+-}
++        argv[0] = hotplug_path;
++        argv[1] = "bluetooth";
++        argv[2] = NULL;
+ 
+-/* --------- HCI request handling ------------ */
+-static inline void hci_req_lock(struct hci_dev *hdev)
+-{
+-	down(&hdev->req_lock);
++	envp[0] = "HOME=/";
++	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++	envp[2] = dstr;
++	envp[3] = astr;
++	envp[4] = NULL;
++	
++	return call_usermodehelper(argv[0], argv, envp);
+ }
++#else
++#define hci_run_hotplug(A...)
++#endif
+ 
+-static inline void hci_req_unlock(struct hci_dev *hdev)
+-{
+-	up(&hdev->req_lock);
+-}
++/* ---- HCI requests ---- */
+ 
+-static inline void hci_req_complete(struct hci_dev *hdev, int result)
++void hci_req_complete(struct hci_dev *hdev, int result)
+ {
+-	DBG("%s result 0x%2.2x", hdev->name, result);
++	BT_DBG("%s result 0x%2.2x", hdev->name, result);
+ 
+ 	if (hdev->req_status == HCI_REQ_PEND) {
+ 		hdev->req_result = result;
+@@ -344,9 +134,9 @@
+ 	}
+ }
+ 
+-static inline void hci_req_cancel(struct hci_dev *hdev, int err)
++void hci_req_cancel(struct hci_dev *hdev, int err)
+ {
+-	DBG("%s err 0x%2.2x", hdev->name, err);
++	BT_DBG("%s err 0x%2.2x", hdev->name, err);
+ 
+ 	if (hdev->req_status == HCI_REQ_PEND) {
+ 		hdev->req_result = err;
+@@ -356,23 +146,22 @@
+ }
+ 
+ /* Execute request and wait for completion. */
+-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
+-                         unsigned long opt, __u32 timeout)
++static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout)
+ {
+ 	DECLARE_WAITQUEUE(wait, current);
+ 	int err = 0;
+ 
+-	DBG("%s start", hdev->name);
++	BT_DBG("%s start", hdev->name);
+ 
+ 	hdev->req_status = HCI_REQ_PEND;
+ 
+ 	add_wait_queue(&hdev->req_wait_q, &wait);
+-	current->state = TASK_INTERRUPTIBLE;
++	set_current_state(TASK_INTERRUPTIBLE);
+ 
+ 	req(hdev, opt);
+ 	schedule_timeout(timeout);
+ 
+-	current->state = TASK_RUNNING;
++	set_current_state(TASK_RUNNING);
+ 	remove_wait_queue(&hdev->req_wait_q, &wait);
+ 
+ 	if (signal_pending(current))
+@@ -394,7 +183,7 @@
+ 
+ 	hdev->req_status = hdev->req_result = 0;
+ 
+-	DBG("%s end: err %d", hdev->name, err);
++	BT_DBG("%s end: err %d", hdev->name, err);
+ 
+ 	return err;
+ }
+@@ -412,10 +201,9 @@
+ 	return ret;
+ }
+ 
+-/* --------- HCI requests ---------- */
+ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
+ {
+-	DBG("%s %ld", hdev->name, opt);
++	BT_DBG("%s %ld", hdev->name, opt);
+ 
+ 	/* Reset device */
+ 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+@@ -423,10 +211,10 @@
+ 
+ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
+ {
+-	set_event_flt_cp ec;
++	set_event_flt_cp ef;
+ 	__u16 param;
+ 
+-	DBG("%s %ld", hdev->name, opt);
++	BT_DBG("%s %ld", hdev->name, opt);
+ 
+ 	/* Mandatory initialization */
+ 
+@@ -436,14 +224,27 @@
+ 	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
+ 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
+ 
++#if 0
++	/* Host buffer size */
++	{
++		host_buffer_size_cp bs;
++		bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
++		bs.sco_mtu = HCI_MAX_SCO_SIZE;
++		bs.acl_max_pkt = __cpu_to_le16(0xffff);
++		bs.sco_max_pkt = __cpu_to_le16(0xffff);
++		hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE,
++				HOST_BUFFER_SIZE_CP_SIZE, &bs);
++	}
++#endif
++
+ 	/* Read BD Address */
+ 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
+ 
+ 	/* Optional initialization */
+ 
+ 	/* Clear Event Filters */
+-	ec.flt_type  = FLT_CLEAR_ALL;
+-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec);
++	ef.flt_type  = FLT_CLEAR_ALL;
++	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef);
+ 
+ 	/* Page timeout ~20 secs */
+ 	param = __cpu_to_le16(0x8000);
+@@ -458,7 +259,7 @@
+ {
+ 	__u8 scan = opt;
+ 
+-	DBG("%s %x", hdev->name, scan);
++	BT_DBG("%s %x", hdev->name, scan);
+ 
+ 	/* Inquiry and Page scans */
+ 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
+@@ -468,27 +269,190 @@
+ {
+ 	__u8 auth = opt;
+ 
+-	DBG("%s %x", hdev->name, auth);
++	BT_DBG("%s %x", hdev->name, auth);
+ 
+ 	/* Authentication */
+ 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
+ }
+ 
++static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
++{
++	__u8 encrypt = opt;
++
++	BT_DBG("%s %x", hdev->name, encrypt);
++
++	/* Authentication */
++	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
++}
++
++/* Get HCI device by index. 
++ * Device is locked on return. */
++struct hci_dev *hci_dev_get(int index)
++{
++	struct hci_dev *hdev;
++	struct list_head *p;
++
++	BT_DBG("%d", index);
++
++	if (index < 0)
++		return NULL;
++
++	read_lock(&hdev_list_lock);
++	list_for_each(p, &hdev_list) {
++		hdev = list_entry(p, struct hci_dev, list);
++		if (hdev->id == index) {
++			hci_dev_hold(hdev);
++			goto done;
++		}
++	}
++	hdev = NULL;
++done:
++	read_unlock(&hdev_list_lock);
++	return hdev;
++}
++
++/* ---- Inquiry support ---- */
++void inquiry_cache_flush(struct hci_dev *hdev)
++{
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	struct inquiry_entry *next  = cache->list, *e;
++
++	BT_DBG("cache %p", cache);
++
++	cache->list = NULL;
++	while ((e = next)) {
++		next = e->next;
++		kfree(e);
++	}
++}
++
++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
++{
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	struct inquiry_entry *e;
++
++	BT_DBG("cache %p, %s", cache, batostr(bdaddr));
++
++	for (e = cache->list; e; e = e->next)
++		if (!bacmp(&e->info.bdaddr, bdaddr))
++			break;
++	return e;
++}
++
++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info)
++{
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	struct inquiry_entry *e;
++
++	BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr));
++
++	if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) {
++		/* Entry not in the cache. Add new one. */
++		if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
++			return;
++		memset(e, 0, sizeof(struct inquiry_entry));
++		e->next     = cache->list;
++		cache->list = e;
++	}
++
++	memcpy(&e->info, info, sizeof(inquiry_info));
++	e->timestamp = jiffies;
++	cache->timestamp = jiffies;
++}
++
++int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
++{
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	inquiry_info *info = (inquiry_info *) buf;
++	struct inquiry_entry *e;
++	int copied = 0;
++
++	for (e = cache->list; e && copied < num; e = e->next, copied++)
++		memcpy(info++, &e->info, sizeof(inquiry_info));
++
++	BT_DBG("cache %p, copied %d", cache, copied);
++	return copied;
++}
++
+ static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
+ {
+ 	struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
+ 	inquiry_cp ic;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", hdev->name);
++
++	if (test_bit(HCI_INQUIRY, &hdev->flags))
++		return;
+ 
+ 	/* Start Inquiry */
+ 	memcpy(&ic.lap, &ir->lap, 3);
+-	ic.lenght  = ir->length;
++	ic.length  = ir->length;
+ 	ic.num_rsp = ir->num_rsp;
+ 	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
+ }
+ 
+-/* HCI ioctl helpers */
++int hci_inquiry(unsigned long arg)
++{
++	struct hci_inquiry_req ir;
++	struct hci_dev *hdev;
++	int err = 0, do_inquiry = 0, max_rsp;
++	long timeo;
++	__u8 *buf, *ptr;
++
++	ptr = (void *) arg;
++	if (copy_from_user(&ir, ptr, sizeof(ir)))
++		return -EFAULT;
++
++	if (!(hdev = hci_dev_get(ir.dev_id)))
++		return -ENODEV;
++
++	hci_dev_lock_bh(hdev);
++	if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || 
++					inquiry_cache_empty(hdev) ||
++					ir.flags & IREQ_CACHE_FLUSH) {
++		inquiry_cache_flush(hdev);
++		do_inquiry = 1;
++	}
++	hci_dev_unlock_bh(hdev);
++
++	timeo = ir.length * 2 * HZ;
++	if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
++		goto done;
++
++	/* for unlimited number of responses we will use buffer with 255 entries */
++	max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
++
++	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
++	 * copy it to the user space.
++	 */
++	if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) {
++		err = -ENOMEM;
++		goto done;
++	}
++
++	hci_dev_lock_bh(hdev);
++	ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
++	hci_dev_unlock_bh(hdev);
++
++	BT_DBG("num_rsp %d", ir.num_rsp);
++
++	if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + 
++				(sizeof(inquiry_info) * ir.num_rsp))) {
++		copy_to_user(ptr, &ir, sizeof(ir));
++		ptr += sizeof(ir);
++	        copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
++	} else 
++		err = -EFAULT;
++
++	kfree(buf);
++
++done:
++	hci_dev_put(hdev);
++	return err;
++}
++
++/* ---- HCI ioctl helpers ---- */
++
+ int hci_dev_open(__u16 dev)
+ {
+ 	struct hci_dev *hdev;
+@@ -497,11 +461,11 @@
+ 	if (!(hdev = hci_dev_get(dev)))
+ 		return -ENODEV;
+ 
+-	DBG("%s %p", hdev->name, hdev);
++	BT_DBG("%s %p", hdev->name, hdev);
+ 
+ 	hci_req_lock(hdev);
+ 
+-	if (hdev->flags & HCI_UP) {
++	if (test_bit(HCI_UP, &hdev->flags)) {
+ 		ret = -EALREADY;
+ 		goto done;
+ 	}
+@@ -511,18 +475,18 @@
+ 		goto done;
+ 	}
+ 
+-	if (hdev->flags & HCI_NORMAL) {
++	if (!test_bit(HCI_RAW, &hdev->flags)) {
+ 		atomic_set(&hdev->cmd_cnt, 1);
+-		hdev->flags |= HCI_INIT;
++		set_bit(HCI_INIT, &hdev->flags);
+ 
+ 		//__hci_request(hdev, hci_reset_req, 0, HZ);
+ 		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
+        
+-		hdev->flags &= ~HCI_INIT;
++		clear_bit(HCI_INIT, &hdev->flags);
+ 	}
+ 
+ 	if (!ret) {
+-		hdev->flags |= HCI_UP;
++		set_bit(HCI_UP, &hdev->flags);
+ 		hci_notify(hdev, HCI_DEV_UP);
+ 	} else {	
+ 		/* Init failed, cleanup */
+@@ -542,42 +506,36 @@
+ 		}
+ 
+ 		hdev->close(hdev);
++		hdev->flags = 0;
+ 	}
+ 
+ done:
+ 	hci_req_unlock(hdev);
+ 	hci_dev_put(hdev);
+-
+ 	return ret;
+ }
+ 
+-int hci_dev_close(__u16 dev)
++static int hci_dev_do_close(struct hci_dev *hdev)
+ {
+-	struct hci_dev *hdev;
+-
+-	if (!(hdev = hci_dev_get(dev)))
+-		return -ENODEV;
+-
+-	DBG("%s %p", hdev->name, hdev);
++	BT_DBG("%s %p", hdev->name, hdev);
+ 
+ 	hci_req_cancel(hdev, ENODEV);
+ 	hci_req_lock(hdev);
+ 
+-	if (!(hdev->flags & HCI_UP))
+-		goto done;
++	if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
++		hci_req_unlock(hdev);
++		return 0;
++	}
+ 
+ 	/* Kill RX and TX tasks */
+ 	tasklet_kill(&hdev->rx_task);
+ 	tasklet_kill(&hdev->tx_task);
+ 
+-	inquiry_cache_flush(&hdev->inq_cache);
+-
++	hci_dev_lock_bh(hdev);
++	inquiry_cache_flush(hdev);
+ 	hci_conn_hash_flush(hdev);
+-
+-	/* Clear flags */
+-	hdev->flags &= HCI_SOCK;
+-	hdev->flags |= HCI_NORMAL;
+-
++	hci_dev_unlock_bh(hdev);
++	
+ 	hci_notify(hdev, HCI_DEV_DOWN);
+ 
+ 	if (hdev->flush)
+@@ -586,9 +544,9 @@
+ 	/* Reset device */
+ 	skb_queue_purge(&hdev->cmd_q);
+ 	atomic_set(&hdev->cmd_cnt, 1);
+-	hdev->flags |= HCI_INIT;
+-	__hci_request(hdev, hci_reset_req, 0, HZ);
+-	hdev->flags &= ~HCI_INIT;
++	set_bit(HCI_INIT, &hdev->flags);
++	__hci_request(hdev, hci_reset_req, 0, HZ/4);
++	clear_bit(HCI_INIT, &hdev->flags);
+ 
+ 	/* Kill cmd task */
+ 	tasklet_kill(&hdev->cmd_task);
+@@ -605,17 +563,28 @@
+ 	}
+ 
+ 	/* After this point our queues are empty
+-	 * and no tasks are scheduled.
+-	 */
++	 * and no tasks are scheduled. */
+ 	hdev->close(hdev);
+ 
+-done:
+-	hci_req_unlock(hdev);
+-	hci_dev_put(hdev);
++	/* Clear flags */
++	hdev->flags = 0;
+ 
++	hci_req_unlock(hdev);
+ 	return 0;
+ }
+ 
++int hci_dev_close(__u16 dev)
++{
++	struct hci_dev *hdev;
++	int err;
++	
++	if (!(hdev = hci_dev_get(dev)))
++		return -ENODEV;
++	err = hci_dev_do_close(hdev);
++	hci_dev_put(hdev);
++	return err;
++}
++
+ int hci_dev_reset(__u16 dev)
+ {
+ 	struct hci_dev *hdev;
+@@ -627,16 +596,17 @@
+ 	hci_req_lock(hdev);
+ 	tasklet_disable(&hdev->tx_task);
+ 
+-	if (!(hdev->flags & HCI_UP))
++	if (!test_bit(HCI_UP, &hdev->flags))
+ 		goto done;
+ 
+ 	/* Drop queues */
+ 	skb_queue_purge(&hdev->rx_q);
+ 	skb_queue_purge(&hdev->cmd_q);
+ 
+-	inquiry_cache_flush(&hdev->inq_cache);
+-
++	hci_dev_lock_bh(hdev);
++	inquiry_cache_flush(hdev);
+ 	hci_conn_hash_flush(hdev);
++	hci_dev_unlock_bh(hdev);
+ 
+ 	if (hdev->flush)
+ 		hdev->flush(hdev);
+@@ -650,7 +620,6 @@
+ 	tasklet_enable(&hdev->tx_task);
+ 	hci_req_unlock(hdev);
+ 	hci_dev_put(hdev);
+-
+ 	return ret;
+ }
+ 
+@@ -669,30 +638,11 @@
+ 	return ret;
+ }
+ 
+-int hci_dev_setauth(unsigned long arg)
+-{
+-	struct hci_dev *hdev;
+-	struct hci_dev_req dr;
+-	int ret = 0;
+-
+-	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+-		return -EFAULT;
+-
+-	if (!(hdev = hci_dev_get(dr.dev_id)))
+-		return -ENODEV;
+-
+-	ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+-
+-	hci_dev_put(hdev);
+-
+-	return ret;
+-}
+-
+-int hci_dev_setscan(unsigned long arg)
++int hci_dev_cmd(unsigned int cmd, unsigned long arg)
+ {
+ 	struct hci_dev *hdev;
+ 	struct hci_dev_req dr;
+-	int ret = 0;
++	int err = 0;
+ 
+ 	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+ 		return -EFAULT;
+@@ -700,48 +650,78 @@
+ 	if (!(hdev = hci_dev_get(dr.dev_id)))
+ 		return -ENODEV;
+ 
+-	ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+-
+-	hci_dev_put(hdev);
++	switch (cmd) {
++	case HCISETAUTH:
++		err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
++		break;
+ 
+-	return ret;
+-}
++	case HCISETENCRYPT:
++		if (!lmp_encrypt_capable(hdev)) {
++			err = -EOPNOTSUPP;
++			break;
++		}
+ 
+-int hci_dev_setptype(unsigned long arg)
+-{
+-	struct hci_dev *hdev;
+-	struct hci_dev_req dr;
+-	int ret = 0;
++		if (!test_bit(HCI_AUTH, &hdev->flags)) {
++			/* Auth must be enabled first */
++			err = hci_request(hdev, hci_auth_req,
++					dr.dev_opt, HCI_INIT_TIMEOUT);
++			if (err)
++				break;
++		}
++			
++		err = hci_request(hdev, hci_encrypt_req,
++					dr.dev_opt, HCI_INIT_TIMEOUT);
++		break;
++	
++	case HCISETSCAN:
++		err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
++		break;
++	
++	case HCISETPTYPE:
++		hdev->pkt_type = (__u16) dr.dev_opt;
++		break;
++		
++	case HCISETLINKPOL:
++		hdev->link_policy = (__u16) dr.dev_opt;
++		break;
+ 
+-	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+-		return -EFAULT;
++	case HCISETLINKMODE:
++		hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
++		break;
+ 
+-	if (!(hdev = hci_dev_get(dr.dev_id)))
+-		return -ENODEV;
++	case HCISETACLMTU:
++		hdev->acl_mtu  = *((__u16 *)&dr.dev_opt + 1);
++		hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
++		break;
+ 
+-	hdev->pkt_type = (__u16) dr.dev_opt;
++	case HCISETSCOMTU:
++		hdev->sco_mtu  = *((__u16 *)&dr.dev_opt + 1);
++		hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
++		break;
+ 
++	default:
++		err = -EINVAL;
++		break;
++	}	
+ 	hci_dev_put(hdev);
+-
+-	return ret;
++	return err;
+ }
+ 
+-int hci_dev_list(unsigned long arg)
++int hci_get_dev_list(unsigned long arg)
+ {
+ 	struct hci_dev_list_req *dl;
+ 	struct hci_dev_req *dr;
+-	struct hci_dev *hdev;
+-	int i, n, size;
++	struct list_head *p;
++	int n = 0, size;
+ 	__u16 dev_num;
+ 
+ 	if (get_user(dev_num, (__u16 *) arg))
+ 		return -EFAULT;
+ 
+-	/* Avoid long loop, overflow */
+-	if (dev_num > 2048)
++	if (!dev_num)
+ 		return -EINVAL;
+ 	
+-	size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
++	size = dev_num * sizeof(*dr) + sizeof(*dl);
+ 
+ 	if (verify_area(VERIFY_WRITE, (void *) arg, size))
+ 		return -EFAULT;
+@@ -750,25 +730,27 @@
+ 		return -ENOMEM;
+ 	dr = dl->dev_req;
+ 
+-	spin_lock_bh(&hdev_list_lock);
+-	for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) {
+-		if ((hdev = hdev_list[i])) {
+-			(dr + n)->dev_id  = hdev->id;
+-			(dr + n)->dev_opt = hdev->flags;
+-			n++;
+-		}
++	read_lock_bh(&hdev_list_lock);
++	list_for_each(p, &hdev_list) {
++		struct hci_dev *hdev;
++		hdev = list_entry(p, struct hci_dev, list);
++		(dr + n)->dev_id  = hdev->id;
++		(dr + n)->dev_opt = hdev->flags;
++		if (++n >= dev_num)
++			break;
+ 	}
+-	spin_unlock_bh(&hdev_list_lock);
++	read_unlock_bh(&hdev_list_lock);
+ 
+ 	dl->dev_num = n;
+-	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
++	size = n * sizeof(*dr) + sizeof(*dl);
+ 
+ 	copy_to_user((void *) arg, dl, size);
++	kfree(dl);
+ 
+ 	return 0;
+ }
+ 
+-int hci_dev_info(unsigned long arg)
++int hci_get_dev_info(unsigned long arg)
+ {
+ 	struct hci_dev *hdev;
+ 	struct hci_dev_info di;
+@@ -786,9 +768,11 @@
+ 	di.flags    = hdev->flags;
+ 	di.pkt_type = hdev->pkt_type;
+ 	di.acl_mtu  = hdev->acl_mtu;
+-	di.acl_max  = hdev->acl_max;
++	di.acl_pkts = hdev->acl_pkts;
+ 	di.sco_mtu  = hdev->sco_mtu;
+-	di.sco_max  = hdev->sco_max;
++	di.sco_pkts = hdev->sco_pkts;
++	di.link_policy = hdev->link_policy;
++	di.link_mode   = hdev->link_mode;
+ 
+ 	memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
+ 	memcpy(&di.features, &hdev->features, sizeof(di.features));
+@@ -801,258 +785,168 @@
+ 	return err;
+ }
+ 
+-__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode)
+-{
+-	__u32 omode = hdev->flags & HCI_MODE_MASK;
+-
+-	hdev->flags &= ~HCI_MODE_MASK;
+-	hdev->flags |= (mode & HCI_MODE_MASK);
+ 
+-	return omode;
+-}
+-
+-__u32 hci_dev_getmode(struct hci_dev *hdev)
+-{
+-	return hdev->flags & HCI_MODE_MASK;
+-}
++/* ---- Interface to HCI drivers ---- */
+ 
+-int hci_conn_list(unsigned long arg)
++/* Register HCI device */
++int hci_register_dev(struct hci_dev *hdev)
+ {
+-	struct hci_conn_list_req req, *cl;
+-	struct hci_conn_info *ci;
+-	struct hci_dev *hdev;
+-	struct list_head *p;
+-	int n = 0, size;
+-
+-	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+-		return -EFAULT;
++	struct list_head *head = &hdev_list, *p;
++	int id = 0;
+ 
+-	if (!(hdev = hci_dev_get(req.dev_id)))
+-		return -ENODEV;
++	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+ 
+-	/* Set a limit to avoid overlong loops, and also numeric overflow - AC */
+-	if(req.conn_num < 2048)
++	if (!hdev->open || !hdev->close || !hdev->destruct)
+ 		return -EINVAL;
+-	
+-	size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
+ 
+-	if (!(cl = kmalloc(size, GFP_KERNEL)))
+-		return -ENOMEM;
+-	ci = cl->conn_info;
+-
+-	local_bh_disable();
+-	conn_hash_lock(&hdev->conn_hash);
+-	list_for_each(p, &hdev->conn_hash.list) {
+-		register struct hci_conn *c;
+-		c = list_entry(p, struct hci_conn, list);
++	write_lock_bh(&hdev_list_lock);
+ 
+-		(ci + n)->handle = c->handle;
+-		bacpy(&(ci + n)->bdaddr, &c->dst);
+-		n++;
++	/* Find first available device id */
++	list_for_each(p, &hdev_list) {
++	       	if (list_entry(p, struct hci_dev, list)->id != id)
++			break;
++		head = p; id++;
+ 	}
+-	conn_hash_unlock(&hdev->conn_hash);
+-	local_bh_enable();
+-
+-	cl->dev_id = hdev->id;
+-	cl->conn_num = n;
+-	size = n * sizeof(struct hci_conn_info) + sizeof(req);
+-
+-	hci_dev_put(hdev);
+-
+-	if(copy_to_user((void *) arg, cl, size))
+-		return -EFAULT;
+-	return 0;
+-}
+-
+-int hci_inquiry(unsigned long arg)
+-{
+-	struct inquiry_cache *cache;
+-	struct hci_inquiry_req ir;
+-	struct hci_dev *hdev;
+-	int err = 0, do_inquiry = 0;
+-	long timeo;
+-	__u8 *buf, *ptr;
+-
+-	ptr = (void *) arg;
+-	if (copy_from_user(&ir, ptr, sizeof(ir)))
+-		return -EFAULT;
++	
++	sprintf(hdev->name, "hci%d", id);
++	hdev->id = id;
++	list_add(&hdev->list, head);
+ 
+-	if (!(hdev = hci_dev_get(ir.dev_id)))
+-		return -ENODEV;
++	atomic_set(&hdev->refcnt, 1);
++	spin_lock_init(&hdev->lock);
++			
++	hdev->flags = 0;
++	hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
++	hdev->link_mode = (HCI_LM_ACCEPT);
+ 
+-	cache = &hdev->inq_cache;
++	tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
++	tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
++	tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
+ 
+-	inquiry_cache_lock(cache);
+-	if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) {
+-		inquiry_cache_flush(cache);
+-		do_inquiry = 1;
+-	}
+-	inquiry_cache_unlock(cache);
++	skb_queue_head_init(&hdev->rx_q);
++	skb_queue_head_init(&hdev->cmd_q);
++	skb_queue_head_init(&hdev->raw_q);
+ 
+-	/* Limit inquiry time, also avoid overflows */
++	init_waitqueue_head(&hdev->req_wait_q);
++	init_MUTEX(&hdev->req_lock);
+ 
+-	if(ir.length > 2048 || ir.num_rsp > 2048)
+-	{
+-		err = -EINVAL;
+-		goto done;
+-	}
++	inquiry_cache_init(hdev);
+ 
+-	timeo = ir.length * 2 * HZ;
+-	if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
+-		goto done;
++	conn_hash_init(hdev);
+ 
+-	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
+-	 * copy it to the user space.
+-	 */
+-	if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
+-		err = -ENOMEM;
+-		goto done;
+-	}
+-	ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf);
++	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
+ 
+-	DBG("num_rsp %d", ir.num_rsp);
++	atomic_set(&hdev->promisc, 0);
+ 
+-	if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) {
+-		copy_to_user(ptr, &ir, sizeof(ir));
+-		ptr += sizeof(ir);
+-	        copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
+-	} else 
+-		err = -EFAULT;
++	MOD_INC_USE_COUNT;
+ 
+-	kfree(buf);
++	write_unlock_bh(&hdev_list_lock);
+ 
+-done:
+-	hci_dev_put(hdev);
++	hci_notify(hdev, HCI_DEV_REG);
++	hci_run_hotplug(hdev->name, "register");
+ 
+-	return err;
++	return id;
+ }
+ 
+-/* Interface to HCI drivers */
+-
+-/* Register HCI device */
+-int hci_register_dev(struct hci_dev *hdev)
++/* Unregister HCI device */
++int hci_unregister_dev(struct hci_dev *hdev)
+ {
+-	int i;
+-
+-	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+-
+-	/* Find free slot */
+-	spin_lock_bh(&hdev_list_lock);
+-	for (i = 0; i < HCI_MAX_DEV; i++) {
+-		if (!hdev_list[i]) {
+-			hdev_list[i] = hdev;
+-
+-			sprintf(hdev->name, "hci%d", i);
+-			atomic_set(&hdev->refcnt, 0);
+-			hdev->id    = i;
+-			hdev->flags = HCI_NORMAL;
+-
+-			hdev->pkt_type = (HCI_DM1 | HCI_DH1);
+-
+-			tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
+-			tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
+-			tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
+-
+-			skb_queue_head_init(&hdev->rx_q);
+-			skb_queue_head_init(&hdev->cmd_q);
+-			skb_queue_head_init(&hdev->raw_q);
+-
+-			init_waitqueue_head(&hdev->req_wait_q);
+-			init_MUTEX(&hdev->req_lock);
+-
+-			inquiry_cache_init(&hdev->inq_cache);
++	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+ 
+-			conn_hash_init(&hdev->conn_hash);
++	write_lock_bh(&hdev_list_lock);
++	list_del(&hdev->list);
++	write_unlock_bh(&hdev_list_lock);
+ 
+-			memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
++	hci_dev_do_close(hdev);
+ 
+-			hci_notify(hdev, HCI_DEV_REG);
++	hci_notify(hdev, HCI_DEV_UNREG);
++	hci_run_hotplug(hdev->name, "unregister");
+ 
+-			MOD_INC_USE_COUNT;
+-			break;
+-		}
+-	}
+-	spin_unlock_bh(&hdev_list_lock);
++	hci_dev_put(hdev);
+ 
+-	return (i == HCI_MAX_DEV) ? -1 : i;
++	MOD_DEC_USE_COUNT;
++	return 0;
+ }
+ 
+-/* Unregister HCI device */
+-int hci_unregister_dev(struct hci_dev *hdev)
++/* Suspend HCI device */
++int hci_suspend_dev(struct hci_dev *hdev)
+ {
+-	int i;
++	hci_notify(hdev, HCI_DEV_SUSPEND);
++	hci_run_hotplug(hdev->name, "suspend");
++	return 0;
++}
+ 
+-	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
++/* Resume HCI device */
++int hci_resume_dev(struct hci_dev *hdev)
++{
++	hci_notify(hdev, HCI_DEV_RESUME);
++	hci_run_hotplug(hdev->name, "resume");
++	return 0;
++}       
+ 
+-	if (hdev->flags & HCI_UP)
+-		hci_dev_close(hdev->id);
++/* Receive frame from HCI drivers */
++int hci_recv_frame(struct sk_buff *skb)
++{
++	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ 
+-	/* Find device slot */
+-	spin_lock(&hdev_list_lock);
+-	for (i = 0; i < HCI_MAX_DEV; i++) {
+-		if (hdev_list[i] == hdev) {
+-			hdev_list[i] = NULL;
+-			MOD_DEC_USE_COUNT;
+-			break;
+-		}
++	if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && 
++				!test_bit(HCI_INIT, &hdev->flags)) ) {
++		kfree_skb(skb);
++		return -1;
+ 	}
+-	spin_unlock(&hdev_list_lock);
+ 
+-	hci_notify(hdev, HCI_DEV_UNREG);
+-
+-	/* Sleep while device is in use */
+-	while (atomic_read(&hdev->refcnt)) {
+-		int sleep_cnt = 100;
++	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+ 
+-		DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt));
++	/* Incomming skb */
++	bluez_cb(skb)->incomming = 1;
+ 
+-		sleep_on_timeout(&hdev->req_wait_q, HZ*10);
+-		if (!(--sleep_cnt))
+-			break;
+-	}
++	/* Time stamp */
++	do_gettimeofday(&skb->stamp);
+ 
++	/* Queue frame for rx task */
++	skb_queue_tail(&hdev->rx_q, skb);
++	hci_sched_rx(hdev);
+ 	return 0;
+ }
+ 
+-/* Interface to upper protocols */
++/* ---- Interface to upper protocols ---- */
+ 
+ /* Register/Unregister protocols.
+- * hci_task_lock is used to ensure that no tasks are running.
+- */
+-int hci_register_proto(struct hci_proto *hproto)
++ * hci_task_lock is used to ensure that no tasks are running. */
++int hci_register_proto(struct hci_proto *hp)
+ {
+ 	int err = 0;
+ 
+-	DBG("%p name %s", hproto, hproto->name);
++	BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
+ 
+-	if (hproto->id >= HCI_MAX_PROTO)
++	if (hp->id >= HCI_MAX_PROTO)
+ 		return -EINVAL;
+ 
+ 	write_lock_bh(&hci_task_lock);
+ 
+-	if (!hproto_list[hproto->id])
+-		hproto_list[hproto->id] = hproto;
++	if (!hci_proto[hp->id])
++		hci_proto[hp->id] = hp;
+ 	else
+-		err = -1;
++		err = -EEXIST;
+ 
+ 	write_unlock_bh(&hci_task_lock);
+ 
+ 	return err;
+ }
+ 
+-int hci_unregister_proto(struct hci_proto *hproto)
++int hci_unregister_proto(struct hci_proto *hp)
+ {
+ 	int err = 0;
+ 
+-	DBG("%p name %s", hproto, hproto->name);
++	BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
+ 
+-	if (hproto->id > HCI_MAX_PROTO)
++	if (hp->id >= HCI_MAX_PROTO)
+ 		return -EINVAL;
+ 
+ 	write_lock_bh(&hci_task_lock);
+ 
+-	if (hproto_list[hproto->id])
+-		hproto_list[hproto->id] = NULL;
++	if (hci_proto[hp->id])
++		hci_proto[hp->id] = NULL;
+ 	else
+ 		err = -ENOENT;
+ 
+@@ -1070,10 +964,14 @@
+ 		return -ENODEV;
+ 	}
+ 
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
++	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
++
++	if (atomic_read(&hdev->promisc)) {
++		/* Time stamp */
++	        do_gettimeofday(&skb->stamp);
+ 
+-	if (hdev->flags & HCI_SOCK)
+ 		hci_send_to_sock(hdev, skb);
++	}
+ 
+ 	/* Get rid of skb owner, prior to sending to the driver. */
+ 	skb_orphan(skb);
+@@ -1081,128 +979,6 @@
+ 	return hdev->send(skb);
+ }
+ 
+-/* Connection scheduler */
+-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+-{
+-	struct conn_hash *h = &hdev->conn_hash;
+-	struct hci_conn *conn = NULL;
+-	int num = 0, min = 0xffff;
+-        struct list_head *p;
+-
+-	conn_hash_lock(h);
+-	list_for_each(p, &h->list) {
+-		register struct hci_conn *c;
+-
+-		c = list_entry(p, struct hci_conn, list);
+-
+-		if (c->type != type || skb_queue_empty(&c->data_q))
+-			continue;
+-		num++;
+-
+-		if (c->sent < min) {
+-			min  = c->sent;
+-			conn = c;
+-		}
+-	}
+-	conn_hash_unlock(h);
+-
+-	if (conn) {
+-		int q = hdev->acl_cnt / num;
+-		*quote = q ? q : 1;
+-	} else
+-		*quote = 0;
+-
+-	DBG("conn %p quote %d", conn, *quote);
+-
+-	return conn;
+-}
+-
+-static inline void hci_sched_acl(struct hci_dev *hdev)
+-{
+-	struct hci_conn *conn;
+-	struct sk_buff *skb;
+-	int quote;
+-
+-	DBG("%s", hdev->name);
+-
+-	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
+-		while (quote && (skb = skb_dequeue(&conn->data_q))) {
+-			DBG("skb %p len %d", skb, skb->len);
+-
+-			hci_send_frame(skb);
+-
+-			conn->sent++;
+-			hdev->acl_cnt--;
+-			quote--;
+-		}
+-	}
+-}
+-
+-/* Schedule SCO */
+-static inline void hci_sched_sco(struct hci_dev *hdev)
+-{
+-	/* FIXME: For now we queue SCO packets to the raw queue 
+-
+-		while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) {
+-			hci_send_frame(skb);
+-			conn->sco_sent++;
+-			hdev->sco_cnt--;
+-		}
+-	*/
+-}
+-
+-/* Get data from the previously sent command */
+-static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
+-{
+-	hci_command_hdr *hc;
+-
+-	if (!hdev->sent_cmd)
+-		return NULL;
+-
+-	hc = (void *) hdev->sent_cmd->data;
+-
+-	if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
+-		return NULL;
+-
+-	DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
+-
+-	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
+-}
+-
+-/* Send raw HCI frame */
+-int hci_send_raw(struct sk_buff *skb)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+-
+-	if (!hdev) {
+-		kfree_skb(skb);
+-		return -ENODEV;
+-	}
+-
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+-
+-	if (hdev->flags & HCI_NORMAL) {
+-		/* Queue frame according it's type */
+-		switch (skb->pkt_type) {
+-		case HCI_COMMAND_PKT:
+-			skb_queue_tail(&hdev->cmd_q, skb);
+-			hci_sched_cmd(hdev);
+-			return 0;
+-
+-		case HCI_ACLDATA_PKT:
+-		case HCI_SCODATA_PKT:
+-			/* FIXME:
+-		 	 * Check header here and queue to apropriate connection.
+-		 	 */
+-			break;
+-		}
+-	}
+-
+-	skb_queue_tail(&hdev->raw_q, skb);
+-	hci_sched_tx(hdev);
+-	return 0;
+-}
+-
+ /* Send HCI command */
+ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
+ {
+@@ -1210,10 +986,10 @@
+ 	hci_command_hdr *hc;
+ 	struct sk_buff *skb;
+ 
+-	DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
++	BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
+ 
+ 	if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
+-		ERR("%s Can't allocate memory for HCI command", hdev->name);
++		BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
+ 		return -ENOMEM;
+ 	}
+ 	
+@@ -1224,7 +1000,7 @@
+ 	if (plen)
+ 		memcpy(skb_put(skb, plen), param, plen);
+ 
+-	DBG("skb len %d", skb->len);
++	BT_DBG("skb len %d", skb->len);
+ 
+ 	skb->pkt_type = HCI_COMMAND_PKT;
+ 	skb->dev = (void *) hdev;
+@@ -1234,10 +1010,28 @@
+ 	return 0;
+ }
+ 
++/* Get data from the previously sent command */
++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
++{
++	hci_command_hdr *hc;
++
++	if (!hdev->sent_cmd)
++		return NULL;
++
++	hc = (void *) hdev->sent_cmd->data;
++
++	if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
++		return NULL;
++
++	BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
++
++	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
++}
++
+ /* Send ACL data */
+ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
+ {
+-	int len = skb->len;	
++	int len = skb->len;
+ 	hci_acl_hdr *ah;
+ 
+ 	ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
+@@ -1252,7 +1046,7 @@
+ 	struct hci_dev *hdev = conn->hdev;
+ 	struct sk_buff *list;
+ 
+-	DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
++	BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
+ 
+ 	skb->dev = (void *) hdev;
+ 	skb->pkt_type = HCI_ACLDATA_PKT;
+@@ -1260,12 +1054,12 @@
+ 
+ 	if (!(list = skb_shinfo(skb)->frag_list)) {
+ 		/* Non fragmented */
+-		DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
++		BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
+ 		
+ 		skb_queue_tail(&conn->data_q, skb);
+ 	} else {
+ 		/* Fragmented */
+-		DBG("%s frag %p len %d", hdev->name, skb, skb->len);
++		BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
+ 
+ 		skb_shinfo(skb)->frag_list = NULL;
+ 
+@@ -1280,7 +1074,7 @@
+ 			skb->pkt_type = HCI_ACLDATA_PKT;
+ 			hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
+ 		
+-			DBG("%s frag %p len %d", hdev->name, skb, skb->len);
++			BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
+ 
+ 			__skb_queue_tail(&conn->data_q, skb);
+ 		} while (list);
+@@ -1298,7 +1092,7 @@
+ 	struct hci_dev *hdev = conn->hdev;
+ 	hci_sco_hdr hs;
+ 
+-	DBG("%s len %d", hdev->name, skb->len);
++	BT_DBG("%s len %d", hdev->name, skb->len);
+ 
+ 	if (skb->len > hdev->sco_mtu) {
+ 		kfree_skb(skb);
+@@ -1315,544 +1109,136 @@
+ 	skb->pkt_type = HCI_SCODATA_PKT;
+ 	skb_queue_tail(&conn->data_q, skb);
+ 	hci_sched_tx(hdev);
+-
+ 	return 0;
+ }
+ 
+-/* Handle HCI Event packets */
+-
+-/* Command Complete OGF LINK_CTL  */
+-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Complete OGF LINK_POLICY  */
+-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Complete OGF HOST_CTL  */
+-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+-{
+-	__u8 status, param;
+-	void *sent;
+-
+-
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	case OCF_RESET:
+-		status = *((__u8 *) skb->data);
+-
+-		hci_req_complete(hdev, status);
+-		break;
+-
+-	case OCF_SET_EVENT_FLT:
+-		status = *((__u8 *) skb->data);
+-
+-		if (status) {
+-			DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
+-		} else {
+-			DBG("%s SET_EVENT_FLT succeseful", hdev->name);
+-		}
+-		break;
+-
+-	case OCF_WRITE_AUTH_ENABLE:
+-		if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE)))
+-			break;
+-
+-		status = *((__u8 *) skb->data);
+-		param  = *((__u8 *) sent);
+-
+-		if (!status) {
+-			if (param == AUTH_ENABLED)
+-				hdev->flags |= HCI_AUTH;
+-			else
+-				hdev->flags &= ~HCI_AUTH;
+-		}
+-		hci_req_complete(hdev, status);
+-		break;
+-
+-	case OCF_WRITE_CA_TIMEOUT:
+-		status = *((__u8 *) skb->data);
+-
+-		if (status) {
+-			DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
+-		} else {
+-			DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
+-		}
+-		break;
+-
+-	case OCF_WRITE_PG_TIMEOUT:
+-		status = *((__u8 *) skb->data);
+-
+-		if (status) {
+-			DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
+-		} else {
+-			DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
+-		}
+-		break;
+-
+-	case OCF_WRITE_SCAN_ENABLE:
+-		if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE)))
+-			break;
+-		status = *((__u8 *) skb->data);
+-		param  = *((__u8 *) sent);
+-
+-		DBG("param 0x%x", param);
+-
+-		if (!status) {
+-			switch (param) {
+-			case IS_ENA_PS_ENA:
+-				hdev->flags |=  HCI_PSCAN | HCI_ISCAN;
+-				break;
+-
+-			case IS_ENA_PS_DIS:
+-				hdev->flags &= ~HCI_PSCAN;
+-				hdev->flags |=  HCI_ISCAN;
+-				break;
+-
+-			case IS_DIS_PS_ENA:
+-				hdev->flags &= ~HCI_ISCAN;
+-				hdev->flags |=  HCI_PSCAN;
+-				break;
+-
+-			default:
+-				hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN);
+-				break;
+-			};
+-		}
+-		hci_req_complete(hdev, status);
+-		break;
+-
+-	default:
+-		DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Complete OGF INFO_PARAM  */
+-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+-{
+-	read_local_features_rp *lf;
+-	read_buffer_size_rp *bs;
+-	read_bd_addr_rp *ba;
+-
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	case OCF_READ_LOCAL_FEATURES:
+-		lf = (read_local_features_rp *) skb->data;
+-
+-		if (lf->status) {
+-			DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
+-			break;
+-		}
+-
+-		memcpy(hdev->features, lf->features, sizeof(hdev->features));
+-
+-		/* Adjust default settings according to features 
+-		 * supported by device. */
+-		if (hdev->features[0] & LMP_3SLOT)
+-			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
+-
+-		if (hdev->features[0] & LMP_5SLOT)
+-			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
+-
+-		DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
+-
+-		break;
+-
+-	case OCF_READ_BUFFER_SIZE:
+-		bs = (read_buffer_size_rp *) skb->data;
+-
+-		if (bs->status) {
+-			DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
+-			break;
+-		}
+-
+-		hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
+-		hdev->sco_mtu = bs->sco_mtu;
+-		hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
+-		hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
+-
+-		DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
+-		    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max);
+-
+-		break;
+-
+-	case OCF_READ_BD_ADDR:
+-		ba = (read_bd_addr_rp *) skb->data;
+-
+-		if (!ba->status) {
+-			bacpy(&hdev->bdaddr, &ba->bdaddr);
+-		} else {
+-			DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
+-		}
+-
+-		hci_req_complete(hdev, ba->status);
+-		break;
+-
+-	default:
+-		DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
++/* ---- HCI TX task (outgoing data) ---- */
+ 
+-/* Command Status OGF LINK_CTL  */
+-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
++/* HCI Connection scheduler */
++static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+ {
+-	struct hci_proto * hp;
+-
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	case OCF_CREATE_CONN:
+-		if (status) {
+-			create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
+-
+-			if (!cc)
+-				break;
++	struct conn_hash *h = &hdev->conn_hash;
++	struct hci_conn  *conn = NULL;
++	int num = 0, min = ~0;
++        struct list_head *p;
+ 
+-			DBG("%s Create connection error: status 0x%x %s", hdev->name,
+-			    status, batostr(&cc->bdaddr));
++	/* We don't have to lock device here. Connections are always 
++	 * added and removed with TX task disabled. */
++	list_for_each(p, &h->list) {
++		struct hci_conn *c;
++		c = list_entry(p, struct hci_conn, list);
+ 
+-			/* Notify upper protocols */
+-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) {
+-				tasklet_disable(&hdev->tx_task);
+-				hp->connect_cfm(hdev, &cc->bdaddr, status, NULL);
+-				tasklet_enable(&hdev->tx_task);
+-			}
+-		}
+-		break;
++		if (c->type != type || c->state != BT_CONNECTED
++				|| skb_queue_empty(&c->data_q))
++			continue;
++		num++;
+ 
+-	case OCF_INQUIRY:
+-		if (status) {
+-			DBG("%s Inquiry error: status 0x%x", hdev->name, status);
+-			hci_req_complete(hdev, status);
++		if (c->sent < min) {
++			min  = c->sent;
++			conn = c;
+ 		}
+-		break;
+-
+-	default:
+-		DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Status OGF LINK_POLICY */
+-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Status OGF HOST_CTL */
+-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Status OGF INFO_PARAM  */
+-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
+-{
+-	DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Inquiry Complete */
+-static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+-{
+-	__u8 status = *((__u8 *) skb->data);
+-
+-	DBG("%s status %d", hdev->name, status);
+-
+-	hci_req_complete(hdev, status);
+-}
+-
+-/* Inquiry Result */
+-static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
+-{
+-	inquiry_info *info = (inquiry_info *) (skb->data + 1);
+-	int num_rsp = *((__u8 *) skb->data);
++	}
+ 
+-	DBG("%s num_rsp %d", hdev->name, num_rsp);
++	if (conn) {
++		int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
++		int q = cnt / num;
++		*quote = q ? q : 1;
++	} else
++		*quote = 0;
+ 
+-	for (; num_rsp; num_rsp--)
+-		inquiry_cache_update(&hdev->inq_cache, info++);
++	BT_DBG("conn %p quote %d", conn, *quote);
++	return conn;
+ }
+ 
+-/* Connect Request */
+-static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
++static inline void hci_acl_tx_to(struct hci_dev *hdev)
+ {
+-	evt_conn_request *cr = (evt_conn_request *) skb->data;
+-	struct hci_proto *hp;
+-	accept_conn_req_cp ac;
+-	int accept = 0;
++	struct conn_hash *h = &hdev->conn_hash;
++	struct list_head *p;
++	struct hci_conn  *c;
+ 
+-	DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type);
++	BT_ERR("%s ACL tx timeout", hdev->name);
+ 
+-	/* Notify upper protocols */
+-	if (cr->link_type == ACL_LINK) {
+-		/* ACL link notify L2CAP */
+-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) {
+-			tasklet_disable(&hdev->tx_task);
+-			accept = hp->connect_ind(hdev, &cr->bdaddr);
+-			tasklet_enable(&hdev->tx_task);
++	/* Kill stalled connections */
++	list_for_each(p, &h->list) {
++		c = list_entry(p, struct hci_conn, list);
++		if (c->type == ACL_LINK && c->sent) {
++			BT_ERR("%s killing stalled ACL connection %s",
++				hdev->name, batostr(&c->dst));
++			hci_acl_disconn(c, 0x13);
+ 		}
+-	} else {
+-		/* SCO link (no notification) */
+-		/* FIXME: Should be accept it here or let the requester (app) accept it ? */
+-		accept = 1;
+-	}
+-
+-	if (accept) {
+-		/* Connection accepted by upper layer */
+-		bacpy(&ac.bdaddr, &cr->bdaddr);
+-		ac.role = 0x01; /* Remain slave */
+-		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac);
+-	} else {
+-		/* Connection rejected by upper layer */
+-		/* FIXME: 
+-		 * Should we use HCI reject here ?
+-		 */
+-		return;
+ 	}
+ }
+ 
+-/* Connect Complete */
+-static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++static inline void hci_sched_acl(struct hci_dev *hdev)
+ {
+-	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
+-	struct hci_conn *conn = NULL;
+-	struct hci_proto *hp;
++	struct hci_conn *conn;
++	struct sk_buff *skb;
++	int quote;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", hdev->name);
+ 
+-	tasklet_disable(&hdev->tx_task);
++	/* ACL tx timeout must be longer than maximum
++	 * link supervision timeout (40.9 seconds) */
++	if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
++		hci_acl_tx_to(hdev);
+ 
+-	if (!cc->status)
+- 		conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr);
++	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
++		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
++			BT_DBG("skb %p len %d", skb, skb->len);
++			hci_send_frame(skb);
++			hdev->acl_last_tx = jiffies;
+ 
+-	/* Notify upper protocols */
+-	if (cc->link_type == ACL_LINK) {
+-		/* ACL link notify L2CAP layer */
+-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm)
+-			hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn);
+-	} else {
+-		/* SCO link (no notification) */
++			hdev->acl_cnt--;
++			conn->sent++;
++		}
+ 	}
+-
+-	tasklet_enable(&hdev->tx_task);
+ }
+ 
+-/* Disconnect Complete */
+-static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++/* Schedule SCO */
++static inline void hci_sched_sco(struct hci_dev *hdev)
+ {
+-	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
+-	struct hci_conn *conn = NULL;
+-	struct hci_proto *hp;
+-	__u16 handle = __le16_to_cpu(dc->handle);
++	struct hci_conn *conn;
++	struct sk_buff *skb;
++	int quote;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", hdev->name);
+ 
+-	if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
+-		tasklet_disable(&hdev->tx_task);
++	while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
++		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
++			BT_DBG("skb %p len %d", skb, skb->len);
++			hci_send_frame(skb);
+ 
+-		/* Notify upper protocols */
+-		if (conn->type == ACL_LINK) {
+-			/* ACL link notify L2CAP layer */
+-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
+-				hp->disconn_ind(conn, dc->reason);
+-		} else {
+-			/* SCO link (no notification) */
++			conn->sent++;
++			if (conn->sent == ~0)
++				conn->sent = 0;
+ 		}
+-
+-		hci_conn_del(hdev, conn);
+-
+-		tasklet_enable(&hdev->tx_task);
+ 	}
+ }
+ 
+-/* Number of completed packets */
+-static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
++static void hci_tx_task(unsigned long arg)
+ {
+-	evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
+-	__u16 *ptr;
+-	int i;
+-
+-	skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
+-
+-	DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
++	struct hci_dev *hdev = (struct hci_dev *) arg;
++	struct sk_buff *skb;
+ 
+-	if (skb->len < nc->num_hndl * 4) {
+-		DBG("%s bad parameters", hdev->name);
+-		return;
+-	}
++	read_lock(&hci_task_lock);
+ 
+-	tasklet_disable(&hdev->tx_task);
++	BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
+ 
+-	for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
+-		struct hci_conn *conn;
+-		__u16 handle, count;
++	/* Schedule queues and send stuff to HCI driver */
+ 
+-		handle = __le16_to_cpu(get_unaligned(ptr++));
+-		count  = __le16_to_cpu(get_unaligned(ptr++));
++	hci_sched_acl(hdev);
+ 
+-		hdev->acl_cnt += count;
++	hci_sched_sco(hdev);
+ 
+-		if ((conn = conn_hash_lookup(&hdev->conn_hash, handle)))
+-			conn->sent -= count;
+-	}
++	/* Send next queued raw (unknown type) packet */
++	while ((skb = skb_dequeue(&hdev->raw_q)))
++		hci_send_frame(skb);
+ 
+-	tasklet_enable(&hdev->tx_task);
+-	
+-	hci_sched_tx(hdev);
++	read_unlock(&hci_task_lock);
+ }
+ 
+-static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+-{
+-	hci_event_hdr *he = (hci_event_hdr *) skb->data;
+-	evt_cmd_status *cs;
+-	evt_cmd_complete *ec;
+-	__u16 opcode, ocf, ogf;
+-
+-	skb_pull(skb, HCI_EVENT_HDR_SIZE);
+-
+-	DBG("%s evt 0x%x", hdev->name, he->evt);
+-
+-	switch (he->evt) {
+-	case EVT_NUM_COMP_PKTS:
+-		hci_num_comp_pkts_evt(hdev, skb);
+-		break;
+-
+-	case EVT_INQUIRY_COMPLETE:
+-		hci_inquiry_complete_evt(hdev, skb);
+-		break;
+-
+-	case EVT_INQUIRY_RESULT:
+-		hci_inquiry_result_evt(hdev, skb);
+-		break;
+-
+-	case EVT_CONN_REQUEST:
+-		hci_conn_request_evt(hdev, skb);
+-		break;
+-
+-	case EVT_CONN_COMPLETE:
+-		hci_conn_complete_evt(hdev, skb);
+-		break;
+-
+-	case EVT_DISCONN_COMPLETE:
+-		hci_disconn_complete_evt(hdev, skb);
+-		break;
+-
+-	case EVT_CMD_STATUS:
+-		cs = (evt_cmd_status *) skb->data;
+-		skb_pull(skb, EVT_CMD_STATUS_SIZE);
+-				
+-		opcode = __le16_to_cpu(cs->opcode);
+-		ogf = cmd_opcode_ogf(opcode);
+-		ocf = cmd_opcode_ocf(opcode);
+-
+-		switch (ogf) {
+-		case OGF_INFO_PARAM:
+-			hci_cs_info_param(hdev, ocf, cs->status);
+-			break;
+-
+-		case OGF_HOST_CTL:
+-			hci_cs_host_ctl(hdev, ocf, cs->status);
+-			break;
+ 
+-		case OGF_LINK_CTL:
+-			hci_cs_link_ctl(hdev, ocf, cs->status);
+-			break;
+-
+-		case OGF_LINK_POLICY:
+-			hci_cs_link_policy(hdev, ocf, cs->status);
+-			break;
+-
+-		default:
+-			DBG("%s Command Status OGF %x", hdev->name, ogf);
+-			break;
+-		};
+-
+-		if (cs->ncmd) {
+-			atomic_set(&hdev->cmd_cnt, 1);
+-			if (!skb_queue_empty(&hdev->cmd_q))
+-				hci_sched_cmd(hdev);
+-		}
+-		break;
+-
+-	case EVT_CMD_COMPLETE:
+-		ec = (evt_cmd_complete *) skb->data;
+-		skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
+-
+-		opcode = __le16_to_cpu(ec->opcode);
+-		ogf = cmd_opcode_ogf(opcode);
+-		ocf = cmd_opcode_ocf(opcode);
+-
+-		switch (ogf) {
+-		case OGF_INFO_PARAM:
+-			hci_cc_info_param(hdev, ocf, skb);
+-			break;
+-
+-		case OGF_HOST_CTL:
+-			hci_cc_host_ctl(hdev, ocf, skb);
+-			break;
+-
+-		case OGF_LINK_CTL:
+-			hci_cc_link_ctl(hdev, ocf, skb);
+-			break;
+-
+-		case OGF_LINK_POLICY:
+-			hci_cc_link_policy(hdev, ocf, skb);
+-			break;
+-
+-		default:
+-			DBG("%s Command Completed OGF %x", hdev->name, ogf);
+-			break;
+-		};
+-
+-		if (ec->ncmd) {
+-			atomic_set(&hdev->cmd_cnt, 1);
+-			if (!skb_queue_empty(&hdev->cmd_q))
+-				hci_sched_cmd(hdev);
+-		}
+-		break;
+-	};
+-
+-	kfree_skb(skb);
+-	hdev->stat.evt_rx++;
+-}
++/* ----- HCI RX task (incomming data proccessing) ----- */
+ 
+ /* ACL data packet */
+ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+@@ -1867,51 +1253,86 @@
+ 	flags  = acl_flags(handle);
+ 	handle = acl_handle(handle);
+ 
+-	DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
++	BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
+ 
+-	if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
++	hdev->stat.acl_rx++;
++
++	hci_dev_lock(hdev);
++	conn = conn_hash_lookup_handle(hdev, handle);
++	hci_dev_unlock(hdev);
++	
++	if (conn) {
+ 		register struct hci_proto *hp;
+ 
+ 		/* Send to upper protocol */
+-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) {
++		if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
+ 			hp->recv_acldata(conn, skb, flags);
+-			goto sent;
++			return;
+ 		}
+ 	} else {
+-		ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle);
++		BT_ERR("%s ACL packet for unknown connection handle %d", 
++			hdev->name, handle);
+ 	}
+ 
+ 	kfree_skb(skb);
+-sent:
+-	hdev->stat.acl_rx++;
+ }
+ 
+ /* SCO data packet */
+ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+-	DBG("%s len %d", hdev->name, skb->len);
++	hci_sco_hdr *sh = (void *) skb->data;
++	struct hci_conn *conn;
++	__u16 handle;
++
++	skb_pull(skb, HCI_SCO_HDR_SIZE);
++
++	handle = __le16_to_cpu(sh->handle);
++
++	BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
+ 
+-	kfree_skb(skb);
+ 	hdev->stat.sco_rx++;
++
++	hci_dev_lock(hdev);
++	conn = conn_hash_lookup_handle(hdev, handle);
++	hci_dev_unlock(hdev);
++	
++	if (conn) {
++		register struct hci_proto *hp;
++
++		/* Send to upper protocol */
++		if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) {
++			hp->recv_scodata(conn, skb);
++			return;
++		}
++	} else {
++		BT_ERR("%s SCO packet for unknown connection handle %d", 
++			hdev->name, handle);
++	}
++
++	kfree_skb(skb);
+ }
+ 
+-/* ----- HCI tasks ----- */
+ void hci_rx_task(unsigned long arg)
+ {
+ 	struct hci_dev *hdev = (struct hci_dev *) arg;
+ 	struct sk_buff *skb;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", hdev->name);
+ 
+ 	read_lock(&hci_task_lock);
+ 
+ 	while ((skb = skb_dequeue(&hdev->rx_q))) {
+-		if (hdev->flags & HCI_SOCK) {
++		if (atomic_read(&hdev->promisc)) {
+ 			/* Send copy to the sockets */
+ 			hci_send_to_sock(hdev, skb);
+ 		}
+ 
+-		if (hdev->flags & HCI_INIT) {
++		if (test_bit(HCI_RAW, &hdev->flags)) {
++			kfree_skb(skb);
++			continue;
++		}
++
++		if (test_bit(HCI_INIT, &hdev->flags)) {
+ 			/* Don't process data packets in this states. */
+ 			switch (skb->pkt_type) {
+ 			case HCI_ACLDATA_PKT:
+@@ -1921,64 +1342,43 @@
+ 			};
+ 		}
+ 
+-		if (hdev->flags & HCI_NORMAL) {
+-			/* Process frame */
+-			switch (skb->pkt_type) {
+-			case HCI_EVENT_PKT:
+-				hci_event_packet(hdev, skb);
+-				break;
++		/* Process frame */
++		switch (skb->pkt_type) {
++		case HCI_EVENT_PKT:
++			hci_event_packet(hdev, skb);
++			break;
+ 
+-			case HCI_ACLDATA_PKT:
+-				DBG("%s ACL data packet", hdev->name);
+-				hci_acldata_packet(hdev, skb);
+-				break;
++		case HCI_ACLDATA_PKT:
++			BT_DBG("%s ACL data packet", hdev->name);
++			hci_acldata_packet(hdev, skb);
++			break;
+ 
+-			case HCI_SCODATA_PKT:
+-				DBG("%s SCO data packet", hdev->name);
+-				hci_scodata_packet(hdev, skb);
+-				break;
++		case HCI_SCODATA_PKT:
++			BT_DBG("%s SCO data packet", hdev->name);
++			hci_scodata_packet(hdev, skb);
++			break;
+ 
+-			default:
+-				kfree_skb(skb);
+-				break;
+-			};
+-		} else {
++		default:
+ 			kfree_skb(skb);
++			break;
+ 		}
+ 	}
+ 
+ 	read_unlock(&hci_task_lock);
+ }
+ 
+-static void hci_tx_task(unsigned long arg)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) arg;
+-	struct sk_buff *skb;
+-
+-	read_lock(&hci_task_lock);
+-
+-	DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
+-
+-	/* Schedule queues and send stuff to HCI driver */
+-
+-	hci_sched_acl(hdev);
+-
+-	hci_sched_sco(hdev);
+-
+-	/* Send next queued raw (unknown type) packet */
+-	while ((skb = skb_dequeue(&hdev->raw_q)))
+-		hci_send_frame(skb);
+-
+-	read_unlock(&hci_task_lock);
+-}
+-
+ static void hci_cmd_task(unsigned long arg)
+ {
+ 	struct hci_dev *hdev = (struct hci_dev *) arg;
+ 	struct sk_buff *skb;
+ 
+-	DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
++	BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
+ 
++	if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) {
++		BT_ERR("%s command tx timeout", hdev->name);
++		atomic_set(&hdev->cmd_cnt, 1);
++	}
++	
+ 	/* Send queued commands */
+ 	if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
+ 		if (hdev->sent_cmd)
+@@ -1987,6 +1387,7 @@
+ 		if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
+ 			atomic_dec(&hdev->cmd_cnt);
+ 			hci_send_frame(skb);
++			hdev->cmd_last_tx = jiffies;
+ 		} else {
+ 			skb_queue_head(&hdev->cmd_q, skb);
+ 			hci_sched_cmd(hdev);
+@@ -1994,33 +1395,10 @@
+ 	}
+ }
+ 
+-/* Receive frame from HCI drivers */
+-int hci_recv_frame(struct sk_buff *skb)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+-
+-	if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) {
+-		kfree_skb(skb);
+-		return -1;
+-	}
+-
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+-
+-	/* Incomming skb */
+-	bluez_cb(skb)->incomming = 1;
+-
+-	/* Queue frame for rx task */
+-	skb_queue_tail(&hdev->rx_q, skb);
+-	hci_sched_rx(hdev);
+-
+-	return 0;
+-}
++/* ---- Initialization ---- */
+ 
+ int hci_core_init(void)
+ {
+-	/* Init locks */
+-	spin_lock_init(&hdev_list_lock);
+-
+ 	return 0;
+ }
+ 
+@@ -2028,5 +1406,3 @@
+ {
+ 	return 0;
+ }
+-
+-MODULE_LICENSE("GPL");
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/hci_event.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,910 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * HCI Events.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/notifier.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++#ifndef HCI_CORE_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++/* Handle HCI Event packets */
++
++/* Command Complete OGF LINK_CTL  */
++static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	__u8 status;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_INQUIRY_CANCEL:
++		status = *((__u8 *) skb->data);
++
++		if (status) {
++			BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
++		} else {
++			clear_bit(HCI_INQUIRY, &hdev->flags);
++			hci_req_complete(hdev, status);
++		}
++		break;
++
++	default:
++		BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Complete OGF LINK_POLICY  */
++static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	struct hci_conn *conn;
++	role_discovery_rp *rd;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_ROLE_DISCOVERY: 
++		rd = (void *) skb->data;
++
++		if (rd->status)
++			break;
++		
++		hci_dev_lock(hdev);
++	
++		conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
++		if (conn) {
++			if (rd->role)
++				conn->link_mode &= ~HCI_LM_MASTER;
++			else
++				conn->link_mode |= HCI_LM_MASTER;
++		}
++			
++		hci_dev_unlock(hdev);
++		break;
++
++	default:
++		BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", 
++				hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Complete OGF HOST_CTL  */
++static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	__u8 status, param;
++	void *sent;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_RESET:
++		status = *((__u8 *) skb->data);
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_SET_EVENT_FLT:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
++		} else {
++			BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
++		}
++		break;
++
++	case OCF_WRITE_AUTH_ENABLE:
++		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
++		if (!sent)
++			break;
++
++		status = *((__u8 *) skb->data);
++		param  = *((__u8 *) sent);
++
++		if (!status) {
++			if (param == AUTH_ENABLED)
++				set_bit(HCI_AUTH, &hdev->flags);
++			else
++				clear_bit(HCI_AUTH, &hdev->flags);
++		}
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_WRITE_ENCRYPT_MODE:
++		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
++		if (!sent)
++			break;
++
++		status = *((__u8 *) skb->data);
++		param  = *((__u8 *) sent);
++
++		if (!status) {
++			if (param)
++				set_bit(HCI_ENCRYPT, &hdev->flags);
++			else
++				clear_bit(HCI_ENCRYPT, &hdev->flags);
++		}
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_WRITE_CA_TIMEOUT:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
++		} else {
++			BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
++		}
++		break;
++
++	case OCF_WRITE_PG_TIMEOUT:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
++		} else {
++			BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
++		}
++		break;
++
++	case OCF_WRITE_SCAN_ENABLE:
++		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
++		if (!sent)
++			break;
++		status = *((__u8 *) skb->data);
++		param  = *((__u8 *) sent);
++
++		BT_DBG("param 0x%x", param);
++
++		if (!status) {
++			clear_bit(HCI_PSCAN, &hdev->flags);
++			clear_bit(HCI_ISCAN, &hdev->flags);
++			if (param & SCAN_INQUIRY) 
++				set_bit(HCI_ISCAN, &hdev->flags);
++
++			if (param & SCAN_PAGE) 
++				set_bit(HCI_PSCAN, &hdev->flags);
++		}
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_HOST_BUFFER_SIZE:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
++			hci_req_complete(hdev, status);
++		}
++		break;
++
++	default:
++		BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Complete OGF INFO_PARAM  */
++static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	read_local_features_rp *lf;
++	read_buffer_size_rp *bs;
++	read_bd_addr_rp *ba;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_READ_LOCAL_FEATURES:
++		lf = (read_local_features_rp *) skb->data;
++
++		if (lf->status) {
++			BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
++			break;
++		}
++
++		memcpy(hdev->features, lf->features, sizeof(hdev->features));
++
++		/* Adjust default settings according to features 
++		 * supported by device. */
++		if (hdev->features[0] & LMP_3SLOT)
++			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
++
++		if (hdev->features[0] & LMP_5SLOT)
++			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
++
++		if (hdev->features[1] & LMP_HV2)
++			hdev->pkt_type |= (HCI_HV2);
++
++		if (hdev->features[1] & LMP_HV3)
++			hdev->pkt_type |= (HCI_HV3);
++
++		BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
++
++		break;
++
++	case OCF_READ_BUFFER_SIZE:
++		bs = (read_buffer_size_rp *) skb->data;
++
++		if (bs->status) {
++			BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
++			hci_req_complete(hdev, bs->status);
++			break;
++		}
++
++		hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
++		hdev->sco_mtu  = bs->sco_mtu ? bs->sco_mtu : 64;
++		hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
++		hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
++
++		BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
++		    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
++		break;
++
++	case OCF_READ_BD_ADDR:
++		ba = (read_bd_addr_rp *) skb->data;
++
++		if (!ba->status) {
++			bacpy(&hdev->bdaddr, &ba->bdaddr);
++		} else {
++			BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
++		}
++
++		hci_req_complete(hdev, ba->status);
++		break;
++
++	default:
++		BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Status OGF LINK_CTL  */
++static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
++{
++	struct hci_conn *conn;
++	create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
++
++	if (!cc)
++		return;
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr);
++
++	BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, 
++			status, batostr(&cc->bdaddr), conn);
++
++	if (status) {
++		if (conn) {
++			conn->state = BT_CLOSED;
++			hci_proto_connect_cfm(conn, status);
++			hci_conn_del(conn);
++		}
++	} else {
++		if (!conn) {
++			conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr);
++			if (conn) {
++				conn->out = 1;
++				conn->link_mode |= HCI_LM_MASTER;
++			} else
++				BT_ERR("No memmory for new connection");
++		}
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_CREATE_CONN:
++		hci_cs_create_conn(hdev, status);
++		break;
++
++	case OCF_ADD_SCO:
++		if (status) {
++			struct hci_conn *acl, *sco;
++			add_sco_cp *cp = hci_sent_cmd_data(hdev, 
++						OGF_LINK_CTL, OCF_ADD_SCO);
++			__u16 handle;
++
++			if (!cp)
++				break;
++
++			handle = __le16_to_cpu(cp->handle);
++
++			BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
++
++			hci_dev_lock(hdev);
++	
++			acl = conn_hash_lookup_handle(hdev, handle);
++			if (acl && (sco = acl->link)) {
++				sco->state = BT_CLOSED;
++				hci_proto_connect_cfm(sco, status);
++				hci_conn_del(sco);
++			}
++
++			hci_dev_unlock(hdev);
++		}
++		break;
++
++	case OCF_INQUIRY:
++		if (status) {
++			BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
++			hci_req_complete(hdev, status);
++		} else {
++			set_bit(HCI_INQUIRY, &hdev->flags);
++		}
++		break;
++
++	default:
++		BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", 
++			hdev->name, ocf, status);
++		break;
++	};
++}
++
++/* Command Status OGF LINK_POLICY */
++static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	default:
++		BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Status OGF HOST_CTL */
++static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	default:
++		BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Status OGF INFO_PARAM  */
++static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	default:
++		BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Inquiry Complete */
++static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	__u8 status = *((__u8 *) skb->data);
++
++	BT_DBG("%s status %d", hdev->name, status);
++
++	clear_bit(HCI_INQUIRY, &hdev->flags);
++	hci_req_complete(hdev, status);
++}
++
++/* Inquiry Result */
++static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	inquiry_info *info = (inquiry_info *) (skb->data + 1);
++	int num_rsp = *((__u8 *) skb->data);
++
++	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
++
++	hci_dev_lock(hdev);
++	for (; num_rsp; num_rsp--)
++		inquiry_cache_update(hdev, info++);
++	hci_dev_unlock(hdev);
++}
++
++/* Inquiry Result With RSSI */
++static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	inquiry_info_with_rssi *info = (inquiry_info_with_rssi *) (skb->data + 1);
++	int num_rsp = *((__u8 *) skb->data);
++
++	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
++
++	hci_dev_lock(hdev);
++	for (; num_rsp; num_rsp--) {
++		inquiry_info tmp;
++		bacpy(&tmp.bdaddr, &info->bdaddr);
++		tmp.pscan_rep_mode    = info->pscan_rep_mode;
++		tmp.pscan_period_mode = info->pscan_period_mode;
++		tmp.pscan_mode        = 0x00;
++		memcpy(tmp.dev_class, &info->dev_class, 3);
++		tmp.clock_offset      = info->clock_offset;
++		info++;
++		inquiry_cache_update(hdev, &tmp);
++	}
++	hci_dev_unlock(hdev);
++}
++
++/* Connect Request */
++static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_conn_request *cr = (evt_conn_request *) skb->data;
++	int mask = hdev->link_mode;
++
++	BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
++			batostr(&cr->bdaddr), cr->link_type);
++
++	mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type);
++
++	if (mask & HCI_LM_ACCEPT) {
++		/* Connection accepted */
++		struct hci_conn *conn;
++		accept_conn_req_cp ac;
++
++		hci_dev_lock(hdev);
++		conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr);
++		if (!conn) {
++			if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) {
++				BT_ERR("No memmory for new connection");
++				hci_dev_unlock(hdev);
++				return;
++			}
++		}
++		conn->state = BT_CONNECT;
++		hci_dev_unlock(hdev);
++
++		bacpy(&ac.bdaddr, &cr->bdaddr);
++	
++		if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
++			ac.role = 0x00; /* Become master */
++		else
++			ac.role = 0x01; /* Remain slave */
++
++		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, 
++				ACCEPT_CONN_REQ_CP_SIZE, &ac);
++	} else {
++		/* Connection rejected */
++		reject_conn_req_cp rc;
++
++		bacpy(&rc.bdaddr, &cr->bdaddr);
++		rc.reason = 0x0f;
++		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ,
++				REJECT_CONN_REQ_CP_SIZE, &rc);
++	}
++}
++
++/* Connect Complete */
++static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
++	struct hci_conn *conn = NULL;
++
++	BT_DBG("%s", hdev->name);
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr);
++	if (!conn) {
++		hci_dev_unlock(hdev);
++		return;
++	}
++
++	if (!cc->status) {
++		conn->handle = __le16_to_cpu(cc->handle);
++		conn->state  = BT_CONNECTED;
++
++		if (test_bit(HCI_AUTH, &hdev->flags))
++			conn->link_mode |= HCI_LM_AUTH;
++		
++		if (test_bit(HCI_ENCRYPT, &hdev->flags))
++			conn->link_mode |= HCI_LM_ENCRYPT;
++
++
++		/* Set link policy */
++		if (conn->type == ACL_LINK && hdev->link_policy) {
++			write_link_policy_cp lp;
++			lp.handle = cc->handle;
++			lp.policy = __cpu_to_le16(hdev->link_policy);
++			hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
++				WRITE_LINK_POLICY_CP_SIZE, &lp);
++		}
++
++		/* Set packet type for incomming connection */
++		if (!conn->out) {
++			change_conn_ptype_cp cp;
++			cp.handle = cc->handle;
++			cp.pkt_type = (conn->type == ACL_LINK) ? 
++				__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
++				__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
++
++			hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE,
++				CHANGE_CONN_PTYPE_CP_SIZE, &cp);
++		}
++	} else
++		conn->state = BT_CLOSED;
++
++	if (conn->type == ACL_LINK) {
++		struct hci_conn *sco = conn->link;
++		if (sco) {
++			if (!cc->status)
++				hci_add_sco(sco, conn->handle);
++			else {
++				hci_proto_connect_cfm(sco, cc->status);
++				hci_conn_del(sco);
++			}
++		}
++	}
++
++	hci_proto_connect_cfm(conn, cc->status);
++	if (cc->status)
++		hci_conn_del(conn);
++
++	hci_dev_unlock(hdev);
++}
++
++/* Disconnect Complete */
++static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
++	struct hci_conn *conn = NULL;
++	__u16 handle = __le16_to_cpu(dc->handle);
++
++	BT_DBG("%s status %d", hdev->name, dc->status);
++
++	if (dc->status)
++		return;
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_handle(hdev, handle);
++	if (conn) {
++		conn->state = BT_CLOSED;
++		hci_proto_disconn_ind(conn, dc->reason);
++		hci_conn_del(conn);
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++/* Number of completed packets */
++static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
++	__u16 *ptr;
++	int i;
++
++	skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
++
++	BT_DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
++
++	if (skb->len < nc->num_hndl * 4) {
++		BT_DBG("%s bad parameters", hdev->name);
++		return;
++	}
++
++	tasklet_disable(&hdev->tx_task);
++
++	for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
++		struct hci_conn *conn;
++		__u16  handle, count;
++
++		handle = __le16_to_cpu(get_unaligned(ptr++));
++		count  = __le16_to_cpu(get_unaligned(ptr++));
++
++		conn = conn_hash_lookup_handle(hdev, handle);
++		if (conn) {
++			conn->sent -= count;
++
++			if (conn->type == SCO_LINK) {
++				if ((hdev->sco_cnt += count) > hdev->sco_pkts)
++					hdev->sco_cnt = hdev->sco_pkts;
++			} else {
++				if ((hdev->acl_cnt += count) > hdev->acl_pkts)
++					hdev->acl_cnt = hdev->acl_pkts;
++			}
++		}
++	}
++	hci_sched_tx(hdev);
++
++	tasklet_enable(&hdev->tx_task);
++}
++
++/* Role Change */
++static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_role_change *rc = (evt_role_change *) skb->data;
++	struct hci_conn *conn = NULL;
++
++	BT_DBG("%s status %d", hdev->name, rc->status);
++
++	if (rc->status)
++		return;
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr);
++	if (conn) {
++		if (rc->role)
++			conn->link_mode &= ~HCI_LM_MASTER;
++		else 
++			conn->link_mode |= HCI_LM_MASTER;
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++/* Authentication Complete */
++static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_auth_complete *ac = (evt_auth_complete *) skb->data;
++	struct hci_conn *conn = NULL;
++	__u16 handle = __le16_to_cpu(ac->handle);
++
++	BT_DBG("%s status %d", hdev->name, ac->status);
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_handle(hdev, handle);
++	if (conn) {
++		if (!ac->status)
++			conn->link_mode |= HCI_LM_AUTH;
++		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
++
++		hci_proto_auth_cfm(conn, ac->status);
++		
++		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
++			if (!ac->status) {
++				set_conn_encrypt_cp ce;
++				ce.handle  = __cpu_to_le16(conn->handle);
++				ce.encrypt = 1;
++				hci_send_cmd(conn->hdev, OGF_LINK_CTL,
++						OCF_SET_CONN_ENCRYPT,
++						SET_CONN_ENCRYPT_CP_SIZE, &ce);
++			} else {
++				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
++				hci_proto_encrypt_cfm(conn, ac->status);
++			}
++		}
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++/* Encryption Change */
++static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_encrypt_change *ec = (evt_encrypt_change *) skb->data;
++	struct hci_conn *conn = NULL;
++	__u16 handle = __le16_to_cpu(ec->handle);
++
++	BT_DBG("%s status %d", hdev->name, ec->status);
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_handle(hdev, handle);
++	if (conn) {
++		if (!ec->status) {
++		       	if (ec->encrypt)
++				conn->link_mode |= HCI_LM_ENCRYPT;
++			else
++				conn->link_mode &= ~HCI_LM_ENCRYPT;
++		}
++		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
++		
++		hci_proto_encrypt_cfm(conn, ec->status);
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	hci_event_hdr *he = (hci_event_hdr *) skb->data;
++	evt_cmd_status *cs;
++	evt_cmd_complete *ec;
++	__u16 opcode, ocf, ogf;
++
++	skb_pull(skb, HCI_EVENT_HDR_SIZE);
++
++	BT_DBG("%s evt 0x%x", hdev->name, he->evt);
++
++	switch (he->evt) {
++	case EVT_NUM_COMP_PKTS:
++		hci_num_comp_pkts_evt(hdev, skb);
++		break;
++
++	case EVT_INQUIRY_COMPLETE:
++		hci_inquiry_complete_evt(hdev, skb);
++		break;
++
++	case EVT_INQUIRY_RESULT:
++		hci_inquiry_result_evt(hdev, skb);
++		break;
++
++	case EVT_INQUIRY_RESULT_WITH_RSSI:
++		hci_inquiry_result_with_rssi_evt(hdev, skb);
++		break;
++
++	case EVT_CONN_REQUEST:
++		hci_conn_request_evt(hdev, skb);
++		break;
++
++	case EVT_CONN_COMPLETE:
++		hci_conn_complete_evt(hdev, skb);
++		break;
++
++	case EVT_DISCONN_COMPLETE:
++		hci_disconn_complete_evt(hdev, skb);
++		break;
++
++	case EVT_ROLE_CHANGE:
++		hci_role_change_evt(hdev, skb);
++		break;
++
++	case EVT_AUTH_COMPLETE:
++		hci_auth_complete_evt(hdev, skb);
++		break;
++
++	case EVT_ENCRYPT_CHANGE:
++		hci_encrypt_change_evt(hdev, skb);
++		break;
++
++	case EVT_CMD_STATUS:
++		cs = (evt_cmd_status *) skb->data;
++		skb_pull(skb, EVT_CMD_STATUS_SIZE);
++				
++		opcode = __le16_to_cpu(cs->opcode);
++		ogf = cmd_opcode_ogf(opcode);
++		ocf = cmd_opcode_ocf(opcode);
++
++		switch (ogf) {
++		case OGF_INFO_PARAM:
++			hci_cs_info_param(hdev, ocf, cs->status);
++			break;
++
++		case OGF_HOST_CTL:
++			hci_cs_host_ctl(hdev, ocf, cs->status);
++			break;
++
++		case OGF_LINK_CTL:
++			hci_cs_link_ctl(hdev, ocf, cs->status);
++			break;
++
++		case OGF_LINK_POLICY:
++			hci_cs_link_policy(hdev, ocf, cs->status);
++			break;
++
++		default:
++			BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
++			break;
++		};
++
++		if (cs->ncmd) {
++			atomic_set(&hdev->cmd_cnt, 1);
++			if (!skb_queue_empty(&hdev->cmd_q))
++				hci_sched_cmd(hdev);
++		}
++		break;
++
++	case EVT_CMD_COMPLETE:
++		ec = (evt_cmd_complete *) skb->data;
++		skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
++
++		opcode = __le16_to_cpu(ec->opcode);
++		ogf = cmd_opcode_ogf(opcode);
++		ocf = cmd_opcode_ocf(opcode);
++
++		switch (ogf) {
++		case OGF_INFO_PARAM:
++			hci_cc_info_param(hdev, ocf, skb);
++			break;
++
++		case OGF_HOST_CTL:
++			hci_cc_host_ctl(hdev, ocf, skb);
++			break;
++
++		case OGF_LINK_CTL:
++			hci_cc_link_ctl(hdev, ocf, skb);
++			break;
++
++		case OGF_LINK_POLICY:
++			hci_cc_link_policy(hdev, ocf, skb);
++			break;
++
++		default:
++			BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
++			break;
++		};
++
++		if (ec->ncmd) {
++			atomic_set(&hdev->cmd_cnt, 1);
++			if (!skb_queue_empty(&hdev->cmd_q))
++				hci_sched_cmd(hdev);
++		}
++		break;
++	};
++
++	kfree_skb(skb);
++	hdev->stat.evt_rx++;
++}
++
++/* General internal stack event */
++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
++{
++	hci_event_hdr *eh;
++	evt_stack_internal *si;
++	struct sk_buff *skb;
++	int size;
++	void *ptr;
++
++	size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen;
++	skb  = bluez_skb_alloc(size, GFP_ATOMIC);
++	if (!skb)
++		return;
++
++	ptr = skb_put(skb, size);
++
++	eh = ptr;
++       	eh->evt  = EVT_STACK_INTERNAL;
++	eh->plen = EVT_STACK_INTERNAL_SIZE + dlen;
++	ptr += HCI_EVENT_HDR_SIZE;
++
++	si = ptr;
++	si->type = type;
++	memcpy(si->data, data, dlen);
++	
++	skb->pkt_type = HCI_EVENT_PKT;
++	skb->dev = (void *) hdev;
++	hci_send_to_sock(hdev, skb);
++	kfree_skb(skb);
++}
+--- linux/net/bluetooth/hci_sock.c~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/net/bluetooth/hci_sock.c	2004-01-25 23:37:39.000000000 +0100
+@@ -25,7 +25,7 @@
+ /*
+  * BlueZ HCI socket layer.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/config.h>
+@@ -49,45 +49,54 @@
+ 
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
++#include <asm/unaligned.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+ 
+ #ifndef HCI_SOCK_DEBUG
+-#undef  DBG
+-#define DBG( A... )
++#undef  BT_DBG
++#define BT_DBG( A... )
+ #endif
+ 
+-/* HCI socket interface */
++/* ----- HCI socket interface ----- */
++
++/* Security filter */
++static struct hci_sec_filter hci_sec_filter = {
++	/* Packet types */
++	0x10,
++	/* Events */
++	{ 0x1000d9fe, 0x0000300c },
++	/* Commands */
++	{
++		{ 0x0 },
++		/* OGF_LINK_CTL */
++		{ 0xbe000006, 0x00000001, 0x0000, 0x00 },
++		/* OGF_LINK_POLICY */
++		{ 0x00005200, 0x00000000, 0x0000, 0x00 },
++		/* OGF_HOST_CTL */
++		{ 0xaab00200, 0x2b402aaa, 0x0154, 0x00 },
++		/* OGF_INFO_PARAM */
++		{ 0x000002be, 0x00000000, 0x0000, 0x00 },
++		/* OGF_STATUS_PARAM */
++		{ 0x000000ea, 0x00000000, 0x0000, 0x00 }
++	}
++};
+ 
+ static struct bluez_sock_list hci_sk_list = {
+ 	lock: RW_LOCK_UNLOCKED
+ };
+ 
+-static struct sock *hci_sock_lookup(struct hci_dev *hdev)
+-{
+-	struct sock *sk;
+-
+-	read_lock(&hci_sk_list.lock);
+-	for (sk = hci_sk_list.head; sk; sk = sk->next) {
+-		if (hci_pi(sk)->hdev == hdev)
+-			break;
+-	}
+-	read_unlock(&hci_sk_list.lock);
+-	return sk;
+-}
+-
+ /* Send frame to RAW socket */
+ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+ 	struct sock * sk;
+ 
+-	DBG("hdev %p len %d", hdev, skb->len);
++	BT_DBG("hdev %p len %d", hdev, skb->len);
+ 
+ 	read_lock(&hci_sk_list.lock);
+ 	for (sk = hci_sk_list.head; sk; sk = sk->next) {
+-		struct hci_filter *flt;	
++		struct hci_filter *flt;
+ 		struct sk_buff *nskb;
+ 
+ 		if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
+@@ -100,13 +109,19 @@
+ 		/* Apply filter */
+ 		flt = &hci_pi(sk)->filter;
+ 
+-		if (!test_bit(skb->pkt_type, &flt->type_mask))
++		if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+ 			continue;
+ 
+ 		if (skb->pkt_type == HCI_EVENT_PKT) {
+-			register int evt = (*(__u8 *)skb->data & 63);
++			register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
++			
++			if (!hci_test_bit(evt, &flt->event_mask))
++				continue;
+ 
+-			if (!test_bit(evt, &flt->event_mask))
++			if (flt->opcode && ((evt == EVT_CMD_COMPLETE && 
++					flt->opcode != *(__u16 *)(skb->data + 3)) ||
++					(evt == EVT_CMD_STATUS && 
++					flt->opcode != *(__u16 *)(skb->data + 4))))
+ 				continue;
+ 		}
+ 
+@@ -116,8 +131,8 @@
+ 		/* Put type byte before the data */
+ 		memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
+ 
+-		skb_queue_tail(&sk->receive_queue, nskb);
+-		sk->data_ready(sk, nskb->len);
++		if (sock_queue_rcv_skb(sk, nskb))
++			kfree_skb(nskb);
+ 	}
+ 	read_unlock(&hci_sk_list.lock);
+ }
+@@ -127,7 +142,7 @@
+ 	struct sock *sk = sock->sk;
+ 	struct hci_dev *hdev = hci_pi(sk)->hdev;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p sk %p", sock, sk);
+ 
+ 	if (!sk)
+ 		return 0;
+@@ -135,9 +150,7 @@
+ 	bluez_sock_unlink(&hci_sk_list, sk);
+ 
+ 	if (hdev) {
+-		if (!hci_sock_lookup(hdev))
+-			hdev->flags &= ~HCI_SOCK;
+-
++		atomic_dec(&hdev->promisc);
+ 		hci_dev_put(hdev);
+ 	}
+ 
+@@ -149,24 +162,55 @@
+ 	sock_put(sk);
+ 
+ 	MOD_DEC_USE_COUNT;
+-
+ 	return 0;
+ }
+ 
+-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++/* Ioctls that require bound socket */ 
++static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+ {
+-	struct sock *sk = sock->sk;
+ 	struct hci_dev *hdev = hci_pi(sk)->hdev;
+-	__u32 mode;
+ 
+-	DBG("cmd %x arg %lx", cmd, arg);
++	if (!hdev)
++		return -EBADFD;
+ 
+ 	switch (cmd) {
+-	case HCIGETINFO:
+-		return hci_dev_info(arg);
++	case HCISETRAW:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (arg)
++			set_bit(HCI_RAW, &hdev->flags);
++		else
++			clear_bit(HCI_RAW, &hdev->flags);
++
++		return 0;
++
++	case HCIGETCONNINFO:
++		return hci_get_conn_info(hdev, arg);
+ 
++	default:
++		if (hdev->ioctl)
++			return hdev->ioctl(hdev, cmd, arg);
++		return -EINVAL;
++	}
++}
++
++static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct sock *sk = sock->sk;
++	int err;
++
++	BT_DBG("cmd %x arg %lx", cmd, arg);
++
++	switch (cmd) {
+ 	case HCIGETDEVLIST:
+-		return hci_dev_list(arg);
++		return hci_get_dev_list(arg);
++
++	case HCIGETDEVINFO:
++		return hci_get_dev_info(arg);
++
++	case HCIGETCONNLIST:
++		return hci_get_conn_list(arg);
+ 
+ 	case HCIDEVUP:
+ 		if (!capable(CAP_NET_ADMIN))
+@@ -183,48 +227,31 @@
+ 			return -EACCES;
+ 		return hci_dev_reset(arg);
+ 
+-	case HCIRESETSTAT:
++	case HCIDEVRESTAT:
+ 		if (!capable(CAP_NET_ADMIN))
+ 			return -EACCES;
+ 		return hci_dev_reset_stat(arg);
+ 
+ 	case HCISETSCAN:
+-		if (!capable(CAP_NET_ADMIN))
+-			return -EACCES;
+-		return hci_dev_setscan(arg);
+-
+ 	case HCISETAUTH:
+-		if (!capable(CAP_NET_ADMIN))
+-			return -EACCES;
+-		return hci_dev_setauth(arg);
+-
+-	case HCISETRAW:
+-		if (!capable(CAP_NET_ADMIN))
+-			return -EACCES;
+-
+-		if (!hdev)
+-			return -EBADFD;
+-
+-		if (arg)
+-			mode = HCI_RAW;
+-		else
+-			mode = HCI_NORMAL;
+-
+-		return hci_dev_setmode(hdev, mode);
+-
++	case HCISETENCRYPT:
+ 	case HCISETPTYPE:
++	case HCISETLINKPOL:
++	case HCISETLINKMODE:
++	case HCISETACLMTU:
++	case HCISETSCOMTU:
+ 		if (!capable(CAP_NET_ADMIN))
+ 			return -EACCES;
+-		return hci_dev_setptype(arg);
++		return hci_dev_cmd(cmd, arg);
+ 
+ 	case HCIINQUIRY:
+ 		return hci_inquiry(arg);
+ 
+-	case HCIGETCONNLIST:
+-		return hci_conn_list(arg);
+-
+ 	default:
+-		return -EINVAL;
++		lock_sock(sk);
++		err = hci_sock_bound_ioctl(sk, cmd, arg);
++		release_sock(sk);
++		return err;
+ 	};
+ }
+ 
+@@ -233,28 +260,35 @@
+ 	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
+ 	struct sock *sk = sock->sk;
+ 	struct hci_dev *hdev = NULL;
++	int err = 0;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p sk %p", sock, sk);
+ 
+ 	if (!haddr || haddr->hci_family != AF_BLUETOOTH)
+ 		return -EINVAL;
+ 
++	lock_sock(sk);
++
+ 	if (hci_pi(sk)->hdev) {
+-		/* Already bound */
+-		return 0;
++		err = -EALREADY;
++		goto done;
+ 	}
+ 
+ 	if (haddr->hci_dev != HCI_DEV_NONE) {
+-		if (!(hdev = hci_dev_get(haddr->hci_dev)))
+-			return -ENODEV;
++		if (!(hdev = hci_dev_get(haddr->hci_dev))) {
++			err = -ENODEV;
++			goto done;
++		}
+ 
+-		hdev->flags |= HCI_SOCK;
++		atomic_inc(&hdev->promisc);
+ 	}
+ 
+ 	hci_pi(sk)->hdev = hdev;
+ 	sk->state = BT_BOUND;
+ 
+-	return 0;
++done:
++	release_sock(sk);
++	return err;
+ }
+ 
+ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
+@@ -262,73 +296,44 @@
+ 	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
+ 	struct sock *sk = sock->sk;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	lock_sock(sk);
+ 
+ 	*addr_len = sizeof(*haddr);
+ 	haddr->hci_family = AF_BLUETOOTH;
+ 	haddr->hci_dev    = hci_pi(sk)->hdev->id;
+ 
++	release_sock(sk);
+ 	return 0;
+ }
+ 
+-static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+-                            struct scm_cookie *scm)
+-{
+-	struct sock *sk = sock->sk;
+-	struct hci_dev *hdev = hci_pi(sk)->hdev;
+-	struct sk_buff *skb;
+-	int err;
+-
+-	DBG("sock %p sk %p", sock, sk);
+-
+-	if (msg->msg_flags & MSG_OOB)
+-		return -EOPNOTSUPP;
+-
+-	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
+-		return -EINVAL;
+-
+-	if (!hdev)
+-		return -EBADFD;
+-
+-	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
+-		return err;
+-
+-	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
+-		kfree_skb(skb);
+-		return -EFAULT;
+-	}
+-
+-	skb->dev = (void *) hdev;
+-	skb->pkt_type = *((unsigned char *) skb->data);
+-	skb_pull(skb, 1);
+-
+-	/* Send frame to HCI core */
+-	hci_send_raw(skb);
+-
+-	return len;
+-}
+-
+ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+ {
+ 	__u32 mask = hci_pi(sk)->cmsg_mask;
+ 
+ 	if (mask & HCI_CMSG_DIR)
+         	put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
++
++	if (mask & HCI_CMSG_TSTAMP)
++        	put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
+ }
+  
+-static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len,
+-                            int flags, struct scm_cookie *scm)
++static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+ {
+ 	int noblock = flags & MSG_DONTWAIT;
+ 	struct sock *sk = sock->sk;
+ 	struct sk_buff *skb;
+ 	int copied, err;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p, sk %p", sock, sk);
+ 
+-	if (flags & (MSG_OOB | MSG_PEEK))
++	if (flags & (MSG_OOB))
+ 		return -EOPNOTSUPP;
+ 
++	if (sk->state == BT_CLOSED)
++		return 0;
++
+ 	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
+ 		return err;
+ 
+@@ -343,28 +348,107 @@
+ 	skb->h.raw = skb->data;
+ 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ 
+-	if (hci_pi(sk)->cmsg_mask)
+-		hci_sock_cmsg(sk, msg, skb);
+-
++	hci_sock_cmsg(sk, msg, skb);
++	
+ 	skb_free_datagram(sk, skb);
+ 
+ 	return err ? : copied;
+ }
+ 
++static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
++                            struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	struct hci_dev *hdev;
++	struct sk_buff *skb;
++	int err;
++
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
++		return -EINVAL;
++
++	if (len < 4)
++		return -EINVAL;
++	
++	lock_sock(sk);
++
++	if (!(hdev = hci_pi(sk)->hdev)) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
++		goto done;
++
++	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
++		err = -EFAULT;
++		goto drop;
++	}
++
++	skb->pkt_type = *((unsigned char *) skb->data);
++	skb_pull(skb, 1);
++	skb->dev = (void *) hdev;
++
++	if (skb->pkt_type == HCI_COMMAND_PKT) {
++		u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
++		u16 ogf = cmd_opcode_ogf(opcode);
++		u16 ocf = cmd_opcode_ocf(opcode);
++
++		if (((ogf > HCI_SFLT_MAX_OGF) || 
++				!hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
++		    			!capable(CAP_NET_RAW)) {
++			err = -EPERM;
++			goto drop;
++		}
++
++		if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
++			skb_queue_tail(&hdev->raw_q, skb);
++			hci_sched_tx(hdev);
++		} else {
++			skb_queue_tail(&hdev->cmd_q, skb);
++			hci_sched_cmd(hdev);
++		}
++	} else {
++		if (!capable(CAP_NET_RAW)) {
++			err = -EPERM;
++			goto drop;
++		}
++
++		skb_queue_tail(&hdev->raw_q, skb);
++		hci_sched_tx(hdev);
++	}
++
++	err = len;
++
++done:
++	release_sock(sk);
++	return err;
++
++drop:
++	kfree_skb(skb);
++	goto done;
++}
++
+ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
+ {
+ 	struct sock *sk = sock->sk;
+-	struct hci_filter flt;
++	struct hci_filter flt = { opcode: 0 };
+ 	int err = 0, opt = 0;
+ 
+-	DBG("sk %p, opt %d", sk, optname);
++	BT_DBG("sk %p, opt %d", sk, optname);
+ 
+ 	lock_sock(sk);
+ 
+ 	switch (optname) {
+ 	case HCI_DATA_DIR:
+-		if (get_user(opt, (int *)optval))
+-			return -EFAULT;
++		if (get_user(opt, (int *)optval)) {
++			err = -EFAULT;
++			break;
++		}
+ 
+ 		if (opt)
+ 			hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
+@@ -372,12 +456,31 @@
+ 			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
+ 		break;
+ 
++	case HCI_TIME_STAMP:
++		if (get_user(opt, (int *)optval)) {
++			err = -EFAULT;
++			break;
++		}
++
++		if (opt)
++			hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
++		else
++			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
++		break;
++
+ 	case HCI_FILTER:
+ 		len = MIN(len, sizeof(struct hci_filter));
+ 		if (copy_from_user(&flt, optval, len)) {
+ 			err = -EFAULT;
+ 			break;
+ 		}
++
++		if (!capable(CAP_NET_RAW)) {
++			flt.type_mask     &= hci_sec_filter.type_mask;
++			flt.event_mask[0] &= hci_sec_filter.event_mask[0];
++			flt.event_mask[1] &= hci_sec_filter.event_mask[1];
++		}
++		
+ 		memcpy(&hci_pi(sk)->filter, &flt, len);
+ 		break;
+ 
+@@ -409,6 +512,16 @@
+ 			return -EFAULT;
+ 		break;
+ 
++	case HCI_TIME_STAMP:
++		if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
++			opt = 1;
++		else 
++			opt = 0;
++
++		if (put_user(opt, optval))
++			return -EFAULT;
++		break;
++
+ 	case HCI_FILTER:
+ 		len = MIN(len, sizeof(struct hci_filter));
+ 		if (copy_to_user(optval, &hci_pi(sk)->filter, len))
+@@ -446,7 +559,7 @@
+ {
+ 	struct sock *sk;
+ 
+-	DBG("sock %p", sock);
++	BT_DBG("sock %p", sock);
+ 
+ 	if (sock->type != SOCK_RAW)
+ 		return -ESOCKTNOSUPPORT;
+@@ -464,44 +577,31 @@
+ 	sk->protocol = protocol;
+ 	sk->state    = BT_OPEN;
+ 
+-	/* Initialize filter */
+-	hci_pi(sk)->filter.type_mask  = (1<<HCI_EVENT_PKT);
+-	hci_pi(sk)->filter.event_mask[0] = ~0L;
+-	hci_pi(sk)->filter.event_mask[1] = ~0L;
+-
+ 	bluez_sock_link(&hci_sk_list, sk);
+ 
+ 	MOD_INC_USE_COUNT;
+-
+ 	return 0;
+ }
+ 
+ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+ {
+ 	struct hci_dev *hdev = (struct hci_dev *) ptr;
+-	struct sk_buff *skb;
+-
+-	DBG("hdev %s event %ld", hdev->name, event);
++	evt_si_device sd;
++	
++	BT_DBG("hdev %s event %ld", hdev->name, event);
+ 
+ 	/* Send event to sockets */
+-	if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) {
+-		hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE };
+-		evt_hci_dev_event he = { event, hdev->id };
+-
+-		skb->pkt_type = HCI_EVENT_PKT;
+-		memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE);
+-		memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE);
+-
+-		hci_send_to_sock(NULL, skb);
+-		kfree_skb(skb);
+-	}
+-
++	sd.event  = event;
++	sd.dev_id = hdev->id;
++	hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd);
++	
+ 	if (event == HCI_DEV_UNREG) {
+ 		struct sock *sk;
+ 
+ 		/* Detach sockets from device */
+ 		read_lock(&hci_sk_list.lock);
+ 		for (sk = hci_sk_list.head; sk; sk = sk->next) {
++			bh_lock_sock(sk);
+ 			if (hci_pi(sk)->hdev == hdev) {
+ 				hci_pi(sk)->hdev = NULL;
+ 				sk->err = EPIPE;
+@@ -510,6 +610,7 @@
+ 
+ 				hci_dev_put(hdev);
+ 			}
++			bh_unlock_sock(sk);
+ 		}
+ 		read_unlock(&hci_sk_list.lock);
+ 	}
+@@ -529,21 +630,19 @@
+ int hci_sock_init(void)
+ {
+ 	if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
+-		ERR("Can't register HCI socket");
++		BT_ERR("Can't register HCI socket");
+ 		return -EPROTO;
+ 	}
+ 
+ 	hci_register_notifier(&hci_sock_nblock);
+-
+ 	return 0;
+ }
+ 
+ int hci_sock_cleanup(void)
+ {
+ 	if (bluez_sock_unregister(BTPROTO_HCI))
+-		ERR("Can't unregister HCI socket");
++		BT_ERR("Can't unregister HCI socket");
+ 
+ 	hci_unregister_notifier(&hci_sock_nblock);
+-
+ 	return 0;
+ }
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/l2cap.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,2187 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ L2CAP core and sockets.
++ *
++ * $Id$
++ */
++#define VERSION "2.3"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/proc_fs.h>
++#include <linux/list.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include <net/bluetooth/l2cap.h>
++
++#ifndef L2CAP_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++static struct proto_ops l2cap_sock_ops;
++
++struct bluez_sock_list l2cap_sk_list = {
++	lock: RW_LOCK_UNLOCKED
++};
++
++static int l2cap_conn_del(struct hci_conn *conn, int err);
++
++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
++static void l2cap_chan_del(struct sock *sk, int err);
++static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
++
++static void __l2cap_sock_close(struct sock *sk, int reason);
++static void l2cap_sock_close(struct sock *sk);
++static void l2cap_sock_kill(struct sock *sk);
++
++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
++
++/* ----- L2CAP timers ------ */
++static void l2cap_sock_timeout(unsigned long arg)
++{
++	struct sock *sk = (struct sock *) arg;
++
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	bh_lock_sock(sk);
++	__l2cap_sock_close(sk, ETIMEDOUT);
++	bh_unlock_sock(sk);
++
++	l2cap_sock_kill(sk);
++	sock_put(sk);
++}
++
++static void l2cap_sock_set_timer(struct sock *sk, long timeout)
++{
++	BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout);
++
++	if (!mod_timer(&sk->timer, jiffies + timeout))
++		sock_hold(sk);
++}
++
++static void l2cap_sock_clear_timer(struct sock *sk)
++{
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
++		__sock_put(sk);
++}
++
++static void l2cap_sock_init_timer(struct sock *sk)
++{
++	init_timer(&sk->timer);
++	sk->timer.function = l2cap_sock_timeout;
++	sk->timer.data = (unsigned long)sk;
++}
++
++/* -------- L2CAP connections --------- */
++static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status)
++{
++	struct l2cap_conn *conn;
++
++	if ((conn = hcon->l2cap_data))
++		return conn;
++
++	if (status)
++		return conn;
++
++	if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC)))
++		return NULL;
++	memset(conn, 0, sizeof(struct l2cap_conn));
++
++	hcon->l2cap_data = conn;
++	conn->hcon = hcon;
++	
++	conn->mtu = hcon->hdev->acl_mtu;
++	conn->src = &hcon->hdev->bdaddr;
++	conn->dst = &hcon->dst;
++	
++	spin_lock_init(&conn->lock);
++	conn->chan_list.lock = RW_LOCK_UNLOCKED;
++
++	BT_DBG("hcon %p conn %p", hcon, conn);
++
++	MOD_INC_USE_COUNT;
++	return conn;
++}
++
++static int l2cap_conn_del(struct hci_conn *hcon, int err)
++{
++	struct l2cap_conn *conn;
++	struct sock *sk;
++
++	if (!(conn = hcon->l2cap_data)) 
++		return 0;
++
++	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
++
++	if (conn->rx_skb)
++		kfree_skb(conn->rx_skb);
++
++	/* Kill channels */
++	while ((sk = conn->chan_list.head)) {
++		bh_lock_sock(sk);
++		l2cap_chan_del(sk, err);
++		bh_unlock_sock(sk);
++		l2cap_sock_kill(sk);
++	}
++
++	hcon->l2cap_data = NULL;
++	kfree(conn);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++/* -------- Socket interface ---------- */
++static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
++{
++	struct sock *sk;
++	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
++		if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
++			break;
++	}
++	return sk;
++}
++
++/* Find socket with psm and source bdaddr.
++ * Returns closest match.
++ */
++static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
++{
++	struct sock *sk, *sk1 = NULL;
++
++	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
++		if (state && sk->state != state)
++			continue;
++
++		if (l2cap_pi(sk)->psm == psm) {
++			/* Exact match. */
++			if (!bacmp(&bluez_pi(sk)->src, src))
++				break;
++
++			/* Closest match */
++			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++				sk1 = sk;
++		}
++	}
++	return sk ? sk : sk1;
++}
++
++/* Find socket with given address (psm, src).
++ * Returns locked socket */
++static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
++{
++	struct sock *s;
++	read_lock(&l2cap_sk_list.lock);
++	s = __l2cap_get_sock_by_psm(state, psm, src);
++	if (s) bh_lock_sock(s);
++	read_unlock(&l2cap_sk_list.lock);
++	return s;
++}
++
++static void l2cap_sock_destruct(struct sock *sk)
++{
++	BT_DBG("sk %p", sk);
++
++	skb_queue_purge(&sk->receive_queue);
++	skb_queue_purge(&sk->write_queue);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static void l2cap_sock_cleanup_listen(struct sock *parent)
++{
++	struct sock *sk;
++
++	BT_DBG("parent %p", parent);
++
++	/* Close not yet accepted channels */
++	while ((sk = bluez_accept_dequeue(parent, NULL)))
++		l2cap_sock_close(sk);
++
++	parent->state  = BT_CLOSED;
++	parent->zapped = 1;
++}
++
++/* Kill socket (only if zapped and orphan)
++ * Must be called on unlocked socket.
++ */
++static void l2cap_sock_kill(struct sock *sk)
++{
++	if (!sk->zapped || sk->socket)
++		return;
++
++	BT_DBG("sk %p state %d", sk, sk->state);
++
++	/* Kill poor orphan */
++	bluez_sock_unlink(&l2cap_sk_list, sk);
++	sk->dead = 1;
++	sock_put(sk);
++}
++
++/* Close socket.
++ */
++static void __l2cap_sock_close(struct sock *sk, int reason)
++{
++	BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
++
++	switch (sk->state) {
++	case BT_LISTEN:
++		l2cap_sock_cleanup_listen(sk);
++		break;
++
++	case BT_CONNECTED:
++	case BT_CONFIG:
++	case BT_CONNECT2:
++		if (sk->type == SOCK_SEQPACKET) {
++			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++			l2cap_disconn_req req;
++
++			sk->state = BT_DISCONN;
++			l2cap_sock_set_timer(sk, sk->sndtimeo);
++
++			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
++		} else {
++			l2cap_chan_del(sk, reason);
++		}
++		break;
++
++	case BT_CONNECT:
++	case BT_DISCONN:
++		l2cap_chan_del(sk, reason);
++		break;
++
++	default:
++		sk->zapped = 1;
++		break;
++	};
++}
++
++/* Must be called on unlocked socket. */
++static void l2cap_sock_close(struct sock *sk)
++{
++	l2cap_sock_clear_timer(sk);
++	lock_sock(sk);
++	__l2cap_sock_close(sk, ECONNRESET);
++	release_sock(sk);
++	l2cap_sock_kill(sk);
++}
++
++static void l2cap_sock_init(struct sock *sk, struct sock *parent)
++{
++	struct l2cap_pinfo *pi = l2cap_pi(sk);
++
++	BT_DBG("sk %p", sk);
++
++	if (parent) {
++		sk->type = parent->type;
++		pi->imtu = l2cap_pi(parent)->imtu;
++		pi->omtu = l2cap_pi(parent)->omtu;
++		pi->link_mode = l2cap_pi(parent)->link_mode;
++	} else {
++		pi->imtu = L2CAP_DEFAULT_MTU;
++		pi->omtu = 0;
++		pi->link_mode = 0;
++	}
++
++	/* Default config options */
++	pi->conf_mtu = L2CAP_DEFAULT_MTU;
++	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
++}
++
++static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
++{
++	struct sock *sk;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
++		return NULL;
++
++	bluez_sock_init(sock, sk);
++	
++	sk->zapped   = 0;
++
++	sk->destruct = l2cap_sock_destruct;
++	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
++
++	sk->protocol = proto;
++	sk->state    = BT_OPEN;
++
++	l2cap_sock_init_timer(sk);
++
++	bluez_sock_link(&l2cap_sk_list, sk);
++
++	MOD_INC_USE_COUNT;
++	return sk;
++}
++
++static int l2cap_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	sock->state = SS_UNCONNECTED;
++
++	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
++		return -EPERM;
++	
++	sock->ops = &l2cap_sock_ops;
++
++	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
++		return -ENOMEM;
++
++	l2cap_sock_init(sk, NULL);
++	return 0;
++}
++
++static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
++{
++	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
++
++	if (!addr || addr->sa_family != AF_BLUETOOTH)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_OPEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	write_lock_bh(&l2cap_sk_list.lock);
++	if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
++		err = -EADDRINUSE;
++	} else {
++		/* Save source address */
++		bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
++		l2cap_pi(sk)->psm = la->l2_psm;
++		sk->sport = la->l2_psm;
++		sk->state = BT_BOUND;
++	}
++	write_unlock_bh(&l2cap_sk_list.lock);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_do_connect(struct sock *sk)
++{
++	bdaddr_t *src = &bluez_pi(sk)->src;
++	bdaddr_t *dst = &bluez_pi(sk)->dst;
++	struct l2cap_conn *conn;
++	struct hci_conn   *hcon;
++	struct hci_dev    *hdev;
++	int err = 0;
++
++	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
++
++	if (!(hdev = hci_get_route(dst, src)))
++		return -EHOSTUNREACH;
++
++	hci_dev_lock_bh(hdev);
++
++	err = -ENOMEM;
++
++	hcon = hci_connect(hdev, ACL_LINK, dst);
++	if (!hcon)
++		goto done;
++
++	conn = l2cap_conn_add(hcon, 0);
++	if (!conn) {
++		hci_conn_put(hcon);
++		goto done;
++	}
++
++	err = 0;
++
++	/* Update source addr of the socket */
++	bacpy(src, conn->src);
++
++	l2cap_chan_add(conn, sk, NULL);
++
++	sk->state = BT_CONNECT;
++	l2cap_sock_set_timer(sk, sk->sndtimeo);
++
++	if (hcon->state == BT_CONNECTED) {
++		if (sk->type == SOCK_SEQPACKET) {
++			l2cap_conn_req req;
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			req.psm  = l2cap_pi(sk)->psm;
++			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
++		} else {
++			l2cap_sock_clear_timer(sk);
++			sk->state = BT_CONNECTED;
++		}
++	}
++
++done:
++	hci_dev_unlock_bh(hdev);
++	hci_dev_put(hdev);
++	return err;
++}
++
++static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
++{
++	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	lock_sock(sk);
++
++	BT_DBG("sk %p", sk);
++
++	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
++		err = -EINVAL;
++		goto done;
++	}
++
++	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
++		err = -EINVAL;
++		goto done;
++	}
++
++	switch(sk->state) {
++	case BT_CONNECT:
++	case BT_CONNECT2:
++	case BT_CONFIG:
++		/* Already connecting */
++		goto wait;
++
++	case BT_CONNECTED:
++		/* Already connected */
++		goto done;
++
++	case BT_OPEN:
++	case BT_BOUND:
++		/* Can connect */
++		break;
++
++	default:
++		err = -EBADFD;
++		goto done;
++	}
++
++	/* Set destination address and psm */
++	bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
++	l2cap_pi(sk)->psm = la->l2_psm;
++
++	if ((err = l2cap_do_connect(sk)))
++		goto done;
++
++wait:
++	err = bluez_sock_wait_state(sk, BT_CONNECTED,
++			sock_sndtimeo(sk, flags & O_NONBLOCK));
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int l2cap_sock_listen(struct socket *sock, int backlog)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p backlog %d", sk, backlog);
++
++	lock_sock(sk);
++
++	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	if (!l2cap_pi(sk)->psm) {
++		err = -EINVAL;
++		goto done;
++	}
++
++	sk->max_ack_backlog = backlog;
++	sk->ack_backlog = 0;
++	sk->state = BT_LISTEN;
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct sock *sk = sock->sk, *nsk;
++	long timeo;
++	int err = 0;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_LISTEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
++
++	BT_DBG("sk %p timeo %ld", sk, timeo);
++
++	/* Wait for an incoming connection. (wake-one). */
++	add_wait_queue_exclusive(sk->sleep, &wait);
++	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->state != BT_LISTEN) {
++			err = -EBADFD;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	if (err)
++		goto done;
++
++	newsock->state = SS_CONNECTED;
++
++	BT_DBG("new socket %p", nsk);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
++{
++	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	addr->sa_family = AF_BLUETOOTH;
++	*len = sizeof(struct sockaddr_l2);
++
++	if (peer)
++		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);
++	else
++		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);
++
++	la->l2_psm = l2cap_pi(sk)->psm;
++	return 0;
++}
++
++static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (sk->err)
++		return sock_error(sk);
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	/* Check outgoing MTU */
++	if (len > l2cap_pi(sk)->omtu)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state == BT_CONNECTED)
++		err = l2cap_chan_send(sk, msg, len);
++	else
++		err = -ENOTCONN;
++
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
++{
++	struct sock *sk = sock->sk;
++	struct l2cap_options opts;
++	int err = 0, len;
++	__u32 opt;
++
++	BT_DBG("sk %p", sk);
++
++	lock_sock(sk);
++
++	switch (optname) {
++	case L2CAP_OPTIONS:
++		len = MIN(sizeof(opts), optlen);
++		if (copy_from_user((char *)&opts, optval, len)) {
++			err = -EFAULT;
++			break;
++		}
++		l2cap_pi(sk)->imtu  = opts.imtu;
++		l2cap_pi(sk)->omtu  = opts.omtu;
++		break;
++
++	case L2CAP_LM:
++		if (get_user(opt, (__u32 *)optval)) {
++			err = -EFAULT;
++			break;
++		}
++
++		l2cap_pi(sk)->link_mode = opt;
++		break;
++
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	}
++
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
++{
++	struct sock *sk = sock->sk;
++	struct l2cap_options opts;
++	struct l2cap_conninfo cinfo;
++	int len, err = 0; 
++
++	if (get_user(len, optlen))
++		return -EFAULT;
++
++	lock_sock(sk);
++
++	switch (optname) {
++	case L2CAP_OPTIONS:
++		opts.imtu     = l2cap_pi(sk)->imtu;
++		opts.omtu     = l2cap_pi(sk)->omtu;
++		opts.flush_to = l2cap_pi(sk)->flush_to;
++
++		len = MIN(len, sizeof(opts));
++		if (copy_to_user(optval, (char *)&opts, len))
++			err = -EFAULT;
++
++		break;
++
++	case L2CAP_LM:
++		if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval))
++			err = -EFAULT;
++		break;
++
++	case L2CAP_CONNINFO:
++		if (sk->state != BT_CONNECTED) {
++			err = -ENOTCONN;
++			break;
++		}
++
++		cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
++
++		len = MIN(len, sizeof(cinfo));
++		if (copy_to_user(optval, (char *)&cinfo, len))
++			err = -EFAULT;
++
++		break;
++
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	}
++
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_shutdown(struct socket *sock, int how)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk) return 0;
++
++	lock_sock(sk);
++	if (!sk->shutdown) {
++		sk->shutdown = SHUTDOWN_MASK;
++		l2cap_sock_clear_timer(sk);
++		__l2cap_sock_close(sk, 0);
++
++		if (sk->linger)
++			err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
++	}
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++	int err;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk) return 0;
++
++	err = l2cap_sock_shutdown(sock, 2);
++
++	sock_orphan(sk);
++	l2cap_sock_kill(sk);
++	return err;
++}
++
++/* --------- L2CAP channels --------- */
++static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
++{
++	struct sock *s;
++	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
++		if (l2cap_pi(s)->dcid == cid)
++			break;
++	}
++	return s;
++}
++
++static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
++{
++	struct sock *s;
++	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
++		if (l2cap_pi(s)->scid == cid)
++			break;
++	}
++	return s;
++}
++
++/* Find channel with given SCID.
++ * Returns locked socket */
++static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
++{
++	struct sock *s;
++	read_lock(&l->lock);
++	s = __l2cap_get_chan_by_scid(l, cid);
++	if (s) bh_lock_sock(s);
++	read_unlock(&l->lock);
++	return s;
++}
++
++static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
++{
++	__u16 cid = 0x0040;
++
++	for (; cid < 0xffff; cid++) {
++		if(!__l2cap_get_chan_by_scid(l, cid))
++			return cid;
++	}
++
++	return 0;
++}
++
++static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
++{
++	sock_hold(sk);
++
++	if (l->head)
++		l2cap_pi(l->head)->prev_c = sk;
++
++	l2cap_pi(sk)->next_c = l->head;
++	l2cap_pi(sk)->prev_c = NULL;
++	l->head = sk;
++}
++
++static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
++{
++	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
++
++	write_lock(&l->lock);
++	if (sk == l->head)
++		l->head = next;
++
++	if (next)
++		l2cap_pi(next)->prev_c = prev;
++	if (prev)
++		l2cap_pi(prev)->next_c = next;
++	write_unlock(&l->lock);
++
++	__sock_put(sk);
++}
++
++static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++
++	BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
++
++	l2cap_pi(sk)->conn = conn;
++
++	if (sk->type == SOCK_SEQPACKET) {
++		/* Alloc CID for connection-oriented socket */
++		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
++	} else if (sk->type == SOCK_DGRAM) {
++		/* Connectionless socket */
++		l2cap_pi(sk)->scid = 0x0002;
++		l2cap_pi(sk)->dcid = 0x0002;
++		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
++	} else {
++		/* Raw socket can send/recv signalling messages only */
++		l2cap_pi(sk)->scid = 0x0001;
++		l2cap_pi(sk)->dcid = 0x0001;
++		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
++	}
++
++	__l2cap_chan_link(l, sk);
++
++	if (parent)
++		bluez_accept_enqueue(parent, sk);
++}
++
++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	write_lock(&l->lock);
++	__l2cap_chan_add(conn, sk, parent);
++	write_unlock(&l->lock);
++}
++
++/* Delete channel. 
++ * Must be called on the locked socket. */
++static void l2cap_chan_del(struct sock *sk, int err)
++{
++	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++	struct sock *parent = bluez_pi(sk)->parent;
++
++	l2cap_sock_clear_timer(sk);
++
++	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
++
++	if (conn) { 
++		/* Unlink from channel list */
++		l2cap_chan_unlink(&conn->chan_list, sk);
++		l2cap_pi(sk)->conn = NULL;
++		hci_conn_put(conn->hcon);
++	}
++
++	sk->state  = BT_CLOSED;
++	sk->zapped = 1;
++
++	if (err)
++		sk->err = err;
++
++	if (parent)
++		parent->data_ready(parent, 0);
++	else
++		sk->state_change(sk);
++}
++
++static void l2cap_conn_ready(struct l2cap_conn *conn)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	struct sock *sk;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		bh_lock_sock(sk);
++
++		if (sk->type != SOCK_SEQPACKET) {
++			l2cap_sock_clear_timer(sk);
++			sk->state = BT_CONNECTED;
++			sk->state_change(sk);
++		} else if (sk->state == BT_CONNECT) {
++			l2cap_conn_req req;
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			req.psm  = l2cap_pi(sk)->psm;
++			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
++		}
++
++		bh_unlock_sock(sk);
++	}
++
++	read_unlock(&l->lock);
++}
++
++/* Notify sockets that we cannot guaranty reliability anymore */
++static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	struct sock *sk;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
++			sk->err = err;
++	}
++	read_unlock(&l->lock);
++}
++
++static void l2cap_chan_ready(struct sock *sk)
++{
++	struct sock *parent = bluez_pi(sk)->parent;
++
++	BT_DBG("sk %p, parent %p", sk, parent);
++
++	l2cap_pi(sk)->conf_state = 0;
++	l2cap_sock_clear_timer(sk);
++
++	if (!parent) {
++		/* Outgoing channel.
++		 * Wake up socket sleeping on connect.
++		 */
++		sk->state = BT_CONNECTED;
++		sk->state_change(sk);
++	} else {
++		/* Incomming channel.
++		 * Wake up socket sleeping on accept.
++		 */
++		parent->data_ready(parent, 0);
++	}
++}
++
++/* Copy frame to all raw sockets on that connection */
++void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	struct sk_buff *nskb;
++	struct sock * sk;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		if (sk->type != SOCK_RAW)
++			continue;
++
++		/* Don't send frame to the socket it came from */
++		if (skb->sk == sk)
++			continue;
++
++		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
++			continue;
++
++		if (sock_queue_rcv_skb(sk, nskb))
++			kfree_skb(nskb);
++	}
++	read_unlock(&l->lock);
++}
++
++static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
++{
++	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++	struct sk_buff *skb, **frag;
++	int err, hlen, count, sent=0;
++	l2cap_hdr *lh;
++
++	BT_DBG("sk %p len %d", sk, len);
++
++	/* First fragment (with L2CAP header) */
++	if (sk->type == SOCK_DGRAM)
++		hlen = L2CAP_HDR_SIZE + 2;
++	else
++		hlen = L2CAP_HDR_SIZE;
++
++	count = MIN(conn->mtu - hlen, len);
++
++	skb = bluez_skb_send_alloc(sk, hlen + count,
++			msg->msg_flags & MSG_DONTWAIT, &err);
++	if (!skb)
++		return err;
++
++	/* Create L2CAP header */
++	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
++	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++	lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
++
++	if (sk->type == SOCK_DGRAM)
++		put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));
++
++	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
++		err = -EFAULT;
++		goto fail;
++	}
++
++	sent += count;
++	len  -= count;
++
++	/* Continuation fragments (no L2CAP header) */
++	frag = &skb_shinfo(skb)->frag_list;
++	while (len) {
++		count = MIN(conn->mtu, len);
++
++		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
++		if (!*frag)
++			goto fail;
++		
++		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
++			err = -EFAULT;
++			goto fail;
++		}
++
++		sent += count;
++		len  -= count;
++
++		frag = &(*frag)->next;
++	}
++
++	if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
++		goto fail;
++
++	return sent;
++
++fail:
++	kfree_skb(skb);
++	return err;
++}
++
++/* --------- L2CAP signalling commands --------- */
++static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
++{
++	__u8 id;
++
++	/* Get next available identificator.
++	 *    1 - 199 are used by kernel.
++	 *  200 - 254 are used by utilities like l2ping, etc 
++	 */
++
++	spin_lock(&conn->lock);
++
++	if (++conn->tx_ident > 199)
++		conn->tx_ident = 1;
++
++	id = conn->tx_ident;
++
++	spin_unlock(&conn->lock);
++
++	return id;
++}
++
++static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
++				__u8 code, __u8 ident, __u16 dlen, void *data)
++{
++	struct sk_buff *skb, **frag;
++	l2cap_cmd_hdr *cmd;
++	l2cap_hdr *lh;
++	int len, count;
++
++	BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
++
++	len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
++	count = MIN(conn->mtu, len);
++	
++	skb = bluez_skb_alloc(count, GFP_ATOMIC);
++	if (!skb)
++		return NULL;
++
++	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
++	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
++	lh->cid = __cpu_to_le16(0x0001);
++
++	cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
++	cmd->code  = code;
++	cmd->ident = ident;
++	cmd->len   = __cpu_to_le16(dlen);
++
++	if (dlen) {
++		count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
++		memcpy(skb_put(skb, count), data, count);
++		data += count;
++	}
++
++	len -= skb->len;
++	
++	/* Continuation fragments (no L2CAP header) */
++	frag = &skb_shinfo(skb)->frag_list;
++	while (len) {
++		count = MIN(conn->mtu, len);
++
++		*frag = bluez_skb_alloc(count, GFP_ATOMIC);
++		if (!*frag)
++			goto fail;
++		
++		memcpy(skb_put(*frag, count), data, count);
++
++		len  -= count;
++		data += count;
++		
++		frag = &(*frag)->next;
++	}
++
++	return skb;
++
++fail:
++	kfree_skb(skb);
++	return NULL;
++}
++
++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
++{
++	__u8 ident = l2cap_get_ident(conn);
++	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
++
++	BT_DBG("code 0x%2.2x", code);
++
++	if (!skb)
++		return -ENOMEM;
++	return hci_send_acl(conn->hcon, skb, 0);
++}
++
++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
++{
++	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
++
++	BT_DBG("code 0x%2.2x", code);
++
++	if (!skb)
++		return -ENOMEM;
++	return hci_send_acl(conn->hcon, skb, 0);
++}
++
++static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
++{
++	l2cap_conf_opt *opt = *ptr;
++	int len;
++
++	len = L2CAP_CONF_OPT_SIZE + opt->len;
++	*ptr += len;
++
++	*type = opt->type;
++	*olen = opt->len;
++
++	switch (opt->len) {
++	case 1:
++		*val = *((__u8 *) opt->val);
++		break;
++
++	case 2:
++		*val = __le16_to_cpu(*((__u16 *)opt->val));
++		break;
++
++	case 4:
++		*val = __le32_to_cpu(*((__u32 *)opt->val));
++		break;
++
++	default:
++		*val = (unsigned long) opt->val;
++		break;
++	};
++
++	BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
++	return len;
++}
++
++static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len)
++{
++	int type, hint, olen; 
++	unsigned long val;
++	void *ptr = data;
++
++	BT_DBG("sk %p len %d", sk, len);
++
++	while (len >= L2CAP_CONF_OPT_SIZE) {
++		len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val);
++
++		hint  = type & 0x80;
++		type &= 0x7f;
++
++		switch (type) {
++		case L2CAP_CONF_MTU:
++			l2cap_pi(sk)->conf_mtu = val;
++			break;
++
++		case L2CAP_CONF_FLUSH_TO:
++			l2cap_pi(sk)->flush_to = val;
++			break;
++
++		case L2CAP_CONF_QOS:
++			break;
++		
++		default:
++			if (hint)
++				break;
++
++			/* FIXME: Reject unknown option */
++			break;
++		};
++	}
++}
++
++static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val)
++{
++	register l2cap_conf_opt *opt = *ptr;
++
++	BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
++
++	opt->type = type;
++	opt->len  = len;
++
++	switch (len) {
++	case 1:
++		*((__u8 *) opt->val)  = val;
++		break;
++
++	case 2:
++		*((__u16 *) opt->val) = __cpu_to_le16(val);
++		break;
++
++	case 4:
++		*((__u32 *) opt->val) = __cpu_to_le32(val);
++		break;
++
++	default:
++		memcpy(opt->val, (void *) val, len);
++		break;
++	};
++
++	*ptr += L2CAP_CONF_OPT_SIZE + len;
++}
++
++static int l2cap_build_conf_req(struct sock *sk, void *data)
++{
++	struct l2cap_pinfo *pi = l2cap_pi(sk);
++	l2cap_conf_req *req = (l2cap_conf_req *) data;
++	void *ptr = req->data;
++
++	BT_DBG("sk %p", sk);
++
++	if (pi->imtu != L2CAP_DEFAULT_MTU)
++		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
++
++	/* FIXME. Need actual value of the flush timeout */
++	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
++	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
++
++	req->dcid  = __cpu_to_le16(pi->dcid);
++	req->flags = __cpu_to_le16(0);
++
++	return ptr - data;
++}
++
++static inline int l2cap_conf_output(struct sock *sk, void **ptr)
++{
++	struct l2cap_pinfo *pi = l2cap_pi(sk);
++	int result = 0;
++
++	/* Configure output options and let the other side know
++	 * which ones we don't like.
++	 */
++	if (pi->conf_mtu < pi->omtu) {
++		l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
++		result = L2CAP_CONF_UNACCEPT;
++	} else {
++		pi->omtu = pi->conf_mtu;
++	}
++
++	BT_DBG("sk %p result %d", sk, result);
++	return result;
++}
++
++static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result)
++{
++	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
++	void *ptr = rsp->data;
++	u16 flags = 0;
++
++	BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
++
++	if (result)
++		*result = l2cap_conf_output(sk, &ptr);
++	else	
++		flags |= 0x0001;
++
++	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
++	rsp->result = __cpu_to_le16(result ? *result : 0);
++	rsp->flags  = __cpu_to_le16(flags);
++
++	return ptr - data;
++}
++
++static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	struct l2cap_chan_list *list = &conn->chan_list;
++	l2cap_conn_req *req = (l2cap_conn_req *) data;
++	l2cap_conn_rsp rsp;
++	struct sock *sk, *parent;
++	int result = 0, status = 0;
++
++	__u16 dcid = 0, scid = __le16_to_cpu(req->scid);
++	__u16 psm  = req->psm;
++
++	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
++
++	/* Check if we have socket listening on psm */
++	parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
++	if (!parent) {
++		result = L2CAP_CR_BAD_PSM;
++		goto sendresp;
++	}
++
++	result = L2CAP_CR_NO_MEM;
++
++	/* Check for backlog size */
++	if (parent->ack_backlog > parent->max_ack_backlog) {
++		BT_DBG("backlog full %d", parent->ack_backlog); 
++		goto response;
++	}
++
++	sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
++	if (!sk)
++		goto response;
++
++	write_lock(&list->lock);
++
++	/* Check if we already have channel with that dcid */
++	if (__l2cap_get_chan_by_dcid(list, scid)) {
++		write_unlock(&list->lock);
++		sk->zapped = 1;
++		l2cap_sock_kill(sk);
++		goto response;
++	}
++
++	hci_conn_hold(conn->hcon);
++
++	l2cap_sock_init(sk, parent);
++	bacpy(&bluez_pi(sk)->src, conn->src);
++	bacpy(&bluez_pi(sk)->dst, conn->dst);
++	l2cap_pi(sk)->psm  = psm;
++	l2cap_pi(sk)->dcid = scid;
++
++	__l2cap_chan_add(conn, sk, parent);
++	dcid = l2cap_pi(sk)->scid;
++
++	l2cap_sock_set_timer(sk, sk->sndtimeo);
++
++	/* Service level security */
++	result = L2CAP_CR_PEND;
++	status = L2CAP_CS_AUTHEN_PEND;
++	sk->state = BT_CONNECT2;
++	l2cap_pi(sk)->ident = cmd->ident;
++	
++	if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
++		if (!hci_conn_encrypt(conn->hcon))
++			goto done;
++	} else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
++		if (!hci_conn_auth(conn->hcon))
++			goto done;
++	}
++
++	sk->state = BT_CONFIG;
++	result = status = 0;
++
++done:
++	write_unlock(&list->lock);
++
++response:
++	bh_unlock_sock(parent);
++
++sendresp:
++	rsp.scid   = __cpu_to_le16(scid);
++	rsp.dcid   = __cpu_to_le16(dcid);
++	rsp.result = __cpu_to_le16(result);
++	rsp.status = __cpu_to_le16(status);
++	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
++	return 0;
++}
++
++static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
++	__u16 scid, dcid, result, status;
++	struct sock *sk;
++	char req[128];
++
++	scid   = __le16_to_cpu(rsp->scid);
++	dcid   = __le16_to_cpu(rsp->dcid);
++	result = __le16_to_cpu(rsp->result);
++	status = __le16_to_cpu(rsp->status);
++
++	BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
++		return -ENOENT;
++
++	switch (result) {
++	case L2CAP_CR_SUCCESS:
++		sk->state = BT_CONFIG;
++		l2cap_pi(sk)->dcid = dcid;
++		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
++
++		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
++		break;
++
++	case L2CAP_CR_PEND:
++		break;
++
++	default:
++		l2cap_chan_del(sk, ECONNREFUSED);
++		break;
++	}
++
++	bh_unlock_sock(sk);
++	return 0;
++}
++
++static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_conf_req * req = (l2cap_conf_req *) data;
++	__u16 dcid, flags;
++	__u8 rsp[64];
++	struct sock *sk;
++	int result;
++
++	dcid  = __le16_to_cpu(req->dcid);
++	flags = __le16_to_cpu(req->flags);
++
++	BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
++		return -ENOENT;
++
++	l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
++
++	if (flags & 0x0001) {
++		/* Incomplete config. Send empty response. */
++		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
++		goto unlock;
++	}
++
++	/* Complete config. */
++	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
++
++	if (result)
++		goto unlock;
++
++	/* Output config done */
++	l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
++
++	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
++		sk->state = BT_CONNECTED;
++		l2cap_chan_ready(sk);
++	} else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
++		char req[64];
++		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
++	}
++
++unlock:
++	bh_unlock_sock(sk);
++	return 0;
++}
++
++static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
++	__u16 scid, flags, result;
++	struct sock *sk;
++	int err = 0;
++
++	scid   = __le16_to_cpu(rsp->scid);
++	flags  = __le16_to_cpu(rsp->flags);
++	result = __le16_to_cpu(rsp->result);
++
++	BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
++		return -ENOENT;
++
++	switch (result) {
++	case L2CAP_CONF_SUCCESS:
++		break;
++
++	case L2CAP_CONF_UNACCEPT:
++		if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
++			char req[128];
++			/* 
++			   It does not make sense to adjust L2CAP parameters 
++			   that are currently defined in the spec. We simply 
++			   resend config request that we sent earlier. It is
++			   stupid :) but it helps qualification testing
++			   which expects at least some response from us.
++			*/
++			l2cap_send_req(conn, L2CAP_CONF_REQ,
++				l2cap_build_conf_req(sk, req), req);
++			goto done;
++		}
++	default: 
++		sk->state = BT_DISCONN;
++		sk->err   = ECONNRESET;
++		l2cap_sock_set_timer(sk, HZ * 5);
++		{
++			l2cap_disconn_req req;
++			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
++		}
++		goto done;
++	}
++
++	if (flags & 0x01)
++		goto done;
++
++	/* Input config done */
++	l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
++
++	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
++		sk->state = BT_CONNECTED;
++		l2cap_chan_ready(sk);
++	}
++
++done:
++	bh_unlock_sock(sk);
++	return err;
++}
++
++static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_disconn_req *req = (l2cap_disconn_req *) data;
++	l2cap_disconn_rsp rsp;
++	__u16 dcid, scid;
++	struct sock *sk;
++
++	scid = __le16_to_cpu(req->scid);
++	dcid = __le16_to_cpu(req->dcid);
++
++	BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
++		return 0;
++
++	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
++	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++	l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
++
++	sk->shutdown = SHUTDOWN_MASK;
++	
++	l2cap_chan_del(sk, ECONNRESET);
++	bh_unlock_sock(sk);
++
++	l2cap_sock_kill(sk);
++	return 0;
++}
++
++static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
++	__u16 dcid, scid;
++	struct sock *sk;
++
++	scid = __le16_to_cpu(rsp->scid);
++	dcid = __le16_to_cpu(rsp->dcid);
++
++	BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
++		return 0;
++	l2cap_chan_del(sk, 0);
++	bh_unlock_sock(sk);
++
++	l2cap_sock_kill(sk);
++	return 0;
++}
++
++static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
++{
++	__u8 *data = skb->data;
++	int len = skb->len;
++	l2cap_cmd_hdr cmd;
++	int err = 0;
++
++	while (len >= L2CAP_CMD_HDR_SIZE) {
++		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
++		data += L2CAP_CMD_HDR_SIZE;
++		len  -= L2CAP_CMD_HDR_SIZE;
++
++		cmd.len = __le16_to_cpu(cmd.len);
++
++		BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
++
++		if (cmd.len > len || !cmd.ident) {
++			BT_DBG("corrupted command");
++			break;
++		}
++
++		switch (cmd.code) {
++		case L2CAP_CONN_REQ:
++			err = l2cap_connect_req(conn, &cmd, data);
++			break;
++
++		case L2CAP_CONN_RSP:
++			err = l2cap_connect_rsp(conn, &cmd, data);
++			break;
++
++		case L2CAP_CONF_REQ:
++			err = l2cap_config_req(conn, &cmd, data);
++			break;
++
++		case L2CAP_CONF_RSP:
++			err = l2cap_config_rsp(conn, &cmd, data);
++			break;
++
++		case L2CAP_DISCONN_REQ:
++			err = l2cap_disconnect_req(conn, &cmd, data);
++			break;
++
++		case L2CAP_DISCONN_RSP:
++			err = l2cap_disconnect_rsp(conn, &cmd, data);
++			break;
++
++		case L2CAP_COMMAND_REJ:
++			/* FIXME: We should process this */
++			l2cap_raw_recv(conn, skb);
++			break;
++
++		case L2CAP_ECHO_REQ:
++			l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
++			break;
++
++		case L2CAP_ECHO_RSP:
++		case L2CAP_INFO_REQ:
++		case L2CAP_INFO_RSP:
++			l2cap_raw_recv(conn, skb);
++			break;
++
++		default:
++			BT_ERR("Uknown signaling command 0x%2.2x", cmd.code);
++			err = -EINVAL;
++			break;
++		};
++
++		if (err) {
++			l2cap_cmd_rej rej;
++			BT_DBG("error %d", err);
++
++			/* FIXME: Map err to a valid reason. */
++			rej.reason = __cpu_to_le16(0);
++			l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
++		}
++
++		data += cmd.len;
++		len  -= cmd.len;
++	}
++
++	kfree_skb(skb);
++}
++
++static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
++{
++	struct sock *sk;
++
++	sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
++	if (!sk) {
++		BT_DBG("unknown cid 0x%4.4x", cid);
++		goto drop;
++	}
++
++	BT_DBG("sk %p, len %d", sk, skb->len);
++
++	if (sk->state != BT_CONNECTED)
++		goto drop;
++
++	if (l2cap_pi(sk)->imtu < skb->len)
++		goto drop;
++
++	/* If socket recv buffers overflows we drop data here 
++	 * which is *bad* because L2CAP has to be reliable. 
++	 * But we don't have any other choice. L2CAP doesn't 
++	 * provide flow control mechanism */ 
++	
++	if (!sock_queue_rcv_skb(sk, skb))
++		goto done;
++
++drop:
++	kfree_skb(skb);
++
++done:
++	if (sk) bh_unlock_sock(sk);
++	return 0;
++}
++
++static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb)
++{
++	struct sock *sk;
++
++	sk = l2cap_get_sock_by_psm(0, psm, conn->src);
++	if (!sk)
++		goto drop;
++
++	BT_DBG("sk %p, len %d", sk, skb->len);
++
++	if (sk->state != BT_BOUND && sk->state != BT_CONNECTED)
++		goto drop;
++
++	if (l2cap_pi(sk)->imtu < skb->len)
++		goto drop;
++
++	if (!sock_queue_rcv_skb(sk, skb))
++		goto done;
++
++drop:
++	kfree_skb(skb);
++
++done:
++	if (sk) bh_unlock_sock(sk);
++	return 0;
++}
++
++static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
++{
++	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
++	__u16 cid, psm, len;
++
++	skb_pull(skb, L2CAP_HDR_SIZE);
++	cid = __le16_to_cpu(lh->cid);
++	len = __le16_to_cpu(lh->len);
++
++	BT_DBG("len %d, cid 0x%4.4x", len, cid);
++
++	switch (cid) {
++	case 0x0001:
++		l2cap_sig_channel(conn, skb);
++		break;
++
++	case 0x0002:
++		psm = get_unaligned((__u16 *) skb->data);
++		skb_pull(skb, 2);
++		l2cap_conless_channel(conn, psm, skb);
++		break;
++		
++	default:
++		l2cap_data_channel(conn, cid, skb);
++		break;
++	}
++}
++
++/* ------------ L2CAP interface with lower layer (HCI) ------------- */
++
++static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
++{
++	int exact = 0, lm1 = 0, lm2 = 0;
++	register struct sock *sk;
++
++	if (type != ACL_LINK)
++		return 0;
++
++	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
++
++	/* Find listening sockets and check their link_mode */
++	read_lock(&l2cap_sk_list.lock);
++	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
++		if (sk->state != BT_LISTEN)
++			continue;
++
++		if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) {
++			lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
++			exact++;
++		} else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++			lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
++	}
++	read_unlock(&l2cap_sk_list.lock);
++
++	return exact ? lm1 : lm2;
++}
++
++static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status)
++{
++	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
++
++	if (hcon->type != ACL_LINK)
++		return 0;
++
++	if (!status) {
++		struct l2cap_conn *conn;
++
++		conn = l2cap_conn_add(hcon, status);
++		if (conn)
++			l2cap_conn_ready(conn);
++	} else 
++		l2cap_conn_del(hcon, bterr(status));
++	
++	return 0;
++}
++
++static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason)
++{
++	BT_DBG("hcon %p reason %d", hcon, reason);
++
++	if (hcon->type != ACL_LINK)
++		return 0;
++
++	l2cap_conn_del(hcon, bterr(reason));
++	return 0;
++}
++
++static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status)
++{
++	struct l2cap_chan_list *l;
++	struct l2cap_conn *conn;
++	l2cap_conn_rsp rsp;
++	struct sock *sk;
++	int result;
++	
++	if (!(conn = hcon->l2cap_data))
++		return 0;
++	l = &conn->chan_list;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		bh_lock_sock(sk);
++
++		if (sk->state != BT_CONNECT2 ||
++				(l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) {
++			bh_unlock_sock(sk);
++			continue;
++		}
++
++		if (!status) {
++			sk->state = BT_CONFIG;
++			result = 0;
++		} else {
++			sk->state = BT_DISCONN;
++			l2cap_sock_set_timer(sk, HZ/10);
++			result = L2CAP_CR_SEC_BLOCK;
++		}
++
++		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
++		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
++		rsp.result = __cpu_to_le16(result);
++		rsp.status = __cpu_to_le16(0);
++		l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
++			L2CAP_CONN_RSP_SIZE, &rsp);
++
++		bh_unlock_sock(sk);
++	}
++
++	read_unlock(&l->lock);
++	return 0;
++}
++
++static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status)
++{
++	struct l2cap_chan_list *l;
++	struct l2cap_conn *conn;
++	l2cap_conn_rsp rsp;
++	struct sock *sk;
++	int result;
++	
++	if (!(conn = hcon->l2cap_data))
++		return 0;
++	l = &conn->chan_list;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		bh_lock_sock(sk);
++
++		if (sk->state != BT_CONNECT2) {
++			bh_unlock_sock(sk);
++			continue;
++		}
++
++		if (!status) {
++			sk->state = BT_CONFIG;
++			result = 0;
++		} else {
++			sk->state = BT_DISCONN;
++			l2cap_sock_set_timer(sk, HZ/10);
++			result = L2CAP_CR_SEC_BLOCK;
++		}
++
++		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
++		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
++		rsp.result = __cpu_to_le16(result);
++		rsp.status = __cpu_to_le16(0);
++		l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, 
++			L2CAP_CONN_RSP_SIZE, &rsp);
++
++		bh_unlock_sock(sk);
++	}
++
++	read_unlock(&l->lock);
++	return 0;
++}
++
++static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags)
++{
++	struct l2cap_conn *conn = hcon->l2cap_data;
++
++	if (!conn && !(conn = l2cap_conn_add(hcon, 0)))
++		goto drop;
++
++	BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
++
++	if (flags & ACL_START) {
++		l2cap_hdr *hdr;
++		int len;
++
++		if (conn->rx_len) {
++			BT_ERR("Unexpected start frame (len %d)", skb->len);
++			kfree_skb(conn->rx_skb);
++			conn->rx_skb = NULL;
++			conn->rx_len = 0;
++			l2cap_conn_unreliable(conn, ECOMM);
++		}
++
++		if (skb->len < 2) {
++			BT_ERR("Frame is too short (len %d)", skb->len);
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		hdr = (l2cap_hdr *) skb->data;
++		len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
++
++		if (len == skb->len) {
++			/* Complete frame received */
++			l2cap_recv_frame(conn, skb);
++			return 0;
++		}
++
++		BT_DBG("Start: total len %d, frag len %d", len, skb->len);
++
++		if (skb->len > len) {
++			BT_ERR("Frame is too long (len %d, expected len %d)",
++				skb->len, len);
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		/* Allocate skb for the complete frame including header */
++		conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC);
++		if (!conn->rx_skb)
++			goto drop;
++
++		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
++		conn->rx_len = len - skb->len;
++	} else {
++		BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
++
++		if (!conn->rx_len) {
++			BT_ERR("Unexpected continuation frame (len %d)", skb->len);
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		if (skb->len > conn->rx_len) {
++			BT_ERR("Fragment is too long (len %d, expected %d)",
++					skb->len, conn->rx_len);
++			kfree_skb(conn->rx_skb);
++			conn->rx_skb = NULL;
++			conn->rx_len = 0;
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
++		conn->rx_len -= skb->len;
++
++		if (!conn->rx_len) {
++			/* Complete frame received */
++			l2cap_recv_frame(conn, conn->rx_skb);
++			conn->rx_skb = NULL;
++		}
++	}
++
++drop:
++	kfree_skb(skb);
++	return 0;
++}
++
++/* ----- Proc fs support ------ */
++static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
++{
++	struct l2cap_pinfo *pi;
++	struct sock *sk;
++	char *ptr = buf;
++
++	read_lock_bh(&list->lock);
++
++	for (sk = list->head; sk; sk = sk->next) {
++		pi = l2cap_pi(sk);
++		ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), 
++				sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
++				pi->link_mode);
++	}
++
++	read_unlock_bh(&list->lock);
++
++	ptr += sprintf(ptr, "\n");
++	return ptr - buf;
++}
++
++static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
++{
++	char *ptr = buf;
++	int len;
++
++	BT_DBG("count %d, offset %ld", count, offset);
++
++	ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
++	len  = ptr - buf;
++
++	if (len <= count + offset)
++		*eof = 1;
++
++	*start = buf + offset;
++	len -= offset;
++
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++
++static struct proto_ops l2cap_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	l2cap_sock_release,
++	bind:		l2cap_sock_bind,
++	connect:	l2cap_sock_connect,
++	listen:		l2cap_sock_listen,
++	accept:		l2cap_sock_accept,
++	getname:	l2cap_sock_getname,
++	sendmsg:	l2cap_sock_sendmsg,
++	recvmsg:	bluez_sock_recvmsg,
++	poll:		bluez_sock_poll,
++	socketpair:	sock_no_socketpair,
++	ioctl:		sock_no_ioctl,
++	shutdown:	l2cap_sock_shutdown,
++	setsockopt:	l2cap_sock_setsockopt,
++	getsockopt:	l2cap_sock_getsockopt,
++	mmap:		sock_no_mmap
++};
++
++static struct net_proto_family l2cap_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		l2cap_sock_create
++};
++
++static struct hci_proto l2cap_hci_proto = {
++	name:		"L2CAP",
++	id:		HCI_PROTO_L2CAP,
++	connect_ind:	l2cap_connect_ind,
++	connect_cfm:	l2cap_connect_cfm,
++	disconn_ind:	l2cap_disconn_ind,
++	recv_acldata:	l2cap_recv_acldata,
++	auth_cfm:	l2cap_auth_cfm,
++	encrypt_cfm:	l2cap_encrypt_cfm
++};
++
++int __init l2cap_init(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
++		BT_ERR("Can't register L2CAP socket");
++		return err;
++	}
++
++	if ((err = hci_register_proto(&l2cap_hci_proto))) {
++		BT_ERR("Can't register L2CAP protocol");
++		return err;
++	}
++
++	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
++
++	BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	return 0;
++}
++
++void l2cap_cleanup(void)
++{
++	remove_proc_entry("bluetooth/l2cap", NULL);
++
++	/* Unregister socket and protocol */
++	if (bluez_sock_unregister(BTPROTO_L2CAP))
++		BT_ERR("Can't unregister L2CAP socket");
++
++	if (hci_unregister_proto(&l2cap_hci_proto))
++		BT_ERR("Can't unregister L2CAP protocol");
++}
++
++void l2cap_load(void)
++{
++	/* Dummy function to trigger automatic L2CAP module loading by 
++	   other modules that use L2CAP sockets but do not use any other
++	   symbols from it. */
++	return;
++}
++
++EXPORT_SYMBOL(l2cap_load);
++
++module_init(l2cap_init);
++module_exit(l2cap_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
++MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
++MODULE_LICENSE("GPL");
+--- linux/net/bluetooth/l2cap_core.c~bluetooth-2.4.18-mh11
++++ linux/net/bluetooth/l2cap_core.c
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * BlueZ L2CAP core and sockets.
+- *
+- * $Id$
+- */
+-#define VERSION "1.1"
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/kernel.h>
+-#include <linux/major.h>
+-#include <linux/sched.h>
+-#include <linux/slab.h>
+-#include <linux/poll.h>
+-#include <linux/fcntl.h>
+-#include <linux/init.h>
+-#include <linux/skbuff.h>
+-#include <linux/interrupt.h>
+-#include <linux/socket.h>
+-#include <linux/skbuff.h>
+-#include <linux/proc_fs.h>
+-#include <linux/list.h>
+-#include <net/sock.h>
+-
+-#include <asm/system.h>
+-#include <asm/uaccess.h>
+-
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/l2cap.h>
+-#include <net/bluetooth/l2cap_core.h>
+-
+-#ifndef L2CAP_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#endif
+-
+-struct proto_ops l2cap_sock_ops;
+-
+-struct bluez_sock_list l2cap_sk_list = {
+-	lock: RW_LOCK_UNLOCKED
+-};
+-
+-struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list);
+-rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED;
+-
+-static int  l2cap_conn_del(struct l2cap_conn *conn, int err);
+-
+-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
+-static void l2cap_chan_del(struct sock *sk, int err);
+-static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
+-
+-static void l2cap_sock_close(struct sock *sk);
+-static void l2cap_sock_kill(struct sock *sk);
+-
+-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
+-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
+-
+-/* -------- L2CAP interfaces & routing --------- */
+-/* Add/delete L2CAP interface.
+- * Must be called with locked rt_lock
+- */ 
+-
+-static void l2cap_iff_add(struct hci_dev *hdev)
+-{
+-	struct l2cap_iff *iff;
+-
+-	DBG("%s", hdev->name);
+-
+-	DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev);
+-
+-	/* Allocate new interface and lock HCI device */
+-	if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) {
+-		ERR("Can't allocate new interface %s", hdev->name);
+-		return;
+-	}
+-	memset(iff, 0, sizeof(struct l2cap_iff));
+-
+-	hci_dev_hold(hdev);
+-	hdev->l2cap_data = iff;
+-	iff->hdev   = hdev;
+-	iff->mtu    = hdev->acl_mtu - HCI_ACL_HDR_SIZE;
+-	iff->bdaddr = &hdev->bdaddr;
+-
+-	spin_lock_init(&iff->lock);
+-	INIT_LIST_HEAD(&iff->conn_list);
+-
+-	list_add(&iff->list, &l2cap_iff_list);
+-}
+-
+-static void l2cap_iff_del(struct hci_dev *hdev)
+-{
+-	struct l2cap_iff *iff;
+-
+-	if (!(iff = hdev->l2cap_data))
+-		return;
+-
+-	DBG("%s iff %p", hdev->name, iff);
+-
+-	list_del(&iff->list);
+-
+-	l2cap_iff_lock(iff);
+-
+-	/* Drop connections */
+-	while (!list_empty(&iff->conn_list)) {
+-		struct l2cap_conn *c;
+-
+-		c = list_entry(iff->conn_list.next, struct l2cap_conn, list);
+-		l2cap_conn_del(c, ENODEV);
+-	}
+-
+-	l2cap_iff_unlock(iff);
+-
+-	/* Unlock HCI device */
+-	hdev->l2cap_data = NULL;
+-	hci_dev_put(hdev);
+-
+-	kfree(iff);
+-}
+-
+-/* Get route. Returns L2CAP interface.
+- * Must be called with locked rt_lock
+- */
+-static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst)
+-{
+-	struct list_head *p;
+-	int use_src;
+-
+-	DBG("%s -> %s", batostr(src), batostr(dst));
+-
+-	use_src = bacmp(src, BDADDR_ANY) ? 0 : 1;
+-	
+-	/* Simple routing: 
+-	 * 	No source address - find interface with bdaddr != dst 
+-	 *	Source address 	  - find interface with bdaddr == src 
+-	 */
+-
+-	list_for_each(p, &l2cap_iff_list) {
+-		struct l2cap_iff *iff;
+-
+-		iff = list_entry(p, struct l2cap_iff, list);
+-
+-		if (use_src && !bacmp(iff->bdaddr, src))
+-			return iff;
+-		else if (bacmp(iff->bdaddr, dst))
+-			return iff;
+-	}
+-	return NULL;
+-}
+-
+-/* ----- L2CAP timers ------ */
+-static void l2cap_sock_timeout(unsigned long arg)
+-{
+-	struct sock *sk = (struct sock *) arg;
+-
+-	DBG("sock %p state %d", sk, sk->state);
+-
+-	bh_lock_sock(sk);
+-	switch (sk->state) {
+-	case BT_DISCONN:
+-		l2cap_chan_del(sk, ETIMEDOUT);
+-		break;
+-
+-	default:
+-		sk->err = ETIMEDOUT;
+-		sk->state_change(sk);
+-		break;
+-	};
+-	bh_unlock_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-	sock_put(sk);
+-}
+-
+-static void l2cap_sock_set_timer(struct sock *sk, long timeout)
+-{
+-	DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
+-
+-	if (!mod_timer(&sk->timer, jiffies + timeout))
+-		sock_hold(sk);
+-}
+-
+-static void l2cap_sock_clear_timer(struct sock *sk)
+-{
+-	DBG("sock %p state %d", sk, sk->state);
+-
+-	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
+-		__sock_put(sk);
+-}
+-
+-static void l2cap_sock_init_timer(struct sock *sk)
+-{
+-	init_timer(&sk->timer);
+-	sk->timer.function = l2cap_sock_timeout;
+-	sk->timer.data = (unsigned long)sk;
+-}
+-
+-static void l2cap_conn_timeout(unsigned long arg)
+-{
+-	struct l2cap_conn *conn = (void *)arg;
+-	
+-	DBG("conn %p state %d", conn, conn->state);
+-
+-	if (conn->state == BT_CONNECTED) {
+-		hci_disconnect(conn->hconn, 0x13);
+-	}
+-		
+-	return;
+-}
+-
+-static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout)
+-{
+-	DBG("conn %p state %d timeout %ld", conn, conn->state, timeout);
+-
+-	mod_timer(&conn->timer, jiffies + timeout);
+-}
+-
+-static void l2cap_conn_clear_timer(struct l2cap_conn *conn)
+-{
+-	DBG("conn %p state %d", conn, conn->state);
+-
+-	del_timer(&conn->timer);
+-}
+-
+-static void l2cap_conn_init_timer(struct l2cap_conn *conn)
+-{
+-	init_timer(&conn->timer);
+-	conn->timer.function = l2cap_conn_timeout;
+-	conn->timer.data = (unsigned long)conn;
+-}
+-
+-/* -------- L2CAP connections --------- */
+-/* Add new connection to the interface.
+- * Interface must be locked
+- */
+-static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst)
+-{
+-	struct l2cap_conn *conn;
+-	bdaddr_t *src = iff->bdaddr;
+-
+-	if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL)))
+-		return NULL;
+-
+-	memset(conn, 0, sizeof(struct l2cap_conn));
+-
+-	conn->state = BT_OPEN;
+-	conn->iff   = iff;
+-	bacpy(&conn->src, src);
+-	bacpy(&conn->dst, dst);
+-
+-	spin_lock_init(&conn->lock);
+-	conn->chan_list.lock = RW_LOCK_UNLOCKED;
+-
+-	l2cap_conn_init_timer(conn);
+-	
+-	__l2cap_conn_link(iff, conn);
+-
+-	DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
+-
+-	MOD_INC_USE_COUNT;
+-
+-	return conn;
+-}
+-
+-/* Delete connection on the interface.
+- * Interface must be locked
+- */
+-static int l2cap_conn_del(struct l2cap_conn *conn, int err)
+-{
+-	struct sock *sk;
+-
+-	DBG("conn %p, state %d, err %d", conn, conn->state, err);
+-
+-	l2cap_conn_clear_timer(conn);
+-	__l2cap_conn_unlink(conn->iff, conn);
+-
+-	conn->state = BT_CLOSED;
+-
+-	if (conn->rx_skb)
+-		kfree_skb(conn->rx_skb);
+-
+-	/* Kill channels */
+-	while ((sk = conn->chan_list.head)) {
+-		bh_lock_sock(sk);
+-		l2cap_sock_clear_timer(sk);
+-		l2cap_chan_del(sk, err);
+-		bh_unlock_sock(sk);
+-
+-		l2cap_sock_kill(sk);
+-	}
+-
+-	kfree(conn);
+-
+-	MOD_DEC_USE_COUNT;
+-	return 0;
+-}
+-
+-static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
+-{
+-	struct list_head *p;
+-
+-	list_for_each(p, &iff->conn_list) {
+-		struct l2cap_conn *c;
+-
+-		c = list_entry(p, struct l2cap_conn, list);
+-		if (!bacmp(&c->dst, dst))
+-			return c;
+-	}
+-	return NULL;
+-}
+-
+-int l2cap_connect(struct sock *sk)
+-{
+-	bdaddr_t *src = &l2cap_pi(sk)->src;
+-	bdaddr_t *dst = &l2cap_pi(sk)->dst;
+-	struct l2cap_conn *conn;
+-	struct l2cap_iff *iff;
+-	int err = 0;
+-
+-	DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+-
+-	read_lock_bh(&l2cap_rt_lock);
+-
+-	/* Get route to remote BD address */
+-	if (!(iff = l2cap_get_route(src, dst))) {
+-		err = -EHOSTUNREACH;
+-		goto done;
+-	}
+-
+-	/* Update source addr of the socket */
+-	bacpy(src, iff->bdaddr);
+-
+-	l2cap_iff_lock(iff);
+-
+-	if (!(conn = l2cap_get_conn_by_addr(iff, dst))) {
+-		/* Connection doesn't exist */
+-		if (!(conn = l2cap_conn_add(iff, dst))) {
+-			l2cap_iff_unlock(iff);
+-			err = -ENOMEM;
+-			goto done;
+-		}
+-		conn->out = 1;
+-	}
+-
+-	l2cap_iff_unlock(iff);
+-
+-	l2cap_chan_add(conn, sk, NULL);
+-
+-	sk->state = BT_CONNECT;
+-	l2cap_sock_set_timer(sk, sk->sndtimeo);
+-
+-	switch (conn->state) {
+-	case BT_CONNECTED:
+-		if (sk->type == SOCK_SEQPACKET) {
+-			l2cap_conn_req req;
+-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-			req.psm  = l2cap_pi(sk)->psm;
+-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+-		} else {
+-			l2cap_sock_clear_timer(sk);
+-			sk->state = BT_CONNECTED;
+-		}
+-		break;
+-
+-	case BT_CONNECT:
+-		break;
+-
+-	default:
+-		/* Create ACL connection */
+-		conn->state = BT_CONNECT;
+-		hci_connect(iff->hdev, dst);
+-		break;
+-	};
+-
+-done:
+-	read_unlock_bh(&l2cap_rt_lock);
+-	return err;
+-}
+-
+-/* ------ Channel queues for listening sockets ------ */
+-void l2cap_accept_queue(struct sock *parent, struct sock *sk)
+-{
+-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+-
+-	DBG("parent %p, sk %p", parent, sk);
+-
+-	sock_hold(sk);
+-	l2cap_pi(sk)->parent = parent;
+-	l2cap_pi(sk)->next_q = NULL;
+-
+-	if (!q->head) {
+-		q->head = q->tail = sk;
+-	} else {
+-		struct sock *tail = q->tail;
+-
+-		l2cap_pi(sk)->prev_q = tail;
+-		l2cap_pi(tail)->next_q = sk;
+-		q->tail = sk;
+-	}
+-
+-	parent->ack_backlog++;
+-}
+-
+-void l2cap_accept_unlink(struct sock *sk)
+-{
+-	struct sock *parent = l2cap_pi(sk)->parent;
+-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+-	struct sock *next, *prev;
+-
+-	DBG("sk %p", sk);
+-
+-	next = l2cap_pi(sk)->next_q;
+-	prev = l2cap_pi(sk)->prev_q;
+-
+-	if (sk == q->head)
+-		q->head = next;
+-	if (sk == q->tail)
+-		q->tail = prev;
+-
+-	if (next)
+-		l2cap_pi(next)->prev_q = prev;
+-	if (prev)
+-		l2cap_pi(prev)->next_q = next;
+-
+-	l2cap_pi(sk)->parent = NULL;
+-
+-	parent->ack_backlog--;
+-	__sock_put(sk);
+-}
+-
+-/* Get next connected channel in queue. */
+-struct sock *l2cap_accept_dequeue(struct sock *parent, int state)
+-{
+-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+-	struct sock *sk;
+-
+-	for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) {
+-		if (!state || sk->state == state) {
+-			l2cap_accept_unlink(sk);
+-			break;
+-		}
+-	}
+-
+-	DBG("parent %p, sk %p", parent, sk);
+-
+-	return sk;
+-}
+-
+-/* -------- Socket interface ---------- */
+-static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
+-{
+-	bdaddr_t *src = &addr->l2_bdaddr;
+-	__u16 psm = addr->l2_psm;
+-	struct sock *sk;
+-
+-	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+-		if (l2cap_pi(sk)->psm == psm &&
+-		    !bacmp(&l2cap_pi(sk)->src, src))
+-			break;
+-	}
+-
+-	return sk;
+-}
+-
+-/* Find socket listening on psm and source bdaddr.
+- * Returns closest match.
+- */
+-static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
+-{
+-	struct sock *sk, *sk1 = NULL;
+-
+-	read_lock(&l2cap_sk_list.lock);
+-
+-	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+-		struct l2cap_pinfo *pi;
+-
+-		if (sk->state != BT_LISTEN)
+-			continue;
+-
+-		pi = l2cap_pi(sk);
+-
+-		if (pi->psm == psm) {
+-			/* Exact match. */
+-			if (!bacmp(&pi->src, src))
+-				break;
+-
+-			/* Closest match */
+-			if (!bacmp(&pi->src, BDADDR_ANY))
+-				sk1 = sk;
+-		}
+-	}
+-
+-	read_unlock(&l2cap_sk_list.lock);
+-
+-	return sk ? sk : sk1;
+-}
+-
+-static void l2cap_sock_destruct(struct sock *sk)
+-{
+-	DBG("sk %p", sk);
+-
+-	skb_queue_purge(&sk->receive_queue);
+-	skb_queue_purge(&sk->write_queue);
+-
+-	MOD_DEC_USE_COUNT;
+-}
+-
+-static void l2cap_sock_cleanup_listen(struct sock *parent)
+-{
+-	struct sock *sk;
+-
+-	DBG("parent %p", parent);
+-
+-	/* Close not yet accepted channels */
+-	while ((sk = l2cap_accept_dequeue(parent, 0)))
+-		l2cap_sock_close(sk);
+-
+-	parent->state  = BT_CLOSED;
+-	parent->zapped = 1;
+-}
+-
+-/* Kill socket (only if zapped and orphan)
+- * Must be called on unlocked socket.
+- */
+-static void l2cap_sock_kill(struct sock *sk)
+-{
+-	if (!sk->zapped || sk->socket)
+-		return;
+-
+-	DBG("sk %p state %d", sk, sk->state);
+-
+-	/* Kill poor orphan */
+-	bluez_sock_unlink(&l2cap_sk_list, sk);
+-	sk->dead = 1;
+-	sock_put(sk);
+-}
+-
+-/* Close socket.
+- * Must be called on unlocked socket.
+- */
+-static void l2cap_sock_close(struct sock *sk)
+-{
+-	struct l2cap_conn *conn;
+-
+-	l2cap_sock_clear_timer(sk);
+-
+-	lock_sock(sk);
+-
+-	conn = l2cap_pi(sk)->conn;
+-
+-	DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
+-
+-	switch (sk->state) {
+-	case BT_LISTEN:
+-		l2cap_sock_cleanup_listen(sk);
+-		break;
+-
+-	case BT_CONNECTED:
+-	case BT_CONFIG:
+-		if (sk->type == SOCK_SEQPACKET) {
+-			l2cap_disconn_req req;
+-
+-			sk->state = BT_DISCONN;
+-
+-			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+-
+-			l2cap_sock_set_timer(sk, sk->sndtimeo);
+-		} else {
+-			l2cap_chan_del(sk, ECONNRESET);
+-		}
+-		break;
+-
+-	case BT_CONNECT:
+-	case BT_DISCONN:
+-		l2cap_chan_del(sk, ECONNRESET);
+-		break;
+-
+-	default:
+-		sk->zapped = 1;
+-		break;
+-	};
+-
+-	release_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-}
+-
+-static void l2cap_sock_init(struct sock *sk, struct sock *parent)
+-{
+-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+-
+-	DBG("sk %p", sk);
+-
+-	if (parent) {
+-		sk->type = parent->type;
+-
+-		pi->imtu = l2cap_pi(parent)->imtu;
+-		pi->omtu = l2cap_pi(parent)->omtu;
+-	} else {
+-		pi->imtu = L2CAP_DEFAULT_MTU;
+-		pi->omtu = 0;
+-	}
+-
+-	/* Default config options */
+-	pi->conf_mtu = L2CAP_DEFAULT_MTU;
+-	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+-}
+-
+-static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
+-{
+-	struct sock *sk;
+-
+-	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
+-		return NULL;
+-
+-	sock_init_data(sock, sk);
+-
+-	sk->zapped   = 0;
+-
+-	sk->destruct = l2cap_sock_destruct;
+-	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
+-
+-	sk->protocol = proto;
+-	sk->state    = BT_OPEN;
+-
+-	l2cap_sock_init_timer(sk);
+-
+-	bluez_sock_link(&l2cap_sk_list, sk);
+-
+-	MOD_INC_USE_COUNT;
+-
+-	return sk;
+-}
+-
+-static int l2cap_sock_create(struct socket *sock, int protocol)
+-{
+-	struct sock *sk;
+-
+-	DBG("sock %p", sock);
+-
+-	sock->state = SS_UNCONNECTED;
+-
+-	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
+-		return -ESOCKTNOSUPPORT;
+-
+-	sock->ops = &l2cap_sock_ops;
+-
+-	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
+-		return -ENOMEM;
+-
+-	l2cap_sock_init(sk, NULL);
+-
+-	return 0;
+-}
+-
+-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+-{
+-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
+-
+-	if (!addr || addr->sa_family != AF_BLUETOOTH)
+-		return -EINVAL;
+-
+-	lock_sock(sk);
+-
+-	if (sk->state != BT_OPEN) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	write_lock(&l2cap_sk_list.lock);
+-
+-	if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
+-		err = -EADDRINUSE;
+-		goto unlock;
+-	}
+-
+-	/* Save source address */
+-	bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr);
+-	l2cap_pi(sk)->psm = la->l2_psm;
+-	sk->state = BT_BOUND;
+-
+-unlock:
+-	write_unlock(&l2cap_sk_list.lock);
+-
+-done:
+-	release_sock(sk);
+-
+-	return err;
+-}
+-
+-static int l2cap_sock_w4_connect(struct sock *sk, int flags)
+-{
+-	DECLARE_WAITQUEUE(wait, current);
+-	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+-	int err = 0;
+-
+-	DBG("sk %p", sk);
+-
+-	add_wait_queue(sk->sleep, &wait);
+-	current->state = TASK_INTERRUPTIBLE;
+-
+-	while (sk->state != BT_CONNECTED) {
+-		if (!timeo) {
+-			err = -EAGAIN;
+-			break;
+-		}
+-
+-		release_sock(sk);
+-		timeo = schedule_timeout(timeo);
+-		lock_sock(sk);
+-
+-		err = 0;
+-		if (sk->state == BT_CONNECTED)
+-			break;
+-
+-		if (sk->err) {
+-			err = sock_error(sk);
+-			break;
+-		}
+-
+-		if (signal_pending(current)) {
+-			err = sock_intr_errno(timeo);
+-			break;
+-		}
+-	}
+-	current->state = TASK_RUNNING;
+-	remove_wait_queue(sk->sleep, &wait);
+-
+-	return err;
+-}
+-
+-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+-{
+-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	lock_sock(sk);
+-
+-	DBG("sk %p", sk);
+-
+-	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
+-		err = -EINVAL;
+-		goto done;
+-	}
+-
+-	if (sk->state != BT_OPEN && sk->state != BT_BOUND) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
+-		err = -EINVAL;
+-		goto done;
+-	}
+-
+-	/* Set destination address and psm */
+-	bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr);
+-	l2cap_pi(sk)->psm = la->l2_psm;
+-
+-	if ((err = l2cap_connect(sk)))
+-		goto done;
+-
+-	err = l2cap_sock_w4_connect(sk, flags);
+-
+-done:
+-	release_sock(sk);
+-	return err;
+-}
+-
+-int l2cap_sock_listen(struct socket *sock, int backlog)
+-{
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	DBG("sk %p backlog %d", sk, backlog);
+-
+-	lock_sock(sk);
+-
+-	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	if (!l2cap_pi(sk)->psm) {
+-		err = -EINVAL;
+-		goto done;
+-	}
+-
+-	sk->max_ack_backlog = backlog;
+-	sk->ack_backlog = 0;
+-	sk->state = BT_LISTEN;
+-
+-done:
+-	release_sock(sk);
+-	return err;
+-}
+-
+-int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+-{
+-	DECLARE_WAITQUEUE(wait, current);
+-	struct sock *sk = sock->sk, *ch;
+-	long timeo;
+-	int err = 0;
+-
+-	lock_sock(sk);
+-
+-	if (sk->state != BT_LISTEN) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+-
+-	DBG("sk %p timeo %ld", sk, timeo);
+-
+-	/* Wait for an incoming connection. (wake-one). */
+-	add_wait_queue_exclusive(sk->sleep, &wait);
+-	current->state = TASK_INTERRUPTIBLE;
+-	while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) {
+-		if (!timeo) {
+-			err = -EAGAIN;
+-			break;
+-		}
+-
+-		release_sock(sk);
+-		timeo = schedule_timeout(timeo);
+-		lock_sock(sk);
+-
+-		if (sk->state != BT_LISTEN) {
+-			err = -EBADFD;
+-			break;
+-		}
+-
+-		if (signal_pending(current)) {
+-			err = sock_intr_errno(timeo);
+-			break;
+-		}
+-	}
+-	current->state = TASK_RUNNING;
+-	remove_wait_queue(sk->sleep, &wait);
+-
+-	if (err)
+-		goto done;
+-
+-	sock_graft(ch, newsock);
+-	newsock->state = SS_CONNECTED;
+-
+-	DBG("new socket %p", ch);
+-
+-done:
+-	release_sock(sk);
+-
+-	return err;
+-}
+-
+-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+-{
+-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+-	struct sock *sk = sock->sk;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	addr->sa_family = AF_BLUETOOTH;
+-	*len = sizeof(struct sockaddr_l2);
+-
+-	if (peer)
+-		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst);
+-	else
+-		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src);
+-
+-	la->l2_psm = l2cap_pi(sk)->psm;
+-
+-	return 0;
+-}
+-
+-static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+-{
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	if (sk->err)
+-		return sock_error(sk);
+-
+-	if (msg->msg_flags & MSG_OOB)
+-		return -EOPNOTSUPP;
+-
+-	lock_sock(sk);
+-
+-	if (sk->state == BT_CONNECTED)
+-		err = l2cap_chan_send(sk, msg, len);
+-	else
+-		err = -ENOTCONN;
+-
+-	release_sock(sk);
+-	return err;
+-}
+-
+-static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+-{
+-	struct sock *sk = sock->sk;
+-	int noblock = flags & MSG_DONTWAIT;
+-	int copied, err;
+-	struct sk_buff *skb;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	if (flags & (MSG_OOB))
+-		return -EOPNOTSUPP;
+-
+-	if (sk->state == BT_CLOSED)
+-		return 0;
+-
+-	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
+-		return err;
+-
+-	msg->msg_namelen = 0;
+-
+-	copied = skb->len;
+-	if (len < copied) {
+-		msg->msg_flags |= MSG_TRUNC;
+-		copied = len;
+-	}
+-
+-	skb->h.raw = skb->data;
+-	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+-
+-	skb_free_datagram(sk, skb);
+-
+-	return err ? : copied;
+-}
+-
+-int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+-{
+-	struct sock *sk = sock->sk;
+-	struct l2cap_options opts;
+-	int err = 0;
+-
+-	DBG("sk %p", sk);
+-
+-	lock_sock(sk);
+-
+-	switch (optname) {
+-	case L2CAP_OPTIONS:
+-		if (copy_from_user((char *)&opts, optval, optlen)) {
+-			err = -EFAULT;
+-			break;
+-		}
+-		l2cap_pi(sk)->imtu = opts.imtu;
+-		l2cap_pi(sk)->omtu = opts.omtu;
+-		break;
+-
+-	default:
+-		err = -ENOPROTOOPT;
+-		break;
+-	};
+-
+-	release_sock(sk);
+-	return err;
+-}
+-
+-int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+-{
+-	struct sock *sk = sock->sk;
+-	struct l2cap_options opts;
+-	struct l2cap_conninfo cinfo;
+-	int len, err = 0; 
+-
+-	if (get_user(len, optlen))
+-		return -EFAULT;
+-
+-	lock_sock(sk);
+-
+-	switch (optname) {
+-	case L2CAP_OPTIONS:
+-		opts.imtu     = l2cap_pi(sk)->imtu;
+-		opts.omtu     = l2cap_pi(sk)->omtu;
+-		opts.flush_to = l2cap_pi(sk)->flush_to;
+-
+-		len = MIN(len, sizeof(opts));
+-		if (copy_to_user(optval, (char *)&opts, len))
+-			err = -EFAULT;
+-
+-		break;
+-
+-	case L2CAP_CONNINFO:
+-		if (sk->state != BT_CONNECTED) {
+-			err = -ENOTCONN;
+-			break;
+-		}
+-
+-		cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle;
+-
+-		len = MIN(len, sizeof(cinfo));
+-		if (copy_to_user(optval, (char *)&cinfo, len))
+-			err = -EFAULT;
+-
+-		break;
+-
+-	default:
+-		err = -ENOPROTOOPT;
+-		break;
+-	};
+-
+-	release_sock(sk);
+-	return err;
+-}
+-
+-static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
+-{
+-	struct sock *sk = sock->sk;
+-	struct l2cap_accept_q *aq;
+-	unsigned int mask;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	poll_wait(file, sk->sleep, wait);
+-	mask = 0;
+-
+-	if (sk->err || !skb_queue_empty(&sk->error_queue))
+-		mask |= POLLERR;
+-
+-	if (sk->shutdown == SHUTDOWN_MASK)
+-		mask |= POLLHUP;
+-
+-	aq = &l2cap_pi(sk)->accept_q;
+-	if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN))
+-		mask |= POLLIN | POLLRDNORM;
+-
+-	if (sk->state == BT_CLOSED)
+-		mask |= POLLHUP;
+-
+-	if (sock_writeable(sk))
+-		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+-	else
+-		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+-
+-	return mask;
+-}
+-
+-static int l2cap_sock_release(struct socket *sock)
+-{
+-	struct sock *sk = sock->sk;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	if (!sk)
+-		return 0;
+-
+-	sock_orphan(sk);
+-
+-	l2cap_sock_close(sk);
+-
+-	return 0;
+-}
+-
+-/* --------- L2CAP channels --------- */
+-static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+-		if (l2cap_pi(s)->dcid == cid)
+-			break;
+-	}
+-
+-	return s;
+-}
+-
+-static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	read_lock(&l->lock);
+-	s = __l2cap_get_chan_by_dcid(l, cid);
+-	read_unlock(&l->lock);
+-
+-	return s;
+-}
+-
+-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+-		if (l2cap_pi(s)->scid == cid)
+-			break;
+-	}
+-
+-	return s;
+-}
+-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	read_lock(&l->lock);
+-	s = __l2cap_get_chan_by_scid(l, cid);
+-	read_unlock(&l->lock);
+-
+-	return s;
+-}
+-
+-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
+-{
+-	struct sock *s;
+-
+-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+-		if (l2cap_pi(s)->ident == ident)
+-			break;
+-	}
+-
+-	return s;
+-}
+-
+-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
+-{
+-	struct sock *s;
+-
+-	read_lock(&l->lock);
+-	s = __l2cap_get_chan_by_ident(l, ident);
+-	read_unlock(&l->lock);
+-
+-	return s;
+-}
+-
+-static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
+-{
+-	__u16 cid = 0x0040;
+-
+-	for (; cid < 0xffff; cid++) {
+-		if(!__l2cap_get_chan_by_scid(l, cid))
+-			return cid;
+-	}
+-
+-	return 0;
+-}
+-
+-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
+-{
+-	sock_hold(sk);
+-
+-	if (l->head)
+-		l2cap_pi(l->head)->prev_c = sk;
+-
+-	l2cap_pi(sk)->next_c = l->head;
+-	l2cap_pi(sk)->prev_c = NULL;
+-	l->head = sk;
+-}
+-
+-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
+-{
+-	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
+-
+-	write_lock(&l->lock);
+-	if (sk == l->head)
+-		l->head = next;
+-
+-	if (next)
+-		l2cap_pi(next)->prev_c = prev;
+-	if (prev)
+-		l2cap_pi(prev)->next_c = next;
+-	write_unlock(&l->lock);
+-
+-	__sock_put(sk);
+-}
+-
+-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-
+-	DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+-
+-	l2cap_conn_clear_timer(conn);
+-
+-	atomic_inc(&conn->refcnt);
+-	l2cap_pi(sk)->conn = conn;
+-
+-	if (sk->type == SOCK_SEQPACKET) {
+-		/* Alloc CID for normal socket */
+-		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+-	} else {
+-		/* Raw socket can send only signalling messages */
+-		l2cap_pi(sk)->scid = 0x0001;
+-		l2cap_pi(sk)->dcid = 0x0001;
+-		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+-	}
+-
+-	__l2cap_chan_link(l, sk);
+-
+-	if (parent)
+-		l2cap_accept_queue(parent, sk);
+-}
+-
+-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-
+-	write_lock(&l->lock);
+-	__l2cap_chan_add(conn, sk, parent);
+-	write_unlock(&l->lock);
+-}
+-
+-/* Delete channel. 
+- * Must be called on the locked socket. */
+-static void l2cap_chan_del(struct sock *sk, int err)
+-{
+-	struct l2cap_conn *conn;
+-	struct sock *parent;
+-
+-	conn = l2cap_pi(sk)->conn;
+-	parent = l2cap_pi(sk)->parent;
+-
+-	DBG("sk %p, conn %p, err %d", sk, conn, err);
+-
+-	if (parent) {
+-		/* Unlink from parent accept queue */
+-		bh_lock_sock(parent);
+-		l2cap_accept_unlink(sk);
+-		bh_unlock_sock(parent);
+-	}
+-
+-	if (conn) { 
+-		long timeout;
+-
+-		/* Unlink from channel list */
+-		l2cap_chan_unlink(&conn->chan_list, sk);
+-		l2cap_pi(sk)->conn = NULL;
+-
+-		if (conn->out)
+-			timeout = L2CAP_DISCONN_TIMEOUT;
+-		else
+-			timeout = L2CAP_CONN_IDLE_TIMEOUT;
+-		
+-		if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) {
+-			/* Schedule Baseband disconnect */
+-			l2cap_conn_set_timer(conn, timeout);
+-		}
+-	}
+-
+-	sk->state  = BT_CLOSED;
+-	sk->err    = err;
+-	sk->state_change(sk);
+-
+-	sk->zapped = 1;
+-}
+-
+-static void l2cap_conn_ready(struct l2cap_conn *conn)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-	struct sock *sk;
+-
+-	DBG("conn %p", conn);
+-
+-	read_lock(&l->lock);
+-
+-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+-		bh_lock_sock(sk);
+-
+-		if (sk->type != SOCK_SEQPACKET) {
+-			sk->state = BT_CONNECTED;
+-			sk->state_change(sk);
+-			l2cap_sock_clear_timer(sk);
+-		} else if (sk->state == BT_CONNECT) {
+-			l2cap_conn_req req;
+-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-			req.psm  = l2cap_pi(sk)->psm;
+-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+-
+-			l2cap_sock_set_timer(sk, sk->sndtimeo);
+-		}
+-
+-		bh_unlock_sock(sk);
+-	}
+-
+-	read_unlock(&l->lock);
+-}
+-
+-static void l2cap_chan_ready(struct sock *sk)
+-{
+-	struct sock *parent = l2cap_pi(sk)->parent;
+-
+-	DBG("sk %p, parent %p", sk, parent);
+-
+-	l2cap_pi(sk)->conf_state = 0;
+-	l2cap_sock_clear_timer(sk);
+-
+-	if (!parent) {
+-		/* Outgoing channel.
+-		 * Wake up socket sleeping on connect.
+-		 */
+-		sk->state = BT_CONNECTED;
+-		sk->state_change(sk);
+-	} else {
+-		/* Incomming channel.
+-		 * Wake up socket sleeping on accept.
+-		 */
+-		parent->data_ready(parent, 1);
+-	}
+-}
+-
+-/* Copy frame to all raw sockets on that connection */
+-void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-	struct sk_buff *nskb;
+-	struct sock * sk;
+-
+-	DBG("conn %p", conn);
+-
+-	read_lock(&l->lock);
+-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+-		if (sk->type != SOCK_RAW)
+-			continue;
+-
+-		/* Don't send frame to the socket it came from */
+-		if (skb->sk == sk)
+-			continue;
+-
+-		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
+-			continue;
+-
+-		skb_queue_tail(&sk->receive_queue, nskb);
+-		sk->data_ready(sk, nskb->len);
+-	}
+-	read_unlock(&l->lock);
+-}
+-
+-static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
+-{
+-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+-	struct sk_buff *skb, **frag;
+-	int err, size, count, sent=0;
+-	l2cap_hdr *lh;
+-
+-	/* Check outgoing MTU */
+-	if (len > l2cap_pi(sk)->omtu)
+-		return -EINVAL;
+-
+-	DBG("sk %p len %d", sk, len);
+-
+-	/* First fragment (with L2CAP header) */
+-	count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len);
+-	size  = L2CAP_HDR_SIZE + count;
+-	if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
+-		return err;
+-
+-	/* Create L2CAP header */
+-	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+-	lh->len = __cpu_to_le16(len);
+-	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-
+-	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+-		err = -EFAULT;
+-		goto fail;
+-	}
+-
+-	sent += count;
+-	len  -= count;
+-
+-	/* Continuation fragments (no L2CAP header) */
+-	frag = &skb_shinfo(skb)->frag_list;
+-	while (len) {
+-		count = MIN(conn->iff->mtu, len);
+-
+-		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+-		if (!*frag)
+-			goto fail;
+-		
+-		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
+-			err = -EFAULT;
+-			goto fail;
+-		}
+-
+-		sent += count;
+-		len  -= count;
+-
+-		frag = &(*frag)->next;
+-	}
+-
+-	if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
+-		goto fail;
+-
+-	return sent;
+-
+-fail:
+-	kfree_skb(skb);
+-	return err;
+-}
+-
+-/* --------- L2CAP signalling commands --------- */
+-static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
+-{
+-	__u8 id;
+-
+-	/* Get next available identificator.
+-	 *    1 - 199 are used by kernel.
+-	 *  200 - 254 are used by utilities like l2ping, etc 
+-	 */
+-
+-	spin_lock(&conn->lock);
+-
+-	if (++conn->tx_ident > 199)
+-		conn->tx_ident = 1;
+-
+-	id = conn->tx_ident;
+-
+-	spin_unlock(&conn->lock);
+-
+-	return id;
+-}
+-
+-static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
+-{
+-	struct sk_buff *skb;
+-	l2cap_cmd_hdr *cmd;
+-	l2cap_hdr *lh;
+-	int size;
+-
+-	DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len);
+-
+-	size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len;
+-	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+-		return NULL;
+-
+-	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+-	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len);
+-	lh->cid = __cpu_to_le16(0x0001);
+-
+-	cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
+-	cmd->code  = code;
+-	cmd->ident = ident;
+-	cmd->len   = __cpu_to_le16(len);
+-
+-	if (len)
+-		memcpy(skb_put(skb, len), data, len);
+-
+-	return skb;
+-}
+-
+-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
+-{
+-	struct sk_buff *skb;
+-	__u8 ident;
+-
+-	DBG("code 0x%2.2x", code);
+-
+-	ident = l2cap_get_ident(conn);
+-	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
+-		return -ENOMEM;
+-	return hci_send_acl(conn->hconn, skb, 0);
+-}
+-
+-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
+-{
+-	struct sk_buff *skb;
+-
+-	DBG("code 0x%2.2x", code);
+-
+-	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
+-		return -ENOMEM;
+-	return hci_send_acl(conn->hconn, skb, 0);
+-}
+-
+-static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
+-{
+-	l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
+-	int len;
+-
+-	*type = opt->type;
+-	switch (opt->len) {
+-	case 1:
+-		*val = *((__u8 *) opt->val);
+-		break;
+-
+-	case 2:
+-		*val = __le16_to_cpu(*((__u16 *)opt->val));
+-		break;
+-
+-	case 4:
+-		*val = __le32_to_cpu(*((__u32 *)opt->val));
+-		break;
+-
+-	default:
+-		*val = 0L;
+-		break;
+-	};
+-
+-	DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val);
+-
+-	len = L2CAP_CONF_OPT_SIZE + opt->len;
+-
+-	*ptr += len;
+-
+-	return len;
+-}
+-
+-static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
+-{
+-	__u8 type, hint; __u32 val;
+-	__u8 *ptr = data;
+-
+-	DBG("sk %p len %d", sk, len);
+-
+-	while (len >= L2CAP_CONF_OPT_SIZE) {
+-		len -= l2cap_get_conf_opt(&ptr, &type, &val);
+-
+-		hint  = type & 0x80;
+-		type &= 0x7f;
+-
+-		switch (type) {
+-		case L2CAP_CONF_MTU:
+-			l2cap_pi(sk)->conf_mtu = val;
+-			break;
+-
+-		case L2CAP_CONF_FLUSH_TO:
+-			l2cap_pi(sk)->flush_to = val;
+-			break;
+-
+-		case L2CAP_CONF_QOS:
+-			break;
+-		
+-		default:
+-			if (hint)
+-				break;
+-
+-			/* FIXME: Reject unknon option */
+-			break;
+-		};
+-	}
+-}
+-
+-static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
+-{
+-	register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
+-
+-	DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val);
+-
+-	opt->type = type;
+-	opt->len  = len;
+-	switch (len) {
+-	case 1:
+-		*((__u8 *) opt->val)  = val;
+-		break;
+-
+-	case 2:
+-		*((__u16 *) opt->val) = __cpu_to_le16(val);
+-		break;
+-
+-	case 4:
+-		*((__u32 *) opt->val) = __cpu_to_le32(val);
+-		break;
+-	};
+-
+-	*ptr += L2CAP_CONF_OPT_SIZE + len;
+-}
+-
+-static int l2cap_build_conf_req(struct sock *sk, __u8 *data)
+-{
+-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+-	l2cap_conf_req *req = (l2cap_conf_req *) data;
+-	__u8 *ptr = req->data;
+-
+-	DBG("sk %p", sk);
+-
+-	if (pi->imtu != L2CAP_DEFAULT_MTU)
+-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+-
+-	/* FIXME. Need actual value of the flush timeout */
+-	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
+-	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
+-
+-	req->dcid  = __cpu_to_le16(pi->dcid);
+-	req->flags = __cpu_to_le16(0);
+-
+-	return ptr - data;
+-}
+-
+-static int l2cap_conf_output(struct sock *sk, __u8 **ptr)
+-{
+-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+-	int result = 0;
+-
+-	/* Configure output options and let other side know
+-	 * which ones we don't like.
+-	 */
+-	if (pi->conf_mtu < pi->omtu) {
+-		l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu);
+-		result = L2CAP_CONF_UNACCEPT;
+-	} else {
+-		pi->omtu = pi->conf_mtu;
+-	}
+-
+-	DBG("sk %p result %d", sk, result);
+-	return result;
+-}
+-
+-static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result)
+-{
+-	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
+-	__u8 *ptr = rsp->data;
+-
+-	DBG("sk %p complete %d", sk, result ? 1 : 0);
+-
+-	if (result)
+-		*result = l2cap_conf_output(sk, &ptr);
+-
+-	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-	rsp->result = __cpu_to_le16(result ? *result : 0);
+-	rsp->flags  = __cpu_to_le16(0);
+-
+-	return ptr - data;
+-}
+-
+-static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	struct l2cap_chan_list *list = &conn->chan_list;
+-	l2cap_conn_req *req = (l2cap_conn_req *) data;
+-	l2cap_conn_rsp rsp;
+-	struct sock *sk, *parent;
+-
+-	__u16 scid = __le16_to_cpu(req->scid);
+-	__u16 psm  = req->psm;
+-
+-	DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
+-
+-	/* Check if we have socket listening on psm */
+-	if (!(parent = l2cap_get_sock_listen(&conn->src, psm)))
+-		goto reject;
+-
+-	bh_lock_sock(parent);
+-	write_lock(&list->lock);
+-
+-	/* Check if we already have channel with that dcid */
+-	if (__l2cap_get_chan_by_dcid(list, scid))
+-		goto unlock;
+-
+-	/* Check for backlog size */
+-	if (parent->ack_backlog > parent->max_ack_backlog)
+-		goto unlock;
+-
+-	if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
+-		goto unlock;
+-
+-	l2cap_sock_init(sk, parent);
+-
+-	bacpy(&l2cap_pi(sk)->src, &conn->src);
+-	bacpy(&l2cap_pi(sk)->dst, &conn->dst);
+-	l2cap_pi(sk)->psm  = psm;
+-	l2cap_pi(sk)->dcid = scid;
+-
+-	__l2cap_chan_add(conn, sk, parent);
+-	sk->state = BT_CONFIG;
+-
+-	write_unlock(&list->lock);
+-	bh_unlock_sock(parent);
+-
+-	rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
+-	rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-	rsp.result = __cpu_to_le16(0);
+-	rsp.status = __cpu_to_le16(0);
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
+-
+-	return 0;
+-
+-unlock:
+-	write_unlock(&list->lock);
+-	bh_unlock_sock(parent);
+-
+-reject:
+-	rsp.scid   = __cpu_to_le16(scid);
+-	rsp.dcid   = __cpu_to_le16(0);
+-	rsp.status = __cpu_to_le16(0);
+-	rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM);
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
+-
+-	return 0;
+-}
+-
+-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
+-	__u16 scid, dcid, result, status;
+-	struct sock *sk;
+-
+-	scid   = __le16_to_cpu(rsp->scid);
+-	dcid   = __le16_to_cpu(rsp->dcid);
+-	result = __le16_to_cpu(rsp->result);
+-	status = __le16_to_cpu(rsp->status);
+-
+-	DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-
+-	if (!result) {
+-		char req[64];
+-
+-		sk->state = BT_CONFIG;
+-		l2cap_pi(sk)->dcid = dcid;
+-		l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
+-
+-		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+-	} else {
+-		l2cap_chan_del(sk, ECONNREFUSED);
+-	}
+-
+-	bh_unlock_sock(sk);
+-	return 0;
+-}
+-
+-static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_conf_req * req = (l2cap_conf_req *) data;
+-	__u16 dcid, flags;
+-	__u8 rsp[64];
+-	struct sock *sk;
+-	int result;
+-
+-	dcid  = __le16_to_cpu(req->dcid);
+-	flags = __le16_to_cpu(req->flags);
+-
+-	DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-
+-	l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
+-
+-	if (flags & 0x01) {
+-		/* Incomplete config. Send empty response. */
+-		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
+-		goto unlock;
+-	}
+-
+-	/* Complete config. */
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
+-
+-	if (result)
+-		goto unlock;
+-
+-	/* Output config done */
+-	l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
+-
+-	if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
+-		sk->state = BT_CONNECTED;
+-		l2cap_chan_ready(sk);
+-	} else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
+-		char req[64];
+-		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+-	}
+-
+-unlock:
+-	bh_unlock_sock(sk);
+-
+-	return 0;
+-}
+-
+-static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
+-	__u16 scid, flags, result;
+-	struct sock *sk;
+-	int err = 0;
+-
+-	scid   = __le16_to_cpu(rsp->scid);
+-	flags  = __le16_to_cpu(rsp->flags);
+-	result = __le16_to_cpu(rsp->result);
+-
+-	DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-
+-	if (result) {
+-		l2cap_disconn_req req;
+-
+-		/* They didn't like our options. Well... we do not negotiate.
+-		 * Close channel.
+-		 */
+-		sk->state = BT_DISCONN;
+-
+-		req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-		req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-		l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+-
+-		l2cap_sock_set_timer(sk, sk->sndtimeo);
+-		goto done;
+-	}
+-
+-	if (flags & 0x01)
+-		goto done;
+-
+-	/* Input config done */
+-	l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
+-
+-	if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
+-		sk->state = BT_CONNECTED;
+-		l2cap_chan_ready(sk);
+-	}
+-
+-done:
+-	bh_unlock_sock(sk);
+-
+-	return err;
+-}
+-
+-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_disconn_req *req = (l2cap_disconn_req *) data;
+-	l2cap_disconn_rsp rsp;
+-	__u16 dcid, scid;
+-	struct sock *sk;
+-
+-	scid = __le16_to_cpu(req->scid);
+-	dcid = __le16_to_cpu(req->dcid);
+-
+-	DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+-		return 0;
+-
+-	bh_lock_sock(sk);
+-
+-	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
+-
+-	l2cap_chan_del(sk, ECONNRESET);
+-
+-	bh_unlock_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-
+-	return 0;
+-}
+-
+-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
+-	__u16 dcid, scid;
+-	struct sock *sk;
+-
+-	scid = __le16_to_cpu(rsp->scid);
+-	dcid = __le16_to_cpu(rsp->dcid);
+-
+-	DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-	l2cap_sock_clear_timer(sk);
+-	l2cap_chan_del(sk, ECONNABORTED);
+-	bh_unlock_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-
+-	return 0;
+-}
+-
+-static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+-{
+-	__u8 *data = skb->data;
+-	int len = skb->len;
+-	l2cap_cmd_hdr cmd;
+-	int err = 0;
+-
+-	while (len >= L2CAP_CMD_HDR_SIZE) {
+-		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
+-		data += L2CAP_CMD_HDR_SIZE;
+-		len  -= L2CAP_CMD_HDR_SIZE;
+-
+-		cmd.len = __le16_to_cpu(cmd.len);
+-
+-		DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
+-
+-		if (cmd.len > len || !cmd.ident) {
+-			DBG("corrupted command");
+-			break;
+-		}
+-
+-		switch (cmd.code) {
+-		case L2CAP_CONN_REQ:
+-			err = l2cap_connect_req(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_CONN_RSP:
+-			err = l2cap_connect_rsp(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_CONF_REQ:
+-			err = l2cap_config_req(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_CONF_RSP:
+-			err = l2cap_config_rsp(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_DISCONN_REQ:
+-			err = l2cap_disconnect_req(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_DISCONN_RSP:
+-			err = l2cap_disconnect_rsp(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_COMMAND_REJ:
+-			/* FIXME: We should process this */
+-			l2cap_raw_recv(conn, skb);
+-			break;
+-
+-		case L2CAP_ECHO_REQ:
+-			l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
+-			break;
+-
+-		case L2CAP_ECHO_RSP:
+-		case L2CAP_INFO_REQ:
+-		case L2CAP_INFO_RSP:
+-			l2cap_raw_recv(conn, skb);
+-			break;
+-
+-		default:
+-			ERR("Uknown signaling command 0x%2.2x", cmd.code);
+-			err = -EINVAL;
+-			break;
+-		};
+-
+-		if (err) {
+-			l2cap_cmd_rej rej;
+-			DBG("error %d", err);
+-
+-			/* FIXME: Map err to a valid reason. */
+-			rej.reason = __cpu_to_le16(0);
+-			l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
+-		}
+-
+-		data += cmd.len;
+-		len  -= cmd.len;
+-	}
+-
+-	kfree_skb(skb);
+-}
+-
+-static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
+-{
+-	struct sock *sk;
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) {
+-		DBG("unknown cid 0x%4.4x", cid);
+-		goto drop;
+-	}
+-
+-	DBG("sk %p, len %d", sk, skb->len);
+-
+-	if (sk->state != BT_CONNECTED)
+-		goto drop;
+-
+-	if (l2cap_pi(sk)->imtu < skb->len)
+-		goto drop;
+-
+-	skb_queue_tail(&sk->receive_queue, skb);
+-	sk->data_ready(sk, skb->len);
+-
+-	return 0;
+-
+-drop:
+-	kfree_skb(skb);
+-
+-	return 0;
+-}
+-
+-static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
+-{
+-	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
+-	__u16 cid, len;
+-
+-	skb_pull(skb, L2CAP_HDR_SIZE);
+-	cid = __le16_to_cpu(lh->cid);
+-	len = __le16_to_cpu(lh->len);
+-
+-	DBG("len %d, cid 0x%4.4x", len, cid);
+-
+-	if (cid == 0x0001)
+-		l2cap_sig_channel(conn, skb);
+-	else	
+-		l2cap_data_channel(conn, cid, skb);
+-}
+-
+-/* ------------ L2CAP interface with lower layer (HCI) ------------- */
+-static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) ptr;
+-
+-	DBG("hdev %s, event %ld", hdev->name, event);
+-
+-	write_lock(&l2cap_rt_lock);
+-
+-	switch (event) {
+-	case HCI_DEV_UP:
+-		l2cap_iff_add(hdev);
+-		break;
+-
+-	case HCI_DEV_DOWN:
+-		l2cap_iff_del(hdev);
+-		break;
+-	};
+-
+-	write_unlock(&l2cap_rt_lock);
+-
+-	return NOTIFY_DONE;
+-}
+-
+-int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
+-{
+-	struct l2cap_iff *iff;
+-
+-	DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+-
+-	if (!(iff = hdev->l2cap_data)) {
+-		ERR("unknown interface");
+-		return 0;
+-	}
+-
+-	/* Always accept connection */
+-	return 1;
+-}
+-
+-int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn)
+-{
+-	struct l2cap_conn *conn;
+-	struct l2cap_iff *iff;
+-	int err = 0;
+-
+-	DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn);
+-
+-	if (!(iff = hdev->l2cap_data)) {
+-		ERR("unknown interface");
+-		return 0;
+-	}
+-
+-	l2cap_iff_lock(iff);
+-
+-	conn = l2cap_get_conn_by_addr(iff, bdaddr);
+-
+-	if (conn) {
+-		/* Outgoing connection */
+-		DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status);
+-
+-		if (!status && hconn) {
+-			conn->state = BT_CONNECTED;
+-			conn->hconn = hconn;
+-
+-			hconn->l2cap_data = (void *)conn;
+-
+-			/* Establish channels */
+-			l2cap_conn_ready(conn);
+-		} else {
+-			l2cap_conn_del(conn, bterr(status));
+-		}
+-	} else {
+-		/* Incomming connection */
+-		DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status);
+-	
+-		if (status || !hconn)
+-			goto done;
+-
+-		if (!(conn = l2cap_conn_add(iff, bdaddr))) {
+-			err = -ENOMEM;
+-			goto done;
+-		}
+-
+-		conn->hconn = hconn;
+-		hconn->l2cap_data = (void *)conn;
+-
+-		conn->state = BT_CONNECTED;
+-	}
+-
+-done:
+-	l2cap_iff_unlock(iff);
+-
+-	return err;
+-}
+-
+-int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason)
+-{
+-	struct l2cap_conn *conn = hconn->l2cap_data;
+-
+-	DBG("hconn %p reason %d", hconn, reason);
+-
+-	if (!conn) {
+-		ERR("unknown connection");
+-		return 0;
+-	}
+-	conn->hconn = NULL;
+-
+-	l2cap_iff_lock(conn->iff);
+-	l2cap_conn_del(conn, bterr(reason));
+-	l2cap_iff_unlock(conn->iff);
+-
+-	return 0;
+-}
+-
+-int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags)
+-{
+-	struct l2cap_conn *conn = hconn->l2cap_data;
+-
+-	if (!conn) {
+-		ERR("unknown connection %p", hconn);
+-		goto drop;
+-	}
+-
+-	DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
+-
+-	if (flags & ACL_START) {
+-		int flen, tlen, size;
+-		l2cap_hdr *lh;
+-
+-		if (conn->rx_len) {
+-			ERR("Unexpected start frame (len %d)", skb->len);
+-			kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
+-			conn->rx_len = 0;
+-		}
+-
+-		if (skb->len < L2CAP_HDR_SIZE) {
+-			ERR("Frame is too small (len %d)", skb->len);
+-			goto drop;
+-		}
+-
+-		lh = (l2cap_hdr *)skb->data;
+-		tlen = __le16_to_cpu(lh->len);
+-		flen = skb->len - L2CAP_HDR_SIZE;
+-
+-		DBG("Start: total len %d, frag len %d", tlen, flen);
+-
+-		if (flen == tlen) {
+-			/* Complete frame received */
+-			l2cap_recv_frame(conn, skb);
+-			return 0;
+-		}
+-
+-		/* Allocate skb for the complete frame (with header) */
+-		size = L2CAP_HDR_SIZE + tlen;
+-		if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+-			goto drop;
+-
+-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+-
+-		conn->rx_len = tlen - flen;
+-	} else {
+-		DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
+-
+-		if (!conn->rx_len) {
+-			ERR("Unexpected continuation frame (len %d)", skb->len);
+-			goto drop;
+-		}
+-
+-		if (skb->len > conn->rx_len) {
+-			ERR("Fragment is too large (len %d)", skb->len);
+-			kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
+-			goto drop;
+-		}
+-
+-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+-		conn->rx_len -= skb->len;
+-
+-		if (!conn->rx_len) {
+-			/* Complete frame received */
+-			l2cap_recv_frame(conn, conn->rx_skb);
+-			conn->rx_skb = NULL;
+-		}
+-	}
+-
+-drop:
+-	kfree_skb(skb);
+-	return 0;
+-}
+-
+-struct proto_ops l2cap_sock_ops = {
+-	family:		PF_BLUETOOTH,
+-	release:	l2cap_sock_release,
+-	bind:		l2cap_sock_bind,
+-	connect:	l2cap_sock_connect,
+-	listen:		l2cap_sock_listen,
+-	accept:		l2cap_sock_accept,
+-	getname:	l2cap_sock_getname,
+-	sendmsg:	l2cap_sock_sendmsg,
+-	recvmsg:	l2cap_sock_recvmsg,
+-	poll:		l2cap_sock_poll,
+-	socketpair:	sock_no_socketpair,
+-	ioctl:		sock_no_ioctl,
+-	shutdown:	sock_no_shutdown,
+-	setsockopt:	l2cap_sock_setsockopt,
+-	getsockopt:	l2cap_sock_getsockopt,
+-	mmap:		sock_no_mmap
+-};
+-
+-struct net_proto_family l2cap_sock_family_ops = {
+-	family:		PF_BLUETOOTH,
+-	create:		l2cap_sock_create
+-};
+-
+-struct hci_proto l2cap_hci_proto = {
+-	name:		"L2CAP",
+-	id:		HCI_PROTO_L2CAP,
+-	connect_ind:	l2cap_connect_ind,
+-	connect_cfm:	l2cap_connect_cfm,
+-	disconn_ind:	l2cap_disconn_ind,
+-	recv_acldata:	l2cap_recv_acldata,
+-};
+-
+-struct notifier_block l2cap_nblock = {
+-	notifier_call: l2cap_dev_event
+-};
+-
+-int __init l2cap_init(void)
+-{
+-	INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+-		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+-
+-	if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
+-		ERR("Can't register L2CAP socket");
+-		return -EPROTO;
+-	}
+-
+-	if (hci_register_proto(&l2cap_hci_proto) < 0) {
+-		ERR("Can't register L2CAP protocol");
+-		return -EPROTO;
+-	}
+-
+-	hci_register_notifier(&l2cap_nblock);
+-
+-	l2cap_register_proc();
+-
+-	return 0;
+-}
+-
+-void l2cap_cleanup(void)
+-{
+-	l2cap_unregister_proc();
+-
+-	/* Unregister socket, protocol and notifier */
+-	if (bluez_sock_unregister(BTPROTO_L2CAP))
+-		ERR("Can't unregister L2CAP socket");
+-
+-	if (hci_unregister_proto(&l2cap_hci_proto) < 0)
+-		ERR("Can't unregister L2CAP protocol");
+-
+-	hci_unregister_notifier(&l2cap_nblock);
+-
+-	/* We _must_ not have any sockets and/or connections
+-	 * at this stage.
+-	 */
+-
+-	/* Free interface list and unlock HCI devices */
+-	{
+-		struct list_head *list = &l2cap_iff_list;
+-
+-		while (!list_empty(list)) {
+-			struct l2cap_iff *iff;
+-
+-			iff = list_entry(list->next, struct l2cap_iff, list);
+-			l2cap_iff_del(iff->hdev);
+-		}
+-	}
+-}
+-
+-module_init(l2cap_init);
+-module_exit(l2cap_cleanup);
+-
+-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+-MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
+-MODULE_LICENSE("GPL");
+-
+--- linux/net/bluetooth/l2cap_proc.c~bluetooth-2.4.18-mh11
++++ linux/net/bluetooth/l2cap_proc.c
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * BlueZ L2CAP proc fs support.
+- *
+- * $Id$
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/kernel.h>
+-#include <linux/major.h>
+-#include <linux/sched.h>
+-#include <linux/slab.h>
+-#include <linux/poll.h>
+-#include <linux/fcntl.h>
+-#include <linux/init.h>
+-#include <linux/skbuff.h>
+-#include <linux/interrupt.h>
+-#include <linux/socket.h>
+-#include <linux/skbuff.h>
+-#include <linux/proc_fs.h>
+-#include <linux/list.h>
+-#include <net/sock.h>
+-
+-#include <asm/system.h>
+-#include <asm/uaccess.h>
+-
+-#include <net/bluetooth/bluez.h>
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/l2cap_core.h>
+-
+-#ifndef L2CAP_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#endif
+-
+-/* ----- PROC fs support ----- */
+-static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff)
+-{
+-	struct list_head *p;
+-	char *ptr = buf;
+-
+-	list_for_each(p, &iff->conn_list) {
+-		struct l2cap_conn *c;
+-
+-		c = list_entry(p, struct l2cap_conn, list);
+-		ptr += sprintf(ptr, "    %p %d %p %p %s %s\n", 
+-				c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst));
+-	}
+-
+-	return ptr - buf;
+-}
+-
+-static int l2cap_iff_dump(char *buf)
+-{
+-	struct list_head *p;
+-	char *ptr = buf;
+-
+-	ptr += sprintf(ptr, "Interfaces:\n");
+-
+-	write_lock(&l2cap_rt_lock);
+-
+-	list_for_each(p, &l2cap_iff_list) {
+-		struct l2cap_iff *iff;
+-
+-		iff = list_entry(p, struct l2cap_iff, list);
+-
+-		ptr += sprintf(ptr, "  %s %p %p\n", iff->hdev->name, iff, iff->hdev);
+-		
+-		l2cap_iff_lock(iff);
+-		ptr += l2cap_conn_dump(ptr, iff);
+-		l2cap_iff_unlock(iff);
+-	}
+-
+-	write_unlock(&l2cap_rt_lock);
+-
+-	ptr += sprintf(ptr, "\n");
+-
+-	return ptr - buf;
+-}
+-
+-static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
+-{
+-	struct l2cap_pinfo *pi;
+-	struct sock *sk;
+-	char *ptr = buf;
+-
+-	ptr += sprintf(ptr, "Sockets:\n");
+-
+-	write_lock(&list->lock);
+-
+-	for (sk = list->head; sk; sk = sk->next) {
+-		pi = l2cap_pi(sk);
+-		ptr += sprintf(ptr, "  %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm,
+-		               batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu );
+-	}
+-
+-	write_unlock(&list->lock);
+-
+-	ptr += sprintf(ptr, "\n");
+-
+-	return ptr - buf;
+-}
+-
+-static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+-{
+-	char *ptr = buf;
+-	int len;
+-
+-	DBG("count %d, offset %ld", count, offset);
+-
+-	ptr += l2cap_iff_dump(ptr);
+-	ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
+-	len  = ptr - buf;
+-
+-	if (len <= count + offset)
+-		*eof = 1;
+-
+-	*start = buf + offset;
+-	len -= offset;
+-
+-	if (len > count)
+-		len = count;
+-	if (len < 0)
+-		len = 0;
+-
+-	return len;
+-}
+-
+-void l2cap_register_proc(void)
+-{
+-	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
+-}
+-
+-void l2cap_unregister_proc(void)
+-{
+-	remove_proc_entry("bluetooth/l2cap", NULL);
+-}
+--- linux/net/bluetooth/lib.c~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/net/bluetooth/lib.c	2004-01-25 23:37:39.000000000 +0100
+@@ -25,7 +25,7 @@
+ /*
+  * BlueZ kernel library.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/kernel.h>
+@@ -105,7 +105,7 @@
+ 		return EACCES;
+ 
+ 	case 0x06:
+-		return EINVAL;
++		return EBADE;
+ 
+ 	case 0x07:
+ 		return ENOMEM;
+--- linux/net/bluetooth/Makefile~bluetooth-2.4.18-mh11	2001-06-12 04:15:27.000000000 +0200
++++ linux/net/bluetooth/Makefile	2004-01-25 23:37:39.000000000 +0100
+@@ -1,20 +1,31 @@
+ #
+-# Makefile for the Bluetooth subsystem
++# Makefile for the Linux Bluetooth subsystem
+ #
+-O_TARGET	:= bluetooth.o
+ 
+-list-multi	:= hci.o l2cap.o
+-export-objs	:= syms.o
+-hci-objs	:= af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o
+-l2cap-objs	:= l2cap_core.o l2cap_proc.o
++O_TARGET    := bluetooth.o
+ 
+-obj-$(CONFIG_BLUEZ) += hci.o
++list-multi  := bluez.o
++export-objs := syms.o l2cap.o
++
++bluez-objs  := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
++
++obj-$(CONFIG_BLUEZ) += bluez.o
+ obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
++obj-$(CONFIG_BLUEZ_SCO) += sco.o
+ 
+-include $(TOPDIR)/Rules.make
++subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
++subdir-$(CONFIG_BLUEZ_BNEP) += bnep
++subdir-$(CONFIG_BLUEZ_CMTP) += cmtp
+ 
+-hci.o: $(hci-objs)
+-	$(LD) -r -o $@ $(hci-objs)
++ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
++obj-y += rfcomm/rfcomm.o
++endif
+ 
+-l2cap.o: $(l2cap-objs)
+-	$(LD) -r -o $@ $(l2cap-objs)
++ifeq ($(CONFIG_BLUEZ_BNEP),y)
++obj-y += bnep/bnep.o
++endif
++
++include $(TOPDIR)/Rules.make
++
++bluez.o: $(bluez-objs)
++	$(LD) -r -o $@ $(bluez-objs)
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/rfcomm/Config.in	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,10 @@
++#
++# Bluetooth RFCOMM layer configuration
++#
++
++dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
++
++if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
++   bool '  RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
++fi
++
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/rfcomm/core.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,1939 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/* 
++   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
++*/
++
++/*
++ * RFCOMM core.
++ *
++ * $Id$
++ */
++
++#define __KERNEL_SYSCALLS__
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/init.h>
++#include <linux/wait.h>
++#include <linux/net.h>
++#include <linux/proc_fs.h>
++#include <net/sock.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/l2cap.h>
++#include <net/bluetooth/rfcomm.h>
++
++#define VERSION "1.1"
++
++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++struct task_struct *rfcomm_thread;
++DECLARE_MUTEX(rfcomm_sem);
++unsigned long rfcomm_event;
++
++static LIST_HEAD(session_list);
++static atomic_t terminate, running;
++
++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
++static int rfcomm_queue_disc(struct rfcomm_dlc *d);
++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
++
++static void rfcomm_process_connect(struct rfcomm_session *s);
++
++/* ---- RFCOMM frame parsing macros ---- */
++#define __get_dlci(b)     ((b & 0xfc) >> 2)
++#define __get_channel(b)  ((b & 0xf8) >> 3)
++#define __get_dir(b)      ((b & 0x04) >> 2)
++#define __get_type(b)     ((b & 0xef))
++
++#define __test_ea(b)      ((b & 0x01))
++#define __test_cr(b)      ((b & 0x02))
++#define __test_pf(b)      ((b & 0x10))
++
++#define __addr(cr, dlci)       (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
++#define __ctrl(type, pf)       (((type & 0xef) | (pf << 4)))
++#define __dlci(dir, chn)       (((chn & 0x1f) << 1) | dir)
++#define __srv_channel(dlci)    (dlci >> 1)
++#define __dir(dlci)            (dlci & 0x01)
++
++#define __len8(len)       (((len) << 1) | 1)
++#define __len16(len)      ((len) << 1)
++
++/* MCC macros */
++#define __mcc_type(cr, type)   (((type << 2) | (cr << 1) | 0x01))
++#define __get_mcc_type(b) ((b & 0xfc) >> 2)
++#define __get_mcc_len(b)  ((b & 0xfe) >> 1)
++
++/* RPN macros */
++#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
++#define __get_rpn_data_bits(line) ((line) & 0x3)
++#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
++#define __get_rpn_parity(line)    (((line) >> 3) & 0x3)
++
++/* ---- RFCOMM FCS computation ---- */
++
++/* CRC on 2 bytes */
++#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
++
++/* FCS on 2 bytes */ 
++static inline u8 __fcs(u8 *data)
++{
++	return (0xff - __crc(data));
++}
++
++/* FCS on 3 bytes */ 
++static inline u8 __fcs2(u8 *data)
++{
++	return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
++}
++
++/* Check FCS */
++static inline int __check_fcs(u8 *data, int type, u8 fcs)
++{
++	u8 f = __crc(data);
++
++	if (type != RFCOMM_UIH)
++		f = rfcomm_crc_table[f ^ data[2]];
++
++	return rfcomm_crc_table[f ^ fcs] != 0xcf;
++}
++
++/* ---- L2CAP callbacks ---- */
++static void rfcomm_l2state_change(struct sock *sk)
++{
++	BT_DBG("%p state %d", sk, sk->state);
++	rfcomm_schedule(RFCOMM_SCHED_STATE);
++}
++
++static void rfcomm_l2data_ready(struct sock *sk, int bytes)
++{
++	BT_DBG("%p bytes %d", sk, bytes);
++	rfcomm_schedule(RFCOMM_SCHED_RX);
++}
++
++static int rfcomm_l2sock_create(struct socket **sock)
++{
++	int err;
++
++	BT_DBG("");
++
++	err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
++	if (!err) {
++		struct sock *sk = (*sock)->sk;
++		sk->data_ready   = rfcomm_l2data_ready;
++		sk->state_change = rfcomm_l2state_change;
++	}
++	return err;
++}
++
++/* ---- RFCOMM DLCs ---- */
++static void rfcomm_dlc_timeout(unsigned long arg)
++{
++	struct rfcomm_dlc *d = (void *) arg;
++
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	set_bit(RFCOMM_TIMED_OUT, &d->flags);
++	rfcomm_dlc_put(d);
++	rfcomm_schedule(RFCOMM_SCHED_TIMEO);
++}
++
++static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
++{
++	BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
++
++	if (!mod_timer(&d->timer, jiffies + timeout))
++		rfcomm_dlc_hold(d);
++}
++
++static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	if (timer_pending(&d->timer) && del_timer(&d->timer))
++		rfcomm_dlc_put(d);
++}
++
++static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
++{
++	BT_DBG("%p", d);
++
++	d->state      = BT_OPEN;
++	d->flags      = 0;
++	d->mscex      = 0;
++	d->mtu        = RFCOMM_DEFAULT_MTU;
++	d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
++
++	d->cfc        = RFCOMM_CFC_DISABLED;
++	d->rx_credits = RFCOMM_DEFAULT_CREDITS;
++}
++
++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
++{
++	struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
++	if (!d)
++		return NULL;
++	memset(d, 0, sizeof(*d));
++
++	init_timer(&d->timer);
++	d->timer.function = rfcomm_dlc_timeout;
++	d->timer.data = (unsigned long) d;
++
++	skb_queue_head_init(&d->tx_queue);
++	spin_lock_init(&d->lock);
++	atomic_set(&d->refcnt, 1);
++
++	rfcomm_dlc_clear_state(d);
++	
++	BT_DBG("%p", d);
++	return d;
++}
++
++void rfcomm_dlc_free(struct rfcomm_dlc *d)
++{
++	BT_DBG("%p", d);
++
++	skb_queue_purge(&d->tx_queue);
++	kfree(d);
++}
++
++static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p session %p", d, s);
++
++	rfcomm_session_hold(s);
++
++	rfcomm_dlc_hold(d);
++	list_add(&d->list, &s->dlcs);
++	d->session = s;
++}
++
++static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
++{
++	struct rfcomm_session *s = d->session;
++
++	BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
++
++	list_del(&d->list);
++	d->session = NULL;
++	rfcomm_dlc_put(d);
++
++	rfcomm_session_put(s);
++}
++
++static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p;
++
++	list_for_each(p, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		if (d->dlci == dlci)
++			return d;
++	}
++	return NULL;
++}
++
++static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
++{
++	struct rfcomm_session *s;
++	int err = 0;
++	u8 dlci;
++
++	BT_DBG("dlc %p state %ld %s %s channel %d", 
++			d, d->state, batostr(src), batostr(dst), channel);
++
++	if (channel < 1 || channel > 30)
++		return -EINVAL;
++
++	if (d->state != BT_OPEN && d->state != BT_CLOSED)
++		return 0;
++
++	s = rfcomm_session_get(src, dst);
++	if (!s) {
++		s = rfcomm_session_create(src, dst, &err);
++		if (!s)
++			return err;
++	}
++
++	dlci = __dlci(!s->initiator, channel);
++
++	/* Check if DLCI already exists */
++	if (rfcomm_dlc_get(s, dlci))
++		return -EBUSY;
++
++	rfcomm_dlc_clear_state(d);
++
++	d->dlci     = dlci;
++	d->addr     = __addr(s->initiator, dlci);
++	d->priority = 7;
++
++	d->state    = BT_CONFIG;
++	rfcomm_dlc_link(s, d);
++
++	d->mtu = s->mtu;
++	d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
++
++	if (s->state == BT_CONNECTED)
++		rfcomm_send_pn(s, 1, d);
++	rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
++	return 0;
++}
++
++int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
++{
++	mm_segment_t fs;
++	int r;
++
++	rfcomm_lock();
++
++	fs = get_fs(); set_fs(KERNEL_DS);
++	r = __rfcomm_dlc_open(d, src, dst, channel);
++	set_fs(fs);
++
++	rfcomm_unlock();
++	return r;
++}
++
++static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
++{
++	struct rfcomm_session *s = d->session;
++	if (!s)
++		return 0;
++
++	BT_DBG("dlc %p state %ld dlci %d err %d session %p",
++			d, d->state, d->dlci, err, s);
++
++	switch (d->state) {
++	case BT_CONNECTED:
++	case BT_CONFIG:
++	case BT_CONNECT:
++		d->state = BT_DISCONN;
++		if (skb_queue_empty(&d->tx_queue)) {
++			rfcomm_send_disc(s, d->dlci);
++			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
++		} else {
++			rfcomm_queue_disc(d);
++			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
++		}
++		break;
++
++	default:
++		rfcomm_dlc_clear_timer(d);
++
++		rfcomm_dlc_lock(d);
++		d->state = BT_CLOSED;
++		d->state_change(d, err);
++		rfcomm_dlc_unlock(d);
++
++		skb_queue_purge(&d->tx_queue);
++		rfcomm_dlc_unlink(d);
++	}
++
++	return 0;
++}
++
++int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
++{
++	mm_segment_t fs;
++	int r;
++
++	rfcomm_lock();
++
++	fs = get_fs(); set_fs(KERNEL_DS);
++	r = __rfcomm_dlc_close(d, err);
++	set_fs(fs);
++
++	rfcomm_unlock();
++	return r;
++}
++
++int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
++{
++	int len = skb->len;
++
++	if (d->state != BT_CONNECTED)
++		return -ENOTCONN;
++
++	BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
++
++	if (len > d->mtu)
++		return -EINVAL;
++
++	rfcomm_make_uih(skb, d->addr);
++	skb_queue_tail(&d->tx_queue, skb);
++
++	if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
++		rfcomm_schedule(RFCOMM_SCHED_TX);
++	return len;
++}
++
++void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	if (!d->cfc) {
++		d->v24_sig |= RFCOMM_V24_FC;
++		set_bit(RFCOMM_MSC_PENDING, &d->flags);
++	}
++	rfcomm_schedule(RFCOMM_SCHED_TX);
++}
++
++void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	if (!d->cfc) {
++		d->v24_sig &= ~RFCOMM_V24_FC;
++		set_bit(RFCOMM_MSC_PENDING, &d->flags);
++	}
++	rfcomm_schedule(RFCOMM_SCHED_TX);
++}
++
++/* 
++   Set/get modem status functions use _local_ status i.e. what we report
++   to the other side.
++   Remote status is provided by dlc->modem_status() callback.
++ */
++int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
++{
++	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
++			d, d->state, v24_sig);
++
++	if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
++		v24_sig |= RFCOMM_V24_FC;
++	else
++		v24_sig &= ~RFCOMM_V24_FC;
++	
++	d->v24_sig = v24_sig;
++
++	if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
++		rfcomm_schedule(RFCOMM_SCHED_TX);
++
++	return 0;
++}
++
++int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
++{
++	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
++			d, d->state, d->v24_sig);
++
++	*v24_sig = d->v24_sig;
++	return 0;
++}
++
++/* ---- RFCOMM sessions ---- */
++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
++{
++	struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
++	if (!s)
++		return NULL;
++	memset(s, 0, sizeof(*s));
++	
++	BT_DBG("session %p sock %p", s, sock);
++
++	INIT_LIST_HEAD(&s->dlcs);
++	s->state = state;
++	s->sock  = sock;
++
++	s->mtu   = RFCOMM_DEFAULT_MTU;
++	s->cfc   = RFCOMM_CFC_UNKNOWN;
++	
++	list_add(&s->list, &session_list);
++
++	/* Do not increment module usage count for listeting sessions.
++	 * Otherwise we won't be able to unload the module. */
++	if (state != BT_LISTEN)
++		MOD_INC_USE_COUNT;
++	return s;
++}
++
++void rfcomm_session_del(struct rfcomm_session *s)
++{
++	int state = s->state;
++	
++	BT_DBG("session %p state %ld", s, s->state);
++
++	list_del(&s->list);
++
++	if (state == BT_CONNECTED)
++		rfcomm_send_disc(s, 0);
++
++	sock_release(s->sock);
++	kfree(s);
++
++	if (state != BT_LISTEN)
++		MOD_DEC_USE_COUNT;
++}
++
++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
++{
++	struct rfcomm_session *s;
++	struct list_head *p, *n;
++	struct bluez_pinfo *pi;
++	list_for_each_safe(p, n, &session_list) {
++		s = list_entry(p, struct rfcomm_session, list);
++		pi = bluez_pi(s->sock->sk); 
++
++		if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&
++				!bacmp(&pi->dst, dst))
++			return s;
++	}
++	return NULL;
++}
++
++void rfcomm_session_close(struct rfcomm_session *s, int err)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p, *n;
++
++	BT_DBG("session %p state %ld err %d", s, s->state, err);
++
++	rfcomm_session_hold(s);
++
++	s->state = BT_CLOSED;
++
++	/* Close all dlcs */
++	list_for_each_safe(p, n, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		d->state = BT_CLOSED;
++		__rfcomm_dlc_close(d, err);
++	}
++
++	rfcomm_session_put(s);
++}
++
++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
++{
++	struct rfcomm_session *s = NULL;
++	struct sockaddr_l2 addr;
++	struct l2cap_options opts;
++	struct socket *sock;
++	int    size;
++
++	BT_DBG("%s %s", batostr(src), batostr(dst));
++
++	*err = rfcomm_l2sock_create(&sock);
++	if (*err < 0)
++		return NULL;
++
++	bacpy(&addr.l2_bdaddr, src);
++	addr.l2_family = AF_BLUETOOTH;
++	addr.l2_psm    = 0;
++	*err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
++	if (*err < 0)
++		goto failed;
++
++	/* Set L2CAP options */
++	size = sizeof(opts);
++	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
++	
++	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
++	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
++
++	s = rfcomm_session_add(sock, BT_BOUND);
++	if (!s) {
++		*err = -ENOMEM;
++		goto failed;
++	}
++
++	s->initiator = 1;
++
++	bacpy(&addr.l2_bdaddr, dst);
++	addr.l2_family = AF_BLUETOOTH;
++	addr.l2_psm    = htobs(RFCOMM_PSM);
++	*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
++	if (*err == 0 || *err == -EAGAIN)
++		return s;
++
++	rfcomm_session_del(s);
++	return NULL;
++
++failed:
++	sock_release(sock);
++	return NULL;
++}
++
++void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
++{
++	struct sock *sk = s->sock->sk;
++	if (src)
++		bacpy(src, &bluez_pi(sk)->src);
++	if (dst)
++		bacpy(dst, &bluez_pi(sk)->dst);
++}
++
++/* ---- RFCOMM frame sending ---- */
++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
++{
++	struct socket *sock = s->sock;
++	struct iovec iv = { data, len };
++	struct msghdr msg;
++	int err;
++
++	BT_DBG("session %p len %d", s, len);
++
++	memset(&msg, 0, sizeof(msg));
++	msg.msg_iovlen = 1;
++	msg.msg_iov = &iv;
++
++	err = sock->ops->sendmsg(sock, &msg, len, 0);
++	return err;
++}
++
++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(!s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_UA, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_queue_disc(struct rfcomm_dlc *d)
++{
++	struct rfcomm_cmd *cmd;
++	struct sk_buff *skb;
++
++	BT_DBG("dlc %p dlci %d", d, d->dlci);
++
++	skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
++	if (!skb)
++		return -ENOMEM;
++
++	cmd = (void *) __skb_put(skb, sizeof(*cmd));
++	cmd->addr = d->addr;
++	cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
++	cmd->len  = __len8(0);
++	cmd->fcs  = __fcs2((u8 *) cmd);
++
++	skb_queue_tail(&d->tx_queue, skb);
++	rfcomm_schedule(RFCOMM_SCHED_TX);
++	return 0;
++}
++
++static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(!s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_DM, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d type %d", s, cr, type);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + 1);
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_NSC);
++	mcc->len  = __len8(1);
++
++	/* Type that we didn't like */
++	*ptr = __mcc_type(cr, type); ptr++;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_pn  *pn;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*pn));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_PN);
++	mcc->len  = __len8(sizeof(*pn));
++
++	pn = (void *) ptr; ptr += sizeof(*pn);
++	pn->dlci        = d->dlci;
++	pn->priority    = d->priority;
++	pn->ack_timer   = 0;
++	pn->max_retrans = 0;
++
++	if (s->cfc) {
++		pn->flow_ctrl = cr ? 0xf0 : 0xe0;
++		pn->credits = RFCOMM_DEFAULT_CREDITS;
++	} else {
++		pn->flow_ctrl = 0;
++		pn->credits   = 0;
++	}
++
++	pn->mtu = htobs(d->mtu);
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
++			   u8 bit_rate, u8 data_bits, u8 stop_bits,
++			   u8 parity, u8 flow_ctrl_settings, 
++			   u8 xon_char, u8 xoff_char, u16 param_mask)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_rpn *rpn;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
++	       "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", 
++			s, cr, dlci, bit_rate, data_bits, stop_bits, parity, 
++			flow_ctrl_settings, xon_char, xoff_char, param_mask);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*rpn));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_RPN);
++	mcc->len  = __len8(sizeof(*rpn));
++
++	rpn = (void *) ptr; ptr += sizeof(*rpn);
++	rpn->dlci          = __addr(1, dlci);
++	rpn->bit_rate      = bit_rate;
++	rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
++	rpn->flow_ctrl     = flow_ctrl_settings;
++	rpn->xon_char      = xon_char;
++	rpn->xoff_char     = xoff_char;
++	rpn->param_mask    = param_mask;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_rls *rls;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d status 0x%x", s, cr, status);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*rls));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_RLS);
++	mcc->len  = __len8(sizeof(*rls));
++
++	rls = (void *) ptr; ptr += sizeof(*rls);
++	rls->dlci   = __addr(1, dlci);
++	rls->status = status;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_msc *msc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*msc));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_MSC);
++	mcc->len  = __len8(sizeof(*msc));
++
++	msc = (void *) ptr; ptr += sizeof(*msc);
++	msc->dlci    = __addr(1, dlci);
++	msc->v24_sig = v24_sig | 0x01;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d", s, cr);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
++	mcc->len  = __len8(0);
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d", s, cr);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_FCON);
++	mcc->len  = __len8(0);
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
++{
++	struct socket *sock = s->sock;
++	struct iovec iv[3];
++	struct msghdr msg;
++	unsigned char hdr[5], crc[1];
++
++	if (len > 125)
++		return -EINVAL;
++
++	BT_DBG("%p cr %d", s, cr);
++
++	hdr[0] = __addr(s->initiator, 0);
++	hdr[1] = __ctrl(RFCOMM_UIH, 0);
++	hdr[2] = 0x01 | ((len + 2) << 1);
++	hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
++	hdr[4] = 0x01 | (len << 1);
++
++	crc[0] = __fcs(hdr);
++
++	iv[0].iov_base = hdr;
++	iv[0].iov_len  = 5;
++	iv[1].iov_base = pattern;
++	iv[1].iov_len  = len;
++	iv[2].iov_base = crc;
++	iv[2].iov_len  = 1;
++
++	memset(&msg, 0, sizeof(msg));
++	msg.msg_iovlen = 3;
++	msg.msg_iov = iv;
++	return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
++}
++
++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
++{
++	struct rfcomm_hdr *hdr;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p addr %d credits %d", s, addr, credits);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = addr;
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
++	hdr->len  = __len8(0);
++
++	*ptr = credits; ptr++;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
++{
++	struct rfcomm_hdr *hdr;
++	int len = skb->len;
++	u8 *crc;
++
++	if (len > 127) {
++		hdr = (void *) skb_push(skb, 4);
++		put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
++	} else {
++		hdr = (void *) skb_push(skb, 3);
++		hdr->len = __len8(len);
++	}
++	hdr->addr = addr;
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++
++	crc = skb_put(skb, 1);
++	*crc = __fcs((void *) hdr);
++}
++
++/* ---- RFCOMM frame reception ---- */
++static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
++{
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (dlci) {
++		/* Data channel */
++		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
++		if (!d) {
++			rfcomm_send_dm(s, dlci);
++			return 0;
++		}
++
++		switch (d->state) {
++		case BT_CONNECT:
++			rfcomm_dlc_clear_timer(d);
++
++			rfcomm_dlc_lock(d);
++			d->state = BT_CONNECTED;
++			d->state_change(d, 0);
++			rfcomm_dlc_unlock(d);
++
++			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
++			break;
++
++		case BT_DISCONN:
++			d->state = BT_CLOSED;
++			__rfcomm_dlc_close(d, 0);
++			break;
++		}
++	} else {
++		/* Control channel */
++		switch (s->state) {
++		case BT_CONNECT:
++			s->state = BT_CONNECTED;
++			rfcomm_process_connect(s);
++			break;
++		}
++	}
++	return 0;
++}
++
++static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
++{
++	int err = 0;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (dlci) {
++		/* Data DLC */
++		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
++		if (d) {
++			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
++				err = ECONNREFUSED;
++			else
++				err = ECONNRESET;
++
++			d->state = BT_CLOSED;
++			__rfcomm_dlc_close(d, err);
++		}
++	} else {
++		if (s->state == BT_CONNECT)
++			err = ECONNREFUSED;
++		else
++			err = ECONNRESET;
++
++		s->state = BT_CLOSED;
++		rfcomm_session_close(s, err);
++	}
++	return 0;
++}
++
++static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
++{
++	int err = 0;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (dlci) {
++		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
++		if (d) {
++			rfcomm_send_ua(s, dlci);
++
++			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
++				err = ECONNREFUSED;
++			else
++				err = ECONNRESET;
++
++			d->state = BT_CLOSED;
++			__rfcomm_dlc_close(d, err);
++		} else 
++			rfcomm_send_dm(s, dlci);
++			
++	} else {
++		rfcomm_send_ua(s, 0);
++
++		if (s->state == BT_CONNECT)
++			err = ECONNREFUSED;
++		else
++			err = ECONNRESET;
++
++		s->state = BT_CLOSED;
++		rfcomm_session_close(s, err);
++	}
++
++	return 0;
++}
++
++static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_dlc *d;
++	u8 channel;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (!dlci) {
++		rfcomm_send_ua(s, 0);
++
++		if (s->state == BT_OPEN) {
++			s->state = BT_CONNECTED;
++			rfcomm_process_connect(s);
++		}
++		return 0;
++	}
++
++	/* Check if DLC exists */
++	d = rfcomm_dlc_get(s, dlci);
++	if (d) {
++		if (d->state == BT_OPEN) {
++			/* DLC was previously opened by PN request */
++			rfcomm_send_ua(s, dlci);
++
++			rfcomm_dlc_lock(d);
++			d->state = BT_CONNECTED;
++			d->state_change(d, 0);
++			rfcomm_dlc_unlock(d);
++
++			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
++		}
++		return 0;
++	}
++
++	/* Notify socket layer about incomming connection */
++	channel = __srv_channel(dlci);
++	if (rfcomm_connect_ind(s, channel, &d)) {
++		d->dlci = dlci;
++		d->addr = __addr(s->initiator, dlci);
++		rfcomm_dlc_link(s, d);
++
++		rfcomm_send_ua(s, dlci);
++
++		rfcomm_dlc_lock(d);
++		d->state = BT_CONNECTED;
++		d->state_change(d, 0);
++		rfcomm_dlc_unlock(d);
++
++		rfcomm_send_msc(s, 1, dlci, d->v24_sig);
++	} else {
++		rfcomm_send_dm(s, dlci);
++	}
++
++	return 0;
++}
++
++static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
++{
++	struct rfcomm_session *s = d->session;
++
++	BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", 
++			d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
++
++	if (pn->flow_ctrl == 0xf0 || pn->flow_ctrl == 0xe0) {
++		d->cfc = s->cfc = RFCOMM_CFC_ENABLED;
++		d->tx_credits = pn->credits;
++	} else {
++		d->cfc = s->cfc = RFCOMM_CFC_DISABLED;
++		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
++	}
++
++	d->priority = pn->priority;
++
++	d->mtu = s->mtu = btohs(pn->mtu);
++
++	return 0;
++}
++
++static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
++{
++	struct rfcomm_pn *pn = (void *) skb->data;
++	struct rfcomm_dlc *d;
++	u8 dlci = pn->dlci;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (!dlci)
++		return 0;
++
++	d = rfcomm_dlc_get(s, dlci);
++	if (d) {
++		if (cr) {
++			/* PN request */
++			rfcomm_apply_pn(d, cr, pn);
++			rfcomm_send_pn(s, 0, d);
++		} else {
++			/* PN response */
++			switch (d->state) {
++			case BT_CONFIG:
++				rfcomm_apply_pn(d, cr, pn);
++
++				d->state = BT_CONNECT;
++				rfcomm_send_sabm(s, d->dlci);
++				break;
++			}
++		}
++	} else {
++		u8 channel = __srv_channel(dlci);
++
++		if (!cr)
++			return 0;
++
++		/* PN request for non existing DLC.
++		 * Assume incomming connection. */
++		if (rfcomm_connect_ind(s, channel, &d)) {
++			d->dlci = dlci;
++			d->addr = __addr(s->initiator, dlci);
++			rfcomm_dlc_link(s, d);
++
++			rfcomm_apply_pn(d, cr, pn);
++
++			d->state = BT_OPEN;
++			rfcomm_send_pn(s, 0, d);
++		} else {
++			rfcomm_send_dm(s, dlci);
++		}
++	}
++	return 0;
++}
++
++static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
++{
++	struct rfcomm_rpn *rpn = (void *) skb->data;
++	u8 dlci = __get_dlci(rpn->dlci);
++
++	u8 bit_rate  = 0;
++	u8 data_bits = 0;
++	u8 stop_bits = 0;
++	u8 parity    = 0;
++	u8 flow_ctrl = 0;
++	u8 xon_char  = 0;
++	u8 xoff_char = 0;
++	u16 rpn_mask = RFCOMM_RPN_PM_ALL;
++	
++	BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", 
++	       dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
++	       rpn->xon_char, rpn->xoff_char, rpn->param_mask);
++	
++	if (!cr) 
++		return 0;
++	
++	if (len == 1) {
++		/* request: return default setting */
++		bit_rate  = RFCOMM_RPN_BR_115200;
++		data_bits = RFCOMM_RPN_DATA_8;
++		stop_bits = RFCOMM_RPN_STOP_1;
++		parity    = RFCOMM_RPN_PARITY_NONE;
++		flow_ctrl = RFCOMM_RPN_FLOW_NONE;
++		xon_char  = RFCOMM_RPN_XON_CHAR;
++		xoff_char = RFCOMM_RPN_XOFF_CHAR;
++
++		goto rpn_out;
++	}
++	/* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
++	                          no flow control lines, normal XON/XOFF chars */
++	if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
++		bit_rate = rpn->bit_rate;
++		if (bit_rate != RFCOMM_RPN_BR_115200) {
++			BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
++			bit_rate = RFCOMM_RPN_BR_115200;
++			rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
++		data_bits = __get_rpn_data_bits(rpn->line_settings);
++		if (data_bits != RFCOMM_RPN_DATA_8) {
++			BT_DBG("RPN data bits mismatch 0x%x", data_bits);
++			data_bits = RFCOMM_RPN_DATA_8;
++			rpn_mask ^= RFCOMM_RPN_PM_DATA;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
++		stop_bits = __get_rpn_stop_bits(rpn->line_settings);
++		if (stop_bits != RFCOMM_RPN_STOP_1) {
++			BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
++			stop_bits = RFCOMM_RPN_STOP_1;
++			rpn_mask ^= RFCOMM_RPN_PM_STOP;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
++		parity = __get_rpn_parity(rpn->line_settings);
++		if (parity != RFCOMM_RPN_PARITY_NONE) {
++			BT_DBG("RPN parity mismatch 0x%x", parity);
++			parity = RFCOMM_RPN_PARITY_NONE;
++			rpn_mask ^= RFCOMM_RPN_PM_PARITY;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
++		flow_ctrl = rpn->flow_ctrl;
++		if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
++			BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
++			flow_ctrl = RFCOMM_RPN_FLOW_NONE;
++			rpn_mask ^= RFCOMM_RPN_PM_FLOW;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
++		xon_char = rpn->xon_char;
++		if (xon_char != RFCOMM_RPN_XON_CHAR) {
++			BT_DBG("RPN XON char mismatch 0x%x", xon_char);
++			xon_char = RFCOMM_RPN_XON_CHAR;
++			rpn_mask ^= RFCOMM_RPN_PM_XON;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
++		xoff_char = rpn->xoff_char;
++		if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
++			BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
++			xoff_char = RFCOMM_RPN_XOFF_CHAR;
++			rpn_mask ^= RFCOMM_RPN_PM_XOFF;
++		}
++	}
++
++rpn_out:
++	rfcomm_send_rpn(s, 0, dlci, 
++			bit_rate, data_bits, stop_bits, parity, flow_ctrl,
++			xon_char, xoff_char, rpn_mask);
++
++	return 0;
++}
++
++static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
++{
++	struct rfcomm_rls *rls = (void *) skb->data;
++	u8 dlci = __get_dlci(rls->dlci);
++
++	BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
++	
++	if (!cr)
++		return 0;
++
++	/* FIXME: We should probably do something with this
++	   information here. But for now it's sufficient just
++	   to reply -- Bluetooth 1.1 says it's mandatory to 
++	   recognise and respond to RLS */
++
++	rfcomm_send_rls(s, 0, dlci, rls->status);
++
++	return 0;
++}
++
++static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
++{
++	struct rfcomm_msc *msc = (void *) skb->data;
++	struct rfcomm_dlc *d;
++	u8 dlci = __get_dlci(msc->dlci);
++
++	BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
++
++	d = rfcomm_dlc_get(s, dlci);
++	if (!d)
++		return 0;
++
++	if (cr) {
++		if (msc->v24_sig & RFCOMM_V24_FC && !d->cfc)
++			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
++		else
++			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
++		
++		rfcomm_dlc_lock(d);
++		if (d->modem_status)
++			d->modem_status(d, msc->v24_sig);
++		rfcomm_dlc_unlock(d);
++		
++		rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
++
++		d->mscex |= RFCOMM_MSCEX_RX;
++	} else 
++		d->mscex |= RFCOMM_MSCEX_TX;
++
++	return 0;
++}
++
++static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
++{
++	struct rfcomm_mcc *mcc = (void *) skb->data;
++	u8 type, cr, len;
++
++	cr   = __test_cr(mcc->type);
++	type = __get_mcc_type(mcc->type);
++	len  = __get_mcc_len(mcc->len);
++
++	BT_DBG("%p type 0x%x cr %d", s, type, cr);
++
++	skb_pull(skb, 2);
++
++	switch (type) {
++	case RFCOMM_PN:
++		rfcomm_recv_pn(s, cr, skb);
++		break;
++
++	case RFCOMM_RPN:
++		rfcomm_recv_rpn(s, cr, len, skb);
++		break;
++
++	case RFCOMM_RLS:
++		rfcomm_recv_rls(s, cr, skb);
++		break;
++
++	case RFCOMM_MSC:
++		rfcomm_recv_msc(s, cr, skb);
++		break;
++
++	case RFCOMM_FCOFF:
++		if (cr) {
++			set_bit(RFCOMM_TX_THROTTLED, &s->flags);
++			rfcomm_send_fcoff(s, 0);
++		}
++		break;
++
++	case RFCOMM_FCON:
++		if (cr) {
++			clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
++			rfcomm_send_fcon(s, 0);
++		}
++		break;
++
++	case RFCOMM_TEST:
++		if (cr)
++			rfcomm_send_test(s, 0, skb->data, skb->len);
++		break;
++
++	case RFCOMM_NSC:
++		break;
++
++	default:
++		BT_ERR("Unknown control type 0x%02x", type);
++		rfcomm_send_nsc(s, cr, type);
++		break;
++	}
++	return 0;
++}
++
++static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb)
++{
++	struct rfcomm_dlc *d;
++
++	BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
++
++	d = rfcomm_dlc_get(s, dlci);
++	if (!d) {
++		rfcomm_send_dm(s, dlci);
++		goto drop;
++	}
++
++	if (pf && d->cfc) {
++		u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
++
++		d->tx_credits += credits;
++		if (d->tx_credits)
++			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
++	}
++
++	if (skb->len && d->state == BT_CONNECTED) {
++		rfcomm_dlc_lock(d);
++		d->rx_credits--;
++		d->data_ready(d, skb);
++		rfcomm_dlc_unlock(d);
++		return 0;
++	}
++
++drop:
++	kfree_skb(skb);
++	return 0;
++}
++
++static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
++{
++	struct rfcomm_hdr *hdr = (void *) skb->data;
++	u8 type, dlci, fcs;
++
++	dlci = __get_dlci(hdr->addr);
++	type = __get_type(hdr->ctrl);
++
++	/* Trim FCS */
++	skb->len--; skb->tail--;
++	fcs = *(u8 *) skb->tail;
++	
++	if (__check_fcs(skb->data, type, fcs)) {
++		BT_ERR("bad checksum in packet");
++		kfree_skb(skb);
++		return -EILSEQ;
++	}
++
++	if (__test_ea(hdr->len))
++		skb_pull(skb, 3);
++	else
++		skb_pull(skb, 4);
++	
++	switch (type) {
++	case RFCOMM_SABM:
++		if (__test_pf(hdr->ctrl))
++			rfcomm_recv_sabm(s, dlci);
++		break;
++
++	case RFCOMM_DISC:
++		if (__test_pf(hdr->ctrl))
++			rfcomm_recv_disc(s, dlci);
++		break;
++
++	case RFCOMM_UA:
++		if (__test_pf(hdr->ctrl))
++			rfcomm_recv_ua(s, dlci);
++		break;
++
++	case RFCOMM_DM:
++		rfcomm_recv_dm(s, dlci);
++		break;
++
++	case RFCOMM_UIH:
++		if (dlci)
++			return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
++
++		rfcomm_recv_mcc(s, skb);
++		break;
++
++	default:
++		BT_ERR("Unknown packet type 0x%02x\n", type);
++		break;
++	}
++	kfree_skb(skb);
++	return 0;
++}
++
++/* ---- Connection and data processing ---- */
++
++static void rfcomm_process_connect(struct rfcomm_session *s)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p, *n;
++
++	BT_DBG("session %p state %ld", s, s->state);
++
++	list_for_each_safe(p, n, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		if (d->state == BT_CONFIG) {
++			d->mtu = s->mtu;
++			rfcomm_send_pn(s, 1, d);
++		}
++	}
++}
++
++/* Send data queued for the DLC.
++ * Return number of frames left in the queue.
++ */
++static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
++{
++	struct sk_buff *skb;
++	int err;
++
++	BT_DBG("dlc %p state %ld cfc %d rx_credits %d tx_credits %d", 
++			d, d->state, d->cfc, d->rx_credits, d->tx_credits);
++
++	/* Send pending MSC */
++	if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
++		rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
++	
++	if (d->cfc) {
++		/* CFC enabled. 
++		 * Give them some credits */
++		if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
++			       	d->rx_credits <= (d->cfc >> 2)) {
++			rfcomm_send_credits(d->session, d->addr, d->cfc - d->rx_credits);
++			d->rx_credits = d->cfc;
++		}
++	} else {
++		/* CFC disabled. 
++		 * Give ourselves some credits */
++		d->tx_credits = 5;
++	}
++
++	if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
++		return skb_queue_len(&d->tx_queue);
++
++	while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
++		err = rfcomm_send_frame(d->session, skb->data, skb->len);
++		if (err < 0) {
++			skb_queue_head(&d->tx_queue, skb);
++			break;
++		}
++		kfree_skb(skb);
++		d->tx_credits--;
++	}
++
++	if (d->cfc && !d->tx_credits) {
++		/* We're out of TX credits.
++		 * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
++		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
++	}
++
++	return skb_queue_len(&d->tx_queue);
++}
++
++static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p, *n;
++
++	BT_DBG("session %p state %ld", s, s->state);
++
++	list_for_each_safe(p, n, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
++			__rfcomm_dlc_close(d, ETIMEDOUT);
++			continue;
++		}
++
++		if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
++			continue;
++
++		if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
++				d->mscex == RFCOMM_MSCEX_OK)
++			rfcomm_process_tx(d);
++	}
++}
++
++static inline void rfcomm_process_rx(struct rfcomm_session *s)
++{
++	struct socket *sock = s->sock;
++	struct sock *sk = sock->sk;
++	struct sk_buff *skb;
++
++	BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue));
++
++	/* Get data directly from socket receive queue without copying it. */
++	while ((skb = skb_dequeue(&sk->receive_queue))) {
++		skb_orphan(skb);
++		rfcomm_recv_frame(s, skb);
++	}
++
++	if (sk->state == BT_CLOSED) {
++		if (!s->initiator)
++			rfcomm_session_put(s);
++
++		rfcomm_session_close(s, sk->err);
++	}
++}
++
++static inline void rfcomm_accept_connection(struct rfcomm_session *s)
++{
++	struct socket *sock = s->sock, *nsock;
++	int err;
++
++	/* Fast check for a new connection.
++	 * Avoids unnesesary socket allocations. */
++	if (list_empty(&bluez_pi(sock->sk)->accept_q))
++		return;
++
++	BT_DBG("session %p", s);
++
++	nsock = sock_alloc();
++	if (!nsock)
++		return;
++
++	nsock->type = sock->type;
++	nsock->ops  = sock->ops;
++	
++	err = sock->ops->accept(sock, nsock, O_NONBLOCK);
++	if (err < 0) {
++		sock_release(nsock);
++		return;
++	}
++
++	/* Set our callbacks */
++	nsock->sk->data_ready   = rfcomm_l2data_ready;
++	nsock->sk->state_change = rfcomm_l2state_change;
++
++	s = rfcomm_session_add(nsock, BT_OPEN);
++	if (s)
++		rfcomm_session_hold(s);
++	else
++		sock_release(nsock);
++}
++
++static inline void rfcomm_check_connection(struct rfcomm_session *s)
++{
++	struct sock *sk = s->sock->sk;
++
++	BT_DBG("%p state %ld", s, s->state);
++
++	switch(sk->state) {
++	case BT_CONNECTED:
++		s->state = BT_CONNECT;
++
++		/* We can adjust MTU on outgoing sessions.
++		 * L2CAP MTU minus UIH header and FCS. */
++		s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
++
++		rfcomm_send_sabm(s, 0);
++		break;
++
++	case BT_CLOSED:
++		s->state = BT_CLOSED;
++		rfcomm_session_close(s, sk->err);
++		break;
++	}
++}
++
++static inline void rfcomm_process_sessions(void)
++{
++	struct list_head *p, *n;
++
++	rfcomm_lock();
++
++	list_for_each_safe(p, n, &session_list) {
++		struct rfcomm_session *s;
++		s = list_entry(p, struct rfcomm_session, list);
++
++		if (s->state == BT_LISTEN) {
++			rfcomm_accept_connection(s);
++			continue;
++		}
++
++		rfcomm_session_hold(s);
++
++		switch (s->state) {
++		case BT_BOUND:
++			rfcomm_check_connection(s);
++			break;
++
++		default:
++			rfcomm_process_rx(s);
++			break;
++		}
++
++		rfcomm_process_dlcs(s);
++
++		rfcomm_session_put(s);
++	}
++	
++	rfcomm_unlock();
++}
++
++static void rfcomm_worker(void)
++{
++	BT_DBG("");
++
++	daemonize(); reparent_to_init();
++	set_fs(KERNEL_DS);
++
++	while (!atomic_read(&terminate)) {
++		BT_DBG("worker loop event 0x%lx", rfcomm_event);
++
++		if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
++			/* No pending events. Let's sleep.
++			 * Incomming connections and data will wake us up. */
++			set_current_state(TASK_INTERRUPTIBLE);
++			schedule();
++		}
++
++		/* Process stuff */
++		clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
++		rfcomm_process_sessions();
++	}
++	set_current_state(TASK_RUNNING);
++	return;
++}
++
++static int rfcomm_add_listener(bdaddr_t *ba)
++{
++	struct sockaddr_l2 addr;
++	struct l2cap_options opts;
++	struct socket *sock;
++	struct rfcomm_session *s;
++	int    size, err = 0;
++
++	/* Create socket */
++	err = rfcomm_l2sock_create(&sock);
++	if (err < 0) { 
++		BT_ERR("Create socket failed %d", err);
++		return err;
++	}
++
++	/* Bind socket */
++	bacpy(&addr.l2_bdaddr, ba);
++	addr.l2_family = AF_BLUETOOTH;
++	addr.l2_psm    = htobs(RFCOMM_PSM);
++	err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
++	if (err < 0) {
++		BT_ERR("Bind failed %d", err);
++		goto failed;
++	}
++
++	/* Set L2CAP options */
++	size = sizeof(opts);
++	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
++
++	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
++	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
++
++	/* Start listening on the socket */
++	err = sock->ops->listen(sock, 10);
++	if (err) {
++		BT_ERR("Listen failed %d", err);
++		goto failed;
++	}
++
++	/* Add listening session */
++	s = rfcomm_session_add(sock, BT_LISTEN);
++	if (!s)
++		goto failed;
++
++	rfcomm_session_hold(s);
++	return 0;
++failed:
++	sock_release(sock);
++	return err;
++}
++
++static void rfcomm_kill_listener(void)
++{
++	struct rfcomm_session *s;
++	struct list_head *p, *n;
++
++	BT_DBG("");
++
++	list_for_each_safe(p, n, &session_list) {
++		s = list_entry(p, struct rfcomm_session, list);
++		rfcomm_session_del(s);
++	}
++}
++
++static int rfcomm_run(void *unused)
++{
++	rfcomm_thread = current;
++
++	atomic_inc(&running);
++
++	daemonize(); reparent_to_init();
++
++	sigfillset(&current->blocked);
++	set_fs(KERNEL_DS);
++
++	sprintf(current->comm, "krfcommd");
++
++	BT_DBG("");
++
++	rfcomm_add_listener(BDADDR_ANY);
++
++	rfcomm_worker();
++
++	rfcomm_kill_listener();
++
++	atomic_dec(&running);
++	return 0;
++}
++
++/* ---- Proc fs support ---- */
++static int rfcomm_dlc_dump(char *buf)
++{
++	struct rfcomm_session *s;
++	struct sock *sk;
++	struct list_head *p, *pp;
++	char *ptr = buf;
++
++	rfcomm_lock();
++
++	list_for_each(p, &session_list) {
++		s = list_entry(p, struct rfcomm_session, list);
++		sk = s->sock->sk;
++
++		list_for_each(pp, &s->dlcs) {
++		struct rfcomm_dlc *d;
++			d = list_entry(pp, struct rfcomm_dlc, list);
++
++			ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
++				d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
++		}
++	}
++	
++	rfcomm_unlock();
++
++	return ptr - buf;
++}
++
++extern int rfcomm_sock_dump(char *buf);
++
++static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
++{
++	char *ptr = buf;
++	int len;
++
++	BT_DBG("count %d, offset %ld", count, offset);
++
++	ptr += rfcomm_dlc_dump(ptr);
++	ptr += rfcomm_sock_dump(ptr);
++	len  = ptr - buf;
++
++	if (len <= count + offset)
++		*eof = 1;
++
++	*start = buf + offset;
++	len -= offset;
++
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++
++/* ---- Initialization ---- */
++int __init rfcomm_init(void)
++{
++	l2cap_load();
++
++	kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++
++	rfcomm_init_sockets();
++
++#ifdef CONFIG_BLUEZ_RFCOMM_TTY
++	rfcomm_init_ttys();
++#endif
++
++	create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
++
++	BT_INFO("BlueZ RFCOMM ver %s", VERSION);
++	BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
++	return 0;
++}
++
++void rfcomm_cleanup(void)
++{
++	/* Terminate working thread.
++	 * ie. Set terminate flag and wake it up */
++	atomic_inc(&terminate);
++	rfcomm_schedule(RFCOMM_SCHED_STATE);
++
++	/* Wait until thread is running */
++	while (atomic_read(&running))
++		schedule();
++
++	remove_proc_entry("bluetooth/rfcomm", NULL);
++
++#ifdef CONFIG_BLUEZ_RFCOMM_TTY
++	rfcomm_cleanup_ttys();
++#endif
++
++	rfcomm_cleanup_sockets();
++	return;
++}
++
++module_init(rfcomm_init);
++module_exit(rfcomm_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
++MODULE_LICENSE("GPL");
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/rfcomm/crc.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,71 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * RFCOMM FCS calculation.
++ *
++ * $Id$
++ */
++
++/* reversed, 8-bit, poly=0x07 */
++unsigned char rfcomm_crc_table[256] = { 
++	0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
++	0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
++	0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
++	0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
++
++	0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
++	0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
++	0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
++	0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
++
++	0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
++	0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
++	0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
++	0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
++
++	0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
++	0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
++	0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
++	0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
++
++	0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
++	0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
++	0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
++	0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
++
++	0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
++	0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
++	0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
++	0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
++
++	0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
++	0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
++	0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
++	0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
++
++	0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
++	0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
++	0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
++	0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
++};
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/rfcomm/Makefile	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,11 @@
++#
++# Makefile for the Linux Bluetooth RFCOMM layer
++#
++
++O_TARGET := rfcomm.o
++
++obj-y				:= core.o sock.o crc.o
++obj-$(CONFIG_BLUEZ_RFCOMM_TTY)	+= tty.o
++obj-m				+= $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/rfcomm/sock.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,847 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * RFCOMM sockets.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/rfcomm.h>
++
++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++static struct proto_ops rfcomm_sock_ops;
++
++static struct bluez_sock_list rfcomm_sk_list = {
++	lock: RW_LOCK_UNLOCKED
++};
++
++static void rfcomm_sock_close(struct sock *sk);
++static void rfcomm_sock_kill(struct sock *sk);
++
++/* ---- DLC callbacks ----
++ *
++ * called under rfcomm_dlc_lock()
++ */
++static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
++{
++	struct sock *sk = d->owner;
++	if (!sk)
++		return;
++
++	atomic_add(skb->len, &sk->rmem_alloc);
++	skb_queue_tail(&sk->receive_queue, skb);
++	sk->data_ready(sk, skb->len);
++
++	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
++		rfcomm_dlc_throttle(d);
++}
++
++static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
++{
++	struct sock *sk = d->owner, *parent;
++	if (!sk)
++		return;
++
++	BT_DBG("dlc %p state %ld err %d", d, d->state, err);
++
++	bh_lock_sock(sk);
++
++	if (err)
++		sk->err = err;
++	sk->state = d->state;
++
++	parent = bluez_pi(sk)->parent;
++	if (!parent) {
++		if (d->state == BT_CONNECTED)
++			rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL);
++		sk->state_change(sk);
++	} else
++		parent->data_ready(parent, 0);
++
++	bh_unlock_sock(sk);
++}
++
++/* ---- Socket functions ---- */
++static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
++{
++	struct sock *sk;
++
++	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
++		if (rfcomm_pi(sk)->channel == channel && 
++				!bacmp(&bluez_pi(sk)->src, src))
++			break;
++	}
++
++	return sk;
++}
++
++/* Find socket with channel and source bdaddr.
++ * Returns closest match.
++ */
++static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
++{
++	struct sock *sk, *sk1 = NULL;
++
++	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
++		if (state && sk->state != state)
++			continue;
++
++		if (rfcomm_pi(sk)->channel == channel) {
++			/* Exact match. */
++			if (!bacmp(&bluez_pi(sk)->src, src))
++				break;
++
++			/* Closest match */
++			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++				sk1 = sk;
++		}
++	}
++	return sk ? sk : sk1;
++}
++
++/* Find socket with given address (channel, src).
++ * Returns locked socket */
++static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
++{
++	struct sock *s;
++	read_lock(&rfcomm_sk_list.lock);
++	s = __rfcomm_get_sock_by_channel(state, channel, src);
++	if (s) bh_lock_sock(s);
++	read_unlock(&rfcomm_sk_list.lock);
++	return s;
++}
++
++static void rfcomm_sock_destruct(struct sock *sk)
++{
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++
++	BT_DBG("sk %p dlc %p", sk, d);
++
++	skb_queue_purge(&sk->receive_queue);
++	skb_queue_purge(&sk->write_queue);
++
++	rfcomm_dlc_lock(d);
++	rfcomm_pi(sk)->dlc = NULL;
++	
++	/* Detach DLC if it's owned by this socket */
++	if (d->owner == sk)
++		d->owner = NULL;
++	rfcomm_dlc_unlock(d);
++
++	rfcomm_dlc_put(d);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static void rfcomm_sock_cleanup_listen(struct sock *parent)
++{
++	struct sock *sk;
++
++	BT_DBG("parent %p", parent);
++
++	/* Close not yet accepted dlcs */
++	while ((sk = bluez_accept_dequeue(parent, NULL))) {
++		rfcomm_sock_close(sk);
++		rfcomm_sock_kill(sk);
++	}
++
++	parent->state  = BT_CLOSED;
++	parent->zapped = 1;
++}
++
++/* Kill socket (only if zapped and orphan)
++ * Must be called on unlocked socket.
++ */
++static void rfcomm_sock_kill(struct sock *sk)
++{
++	if (!sk->zapped || sk->socket)
++		return;
++
++	BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
++
++	/* Kill poor orphan */
++	bluez_sock_unlink(&rfcomm_sk_list, sk);
++	sk->dead = 1;
++	sock_put(sk);
++}
++
++static void __rfcomm_sock_close(struct sock *sk)
++{
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++
++	BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
++
++	switch (sk->state) {
++	case BT_LISTEN:
++		rfcomm_sock_cleanup_listen(sk);
++		break;
++
++	case BT_CONNECT:
++	case BT_CONNECT2:
++	case BT_CONFIG:
++	case BT_CONNECTED:
++		rfcomm_dlc_close(d, 0);
++
++	default:
++		sk->zapped = 1;
++		break;
++	}
++}
++
++/* Close socket.
++ * Must be called on unlocked socket.
++ */
++static void rfcomm_sock_close(struct sock *sk)
++{
++	lock_sock(sk);
++	__rfcomm_sock_close(sk);
++	release_sock(sk);
++}
++
++static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
++{
++	BT_DBG("sk %p", sk);
++
++	if (parent) 
++		sk->type = parent->type;
++}
++
++static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
++{
++	struct rfcomm_dlc *d;
++	struct sock *sk;
++
++	sk = sk_alloc(PF_BLUETOOTH, prio, 1);
++	if (!sk)
++		return NULL;
++
++	d = rfcomm_dlc_alloc(prio);
++	if (!d) {
++		sk_free(sk);
++		return NULL;
++	}
++	d->data_ready   = rfcomm_sk_data_ready;
++	d->state_change = rfcomm_sk_state_change;
++
++	rfcomm_pi(sk)->dlc = d;
++	d->owner = sk;
++
++	bluez_sock_init(sock, sk);
++
++	sk->zapped   = 0;
++
++	sk->destruct = rfcomm_sock_destruct;
++	sk->sndtimeo = RFCOMM_CONN_TIMEOUT;
++
++	sk->sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
++	sk->rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
++
++	sk->protocol = proto;
++	sk->state    = BT_OPEN;
++
++	bluez_sock_link(&rfcomm_sk_list, sk);
++
++	BT_DBG("sk %p", sk);
++
++	MOD_INC_USE_COUNT;
++	return sk;
++}
++
++static int rfcomm_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	sock->state = SS_UNCONNECTED;
++
++	if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &rfcomm_sock_ops;
++
++	if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
++		return -ENOMEM;
++
++	rfcomm_sock_init(sk, NULL);
++	return 0;
++}
++
++static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
++{
++	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
++
++	if (!addr || addr->sa_family != AF_BLUETOOTH)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_OPEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	write_lock_bh(&rfcomm_sk_list.lock);
++
++	if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
++		err = -EADDRINUSE;
++	} else {
++		/* Save source address */
++		bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr);
++		rfcomm_pi(sk)->channel = sa->rc_channel;
++		sk->state = BT_BOUND;
++	}
++
++	write_unlock_bh(&rfcomm_sk_list.lock);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
++{
++	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
++	struct sock *sk = sock->sk;
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
++		return -EINVAL;
++
++	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
++		return -EBADFD;
++
++	if (sk->type != SOCK_STREAM)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	sk->state = BT_CONNECT;
++	bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr);
++	rfcomm_pi(sk)->channel = sa->rc_channel;
++	
++	err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
++	if (!err)
++		err = bluez_sock_wait_state(sk, BT_CONNECTED,
++				sock_sndtimeo(sk, flags & O_NONBLOCK));
++
++	release_sock(sk);
++	return err;
++}
++
++int rfcomm_sock_listen(struct socket *sock, int backlog)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p backlog %d", sk, backlog);
++
++	lock_sock(sk);
++
++	if (sk->state != BT_BOUND) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	sk->max_ack_backlog = backlog;
++	sk->ack_backlog = 0;
++	sk->state = BT_LISTEN;
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct sock *sk = sock->sk, *nsk;
++	long timeo;
++	int err = 0;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_LISTEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
++
++	BT_DBG("sk %p timeo %ld", sk, timeo);
++
++	/* Wait for an incoming connection. (wake-one). */
++	add_wait_queue_exclusive(sk->sleep, &wait);
++	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->state != BT_LISTEN) {
++			err = -EBADFD;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	if (err)
++		goto done;
++
++	newsock->state = SS_CONNECTED;
++
++	BT_DBG("new socket %p", nsk);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
++{
++	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	sa->rc_family  = AF_BLUETOOTH;
++	sa->rc_channel = rfcomm_pi(sk)->channel;
++	if (peer)
++		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst);
++	else
++		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src);
++
++	*len = sizeof(struct sockaddr_rc);
++	return 0;
++}
++
++static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
++			       struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++	struct sk_buff *skb;
++	int err, size;
++	int sent = 0;
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	if (sk->shutdown & SEND_SHUTDOWN)
++		return -EPIPE;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	lock_sock(sk);
++
++	while (len) {
++		size = min_t(uint, len, d->mtu);
++		
++		skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
++				msg->msg_flags & MSG_DONTWAIT, &err);
++		if (!skb)
++			break;
++		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
++
++		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
++		if (err) {
++			kfree_skb(skb);
++			sent = err;
++			break;
++		}
++
++		err = rfcomm_dlc_send(d, skb);
++		if (err < 0) {
++			kfree_skb(skb);
++			break;
++		}
++
++		sent += size;
++		len  -= size;
++	}
++
++	release_sock(sk);
++
++	return sent ? sent : err;
++}
++
++static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
++{
++	DECLARE_WAITQUEUE(wait, current);
++
++	add_wait_queue(sk->sleep, &wait);
++	for (;;) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) ||
++				signal_pending(current) || !timeo)
++			break;
++
++		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
++	}
++
++	__set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++	return timeo;
++}
++
++static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
++			       int flags, struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	int target, err = 0, copied = 0;
++	long timeo;
++
++	if (flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	msg->msg_namelen = 0;
++
++	BT_DBG("sk %p size %d", sk, size);
++
++	lock_sock(sk);
++
++	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
++	timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
++
++	do {
++		struct sk_buff *skb;
++		int chunk;
++
++		skb = skb_dequeue(&sk->receive_queue);
++		if (!skb) {
++			if (copied >= target)
++				break;
++
++			if ((err = sock_error(sk)) != 0)
++				break;
++			if (sk->shutdown & RCV_SHUTDOWN)
++				break;
++
++			err = -EAGAIN;
++			if (!timeo)
++				break;
++
++			timeo = rfcomm_sock_data_wait(sk, timeo);
++
++			if (signal_pending(current)) {
++				err = sock_intr_errno(timeo);
++				goto out;
++			}
++			continue;
++		}
++
++		chunk = min_t(unsigned int, skb->len, size);
++		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
++			skb_queue_head(&sk->receive_queue, skb);
++			if (!copied)
++				copied = -EFAULT;
++			break;
++		}
++		copied += chunk;
++		size   -= chunk;
++
++		if (!(flags & MSG_PEEK)) {
++			atomic_sub(chunk, &sk->rmem_alloc);
++
++			skb_pull(skb, chunk);
++			if (skb->len) {
++				skb_queue_head(&sk->receive_queue, skb);
++				break;
++			}
++			kfree_skb(skb);
++
++		} else {
++			/* put message back and return */
++			skb_queue_head(&sk->receive_queue, skb);
++			break;
++		}
++	} while (size);
++
++out:
++	if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2))
++		rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
++
++	release_sock(sk);
++	return copied ? : err;
++}
++
++static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	lock_sock(sk);
++
++	switch (optname) {
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
++{
++	struct sock *sk = sock->sk;
++	int len, err = 0; 
++
++	BT_DBG("sk %p", sk);
++
++	if (get_user(len, optlen))
++		return -EFAULT;
++
++	lock_sock(sk);
++
++	switch (optname) {
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct sock *sk = sock->sk;
++	int err;
++
++	lock_sock(sk);
++
++#ifdef CONFIG_BLUEZ_RFCOMM_TTY
++	err = rfcomm_dev_ioctl(sk, cmd, arg);
++#else
++	err = -EOPNOTSUPP;
++#endif
++
++	release_sock(sk);
++
++	return err;
++}
++
++static int rfcomm_sock_shutdown(struct socket *sock, int how)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk) return 0;
++
++	lock_sock(sk);
++	if (!sk->shutdown) {
++		sk->shutdown = SHUTDOWN_MASK;
++		__rfcomm_sock_close(sk);
++
++		if (sk->linger)
++			err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
++	}
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	err = rfcomm_sock_shutdown(sock, 2);
++
++	sock_orphan(sk);
++	rfcomm_sock_kill(sk);
++	return err;
++}
++
++/* ---- RFCOMM core layer callbacks ---- 
++ *
++ * called under rfcomm_lock()
++ */
++int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
++{
++	struct sock *sk, *parent;
++	bdaddr_t src, dst;
++	int result = 0;
++
++	BT_DBG("session %p channel %d", s, channel);
++
++	rfcomm_session_getaddr(s, &src, &dst);
++
++	/* Check if we have socket listening on this channel */
++	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
++	if (!parent)
++		return 0;
++
++	/* Check for backlog size */
++	if (parent->ack_backlog > parent->max_ack_backlog) {
++		BT_DBG("backlog full %d", parent->ack_backlog); 
++		goto done;
++	}
++
++	sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
++	if (!sk)
++		goto done;
++
++	rfcomm_sock_init(sk, parent);
++	bacpy(&bluez_pi(sk)->src, &src);
++	bacpy(&bluez_pi(sk)->dst, &dst);
++	rfcomm_pi(sk)->channel = channel;
++
++	sk->state = BT_CONFIG;
++	bluez_accept_enqueue(parent, sk);
++
++	/* Accept connection and return socket DLC */
++	*d = rfcomm_pi(sk)->dlc;
++	result = 1;
++
++done:
++	bh_unlock_sock(parent);
++	return result;
++}
++
++/* ---- Proc fs support ---- */
++int rfcomm_sock_dump(char *buf)
++{
++	struct bluez_sock_list *list = &rfcomm_sk_list;
++	struct rfcomm_pinfo *pi;
++	struct sock *sk;
++	char *ptr = buf;
++
++	write_lock_bh(&list->lock);
++
++	for (sk = list->head; sk; sk = sk->next) {
++		pi = rfcomm_pi(sk);
++		ptr += sprintf(ptr, "sk  %s %s %d %d\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
++				sk->state, rfcomm_pi(sk)->channel);
++	}
++
++	write_unlock_bh(&list->lock);
++
++	return ptr - buf;
++}
++
++static struct proto_ops rfcomm_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	rfcomm_sock_release,
++	bind:		rfcomm_sock_bind,
++	connect:	rfcomm_sock_connect,
++	listen:		rfcomm_sock_listen,
++	accept:		rfcomm_sock_accept,
++	getname:	rfcomm_sock_getname,
++	sendmsg:	rfcomm_sock_sendmsg,
++	recvmsg:	rfcomm_sock_recvmsg,
++	shutdown:	rfcomm_sock_shutdown,
++	setsockopt:	rfcomm_sock_setsockopt,
++	getsockopt:	rfcomm_sock_getsockopt,
++	ioctl:		rfcomm_sock_ioctl,
++	poll:		bluez_sock_poll,
++	socketpair:	sock_no_socketpair,
++	mmap:		sock_no_mmap
++};
++
++static struct net_proto_family rfcomm_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		rfcomm_sock_create
++};
++
++int rfcomm_init_sockets(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
++		BT_ERR("Can't register RFCOMM socket layer");
++		return err;
++	}
++
++	return 0;
++}
++
++void rfcomm_cleanup_sockets(void)
++{
++	int err;
++
++	/* Unregister socket, protocol and notifier */
++	if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
++		BT_ERR("Can't unregister RFCOMM socket layer %d", err);
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/rfcomm/tty.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,945 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * RFCOMM TTY.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++
++#include <linux/slab.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/rfcomm.h>
++
++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define RFCOMM_TTY_MAGIC 0x6d02		/* magic number for rfcomm struct */
++#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV	/* whole lotta rfcomm devices */
++#define RFCOMM_TTY_MAJOR 216		/* device node major id of the usb/bluetooth.c driver */
++#define RFCOMM_TTY_MINOR 0
++
++struct rfcomm_dev {
++	struct list_head	list;
++	atomic_t		refcnt;
++
++	char			name[12];
++	int			id;
++	unsigned long		flags;
++	int			opened;
++	int			err;
++
++	bdaddr_t		src;
++	bdaddr_t		dst;
++	u8 			channel;
++
++	uint 			modem_status;
++
++	struct rfcomm_dlc	*dlc;
++	struct tty_struct	*tty;
++	wait_queue_head_t       wait;
++	struct tasklet_struct   wakeup_task;
++
++	atomic_t 		wmem_alloc;
++};
++
++static LIST_HEAD(rfcomm_dev_list);
++static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED;
++
++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
++
++static void rfcomm_tty_wakeup(unsigned long arg);
++
++/* ---- Device functions ---- */
++static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
++{
++	struct rfcomm_dlc *dlc = dev->dlc;
++
++	BT_DBG("dev %p dlc %p", dev, dlc);
++
++	rfcomm_dlc_lock(dlc);
++	/* Detach DLC if it's owned by this dev */
++	if (dlc->owner == dev)
++		dlc->owner = NULL;
++	rfcomm_dlc_unlock(dlc);
++
++	rfcomm_dlc_put(dlc);
++	kfree(dev);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
++{
++	atomic_inc(&dev->refcnt);
++}
++
++static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
++{
++	if (atomic_dec_and_test(&dev->refcnt))
++		rfcomm_dev_destruct(dev);
++}
++
++static struct rfcomm_dev *__rfcomm_dev_get(int id)
++{
++	struct rfcomm_dev *dev;
++	struct list_head  *p;
++
++	list_for_each(p, &rfcomm_dev_list) {
++		dev = list_entry(p, struct rfcomm_dev, list);
++		if (dev->id == id)
++			return dev;
++	}
++
++	return NULL;
++}
++
++static inline struct rfcomm_dev *rfcomm_dev_get(int id)
++{
++	struct rfcomm_dev *dev;
++
++	read_lock(&rfcomm_dev_lock);
++	dev = __rfcomm_dev_get(id);
++	read_unlock(&rfcomm_dev_lock);
++
++	if (dev) rfcomm_dev_hold(dev);
++	return dev;
++}
++
++static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
++{
++	struct rfcomm_dev *dev;
++	struct list_head *head = &rfcomm_dev_list, *p;
++	int err = 0;
++
++	BT_DBG("id %d channel %d", req->dev_id, req->channel);
++	
++	dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
++	if (!dev)
++		return -ENOMEM;
++	memset(dev, 0, sizeof(struct rfcomm_dev));
++
++	write_lock_bh(&rfcomm_dev_lock);
++
++	if (req->dev_id < 0) {
++		dev->id = 0;
++
++		list_for_each(p, &rfcomm_dev_list) {
++			if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
++				break;
++
++			dev->id++;
++			head = p;
++		}
++	} else {
++		dev->id = req->dev_id;
++
++		list_for_each(p, &rfcomm_dev_list) {
++			struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
++
++			if (entry->id == dev->id) {
++				err = -EADDRINUSE;
++				goto out;
++			}
++
++			if (entry->id > dev->id - 1)
++				break;
++
++			head = p;
++		}
++	}
++
++	if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
++		err = -ENFILE;
++		goto out;
++	}
++
++	sprintf(dev->name, "rfcomm%d", dev->id);
++
++	list_add(&dev->list, head);
++	atomic_set(&dev->refcnt, 1);
++
++	bacpy(&dev->src, &req->src);
++	bacpy(&dev->dst, &req->dst);
++	dev->channel = req->channel;
++
++	dev->flags = req->flags & 
++		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
++
++	init_waitqueue_head(&dev->wait);
++	tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
++
++	rfcomm_dlc_lock(dlc);
++	dlc->data_ready   = rfcomm_dev_data_ready;
++	dlc->state_change = rfcomm_dev_state_change;
++	dlc->modem_status = rfcomm_dev_modem_status;
++
++	dlc->owner = dev;
++	dev->dlc   = dlc;
++	rfcomm_dlc_unlock(dlc);
++
++	MOD_INC_USE_COUNT;
++	
++out:
++	write_unlock_bh(&rfcomm_dev_lock);
++
++	if (err) {
++		kfree(dev);
++		return err;
++	} else
++		return dev->id;
++}
++
++static void rfcomm_dev_del(struct rfcomm_dev *dev)
++{
++	BT_DBG("dev %p", dev);
++
++	write_lock_bh(&rfcomm_dev_lock);
++	list_del_init(&dev->list);
++	write_unlock_bh(&rfcomm_dev_lock);
++
++	rfcomm_dev_put(dev);
++}
++
++/* ---- Send buffer ---- */
++
++static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
++{
++	/* We can't let it be zero, because we don't get a callback 
++	   when tx_credits becomes nonzero, hence we'd never wake up */
++	return dlc->mtu * (dlc->tx_credits?:1);
++}
++
++static void rfcomm_wfree(struct sk_buff *skb)
++{
++	struct rfcomm_dev *dev = (void *) skb->sk;
++	atomic_sub(skb->truesize, &dev->wmem_alloc);
++	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
++		tasklet_schedule(&dev->wakeup_task);
++	rfcomm_dev_put(dev);
++}
++
++static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
++{
++	rfcomm_dev_hold(dev);
++	atomic_add(skb->truesize, &dev->wmem_alloc);
++	skb->sk = (void *) dev;
++	skb->destructor = rfcomm_wfree;
++}
++
++static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority)
++{
++	if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
++		struct sk_buff *skb = alloc_skb(size, priority);
++		if (skb) {
++			rfcomm_set_owner_w(skb, dev);
++			return skb;
++		}
++	}
++	return NULL;
++}
++
++/* ---- Device IOCTLs ---- */
++
++#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
++
++static int rfcomm_create_dev(struct sock *sk, unsigned long arg)
++{
++	struct rfcomm_dev_req req;
++	struct rfcomm_dlc *dlc;
++	int id;
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
++
++	if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
++		return -EPERM;
++
++	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
++		/* Socket must be connected */
++		if (sk->state != BT_CONNECTED)
++			return -EBADFD;
++
++		dlc = rfcomm_pi(sk)->dlc;
++		rfcomm_dlc_hold(dlc);
++	} else {
++		dlc = rfcomm_dlc_alloc(GFP_KERNEL);
++		if (!dlc)
++			return -ENOMEM;
++	}
++
++	id = rfcomm_dev_add(&req, dlc);
++	if (id < 0) {
++		rfcomm_dlc_put(dlc);
++		return id;
++	}
++
++	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
++		/* DLC is now used by device.
++		 * Socket must be disconnected */
++		sk->state = BT_CLOSED;
++	}
++
++	return id;
++}
++
++static int rfcomm_release_dev(unsigned long arg)
++{
++	struct rfcomm_dev_req req;
++	struct rfcomm_dev *dev;
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
++
++	if (!capable(CAP_NET_ADMIN))
++		return -EPERM;
++
++	if (!(dev = rfcomm_dev_get(req.dev_id)))
++		return -ENODEV;
++
++	if (req.flags & (1 << RFCOMM_HANGUP_NOW))
++		rfcomm_dlc_close(dev->dlc, 0);
++
++	rfcomm_dev_del(dev);
++	rfcomm_dev_put(dev);
++	return 0;
++}
++
++static int rfcomm_get_dev_list(unsigned long arg)
++{
++	struct rfcomm_dev_list_req *dl;
++	struct rfcomm_dev_info *di;
++	struct list_head *p;
++	int n = 0, size;
++	u16 dev_num;
++
++	BT_DBG("");
++
++	if (get_user(dev_num, (u16 *) arg))
++		return -EFAULT;
++
++	if (!dev_num)
++		return -EINVAL;
++
++	size = sizeof(*dl) + dev_num * sizeof(*di);
++
++	if (verify_area(VERIFY_WRITE, (void *)arg, size))
++		return -EFAULT;
++
++	if (!(dl = kmalloc(size, GFP_KERNEL)))
++		return -ENOMEM;
++
++	di = dl->dev_info;
++
++	read_lock_bh(&rfcomm_dev_lock);
++
++	list_for_each(p, &rfcomm_dev_list) {
++		struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
++		(di + n)->id      = dev->id;
++		(di + n)->flags   = dev->flags;
++		(di + n)->state   = dev->dlc->state;
++		(di + n)->channel = dev->channel;
++		bacpy(&(di + n)->src, &dev->src);
++		bacpy(&(di + n)->dst, &dev->dst);
++		if (++n >= dev_num)
++			break;
++	}
++
++	read_unlock_bh(&rfcomm_dev_lock);
++
++	dl->dev_num = n;
++	size = sizeof(*dl) + n * sizeof(*di);
++
++	copy_to_user((void *) arg, dl, size);
++	kfree(dl);
++	return 0;
++}
++
++static int rfcomm_get_dev_info(unsigned long arg)
++{
++	struct rfcomm_dev *dev;
++	struct rfcomm_dev_info di;
++	int err = 0;
++
++	BT_DBG("");
++
++	if (copy_from_user(&di, (void *)arg, sizeof(di)))
++		return -EFAULT;
++
++	if (!(dev = rfcomm_dev_get(di.id)))
++		return -ENODEV;
++
++	di.flags   = dev->flags;
++	di.channel = dev->channel;
++	di.state   = dev->dlc->state;
++	bacpy(&di.src, &dev->src);
++	bacpy(&di.dst, &dev->dst);
++
++	if (copy_to_user((void *)arg, &di, sizeof(di)))
++		err = -EFAULT;
++
++	rfcomm_dev_put(dev);
++	return err;
++}
++
++int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
++{
++	BT_DBG("cmd %d arg %ld", cmd, arg);
++
++	switch (cmd) {
++	case RFCOMMCREATEDEV:
++		return rfcomm_create_dev(sk, arg);
++
++	case RFCOMMRELEASEDEV:
++		return rfcomm_release_dev(arg);
++
++	case RFCOMMGETDEVLIST:
++		return rfcomm_get_dev_list(arg);
++
++	case RFCOMMGETDEVINFO:
++		return rfcomm_get_dev_info(arg);
++	}
++
++	return -EINVAL;
++}
++
++/* ---- DLC callbacks ---- */
++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
++{
++	struct rfcomm_dev *dev = dlc->owner;
++	struct tty_struct *tty;
++       
++	if (!dev || !(tty = dev->tty)) {
++		kfree_skb(skb);
++		return;
++	}
++
++	BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
++
++	if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
++		register int i;
++		for (i = 0; i < skb->len; i++) {
++			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++				tty_flip_buffer_push(tty);
++
++			tty_insert_flip_char(tty, skb->data[i], 0);
++		}
++		tty_flip_buffer_push(tty);
++	} else
++		tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
++
++	kfree_skb(skb);
++}
++
++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
++{
++	struct rfcomm_dev *dev = dlc->owner;
++	if (!dev)
++		return;
++	
++	BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
++
++	dev->err = err;
++	wake_up_interruptible(&dev->wait);
++
++	if (dlc->state == BT_CLOSED) {
++		if (!dev->tty) {
++			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
++				rfcomm_dev_hold(dev);
++				rfcomm_dev_del(dev);
++
++				/* We have to drop DLC lock here, otherwise
++				 * rfcomm_dev_put() will dead lock if it's the last refference */
++				rfcomm_dlc_unlock(dlc);
++				rfcomm_dev_put(dev);
++				rfcomm_dlc_lock(dlc);
++			}
++		} else 
++			tty_hangup(dev->tty);
++	}
++}
++
++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
++{
++	struct rfcomm_dev *dev = dlc->owner;
++	if (!dev)
++		return;
++	
++	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
++
++	dev->modem_status = 
++		((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
++		((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
++		((v24_sig & RFCOMM_V24_IC)  ? TIOCM_RI : 0) |
++		((v24_sig & RFCOMM_V24_DV)  ? TIOCM_CD : 0);
++}
++
++/* ---- TTY functions ---- */
++static void rfcomm_tty_wakeup(unsigned long arg)
++{
++	struct rfcomm_dev *dev = (void *) arg;
++	struct tty_struct *tty = dev->tty;
++	if (!tty)
++		return;
++
++	BT_DBG("dev %p tty %p", dev, tty);
++
++	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
++                (tty->ldisc.write_wakeup)(tty);
++
++	wake_up_interruptible(&tty->write_wait);
++#ifdef SERIAL_HAVE_POLL_WAIT
++	wake_up_interruptible(&tty->poll_wait);
++#endif
++}
++
++static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct rfcomm_dev *dev;
++	struct rfcomm_dlc *dlc;
++	int err, id;
++
++	id = MINOR(tty->device) - tty->driver.minor_start;
++
++	BT_DBG("tty %p id %d", tty, id);
++
++	dev = rfcomm_dev_get(id);
++	if (!dev)
++		return -ENODEV;
++
++	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
++
++	if (dev->opened++ != 0)
++		return 0;
++
++	dlc = dev->dlc;
++
++	/* Attach TTY and open DLC */
++
++	rfcomm_dlc_lock(dlc);
++	tty->driver_data = dev;
++	dev->tty = tty;
++	rfcomm_dlc_unlock(dlc);
++	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
++
++	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
++	if (err < 0)
++		return err;
++
++	/* Wait for DLC to connect */
++	add_wait_queue(&dev->wait, &wait);
++	while (1) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (dlc->state == BT_CLOSED) {
++			err = -dev->err;
++			break;
++		}
++
++		if (dlc->state == BT_CONNECTED)
++			break;
++
++		if (signal_pending(current)) {
++			err = -EINTR;
++			break;
++		}
++
++		schedule();
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&dev->wait, &wait);
++
++	return err;
++}
++
++static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	if (!dev)
++		return;
++
++	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
++
++	if (--dev->opened == 0) {
++		/* Close DLC and dettach TTY */
++		rfcomm_dlc_close(dev->dlc, 0);
++
++		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
++		tasklet_kill(&dev->wakeup_task);
++
++		rfcomm_dlc_lock(dev->dlc);
++		tty->driver_data = NULL;
++		dev->tty = NULL;
++		rfcomm_dlc_unlock(dev->dlc);
++	}
++
++	rfcomm_dev_put(dev);
++}
++
++static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++	struct sk_buff *skb;
++	int err = 0, sent = 0, size;
++
++	BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
++
++	while (count) {
++		size = min_t(uint, count, dlc->mtu);
++
++		if (from_user)
++			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL);
++		else
++			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC);
++		
++		if (!skb)
++			break;
++
++		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
++
++		if (from_user)
++			copy_from_user(skb_put(skb, size), buf + sent, size);
++		else
++			memcpy(skb_put(skb, size), buf + sent, size);
++
++		if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
++			kfree_skb(skb);
++			break;
++		}
++
++		sent  += size;
++		count -= size;
++	}
++
++	return sent ? sent : err;
++}
++
++static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++	struct sk_buff *skb;
++
++	BT_DBG("tty %p char %x", tty, ch);
++
++	skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC);
++
++	if (!skb)
++		return;
++
++	skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
++
++	*(char *)skb_put(skb, 1) = ch;
++
++	if ((rfcomm_dlc_send(dlc, skb)) < 0)
++		kfree_skb(skb);	
++}
++
++static int rfcomm_tty_write_room(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	int room;
++	
++	BT_DBG("tty %p", tty);
++
++	room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
++	if (room < 0)
++		room = 0;
++
++	return room;
++}
++
++static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
++{
++	u8 v24_sig, mask;
++
++	BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
++
++	if (cmd == TIOCMSET)
++		v24_sig = 0;
++	else
++		rfcomm_dlc_get_modem_status(dlc, &v24_sig);
++
++	mask =  ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
++		((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
++		((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
++		((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
++		((status & TIOCM_RI)  ? RFCOMM_V24_IC  : 0) |
++		((status & TIOCM_CD)  ? RFCOMM_V24_DV  : 0);
++
++	if (cmd == TIOCMBIC)
++		v24_sig &= ~mask;
++	else
++		v24_sig |= mask;
++
++	rfcomm_dlc_set_modem_status(dlc, v24_sig);
++	return 0;
++}
++
++static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++	uint status;
++	int err;
++
++	BT_DBG("tty %p cmd 0x%02x", tty, cmd);
++
++	switch (cmd) {
++	case TCGETS:
++		BT_DBG("TCGETS is not supported");
++		return -ENOIOCTLCMD;
++
++	case TCSETS:
++		BT_DBG("TCSETS is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCMGET:
++		BT_DBG("TIOCMGET");
++
++		return put_user(dev->modem_status, (unsigned int *)arg);
++
++	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
++	case TIOCMBIS: /* Turns on the lines as specified by the mask */
++	case TIOCMBIC: /* Turns off the lines as specified by the mask */
++		if ((err = get_user(status, (unsigned int *)arg)))
++			return err;
++		return rfcomm_tty_set_modem_status(cmd, dlc, status);
++
++	case TIOCMIWAIT:
++		BT_DBG("TIOCMIWAIT");
++		break;
++
++	case TIOCGICOUNT:
++		BT_DBG("TIOCGICOUNT");
++		break;
++
++	case TIOCGSERIAL:
++		BT_ERR("TIOCGSERIAL is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSSERIAL:
++		BT_ERR("TIOCSSERIAL is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSERGSTRUCT:
++		BT_ERR("TIOCSERGSTRUCT is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSERGETLSR:
++		BT_ERR("TIOCSERGETLSR is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSERCONFIG:
++		BT_ERR("TIOCSERCONFIG is not supported");
++		return -ENOIOCTLCMD;
++
++	default:
++		return -ENOIOCTLCMD;	/* ioctls which we must ignore */
++
++	}
++
++	return -ENOIOCTLCMD;
++}
++
++#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
++
++static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
++{
++	BT_DBG("tty %p", tty);
++
++	if ((tty->termios->c_cflag == old->c_cflag) &&
++		(RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
++		return;
++
++	/* handle turning off CRTSCTS */
++	if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
++		BT_DBG("turning off CRTSCTS");
++	}
++}
++
++static void rfcomm_tty_throttle(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++	
++	rfcomm_dlc_throttle(dev->dlc);
++}
++
++static void rfcomm_tty_unthrottle(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++	
++	rfcomm_dlc_unthrottle(dev->dlc);
++}
++
++static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++
++	if (skb_queue_len(&dlc->tx_queue))
++		return dlc->mtu;
++
++	return 0;
++}
++
++static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	if (!dev)
++		return;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++
++	skb_queue_purge(&dev->dlc->tx_queue);
++
++	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
++		tty->ldisc.write_wakeup(tty);
++}
++
++static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
++{
++	BT_DBG("tty %p ch %c", tty, ch);
++}
++
++static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++	BT_DBG("tty %p timeout %d", tty, timeout);
++}
++
++static void rfcomm_tty_hangup(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	if (!dev)
++		return;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++
++	rfcomm_tty_flush_buffer(tty);
++
++	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
++		rfcomm_dev_del(dev);
++}
++
++static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
++{
++	return 0;
++}
++
++/* ---- TTY structure ---- */
++static int    rfcomm_tty_refcount;       /* If we manage several devices */
++
++static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS];
++static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
++static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
++
++static struct tty_driver rfcomm_tty_driver = {
++	magic:			TTY_DRIVER_MAGIC,
++	driver_name:		"rfcomm",
++#ifdef CONFIG_DEVFS_FS
++	name:			"bluetooth/rfcomm/%d",
++#else
++	name:			"rfcomm",
++#endif
++	major:			RFCOMM_TTY_MAJOR,
++	minor_start:		RFCOMM_TTY_MINOR,
++	num:			RFCOMM_TTY_PORTS,
++	type:			TTY_DRIVER_TYPE_SERIAL,
++	subtype:		SERIAL_TYPE_NORMAL,
++	flags:			TTY_DRIVER_REAL_RAW,
++
++	refcount:		&rfcomm_tty_refcount,
++	table:			rfcomm_tty_table,
++	termios:		rfcomm_tty_termios,
++	termios_locked:		rfcomm_tty_termios_locked,
++
++	open:			rfcomm_tty_open,
++	close:			rfcomm_tty_close,
++	put_char:		rfcomm_tty_put_char,
++	write:			rfcomm_tty_write,
++	write_room:		rfcomm_tty_write_room,
++	chars_in_buffer:	rfcomm_tty_chars_in_buffer,
++	flush_buffer:		rfcomm_tty_flush_buffer,
++	ioctl:			rfcomm_tty_ioctl,
++	throttle:		rfcomm_tty_throttle,
++	unthrottle:		rfcomm_tty_unthrottle,
++	set_termios:		rfcomm_tty_set_termios,
++	send_xchar:		rfcomm_tty_send_xchar,
++	stop:			NULL,
++	start:			NULL,
++	hangup:			rfcomm_tty_hangup,
++	wait_until_sent:	rfcomm_tty_wait_until_sent,
++	read_proc:		rfcomm_tty_read_proc,
++};
++
++int rfcomm_init_ttys(void)
++{
++	int i;
++
++	/* Initalize our global data */
++	for (i = 0; i < RFCOMM_TTY_PORTS; i++)
++		rfcomm_tty_table[i] = NULL;
++
++	/* Register the TTY driver */
++	rfcomm_tty_driver.init_termios = tty_std_termios;
++	rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++	rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
++
++	if (tty_register_driver(&rfcomm_tty_driver)) {
++		BT_ERR("Can't register RFCOMM TTY driver");
++		return -1;
++	}
++
++	return 0;
++}
++
++void rfcomm_cleanup_ttys(void)
++{
++	tty_unregister_driver(&rfcomm_tty_driver);
++	return;
++}
+--- /dev/null	1970-01-01 01:00:00.000000000 +0100
++++ linux/net/bluetooth/sco.c	2004-01-25 23:37:39.000000000 +0100
+@@ -0,0 +1,1019 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ SCO sockets.
++ *
++ * $Id$
++ */
++#define VERSION "0.3"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/proc_fs.h>
++#include <linux/list.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include <net/bluetooth/sco.h>
++
++#ifndef SCO_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++static struct proto_ops sco_sock_ops;
++
++static struct bluez_sock_list sco_sk_list = {
++	lock: RW_LOCK_UNLOCKED
++};
++
++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
++static void sco_chan_del(struct sock *sk, int err);
++static inline struct sock * sco_chan_get(struct sco_conn *conn);
++
++static int  sco_conn_del(struct hci_conn *conn, int err);
++
++static void sco_sock_close(struct sock *sk);
++static void sco_sock_kill(struct sock *sk);
++
++/* ----- SCO timers ------ */
++static void sco_sock_timeout(unsigned long arg)
++{
++	struct sock *sk = (struct sock *) arg;
++
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	bh_lock_sock(sk);
++	sk->err = ETIMEDOUT;
++	sk->state_change(sk);
++	bh_unlock_sock(sk);
++
++	sco_sock_kill(sk);
++	sock_put(sk);
++}
++
++static void sco_sock_set_timer(struct sock *sk, long timeout)
++{
++	BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
++
++	if (!mod_timer(&sk->timer, jiffies + timeout))
++		sock_hold(sk);
++}
++
++static void sco_sock_clear_timer(struct sock *sk)
++{
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
++		__sock_put(sk);
++}
++
++static void sco_sock_init_timer(struct sock *sk)
++{
++	init_timer(&sk->timer);
++	sk->timer.function = sco_sock_timeout;
++	sk->timer.data = (unsigned long)sk;
++}
++
++/* -------- SCO connections --------- */
++static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
++{
++	struct hci_dev *hdev = hcon->hdev;
++	struct sco_conn *conn;
++
++	if ((conn = hcon->sco_data))
++		return conn;
++
++	if (status)
++		return conn;
++
++	if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC)))
++		return NULL;
++	memset(conn, 0, sizeof(struct sco_conn));
++
++	spin_lock_init(&conn->lock);
++
++	hcon->sco_data = conn;
++	conn->hcon = hcon;
++
++	conn->src = &hdev->bdaddr;
++	conn->dst = &hcon->dst;
++	
++	if (hdev->sco_mtu > 0)
++		conn->mtu = hdev->sco_mtu;
++	else
++		conn->mtu = 60;
++
++	BT_DBG("hcon %p conn %p", hcon, conn);
++
++	MOD_INC_USE_COUNT;
++	return conn;
++}
++
++static int sco_conn_del(struct hci_conn *hcon, int err)
++{
++	struct sco_conn *conn;
++	struct sock *sk;
++
++	if (!(conn = hcon->sco_data)) 
++		return 0;
++
++	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
++
++	/* Kill socket */
++	if ((sk = sco_chan_get(conn))) {
++		bh_lock_sock(sk);
++		sco_sock_clear_timer(sk);
++		sco_chan_del(sk, err);
++		bh_unlock_sock(sk);
++		sco_sock_kill(sk);
++	}
++
++	hcon->sco_data = NULL;
++	kfree(conn);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++int sco_connect(struct sock *sk)
++{
++	bdaddr_t *src = &bluez_pi(sk)->src;
++	bdaddr_t *dst = &bluez_pi(sk)->dst;
++	struct sco_conn *conn;
++	struct hci_conn *hcon;
++	struct hci_dev  *hdev;
++	int err = 0;
++
++	BT_DBG("%s -> %s", batostr(src), batostr(dst));
++
++	if (!(hdev = hci_get_route(dst, src)))
++		return -EHOSTUNREACH;
++
++	hci_dev_lock_bh(hdev);
++
++	err = -ENOMEM;
++
++	hcon = hci_connect(hdev, SCO_LINK, dst);
++	if (!hcon)
++		goto done;
++
++	conn = sco_conn_add(hcon, 0);
++	if (!conn) {
++		hci_conn_put(hcon);
++		goto done;
++	}
++
++	/* Update source addr of the socket */
++	bacpy(src, conn->src);
++
++	err = sco_chan_add(conn, sk, NULL);
++	if (err)
++		goto done;
++
++	if (hcon->state == BT_CONNECTED) {
++		sco_sock_clear_timer(sk);
++		sk->state = BT_CONNECTED;
++	} else {
++		sk->state = BT_CONNECT;
++		sco_sock_set_timer(sk, sk->sndtimeo);
++	}
++done:
++	hci_dev_unlock_bh(hdev);
++	hci_dev_put(hdev);
++	return err;
++}
++
++static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
++{
++	struct sco_conn *conn = sco_pi(sk)->conn;
++	struct sk_buff *skb;
++	int err, count;
++
++	/* Check outgoing MTU */
++	if (len > conn->mtu)
++		return -EINVAL;
++
++	BT_DBG("sk %p len %d", sk, len);
++
++	count = MIN(conn->mtu, len);
++	if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
++		return err;
++
++	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
++		err = -EFAULT;
++		goto fail;
++	}
++
++	if ((err = hci_send_sco(conn->hcon, skb)) < 0)
++		goto fail;
++
++	return count;
++
++fail:
++	kfree_skb(skb);
++	return err;
++}
++
++static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
++{
++	struct sock *sk = sco_chan_get(conn);
++
++	if (!sk)
++		goto drop;
++
++	BT_DBG("sk %p len %d", sk, skb->len);
++
++	if (sk->state != BT_CONNECTED)
++		goto drop;
++
++	if (!sock_queue_rcv_skb(sk, skb))
++		return;
++
++drop:
++	kfree_skb(skb);
++	return;
++}
++
++/* -------- Socket interface ---------- */
++static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
++{
++	struct sock *sk;
++
++	for (sk = sco_sk_list.head; sk; sk = sk->next) {
++		if (!bacmp(&bluez_pi(sk)->src, ba))
++			break;
++	}
++
++	return sk;
++}
++
++/* Find socket listening on source bdaddr.
++ * Returns closest match.
++ */
++static struct sock *sco_get_sock_listen(bdaddr_t *src)
++{
++	struct sock *sk, *sk1 = NULL;
++
++	read_lock(&sco_sk_list.lock);
++
++	for (sk = sco_sk_list.head; sk; sk = sk->next) {
++		if (sk->state != BT_LISTEN)
++			continue;
++
++		/* Exact match. */
++		if (!bacmp(&bluez_pi(sk)->src, src))
++			break;
++
++		/* Closest match */
++		if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++			sk1 = sk;
++	}
++
++	read_unlock(&sco_sk_list.lock);
++
++	return sk ? sk : sk1;
++}
++
++static void sco_sock_destruct(struct sock *sk)
++{
++	BT_DBG("sk %p", sk);
++
++	skb_queue_purge(&sk->receive_queue);
++	skb_queue_purge(&sk->write_queue);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static void sco_sock_cleanup_listen(struct sock *parent)
++{
++	struct sock *sk;
++
++	BT_DBG("parent %p", parent);
++
++	/* Close not yet accepted channels */
++	while ((sk = bluez_accept_dequeue(parent, NULL))) {
++		sco_sock_close(sk);
++		sco_sock_kill(sk);
++	}
++
++	parent->state  = BT_CLOSED;
++	parent->zapped = 1;
++}
++
++/* Kill socket (only if zapped and orphan)
++ * Must be called on unlocked socket.
++ */
++static void sco_sock_kill(struct sock *sk)
++{
++	if (!sk->zapped || sk->socket)
++		return;
++
++	BT_DBG("sk %p state %d", sk, sk->state);
++
++	/* Kill poor orphan */
++	bluez_sock_unlink(&sco_sk_list, sk);
++	sk->dead = 1;
++	sock_put(sk);
++}
++
++/* Close socket.
++ * Must be called on unlocked socket.
++ */
++static void sco_sock_close(struct sock *sk)
++{
++	struct sco_conn *conn;
++
++	sco_sock_clear_timer(sk);
++
++	lock_sock(sk);
++
++	conn = sco_pi(sk)->conn;
++
++	BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
++
++	switch (sk->state) {
++	case BT_LISTEN:
++		sco_sock_cleanup_listen(sk);
++		break;
++
++	case BT_CONNECTED:
++	case BT_CONFIG:
++	case BT_CONNECT:
++	case BT_DISCONN:
++		sco_chan_del(sk, ECONNRESET);
++		break;
++
++	default:
++		sk->zapped = 1;
++		break;
++	};
++
++	release_sock(sk);
++}
++
++static void sco_sock_init(struct sock *sk, struct sock *parent)
++{
++	BT_DBG("sk %p", sk);
++
++	if (parent) 
++		sk->type = parent->type;
++}
++
++static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
++{
++	struct sock *sk;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
++		return NULL;
++
++	bluez_sock_init(sock, sk);
++
++	sk->zapped   = 0;
++
++	sk->destruct = sco_sock_destruct;
++	sk->sndtimeo = SCO_CONN_TIMEOUT;
++
++	sk->protocol = proto;
++	sk->state    = BT_OPEN;
++
++	sco_sock_init_timer(sk);
++
++	bluez_sock_link(&sco_sk_list, sk);
++
++	MOD_INC_USE_COUNT;
++	return sk;
++}
++
++static int sco_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	sock->state = SS_UNCONNECTED;
++
++	if (sock->type != SOCK_SEQPACKET)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &sco_sock_ops;
++
++	if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
++		return -ENOMEM;
++
++	sco_sock_init(sk, NULL);
++	return 0;
++}
++
++static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
++{
++	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
++	struct sock *sk = sock->sk;
++	bdaddr_t *src = &sa->sco_bdaddr;
++	int err = 0;
++
++	BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
++
++	if (!addr || addr->sa_family != AF_BLUETOOTH)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_OPEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	write_lock_bh(&sco_sk_list.lock);
++
++	if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
++		err = -EADDRINUSE;
++	} else {
++		/* Save source address */
++		bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
++		sk->state = BT_BOUND;
++	}
++
++	write_unlock_bh(&sco_sk_list.lock);
++
++done:
++	release_sock(sk);
++
++	return err;
++}
++
++static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
++{
++	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++
++	BT_DBG("sk %p", sk);
++
++	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
++		return -EINVAL;
++
++	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
++		return -EBADFD;
++
++	if (sk->type != SOCK_SEQPACKET)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	/* Set destination address and psm */
++	bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr);
++
++	if ((err = sco_connect(sk)))
++		goto done;
++
++	err = bluez_sock_wait_state(sk, BT_CONNECTED,
++			sock_sndtimeo(sk, flags & O_NONBLOCK));
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_listen(struct socket *sock, int backlog)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p backlog %d", sk, backlog);
++
++	lock_sock(sk);
++
++	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	sk->max_ack_backlog = backlog;
++	sk->ack_backlog = 0;
++	sk->state = BT_LISTEN;
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct sock *sk = sock->sk, *ch;
++	long timeo;
++	int err = 0;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_LISTEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
++
++	BT_DBG("sk %p timeo %ld", sk, timeo);
++
++	/* Wait for an incoming connection. (wake-one). */
++	add_wait_queue_exclusive(sk->sleep, &wait);
++	while (!(ch = bluez_accept_dequeue(sk, newsock))) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->state != BT_LISTEN) {
++			err = -EBADFD;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	if (err)
++		goto done;
++
++	newsock->state = SS_CONNECTED;
++
++	BT_DBG("new socket %p", ch);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
++{
++	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	addr->sa_family = AF_BLUETOOTH;
++	*len = sizeof(struct sockaddr_sco);
++
++	if (peer)
++		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);
++	else
++		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);
++
++	return 0;
++}
++
++static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (sk->err)
++		return sock_error(sk);
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	lock_sock(sk);
++
++	if (sk->state == BT_CONNECTED)
++		err = sco_send_frame(sk, msg, len);
++	else
++		err = -ENOTCONN;
++
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	lock_sock(sk);
++
++	switch (optname) {
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
++{
++	struct sock *sk = sock->sk;
++	struct sco_options opts;
++	struct sco_conninfo cinfo;
++	int len, err = 0; 
++
++	BT_DBG("sk %p", sk);
++
++	if (get_user(len, optlen))
++		return -EFAULT;
++
++	lock_sock(sk);
++
++	switch (optname) {
++	case SCO_OPTIONS:
++		if (sk->state != BT_CONNECTED) {
++			err = -ENOTCONN;
++			break;
++		}
++		
++		opts.mtu = sco_pi(sk)->conn->mtu;
++
++		BT_DBG("mtu %d", opts.mtu);
++
++		len = MIN(len, sizeof(opts));
++		if (copy_to_user(optval, (char *)&opts, len))
++			err = -EFAULT;
++
++		break;
++
++	case SCO_CONNINFO:
++		if (sk->state != BT_CONNECTED) {
++			err = -ENOTCONN;
++			break;
++		}
++
++		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
++
++		len = MIN(len, sizeof(cinfo));
++		if (copy_to_user(optval, (char *)&cinfo, len))
++			err = -EFAULT;
++
++		break;
++
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++static int sco_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	sco_sock_close(sk);
++	if (sk->linger) {
++		lock_sock(sk);
++		err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
++		release_sock(sk);
++	}
++
++	sock_orphan(sk);
++	sco_sock_kill(sk);
++	return err;
++}
++
++static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
++{
++	BT_DBG("conn %p", conn);
++
++	sco_pi(sk)->conn = conn;
++	conn->sk = sk;
++
++	if (parent)
++		bluez_accept_enqueue(parent, sk);
++}
++
++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
++{
++	int err = 0;
++
++	sco_conn_lock(conn);
++	if (conn->sk) {
++		err = -EBUSY;
++	} else {
++		__sco_chan_add(conn, sk, parent);
++	}
++	sco_conn_unlock(conn);
++	return err;
++}
++
++static inline struct sock * sco_chan_get(struct sco_conn *conn)
++{
++	struct sock *sk = NULL;
++	sco_conn_lock(conn);
++	sk = conn->sk;
++	sco_conn_unlock(conn);
++	return sk;
++}
++
++/* Delete channel. 
++ * Must be called on the locked socket. */
++static void sco_chan_del(struct sock *sk, int err)
++{
++	struct sco_conn *conn;
++
++	conn = sco_pi(sk)->conn;
++
++	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
++
++	if (conn) { 
++		sco_conn_lock(conn);
++		conn->sk = NULL;
++		sco_pi(sk)->conn = NULL;
++		sco_conn_unlock(conn);
++		hci_conn_put(conn->hcon);
++	}
++
++	sk->state = BT_CLOSED;
++	sk->err   = err;
++	sk->state_change(sk);
++
++	sk->zapped = 1;
++}
++
++static void sco_conn_ready(struct sco_conn *conn)
++{
++	struct sock *parent, *sk;
++
++	BT_DBG("conn %p", conn);
++
++	sco_conn_lock(conn);
++
++	if ((sk = conn->sk)) {
++		sco_sock_clear_timer(sk);
++		bh_lock_sock(sk);
++		sk->state = BT_CONNECTED;
++		sk->state_change(sk);
++		bh_unlock_sock(sk);
++	} else {
++		parent = sco_get_sock_listen(conn->src);
++		if (!parent)
++			goto done;
++
++		bh_lock_sock(parent);
++
++		sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
++		if (!sk) {
++			bh_unlock_sock(parent);
++                	goto done;
++		}
++
++		sco_sock_init(sk, parent);
++
++		bacpy(&bluez_pi(sk)->src, conn->src);
++		bacpy(&bluez_pi(sk)->dst, conn->dst);
++
++		hci_conn_hold(conn->hcon);
++        	__sco_chan_add(conn, sk, parent);
++
++        	sk->state = BT_CONNECTED;
++
++		/* Wake up parent */
++		parent->data_ready(parent, 1);
++	
++        	bh_unlock_sock(parent);
++	}
++
++done:
++	sco_conn_unlock(conn);
++}
++
++/* ----- SCO interface with lower layer (HCI) ----- */
++int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
++{
++	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
++
++	/* Always accept connection */
++	return HCI_LM_ACCEPT;
++}
++
++int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
++{
++	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
++
++	if (hcon->type != SCO_LINK)
++		return 0;
++
++	if (!status) {
++		struct sco_conn *conn;
++
++		conn = sco_conn_add(hcon, status);
++		if (conn)
++			sco_conn_ready(conn);
++	} else 
++		sco_conn_del(hcon, bterr(status));
++	
++	return 0;
++}
++
++int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
++{
++	BT_DBG("hcon %p reason %d", hcon, reason);
++
++	if (hcon->type != SCO_LINK)
++		return 0;
++
++	sco_conn_del(hcon, bterr(reason));
++	return 0;
++}
++
++int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
++{
++	struct sco_conn *conn = hcon->sco_data;
++
++	if (!conn)
++		goto drop;
++
++	BT_DBG("conn %p len %d", conn, skb->len);
++
++	if (skb->len) {
++		sco_recv_frame(conn, skb);
++		return 0;
++	}
++
++drop:
++	kfree_skb(skb);	
++	return 0;
++}
++
++/* ----- Proc fs support ------ */
++static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
++{
++	struct sco_pinfo *pi;
++	struct sock *sk;
++	char *ptr = buf;
++
++	write_lock_bh(&list->lock);
++
++	for (sk = list->head; sk; sk = sk->next) {
++		pi = sco_pi(sk);
++		ptr += sprintf(ptr, "%s %s %d\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
++				sk->state); 
++	}
++
++	write_unlock_bh(&list->lock);
++
++	ptr += sprintf(ptr, "\n");
++
++	return ptr - buf;
++}
++
++static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
++{
++	char *ptr = buf;
++	int len;
++
++	BT_DBG("count %d, offset %ld", count, offset);
++
++	ptr += sco_sock_dump(ptr, &sco_sk_list);
++	len  = ptr - buf;
++
++	if (len <= count + offset)
++		*eof = 1;
++
++	*start = buf + offset;
++	len -= offset;
++
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++
++static struct proto_ops sco_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	sco_sock_release,
++	bind:		sco_sock_bind,
++	connect:	sco_sock_connect,
++	listen:		sco_sock_listen,
++	accept:		sco_sock_accept,
++	getname:	sco_sock_getname,
++	sendmsg:	sco_sock_sendmsg,
++	recvmsg:	bluez_sock_recvmsg,
++	poll:		bluez_sock_poll,
++	socketpair:	sock_no_socketpair,
++	ioctl:		sock_no_ioctl,
++	shutdown:	sock_no_shutdown,
++	setsockopt:	sco_sock_setsockopt,
++	getsockopt:	sco_sock_getsockopt,
++	mmap:		sock_no_mmap
++};
++
++static struct net_proto_family sco_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		sco_sock_create
++};
++
++static struct hci_proto sco_hci_proto = {
++	name:		"SCO",
++	id:		HCI_PROTO_SCO,
++	connect_ind:	sco_connect_ind,
++	connect_cfm:	sco_connect_cfm,
++	disconn_ind:	sco_disconn_ind,
++	recv_scodata:	sco_recv_scodata,
++};
++
++int __init sco_init(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
++		BT_ERR("Can't register SCO socket layer");
++		return err;
++	}
++
++	if ((err = hci_register_proto(&sco_hci_proto))) {
++		BT_ERR("Can't register SCO protocol");
++		return err;
++	}
++
++	create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);
++
++	BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	return 0;
++}
++
++void sco_cleanup(void)
++{
++	int err;
++
++	remove_proc_entry("bluetooth/sco", NULL);
++
++	/* Unregister socket, protocol and notifier */
++	if ((err = bluez_sock_unregister(BTPROTO_SCO)))
++		BT_ERR("Can't unregister SCO socket layer %d", err);
++
++	if ((err = hci_unregister_proto(&sco_hci_proto)))
++		BT_ERR("Can't unregister SCO protocol %d", err);
++}
++
++module_init(sco_init);
++module_exit(sco_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
++MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);
++MODULE_LICENSE("GPL");
+--- linux/net/bluetooth/syms.c~bluetooth-2.4.18-mh11	2001-09-07 18:28:38.000000000 +0200
++++ linux/net/bluetooth/syms.c	2004-01-25 23:37:39.000000000 +0100
+@@ -25,7 +25,7 @@
+ /*
+  * BlueZ symbols.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/config.h>
+@@ -39,25 +39,28 @@
+ #include <linux/socket.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+ 
+ /* HCI Core */
+ EXPORT_SYMBOL(hci_register_dev);
+ EXPORT_SYMBOL(hci_unregister_dev);
++EXPORT_SYMBOL(hci_suspend_dev);
++EXPORT_SYMBOL(hci_resume_dev);
++
+ EXPORT_SYMBOL(hci_register_proto);
+ EXPORT_SYMBOL(hci_unregister_proto);
+-EXPORT_SYMBOL(hci_register_notifier);
+-EXPORT_SYMBOL(hci_unregister_notifier);
+ 
++EXPORT_SYMBOL(hci_get_route);
+ EXPORT_SYMBOL(hci_connect);
+-EXPORT_SYMBOL(hci_disconnect);
+ EXPORT_SYMBOL(hci_dev_get);
++EXPORT_SYMBOL(hci_conn_auth);
++EXPORT_SYMBOL(hci_conn_encrypt);
+ 
+ EXPORT_SYMBOL(hci_recv_frame);
+ EXPORT_SYMBOL(hci_send_acl);
+ EXPORT_SYMBOL(hci_send_sco);
+-EXPORT_SYMBOL(hci_send_raw);
++EXPORT_SYMBOL(hci_send_cmd);
++EXPORT_SYMBOL(hci_si_event);
+ 
+ /* BlueZ lib */
+ EXPORT_SYMBOL(bluez_dump);
+@@ -68,5 +71,11 @@
+ /* BlueZ sockets */
+ EXPORT_SYMBOL(bluez_sock_register);
+ EXPORT_SYMBOL(bluez_sock_unregister);
++EXPORT_SYMBOL(bluez_sock_init);
+ EXPORT_SYMBOL(bluez_sock_link);
+ EXPORT_SYMBOL(bluez_sock_unlink);
++EXPORT_SYMBOL(bluez_sock_recvmsg);
++EXPORT_SYMBOL(bluez_sock_poll);
++EXPORT_SYMBOL(bluez_accept_enqueue);
++EXPORT_SYMBOL(bluez_accept_dequeue);
++EXPORT_SYMBOL(bluez_sock_wait_state);
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch
index e69de29bb2..c29f0d02f2 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch
@@ -0,0 +1,1174 @@
+diff -Nur linux-orig/drivers/bluetooth/bt950_cs.c linux/drivers/bluetooth/bt950_cs.c
+--- linux-orig/drivers/bluetooth/bt950_cs.c	1970-01-01 03:00:00.000000000 +0300
++++ linux/drivers/bluetooth/bt950_cs.c	2004-02-04 09:55:04.000000000 +0300
+@@ -0,0 +1,1133 @@
++/*
++ *
++ *  Driver for Bluetooth cards with OXCF950 UART interface
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *                           Albert Rybalkin <albertr@iral.com>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++
++#ifdef CONFIG_MODVERSIONS
++#ifndef MODVERSIONS
++#define MODVERSIONS
++#endif
++#include <linux/modversions.h>
++#endif
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++/* Default baud rate: 57600, 115200, 230400 or 460800 */
++#define DEFAULT_BAUD_RATE 460800
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0x86bc;
++static int irq_list[4] = { -1 };
++static long baud_rate = DEFAULT_BAUD_RATE;
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++MODULE_PARM(baud_rate, "l");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Albert Rybalkin <albertr@iral.com>");
++MODULE_DESCRIPTION("BlueZ driver for Bluetooth cards with OXCF950 UART interface");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct bt950_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;	/* For serializing operations */
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++} bt950_info_t;
++
++
++static void bt950_config(dev_link_t *link);
++static void bt950_release(u_long arg);
++static int bt950_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "bt950_cs";
++
++static dev_link_t *bt950_attach(void);
++static void bt950_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++/* Transmit states  */
++#define XMIT_SENDING	1
++#define XMIT_WAKEUP	2
++#define XMIT_WAITING	8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE	0
++#define RECV_WAIT_EVENT_HEADER	1
++#define RECV_WAIT_ACL_HEADER	2
++#define RECV_WAIT_SCO_HEADER	3
++#define RECV_WAIT_DATA		4
++
++/* Special packet types */
++#define PKT_BAUD_RATE_57600   0x80
++#define PKT_BAUD_RATE_115200  0x81
++#define PKT_BAUD_RATE_230400  0x82
++#define PKT_BAUD_RATE_460800  0x83
++
++/* 950-specific stuff */
++#define MAX_WAIT	0xFFFF
++#define FIFO_SIZE	128
++
++#define TR_TX_INT	0x10	/* TTL: TX interrupt trigger level (0-127) */
++#define TR_RX_INT	0x40	/* RTL: RX interrupt trigger level (1-127) */
++#define TR_CTL_LO	0x08	/* FCL: auto flow control LOWER trigger level (0-127) */
++#define TR_CTL_HI	0x60	/* FCH: auto flow control HIGH trigger level (1-127) */
++
++/* 950-specific registers and values we use. It should
++ * eventually go to include/linux/serial_reg.h */
++#define UART_IER_CTS	0x80	/* enable CTS interrupt */
++#define UART_IER_RTS	0x40	/* enable RTS interrupt */
++#define UART_IER_SLP	0x10	/* enable sleep mode */
++#define UART_LCR_650	0xBF	/* enable 650-compatible registers access */
++#define UART_LSR_DE	0x80	/* data error */
++#define UART_LSR_ERR	(UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE)
++#define UART_IIR_RXTOUT	0x0C	/* RX timeout interrupt */
++#define UART_IIR_CTSRTS	0x20	/* CTS or RTS change interrupt */
++#define UART_IIR_RTS	0x40
++#define UART_IIR_CTS	0x80
++#define UART_IIR_MASK	0x3E	/* interrupt mask */
++#define UART_SRT	0x0D	/* soft reset register */
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int bt950_write(unsigned int iobase, int fifo_size, const unsigned char *buf, int len)
++{
++	int i, actual = 0;
++
++	/* Activate DTR and RTS */
++	outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, iobase + UART_MCR);
++
++	/* Wait for CTS flow control */
++	for (i = MAX_WAIT; i; i--)
++		if (inb(iobase + UART_MSR) & UART_MSR_CTS)
++			break;
++
++	if (!i) {
++		printk(KERN_WARNING "bt950_cs: Timeout waiting for CTS on write.\n");
++		return 0;
++	}
++
++	/* The TX FIFO should be empty */
++	for (i = MAX_WAIT; i; i--)
++		if (inb(iobase + UART_LSR) & UART_LSR_THRE)
++			break;
++
++	if (!i) {
++		printk(KERN_WARNING "bt950_cs: Timeout waiting for empty TX FIFO on write.\n");
++		return 0;
++	}
++
++	/* Fill FIFO with current frame */
++	while ((fifo_size-- > 0) && (actual < len)) {
++		/* Transmit next byte */
++		outb(buf[actual], iobase + UART_TX);
++		actual++;
++	}
++
++	return actual;
++}
++
++
++static void bt950_write_wakeup(bt950_info_t *info)
++{
++	unsigned char lcr;
++	unsigned int divisor;
++
++	if (!info) {
++		printk(KERN_WARNING "bt950_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register struct sk_buff *skb;
++		register int len;
++
++		clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (!(info->link.state & DEV_PRESENT))
++			return;
++
++		if (!(skb = skb_dequeue(&(info->txq))))
++			break;
++
++		if (skb->pkt_type & 0x80) {
++			/* Disable RTS */
++			outb((inb(iobase + UART_MCR) & ~UART_MCR_RTS), iobase + UART_MCR);
++		}
++
++		/* Send frame */
++		len = bt950_write(iobase, FIFO_SIZE, skb->data, skb->len);
++
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (skb->pkt_type & 0x80) {
++
++			wait_queue_head_t wait;
++
++			switch (skb->pkt_type) {
++
++			case PKT_BAUD_RATE_460800:
++				divisor = 1;
++				break;
++
++			case PKT_BAUD_RATE_230400:
++				divisor = 2;
++				break;
++
++			case PKT_BAUD_RATE_115200:
++				divisor = 4;
++				break;
++
++			case PKT_BAUD_RATE_57600:
++				/* Fall through... */
++
++			default:
++				divisor = 8;
++				break;
++			}
++
++			/* Wait until the command reaches the baseband */
++			init_waitqueue_head(&wait);
++			interruptible_sleep_on_timeout(&wait, HZ / 10);
++
++			/* Set baud on baseband */
++			/* Enable divisor latch access */
++			lcr = inb(iobase + UART_LCR) & 0x3F;
++			outb(lcr | UART_LCR_DLAB, iobase + UART_LCR);
++
++			/* Setup divisor latch */
++			outb(divisor & 0x00FF, iobase + UART_DLL);		/* divisor latch LOW byte */
++			outb((divisor & 0xFF00) >> 8, iobase + UART_DLM);	/* divisor latch HI byte */
++
++			/* Disable divisor latch access */
++			outb(lcr, iobase + UART_LCR);
++
++			/* Enable RTS */
++			outb((inb(iobase + UART_MCR) | UART_MCR_RTS), iobase + UART_MCR);
++
++			/* Wait before the next HCI packet can be send */
++			interruptible_sleep_on_timeout(&wait, HZ);
++
++		}
++
++		if (len == skb->len) {
++			kfree_skb(skb);
++		} else {
++			skb_pull(skb, len);
++			skb_queue_head(&(info->txq), skb);
++		}
++
++		info->hdev.stat.byte_tx += len;
++
++	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++	clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static inline void bt950_receive(bt950_info_t *info)
++{
++	unsigned int iobase;
++	int boguscount = 0;
++
++	if (!info) {
++		printk(KERN_ERR "bt950_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	/* Fixme: BUG? */
++	inb(iobase + UART_MCR);
++
++	do {
++		info->hdev.stat.byte_rx++;
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL) {
++			info->rx_state = RECV_WAIT_PACKET_TYPE;
++			info->rx_count = 0;
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_ERR "bt950_cs: Can't allocate mem for new packet.\n");
++				return;
++			}
++		}
++
++		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++			info->rx_skb->dev = (void *)&(info->hdev);
++			info->rx_skb->pkt_type = inb(iobase + UART_RX);
++
++			switch (info->rx_skb->pkt_type) {
++
++			case HCI_EVENT_PKT:
++				info->rx_state = RECV_WAIT_EVENT_HEADER;
++				info->rx_count = HCI_EVENT_HDR_SIZE;
++				break;
++
++			case HCI_ACLDATA_PKT:
++				info->rx_state = RECV_WAIT_ACL_HEADER;
++				info->rx_count = HCI_ACL_HDR_SIZE;
++				break;
++
++			case HCI_SCODATA_PKT:
++				info->rx_state = RECV_WAIT_SCO_HEADER;
++				info->rx_count = HCI_SCO_HDR_SIZE;
++				break;
++
++			default:
++				/* Unknown packet */
++				printk(KERN_WARNING "bt950_cs: Unknown HCI packet with type 0x%02X received.\n", info->rx_skb->pkt_type);
++				info->hdev.stat.err_rx++;
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			}
++
++		} else {
++
++			*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
++			info->rx_count--;
++
++			if (info->rx_count == 0) {
++
++				int dlen;
++				hci_event_hdr *eh;
++				hci_acl_hdr *ah;
++				hci_sco_hdr *sh;
++
++
++				switch (info->rx_state) {
++
++				case RECV_WAIT_EVENT_HEADER:
++					eh = (hci_event_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = eh->plen;
++					break;
++
++				case RECV_WAIT_ACL_HEADER:
++					ah = (hci_acl_hdr *)(info->rx_skb->data);
++					dlen = __le16_to_cpu(ah->dlen);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = dlen;
++					break;
++
++				case RECV_WAIT_SCO_HEADER:
++					sh = (hci_sco_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = sh->dlen;
++					break;
++
++				case RECV_WAIT_DATA:
++					hci_recv_frame(info->rx_skb);
++					info->rx_skb = NULL;
++					break;
++
++				}
++
++			}
++
++		}
++
++		/* Make sure we don't stay here too long */
++		if (boguscount++ > 16)
++			break;
++
++	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
++}
++
++
++static void bt950_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	bt950_info_t *info = dev_inst;
++	unsigned int iobase;
++	int boguscount = 0;
++	int iir, lsr;
++
++	if (!info) {
++		printk(KERN_ERR "bt950_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	iir = inb(iobase + UART_IIR);
++
++	while (!(iir & UART_IIR_NO_INT)) {
++
++		switch (iir & UART_IIR_ID) {
++		case UART_IIR_RLSI:
++			/* Clear RLSI interrupt */
++			lsr = inb(iobase + UART_LSR);
++			printk(KERN_NOTICE "bt950_cs: RLSI interrupt, LSR=%#x\n", lsr);
++			/* Fixme: we need to process errors ... */
++			break;
++		case UART_IIR_RDI:
++			/* Receive interrupt */
++			bt950_receive(info);
++			break;
++		case UART_IIR_THRI:
++			/* Transmitter ready for data */
++			bt950_write_wakeup(info);
++			break;
++		default:
++			printk(KERN_NOTICE "bt950_cs: Unhandled IIR=%#x\n", iir);
++			break;
++		}
++
++		/* Make sure we don't stay here too long */
++		if (boguscount++ > 100)
++			break;
++
++		iir = inb(iobase + UART_IIR);
++
++	}
++
++	spin_unlock(&(info->lock));
++}
++
++/* ======================== Device specific HCI commands ======================== */
++
++
++static int bt950_hci_set_baud_rate(struct hci_dev *hdev, int baud)
++{
++	bt950_info_t *info = (bt950_info_t *)(hdev->driver_data);
++	struct sk_buff *skb;
++
++	/* Ericsson baud rate command */
++	unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
++
++	if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++		printk(KERN_WARNING "bt950_cs: Can't allocate mem for new packet.\n");
++		return -1;
++	}
++
++	switch (baud) {
++	case 460800:
++		cmd[4] = 0x00;
++		skb->pkt_type = PKT_BAUD_RATE_460800;
++		break;
++	case 230400:
++		cmd[4] = 0x01;
++		skb->pkt_type = PKT_BAUD_RATE_230400;
++		break;
++	case 115200:
++		cmd[4] = 0x02;
++		skb->pkt_type = PKT_BAUD_RATE_115200;
++		break;
++	case 57600:
++		/* Fall through... */
++	default:
++	    baud = 57600;
++		cmd[4] = 0x03;
++		skb->pkt_type = PKT_BAUD_RATE_57600;
++		break;
++	}
++
++	memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
++
++	skb_queue_tail(&(info->txq), skb);
++
++    printk(KERN_WARNING "bt950_cs: setting baud rate: %d.\n", baud);
++    
++	bt950_write_wakeup(info);
++
++	return 0;
++}
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int bt950_hci_flush(struct hci_dev *hdev)
++{
++	bt950_info_t *info = (bt950_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int bt950_hci_open(struct hci_dev *hdev)
++{
++	bt950_hci_set_baud_rate(hdev, baud_rate);
++	set_bit(HCI_RUNNING, &(hdev->flags));
++
++	return 0;
++}
++
++
++static int bt950_hci_close(struct hci_dev *hdev)
++{
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	bt950_hci_flush(hdev);
++
++	return 0;
++}
++
++
++static int bt950_hci_send_frame(struct sk_buff *skb)
++{
++	bt950_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++	if (!hdev) {
++		printk(KERN_ERR "bt950_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (bt950_info_t *)(hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++	skb_queue_tail(&(info->txq), skb);
++
++	bt950_write_wakeup(info);
++
++	return 0;
++}
++
++
++static void bt950_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int bt950_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++static int bt950_setup_uart(bt950_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	unsigned char lcr, ier = UART_IER_RDI | UART_IER_RLSI | UART_IER_SLP;
++	unsigned int divisor = 8;	/* Fixme: divisor == 0x0c ??? */
++	unsigned char id1, id2, id3, rev;
++	register int i;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Disable interrupts */
++	outb(0, iobase + UART_IER);
++
++	/* Activate RTS and OUT2 */
++	/* Fixme: is OUT2 used to enable interrupts? */
++	outb(UART_MCR_RTS | UART_MCR_OUT2, iobase + UART_MCR);
++
++	/* Setup the FIFO's */
++	outb(0, iobase + UART_FCR);
++	inb(iobase + UART_RX);
++	outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
++	     UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_14, iobase + UART_FCR);
++
++	/* Disable divisor latch access */
++	lcr = inb(iobase + UART_LCR) & 0x3F;	/* mask out UART_LCR_DLAB and UART_LCR_SBC */
++	outb(lcr, iobase + UART_LCR);
++
++	/* Read up to 4 bytes from RX FIFO */
++	for (i = 0; i < 4; i++) {
++		inb(iobase + UART_RX);
++		if (!(inb(iobase + UART_LSR) & UART_LSR_DR))
++			break;
++	}
++
++	/* Wait if CTS/DSR/DCD changing */
++	for (i = 1; i < 0x3E8; i++) {
++		if (!(inb(iobase + UART_MSR) & UART_MSR_ANY_DELTA))
++			break;
++	}
++
++	/* Enable divisor latch access */
++	outb(lcr | UART_LCR_DLAB, iobase + UART_LCR);
++
++	/* Setup divisor latch */
++	outb(divisor & 0x00FF, iobase + UART_DLL);		/* divisor latch LOW byte */
++	outb((divisor & 0xFF00) >> 8, iobase + UART_DLM);	/* divisor latch HIGH byte */
++
++	/* Disable divisor latch access */
++	outb(lcr, iobase + UART_LCR);
++
++	/* Setup interrupts, enable sleep mode */
++	outb(ier, iobase + UART_IER);	/* we don't want to handle TX interrupts */
++
++	/* Skip pending interrupts */
++	for (i = 0; i < 4; i++) {
++		if (inb(iobase + UART_IIR) & UART_IIR_NO_INT)
++			break;
++	}
++
++	/* 8N1 */
++	lcr = UART_LCR_WLEN8;
++	outb(lcr, iobase + UART_LCR);
++
++	/* Setup CTS/RTS flow control and 950 enhanced mode */
++	outb(UART_LCR_650, iobase + UART_LCR);
++	outb(UART_EFR_CTS | UART_EFR_RTS | UART_EFR_ECB,
++	     iobase + UART_EFR);
++	outb(lcr, iobase + UART_LCR);
++
++	/* Read core id and revision */
++	outb(UART_ACR, iobase + UART_EMSR);
++	outb(UART_ACR_ICRRD, iobase + UART_LSR);	/* enable ICR read access, we don't need to save the old value of ACR */
++
++	outb(UART_ID1, iobase + UART_EMSR);
++	id1 = inb(iobase + UART_LSR);
++
++	outb(UART_ID2, iobase + UART_EMSR);
++	id2 = inb(iobase + UART_LSR);
++
++	outb(UART_ID3, iobase + UART_EMSR);
++	id3 = inb(iobase + UART_LSR);
++
++	outb(UART_REV, iobase + UART_EMSR);
++	rev = inb(iobase + UART_LSR);
++
++	if (id1 != 0x16 || id2 != 0xC9 || id3 != 0x50) {
++		printk(KERN_ERR "bt950_cs: Unknown UART core %02X%02X%02X found.\n", id1, id2, id3);
++		spin_unlock_irqrestore(&(info->lock), flags);
++		return -ENODEV;
++	}
++
++
++	/* Init ICR registers */
++	outb(UART_TTL, iobase + UART_EMSR);
++	outb(TR_TX_INT, iobase + UART_LSR);	/* TX interrupt trigger level (0-127) */
++
++	outb(UART_RTL, iobase + UART_EMSR);
++	outb(TR_RX_INT, iobase + UART_LSR);	/* RX interrupt trigger level (1-127) */
++
++	outb(UART_FCL, iobase + UART_EMSR);
++	outb(TR_CTL_LO, iobase + UART_LSR);	/* auto flow control LOWER trigger level (0-127) */
++
++	outb(UART_FCH, iobase + UART_EMSR);
++	outb(TR_CTL_HI, iobase + UART_LSR);	/* auto flow control HIGH trigger level (1-127) */
++
++	outb(UART_ACR, iobase + UART_EMSR);
++	outb(UART_ACR_TLENB, iobase + UART_LSR);	/* disable ICR read access, enable trigger levels */
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	return 0;
++}
++
++
++static void bt950_stop_uart(bt950_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Disable interrupts */
++	outb(0, iobase + UART_IER);
++
++	/* Set RTS and OUT2 low */
++	outb(0, iobase + UART_MCR);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++}
++
++
++static int bt950_open(bt950_info_t *info)
++{
++	struct hci_dev *hdev;
++	int err;
++
++	spin_lock_init(&(info->lock));
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_PACKET_TYPE;
++	info->rx_count = 0;
++	info->rx_skb = NULL;
++
++	/* Setup hardware */
++	if ((err = bt950_setup_uart(info)) < 0)
++		return err;
++
++	/* Timeout before it is safe to send the first HCI packet */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ);
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = bt950_hci_open;
++	hdev->close = bt950_hci_close;
++	hdev->flush = bt950_hci_flush;
++	hdev->send = bt950_hci_send_frame;
++	hdev->destruct = bt950_hci_destruct;
++	hdev->ioctl = bt950_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_ERR "bt950_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++static int bt950_close(bt950_info_t *info)
++{
++	struct hci_dev *hdev = &(info->hdev);
++
++	bt950_hci_close(hdev);
++
++	/* Stop hardware */
++	bt950_stop_uart(info);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_ERR "bt950_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++static dev_link_t *bt950_attach(void)
++{
++	bt950_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &bt950_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = bt950_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++	link->conf.Present =
++		PRESENT_OPTION | PRESENT_STATUS | PRESENT_PIN_REPLACE |
++		PRESENT_COPY;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &bt950_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		bt950_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++static void bt950_detach(dev_link_t *link)
++{
++	bt950_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG)
++		bt950_release((u_long) link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++static void bt950_config(dev_link_t *link)
++{
++	static ioaddr_t base[4] = { 0x2f8, 0x3e8, 0x2e8, 0x0 };
++	client_handle_t handle = link->handle;
++	bt950_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++	config_info_t config;
++	int i, j, try, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	/* First pass: look for a config entry that looks normal. */
++	tuple.TupleData = (cisdata_t *) buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++	/* Two tries: without IO aliases, then with aliases */
++	for (try = 0; try < 2; try++) {
++		i = first_tuple(handle, &tuple, &parse);
++		while (i != CS_NO_MORE_ITEMS) {
++			if (i != CS_SUCCESS)
++				goto next_entry;
++			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
++				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
++			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
++				link->conf.ConfigIndex = cf->index;
++				link->io.BasePort1 = cf->io.win[0].base;
++				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++next_entry:
++			i = next_tuple(handle, &tuple, &parse);
++		}
++	}
++
++	/* Second pass: try to find an entry that isn't picky about
++	   its base address, then try to grab any standard serial port
++	   address, and finally try to get any free port. */
++	i = first_tuple(handle, &tuple, &parse);
++	while (i != CS_NO_MORE_ITEMS) {
++		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
++		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
++			link->conf.ConfigIndex = cf->index;
++			for (j = 0; j < 5; j++) {
++				link->io.BasePort1 = base[j];
++				link->io.IOAddrLines = base[j] ? 16 : 3;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++		}
++		i = next_tuple(handle, &tuple, &parse);
++	}
++
++found_port:
++	if (i != CS_SUCCESS) {
++		printk(KERN_ERR "bt950_cs: No usable port range found. Giving up.\n");
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (bt950_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	bt950_release((u_long)link);
++	link->state &= ~DEV_CONFIG_PENDING;
++}
++
++
++static void bt950_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *) arg;
++	bt950_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		bt950_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++static int bt950_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	bt950_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			bt950_close(info);
++			link->state |= DEV_RELEASE_PENDING;
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		bt950_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG) {
++			bt950_stop_uart(info);
++			CardServices(ReleaseConfiguration, link->handle);
++		}
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (link->state & DEV_CONFIG) {
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++			bt950_setup_uart(info);
++		}
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_bt950_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "bt950_cs: Card Services release does not match!\n");
++//		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &bt950_attach, &bt950_detach);
++
++	return err;
++}
++
++
++void __exit exit_bt950_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		bt950_detach(dev_list);
++}
++
++
++module_init(init_bt950_cs);
++module_exit(exit_bt950_cs);
++
++EXPORT_NO_SYMBOLS;
+diff -Nur linux-orig/drivers/bluetooth/Config.in linux/drivers/bluetooth/Config.in
+--- linux-orig/drivers/bluetooth/Config.in	2004-02-16 08:45:33.000000000 +0300
++++ linux/drivers/bluetooth/Config.in	2004-02-16 08:50:36.000000000 +0300
+@@ -21,7 +21,7 @@
+ 
+ dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
+ 
+-dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
++# dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
+ 
+ dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
+ 
+@@ -29,5 +29,7 @@
+ 
+ dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
+ 
++dep_tristate 'HCI BT950 (BT950 device) driver' CONFIG_BLUEZ_BT950 $CONFIG_BLUEZ
++
+ endmenu
+ 
+diff -Nur linux-orig/drivers/bluetooth/Makefile linux/drivers/bluetooth/Makefile
+--- linux-orig/drivers/bluetooth/Makefile	2004-02-16 08:45:33.000000000 +0300
++++ linux/drivers/bluetooth/Makefile	2004-02-16 08:50:47.000000000 +0300
+@@ -17,10 +17,12 @@
+ obj-$(CONFIG_BLUEZ_HCIBFUSB)	+= bfusb.o
+ 
+ obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
+-obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
++# obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
+ obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
+ obj-$(CONFIG_BLUEZ_HCIBTUART)	+= btuart_cs.o
+ 
++obj-$(CONFIG_BLUEZ_BT950)	+= bt950_cs.o
++
+ include $(TOPDIR)/Rules.make
+ 
+ hci_uart.o: $(uart-y)
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch
index e69de29bb2..554f118936 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/buffered-fbmem.patch
@@ -0,0 +1,19 @@
+
+#
+# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/video/fbmem.c~buffered-fbmem	2003-09-16 00:48:18.000000000 +0200
++++ linux/drivers/video/fbmem.c	2003-09-19 00:38:00.000000000 +0200
+@@ -650,7 +650,11 @@
+ 	pgprot_val(vma->vm_page_prot) &= ~_CACHE_MASK;
+ 	pgprot_val(vma->vm_page_prot) |= _CACHE_UNCACHED;
+ #elif defined(__arm__)
++#ifdef CONFIG_PXA
++	vma->vm_page_prot = pgprot_noncached_buffered(vma->vm_page_prot);
++#else
+ 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++#endif
+ #ifdef CONFIG_POODLE_CONSISTENT_ALLOC
+ 	vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | L_PTE_CACHEABLE);
+ #endif
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch
index e69de29bb2..1a19b85daa 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/compile.patch
@@ -0,0 +1,14 @@
+--- linux/include/linux/jffs2_fs_i.h.old	2003-02-01 00:24:48.000000000 -0600
++++ linux/include/linux/jffs2_fs_i.h	2003-02-01 00:25:14.000000000 -0600
+@@ -48,9 +48,11 @@
+ 	uint32_t nr_frags;
+ #endif
+ 
++#ifdef KERNEL_VERSION
+ #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
+ 	struct inode vfs_inode;
+ #endif
++#endif
+ };
+ 
+ #endif /* _JFFS2_FS_I */
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch
index e69de29bb2..58343c5b55 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/deviceinfo.patch
@@ -0,0 +1,26 @@
+--- linux/arch/arm/mach-pxa/Makefile.old	2004-09-24 20:49:09.000000000 +0930
++++ linux/arch/arm/mach-pxa/Makefile	2004-09-24 20:49:11.000000000 +0930
+@@ -94,6 +94,23 @@
+   endif
+ endif
+ 
++ifeq ($(CONFIG_DEVICEINFO),m)
++  obj-$(CONFIG_DEVICEINFO) += devinfo.o
++  ifeq ($(CONFIG_SABINAL_DISCOVERY),y)
++    devinfo-objs-m += deviceinfo.o
++    devinfo-objs-$(CONFIG_DISCOVERY_DEVICEINFO) += discovery_deviceinfo.o
++  endif
++  ifeq ($(CONFIG_ARCH_PXA_POODLE),y)
++    devinfo-objs-m += sharpsl_deviceinfo.o
++  endif
++  ifeq ($(CONFIG_ARCH_PXA_CORGI),y)
++    devinfo-objs-m += sharpsl_deviceinfo.o
++  endif
++  ifeq ($(CONFIG_ARCH_PXA_TOSA),y)
++    devinfo-objs-m += sharpsl_deviceinfo.o
++  endif
++endif
++
+ obj-m += registers.o
+ 
+ include $(TOPDIR)/Rules.make
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch
index e69de29bb2..79ba036323 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/disable-pcmcia-probe.patch
@@ -0,0 +1,17 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe	2003-05-13 11:18:23.000000000 +0200
++++ linux/drivers/pcmcia/Config.in	2004-05-27 13:59:50.000000000 +0200
+@@ -15,9 +15,6 @@
+ tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+ if [ "$CONFIG_PCMCIA" != "n" ]; then
+    # yes, I really mean the following...
+-   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then
+-      define_bool CONFIG_PCMCIA_PROBE y
+-   fi
+    if [ "$CONFIG_PCI" != "n" ]; then
+       bool '  CardBus support' CONFIG_CARDBUS
+    fi
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch
index e69de29bb2..ece8fd9a5d 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/enable-sysrq.patch
@@ -0,0 +1,45 @@
+--- linux/drivers/char/corgi_keyb.c~enable-sysrq	2003-09-05 01:18:15.000000000 +0200
++++ linux/drivers/char/corgi_keyb.c	2003-09-05 01:40:17.000000000 +0200
+@@ -23,7 +23,7 @@
+ #include <linux/init.h>
+ #include <linux/poll.h>
+ #include <linux/wait.h>
+-#include <asm/arch/keyboard.h>
++#include <asm/keyboard.h>
+ #include <asm/uaccess.h>
+ #include <linux/tqueue.h>
+ #include <linux/kbd_ll.h>
+@@ -46,6 +46,18 @@
+ #endif
+ 
+ /*
++ * This is the KeyCode [not ScanCode!] to ASCII Code mapping table
++ */
++
++#ifdef CONFIG_MAGIC_SYSRQ
++static unsigned char corgi_sysrq_xlate[128] =
++	"\000abcdefghijklmno"						/* 00-0f */
++	"pqrstuvwxyz\000\000\000\000\000"				/* 10-1f */
++	" \000\000\000\000\000\000\000\0001234567"			/* 20-2f */
++	"890\000\000\000\000\000\000\000\000\000\000\000\000\000";	/* 30-3f */
++#endif
++
++/*
+  * common logical driver definition
+  */
+ extern void sharppda_kbd_press(int keycode);
+@@ -251,7 +263,13 @@
+ 	corgi_wakeup_button_init();
+ #endif // USE_WAKEUP_BUTTON
+ 
+-	printk("keyboard initilaized.\n");
++	printk("keyboard initialized.\n");
++#ifdef CONFIG_MAGIC_SYSRQ
++	k_sysrq_key = 0x28; // KEY_HOME
++	k_sysrq_xlate = corgi_sysrq_xlate;
++	printk("magic_sysrq initialized.\n");
++#endif
++
+ }
+ 
+ int corgi_kbd_translate(unsigned char scancode, unsigned char *keycode_p)
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch
index e69de29bb2..62038c34e2 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/idecs.patch
@@ -0,0 +1,77 @@
+--- linux/drivers/ide/ide-cs.c	2003-02-28 17:04:00.000000000 -0600
++++ linux.new/drivers/ide/ide-cs.c	2003-02-28 17:18:53.000000000 -0600
+@@ -2,7 +2,7 @@
+ 
+     A driver for PCMCIA IDE/ATA disk cards
+ 
+-    ide_cs.c 1.26 1999/11/16 02:10:49
++    ide-cs.c 1.26 1999/11/16 02:10:49
+ 
+     The contents of this file are subject to the Mozilla Public
+     License Version 1.1 (the "License"); you may not use this file
+@@ -66,7 +66,7 @@
+ MODULE_PARM(pc_debug, "i");
+ #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+ static char *version =
+-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
++"ide-cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
+ #else
+ #define DEBUG(n, args...)
+ #endif
+@@ -110,7 +110,7 @@
+ static int ide_event(event_t event, int priority,
+ 		     event_callback_args_t *args);
+ 
+-static dev_info_t dev_info = "ide_cs";
++static dev_info_t dev_info = "ide-cs";
+ 
+ static dev_link_t *ide_attach(void);
+ static void ide_detach(dev_link_t *);
+@@ -356,7 +356,7 @@
+     }
+     
+     if (hd < 0) {
+-	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
++	printk(KERN_NOTICE "ide-cs: ide_register() at 0x%03x & 0x%03x"
+ 	       ", irq %u failed\n", io_base, ctl_base,
+ 	       link->irq.AssignedIRQ);
+ 	goto failed;
+@@ -369,7 +369,7 @@
+     info->node.minor = 0;
+     info->hd = hd;
+     link->dev = &info->node;
+-    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
++    printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+ 	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+ 	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+ 
+@@ -409,9 +409,9 @@
+ 	MOD_DEC_USE_COUNT;
+     }
+ 
+-    request_region(link->io.BasePort1, link->io.NumPorts1,"ide_cs");
++    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
+     if (link->io.NumPorts2)
+-	request_region(link->io.BasePort2, link->io.NumPorts2,"ide_cs");
++	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
+     
+     info->ndev = 0;
+     link->dev = NULL;
+@@ -508,7 +508,7 @@
+     DEBUG(0, "%s\n", version);
+     CardServices(GetCardServicesInfo, &serv);
+     if (serv.Revision != CS_RELEASE_CODE) {
+-	printk(KERN_NOTICE "ide_cs: Card Services release "
++	printk(KERN_NOTICE "ide-cs: Card Services release "
+ 	       "does not match!\n");
+ 	return -1;
+     }
+@@ -518,7 +518,7 @@
+ 
+ static void __exit exit_ide_cs(void)
+ {
+-    DEBUG(0, "ide_cs: unloading\n");
++    DEBUG(0, "ide-cs: unloading\n");
+     unregister_pccard_driver(&dev_info);
+     while (dev_list != NULL)
+ 	ide_detach(dev_list);
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch
index e69de29bb2..a672631194 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/initsh.patch
@@ -0,0 +1,14 @@
+--- linux/init/main.c	2002-02-25 13:38:13.000000000 -0600
++++ linux.new/init/main.c	2003-03-16 11:49:45.000000000 -0600
+@@ -830,8 +830,10 @@
+ 	 * trying to recover a really broken machine.
+ 	 */
+ 
+-	if (execute_command)
++	if (execute_command) {
++		argv_init[0] = execute_command; 
+ 		execve(execute_command,argv_init,envp_init);
++	}
+ 	execve("/sbin/init",argv_init,envp_init);
+ 	execve("/etc/init",argv_init,envp_init);
+ 	execve("/bin/init",argv_init,envp_init);
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch
index e69de29bb2..559f4ad564 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/irda-qos.patch
@@ -0,0 +1,108 @@
+diff -urN linux.orig/net/irda/irsysctl.c linux/net/irda/irsysctl.c
+--- linux.orig/net/irda/irsysctl.c	Fri Feb 27 18:28:04 2004
++++ linux/net/irda/irsysctl.c	Wed Jan 14 19:36:40 2004
+@@ -40,7 +40,8 @@
+ 
+ enum { DISCOVERY=1, DEVNAME, DEBUG, FAST_POLL, DISCOVERY_SLOTS,
+        DISCOVERY_TIMEOUT, SLOT_TIMEOUT, MAX_BAUD_RATE, MIN_TX_TURN_TIME,
+-       MAX_NOREPLY_TIME, WARN_NOREPLY_TIME, LAP_KEEPALIVE_TIME, SPECIFIC_DEV };
++       MAX_TX_WINDOW, MAX_NOREPLY_TIME, WARN_NOREPLY_TIME,
++       LAP_KEEPALIVE_TIME, SPECIFIC_DEV };
+ 
+ extern int  sysctl_discovery;
+ extern int  sysctl_discovery_slots;
+@@ -51,6 +52,7 @@
+ extern char sysctl_devname[];
+ extern int  sysctl_max_baud_rate;
+ extern int  sysctl_min_tx_turn_time;
++extern int  sysctl_max_tx_window;
+ extern int  sysctl_max_noreply_time;
+ extern int  sysctl_warn_noreply_time;
+ extern int  sysctl_lap_keepalive_time;
+@@ -71,6 +73,8 @@
+ static int min_max_baud_rate = 2400;
+ static int max_min_tx_turn_time = 10000;	/* See qos.c - IrLAP spec */
+ static int min_min_tx_turn_time = 0;
++static int max_max_tx_window=7;
++static int min_max_tx_window=1;
+ static int max_max_noreply_time = 40;		/* See qos.c - IrLAP spec */
+ static int min_max_noreply_time = 3;
+ static int max_warn_noreply_time = 3;		/* 3s == standard */
+@@ -128,6 +132,9 @@
+ 	{ MIN_TX_TURN_TIME, "min_tx_turn_time", &sysctl_min_tx_turn_time,
+ 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+ 	  NULL, &min_min_tx_turn_time, &max_min_tx_turn_time },
++	{ MAX_TX_WINDOW, "max_tx_window", &sysctl_max_tx_window,
++	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
++	  NULL, &min_max_tx_window, &max_max_tx_window },
+ 	{ MAX_NOREPLY_TIME, "max_noreply_time", &sysctl_max_noreply_time,
+ 	  sizeof(int), 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec,
+ 	  NULL, &min_max_noreply_time, &max_max_noreply_time },
+diff -urN linux.orig/net/irda/parameters.c linux/net/irda/parameters.c
+--- linux.orig/net/irda/parameters.c	Sat Nov 10 01:22:17 2001
++++ linux/net/irda/parameters.c	Wed Jan 14 19:34:23 2004
+@@ -204,12 +204,14 @@
+ {
+ 	irda_param_t p;
+ 	int n = 0;
++	int extract_len;
+ 	int err;
+ 
+ 	p.pi = pi;     /* In case handler needs to know */
+ 	p.pl = buf[1]; /* Extract lenght of value */
+ 	p.pv.i = 0;    /* Clear value */
+-
++	extract_len = p.pl;
++	
+ 	/* Check if buffer is long enough for parsing */
+ 	if (len < (2+p.pl)) {
+ 		WARNING(__FUNCTION__ "(), buffer to short for parsing! "
+@@ -226,12 +228,15 @@
+ 		      "Expected %d bytes, but value had %d bytes!\n",
+ 		      type & PV_MASK, p.pl);
+ 		
+-		/* Skip parameter */
++	    if((p.pl < (type & PV_MASK)) || (type & PV_BIG_ENDIAN)) {
+ 		return p.pl+2;
++	    } else {
++		extract_len = type & PV_MASK;
++	    }
+ 	}
+ 
+ 
+-	switch (p.pl) {
++	switch (extract_len) {
+ 	case 1:
+ 		n += irda_param_unpack(buf+2, "b", &p.pv.i);
+ 		break;
+diff -urN linux.orig/net/irda/qos.c linux/net/irda/qos.c
+--- linux.orig/net/irda/qos.c	Fri Feb 27 18:28:04 2004
++++ linux/net/irda/qos.c	Wed Jan 14 18:18:20 2004
+@@ -65,6 +65,7 @@
+  */
+ unsigned sysctl_min_tx_turn_time = 10;
+ 
++unsigned sysctl_max_tx_window = 7;
+ /*
+  * Specific device list limits some negotiation parameters at the connection
+  * with listed peer devices.
+@@ -212,6 +213,9 @@
+ 	__u16 msb = 0x8000;
+ 	int index = 15;   /* Current MSB */
+ 	
++	if(!word)
++	    word=0x1;
++
+ 	while (msb) {
+ 		if (word & msb)
+ 			break;   /* Found it! */
+@@ -386,6 +390,9 @@
+ 		qos->max_turn_time.value = 500;
+ 	}
+ 	
++	if(qos->window_size.value > sysctl_max_tx_window)
++	    qos->window_size.value = sysctl_max_tx_window;
++	    
+ 	/*
+ 	 * The data size must be adjusted according to the baud rate and max 
+ 	 * turn time
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff
index e69de29bb2..2ebfd8ec12 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw240_we15-6.diff
@@ -0,0 +1,399 @@
+diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h
+--- linux/include/linux/wireless.14.h	Mon Dec  2 18:51:00 2002
++++ linux/include/linux/wireless.h	Mon Dec  2 18:53:35 2002
+@@ -1,7 +1,7 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	14	25.1.02
++ * Version :	15	12.7.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+@@ -80,7 +80,7 @@
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	14
++#define WIRELESS_EXT	15
+ 
+ /*
+  * Changes :
+@@ -153,17 +153,32 @@
+  *	- Define additional specific event numbers
+  *	- Add "addr" and "param" fields in union iwreq_data
+  *	- AP scanning stuff (SIOCSIWSCAN and friends)
++ *
++ * V14 to V15
++ * ----------
++ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
++ *	- Make struct iw_freq signed (both m & e), add explicit padding
++ *	- Add IWEVCUSTOM for driver specific event/scanning token
++ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
++ *	- Add IW_TXPOW_RANGE for range of Tx Powers
++ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
++ *	- Add IW_MODE_MONITOR for passive monitor
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+ /* -------------------------- IOCTL LIST -------------------------- */
+ 
+-/* Basic operations */
++/* Wireless Identification */
+ #define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
+ #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
+-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
+-#define SIOCGIWNWID	0x8B03		/* get network id */
++/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
++ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
++ * Don't put the name of your driver there, it's useless. */
++
++/* Basic operations */
++#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
++#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
+ #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
+ #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
+ #define SIOCSIWMODE	0x8B06		/* set operation mode */
+@@ -178,16 +193,18 @@
+ #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
+ #define SIOCSIWSTATS	0x8B0E		/* Unused */
+ #define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
++/* SIOCGIWSTATS is strictly used between user space and the kernel, and
++ * is never passed to the driver (i.e. the driver will never see it). */
+ 
+-/* Mobile IP support */
++/* Mobile IP support (statistics per MAC address) */
+ #define SIOCSIWSPY	0x8B10		/* set spy addresses */
+ #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
+ 
+ /* Access Point manipulation */
+ #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
+ #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
+-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
+-#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
++#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
++#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
+ #define SIOCGIWSCAN	0x8B19		/* get scanning results */
+ 
+ /* 802.11 specific support */
+@@ -197,9 +214,7 @@
+ #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
+ /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
+  * within the 'iwreq' structure, so we need to use the 'data' member to
+- * point to a string in user space, like it is done for RANGE...
+- * The "flags" member indicate if the ESSID is active or not (promiscuous).
+- */
++ * point to a string in user space, like it is done for RANGE... */
+ 
+ /* Other parameters useful in 802.11 and some other devices */
+ #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
+@@ -257,7 +272,10 @@
+ /* Most events use the same identifier as ioctl requests */
+ 
+ #define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
+-#define IWEVQUAL	0x8C01		/* Quality part of statistics */
++#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
++#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
++#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
++#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
+ 
+ #define IWEVFIRST	0x8C00
+ 
+@@ -273,7 +291,8 @@
+ #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
+ #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
+ #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
+-#define IW_PRIV_TYPE_FLOAT	0x5000
++#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
++#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
+ 
+ #define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
+ 
+@@ -297,13 +316,16 @@
+ 
+ /* Maximum tx powers in the range struct */
+ #define IW_MAX_TXPOWER		8
++/* Note : if you more than 8 TXPowers, just set the max and min or
++ * a few of them in the struct iw_range. */
+ 
+ /* Maximum of address that you may set with SPY */
+-#define IW_MAX_SPY		8
++#define IW_MAX_SPY		8	/* set */
++#define IW_MAX_GET_SPY		64	/* get */
+ 
+ /* Maximum of address that you may get in the
+    list of access points in range */
+-#define IW_MAX_AP		8
++#define IW_MAX_AP		64
+ 
+ /* Maximum size of the ESSID and NICKN strings */
+ #define IW_ESSID_MAX_SIZE	32
+@@ -315,6 +337,7 @@
+ #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
+ #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
+ #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
++#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
+ 
+ /* Maximum number of size of encoding token available
+  * they are listed in the range structure */
+@@ -350,8 +373,10 @@
+ #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+ 
+ /* Transmit Power flags available */
++#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
+ #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
+ #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
++#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
+ 
+ /* Retry limits and lifetime flags available */
+ #define IW_RETRY_ON		0x0000	/* No details... */
+@@ -376,6 +401,9 @@
+ /* Maximum size of returned data */
+ #define IW_SCAN_MAX_DATA	4096	/* In bytes */
+ 
++/* Max number of char in custom event - use multiple of them if needed */
++#define IW_CUSTOM_MAX		256	/* In bytes */
++
+ /****************************** TYPES ******************************/
+ 
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -411,9 +439,10 @@ struct	iw_point
+  */
+ struct	iw_freq
+ {
+-	__u32		m;		/* Mantissa */
+-	__u16		e;		/* Exponent */
++	__s32		m;		/* Mantissa */
++	__s16		e;		/* Exponent */
+ 	__u8		i;		/* List index (when in range struct) */
++	__u8		pad;		/* Unused - just for alignement */
+ };
+ 
+ /*
+diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h
+--- linux/include/net/iw_handler.14.h	Mon Dec  2 18:51:17 2002
++++ linux/include/net/iw_handler.h	Mon Dec  2 18:54:51 2002
+@@ -1,7 +1,7 @@
+ /*
+  * This file define the new driver API for Wireless Extensions
+  *
+- * Version :	3	17.1.02
++ * Version :	4	21.6.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+@@ -206,7 +206,7 @@
+  * will be needed...
+  * I just plan to increment with each new version.
+  */
+-#define IW_HANDLER_VERSION	3
++#define IW_HANDLER_VERSION	4
+ 
+ /*
+  * Changes :
+@@ -217,6 +217,9 @@
+  *	- Add Wireless Event support :
+  *		o wireless_send_event() prototype
+  *		o iwe_stream_add_event/point() inline functions
++ * V3 to V4
++ * --------
++ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+@@ -233,10 +236,10 @@
+ #define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
+ #define IW_HEADER_TYPE_UINT	4	/* __u32 */
+ #define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
+-#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+-#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+-#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
+-#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
++#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
++#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
++#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
++#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
+ 
+ /* Handling flags */
+ /* Most are not implemented. I just use them as a reminder of some
+diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c
+--- linux/net/core/wireless.14.c	Mon Dec  2 18:51:35 2002
++++ linux/net/core/wireless.c	Mon Dec  2 18:53:10 2002
+@@ -33,8 +33,16 @@
+  *	o Propagate events as rtnetlink IFLA_WIRELESS option
+  *	o Generate event on selected SET requests
+  *
+- * v4 - 18.04.01 - Jean II
++ * v4 - 18.04.02 - Jean II
+  *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
++ *
++ * v5 - 21.06.02 - Jean II
++ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
++ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
++ *	o Add IWEVCUSTOM for driver specific event/scanning token
++ *	o Turn on WE_STRICT_WRITE by default + kernel warning
++ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
++ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
+  */
+ 
+ /***************************** INCLUDES *****************************/
+@@ -50,8 +58,9 @@
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+-/* This will be turned on later on... */
+-#undef WE_STRICT_WRITE		/* Check write buffer size */
++/* Enough lenience, let's make sure things are proper... */
++#define WE_STRICT_WRITE		/* Check write buffer size */
++/* I'll probably drop both the define and kernel message in the next version */
+ 
+ /* Debuging stuff */
+ #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+@@ -106,7 +115,7 @@ static const struct iw_ioctl_description
+ 	/* SIOCSIWSPY */
+ 	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
+ 	/* SIOCGIWSPY */
+-	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
+ 	/* -- hole -- */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* -- hole -- */
+@@ -176,25 +185,41 @@ static const struct iw_ioctl_description
+ 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ 	/* IWEVQUAL */
+ 	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
++	/* IWEVCUSTOM */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
++	/* IWEVREGISTERED */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* IWEVEXPIRED */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ };
+ static const int standard_event_num = (sizeof(standard_event) /
+ 				       sizeof(struct iw_ioctl_description));
+ 
+ /* Size (in bytes) of the various private data types */
+-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++static const char priv_type_size[] = {
++	0,				/* IW_PRIV_TYPE_NONE */
++	1,				/* IW_PRIV_TYPE_BYTE */
++	1,				/* IW_PRIV_TYPE_CHAR */
++	0,				/* Not defined */
++	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
++	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
++	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
++	0,				/* Not defined */
++};
+ 
+ /* Size (in bytes) of various events */
+ static const int event_type_size[] = {
+-	IW_EV_LCP_LEN,
++	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
++	0,
++	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
+ 	0,
+-	IW_EV_CHAR_LEN,
++	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
++	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
++	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
+ 	0,
+-	IW_EV_UINT_LEN,
+-	IW_EV_FREQ_LEN,
+ 	IW_EV_POINT_LEN,		/* Without variable payload */
+-	IW_EV_PARAM_LEN,
+-	IW_EV_ADDR_LEN,
+-	IW_EV_QUAL_LEN,
++	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
++	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
+ };
+ 
+ /************************ COMMON SUBROUTINES ************************/
+@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s
+ 		return -EFAULT;
+ #ifdef WE_STRICT_WRITE
+ 	/* Check if there is enough buffer up there */
+-	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
++	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
++		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
+ 		return -E2BIG;
++	}
+ #endif	/* WE_STRICT_WRITE */
+ 
+ 	/* Set the number of available ioctls. */
+@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st
+ 	const struct iw_ioctl_description *	descr;
+ 	struct iw_request_info			info;
+ 	int					ret = -EINVAL;
++	int					user_size = 0;
+ 
+ 	/* Get the description of the IOCTL */
+ 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st
+ 			/* Check NULL pointer */
+ 			if(iwr->u.data.pointer == NULL)
+ 				return -EFAULT;
+-#ifdef WE_STRICT_WRITE
+-			/* Check if there is enough buffer up there */
+-			if(iwr->u.data.length < descr->max_tokens)
+-				return -E2BIG;
+-#endif	/* WE_STRICT_WRITE */
++			/* Save user space buffer size for checking */
++			user_size = iwr->u.data.length;
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st
+ 
+ 		/* If we have something to return to the user */
+ 		if (!ret && IW_IS_GET(cmd)) {
++#ifdef WE_STRICT_WRITE
++			/* Check if there is enough buffer up there */
++			if(user_size < iwr->u.data.length) {
++				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
++				kfree(extra);
++				return -E2BIG;
++			}
++#endif	/* WE_STRICT_WRITE */
++
+ 			err = copy_to_user(iwr->u.data.pointer, extra,
+ 					   iwr->u.data.length *
+ 					   descr->token_size);
+@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str
+ 	/* Compute the size of the set/get arguments */
+ 	if(descr != NULL) {
+ 		if(IW_IS_SET(cmd)) {
++			int	offset = 0;	/* For sub-ioctls */
++			/* Check for sub-ioctl handler */
++			if(descr->name[0] == '\0')
++				/* Reserve one int for sub-ioctl index */
++				offset = sizeof(__u32);
++
+ 			/* Size of set arguments */
+ 			extra_size = get_priv_size(descr->set_args);
+ 
+ 			/* Does it fits in iwr ? */
+ 			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+-			   (extra_size < IFNAMSIZ))
++			   ((extra_size + offset) <= IFNAMSIZ))
+ 				extra_size = 0;
+ 		} else {
+ 			/* Size of set arguments */
+@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str
+ 
+ 			/* Does it fits in iwr ? */
+ 			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+-			   (extra_size < IFNAMSIZ))
++			   (extra_size <= IFNAMSIZ))
+ 				extra_size = 0;
+ 		}
+ 	}
+@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi
+ 		 * The best the driver could do is to log an error message.
+ 		 * We will do it ourselves instead...
+ 		 */
+-	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
++	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+ 		       dev->name, cmd);
+ 		return;
+ 	}
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff
index e69de29bb2..a27a7654a9 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w13-5.diff
@@ -0,0 +1,1513 @@
+diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h
+--- linux/include/linux-w12/netdevice.h	Thu Nov 22 11:47:09 2001
++++ linux/include/linux/netdevice.h	Thu Jan 17 12:00:39 2002
+@@ -278,6 +278,10 @@ struct net_device
+ 	struct net_device_stats* (*get_stats)(struct net_device *dev);
+ 	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);
+ 
++	/* List of functions to handle Wireless Extensions (instead of ioctl).
++	 * See <net/iw_handler.h> for details. Jean II */
++	struct iw_handler_def *	wireless_handlers;
++
+ 	/*
+ 	 * This marks the end of the "visible" part of the structure. All
+ 	 * fields hereafter are internal to the system, and may change at
+diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h
+--- linux/include/linux-w12/wireless.h	Thu Nov 22 11:47:12 2001
++++ linux/include/linux/wireless.h	Thu Jan 17 12:04:08 2002
+@@ -1,9 +1,10 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	12	5.10.01
++ * Version :	13	6.12.01
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _LINUX_WIRELESS_H
+@@ -11,6 +12,8 @@
+ 
+ /************************** DOCUMENTATION **************************/
+ /*
++ * Initial APIs (1996 -> onward) :
++ * -----------------------------
+  * Basically, the wireless extensions are for now a set of standard ioctl
+  * call + /proc/net/wireless
+  *
+@@ -27,16 +30,27 @@
+  * We have the list of command plus a structure descibing the
+  * data exchanged...
+  * Note that to add these ioctl, I was obliged to modify :
+- *	net/core/dev.c (two place + add include)
+- *	net/ipv4/af_inet.c (one place + add include)
++ *	# net/core/dev.c (two place + add include)
++ *	# net/ipv4/af_inet.c (one place + add include)
+  *
+  * /proc/net/wireless is a copy of /proc/net/dev.
+  * We have a structure for data passed from the driver to /proc/net/wireless
+  * Too add this, I've modified :
+- *	net/core/dev.c (two other places)
+- *	include/linux/netdevice.h (one place)
+- *	include/linux/proc_fs.h (one place)
++ *	# net/core/dev.c (two other places)
++ *	# include/linux/netdevice.h (one place)
++ *	# include/linux/proc_fs.h (one place)
++ *
++ * New driver API (2001 -> onward) :
++ * -------------------------------
++ * This file is only concerned with the user space API and common definitions.
++ * The new driver API is defined and documented in :
++ *	# include/net/iw_handler.h
+  *
++ * Note as well that /proc/net/wireless implementation has now moved in :
++ *	# include/linux/wireless.c
++ *
++ * Other comments :
++ * --------------
+  * Do not add here things that are redundant with other mechanisms
+  * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
+  * wireless specific.
+@@ -54,16 +68,14 @@
+ #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
+ #include <linux/if.h>			/* for IFNAMSIZ and co... */
+ 
+-/**************************** CONSTANTS ****************************/
+-
+-/* --------------------------- VERSION --------------------------- */
++/***************************** VERSION *****************************/
+ /*
+  * This constant is used to know the availability of the wireless
+  * extensions and to know which version of wireless extensions it is
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	12
++#define WIRELESS_EXT	13
+ 
+ /*
+  * Changes :
+@@ -123,12 +135,20 @@
+  *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
+  *	- Add new statistics (frag, retry, beacon)
+  *	- Add average quality (for user space calibration)
++ *
++ * V12 to V13
++ * ----------
++ *	- Document creation of new driver API.
++ *	- Extract union iwreq_data from struct iwreq (for new driver API).
++ *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
+  */
+ 
++/**************************** CONSTANTS ****************************/
++
+ /* -------------------------- IOCTL LIST -------------------------- */
+ 
+ /* Basic operations */
+-#define SIOCSIWNAME	0x8B00		/* Unused */
++#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
+ #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
+ #define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
+ #define SIOCGIWNWID	0x8B03		/* get network id */
+@@ -414,13 +434,49 @@ struct	iw_statistics
+ 
+ /* ------------------------ IOCTL REQUEST ------------------------ */
+ /*
++ * This structure defines the payload of an ioctl, and is used 
++ * below.
++ *
++ * Note that this structure should fit on the memory footprint
++ * of iwreq (which is the same as ifreq), which mean a max size of
++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
++ * You should check this when increasing the structures defined
++ * above in this file...
++ */
++union	iwreq_data
++{
++	/* Config - generic */
++	char		name[IFNAMSIZ];
++	/* Name : used to verify the presence of  wireless extensions.
++	 * Name of the protocol/provider... */
++
++	struct iw_point	essid;		/* Extended network name */
++	struct iw_param	nwid;		/* network id (or domain - the cell) */
++	struct iw_freq	freq;		/* frequency or channel :
++					 * 0-1000 = channel
++					 * > 1000 = frequency in Hz */
++
++	struct iw_param	sens;		/* signal level threshold */
++	struct iw_param	bitrate;	/* default bit rate */
++	struct iw_param	txpower;	/* default transmit power */
++	struct iw_param	rts;		/* RTS threshold threshold */
++	struct iw_param	frag;		/* Fragmentation threshold */
++	__u32		mode;		/* Operation mode */
++	struct iw_param	retry;		/* Retry limits & lifetime */
++
++	struct iw_point	encoding;	/* Encoding stuff : tokens */
++	struct iw_param	power;		/* PM duration/timeout */
++
++	struct sockaddr	ap_addr;	/* Access point address */
++
++	struct iw_point	data;		/* Other large parameters */
++};
++
++/*
+  * The structure to exchange data for ioctl.
+  * This structure is the same as 'struct ifreq', but (re)defined for
+  * convenience...
+- *
+- * Note that it should fit on the same memory footprint !
+- * You should check this when increasing the above structures (16 octets)
+- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
++ * Do I need to remind you about structure size (32 octets) ?
+  */
+ struct	iwreq 
+ {
+@@ -429,35 +485,8 @@ struct	iwreq 
+ 		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
+ 	} ifr_ifrn;
+ 
+-	/* Data part */
+-	union
+-	{
+-		/* Config - generic */
+-		char		name[IFNAMSIZ];
+-		/* Name : used to verify the presence of  wireless extensions.
+-		 * Name of the protocol/provider... */
+-
+-		struct iw_point	essid;	/* Extended network name */
+-		struct iw_param	nwid;	/* network id (or domain - the cell) */
+-		struct iw_freq	freq;	/* frequency or channel :
+-					 * 0-1000 = channel
+-					 * > 1000 = frequency in Hz */
+-
+-		struct iw_param	sens;		/* signal level threshold */
+-		struct iw_param	bitrate;	/* default bit rate */
+-		struct iw_param	txpower;	/* default transmit power */
+-		struct iw_param	rts;		/* RTS threshold threshold */
+-		struct iw_param	frag;		/* Fragmentation threshold */
+-		__u32		mode;		/* Operation mode */
+-		struct iw_param	retry;		/* Retry limits & lifetime */
+-
+-		struct iw_point	encoding;	/* Encoding stuff : tokens */
+-		struct iw_param	power;		/* PM duration/timeout */
+-
+-		struct sockaddr	ap_addr;	/* Access point address */
+-
+-		struct iw_point	data;		/* Other large parameters */
+-	}	u;
++	/* Data part (defined just above) */
++	union	iwreq_data	u;
+ };
+ 
+ /* -------------------------- IOCTL DATA -------------------------- */
+diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h
+--- linux/include/net-w12/iw_handler.h	Wed Dec 31 16:00:00 1969
++++ linux/include/net/iw_handler.h	Thu Jan 17 12:16:46 2002
+@@ -0,0 +1,374 @@
++/*
++ * This file define the new driver API for Wireless Extensions
++ *
++ * Version :	2	6.12.01
++ *
++ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
++ */
++
++#ifndef _IW_HANDLER_H
++#define _IW_HANDLER_H
++
++/************************** DOCUMENTATION **************************/
++/*
++ * Initial driver API (1996 -> onward) :
++ * -----------------------------------
++ * The initial API just sends the IOCTL request received from user space
++ * to the driver (via the driver ioctl handler). The driver has to
++ * handle all the rest...
++ *
++ * The initial API also defines a specific handler in struct net_device
++ * to handle wireless statistics.
++ *
++ * The initial APIs served us well and has proven a reasonably good design.
++ * However, there is a few shortcommings :
++ *	o No events, everything is a request to the driver.
++ *	o Large ioctl function in driver with gigantic switch statement
++ *	  (i.e. spaghetti code).
++ *	o Driver has to mess up with copy_to/from_user, and in many cases
++ *	  does it unproperly. Common mistakes are :
++ *		* buffer overflows (no checks or off by one checks)
++ *		* call copy_to/from_user with irq disabled
++ *	o The user space interface is tied to ioctl because of the use
++ *	  copy_to/from_user.
++ *
++ * New driver API (2001 -> onward) :
++ * -------------------------------
++ * The new driver API is just a bunch of standard functions (handlers),
++ * each handling a specific Wireless Extension. The driver just export
++ * the list of handler it supports, and those will be called apropriately.
++ *
++ * I tried to keep the main advantage of the previous API (simplicity,
++ * efficiency and light weight), and also I provide a good dose of backward
++ * compatibility (most structures are the same, driver can use both API
++ * simultaneously, ...).
++ * Hopefully, I've also addressed the shortcomming of the initial API.
++ *
++ * The advantage of the new API are :
++ *	o Handling of Extensions in driver broken in small contained functions
++ *	o Tighter checks of ioctl before calling the driver
++ *	o Flexible commit strategy (at least, the start of it)
++ *	o Backward compatibility (can be mixed with old API)
++ *	o Driver doesn't have to worry about memory and user-space issues
++ * The last point is important for the following reasons :
++ *	o You are now able to call the new driver API from any API you
++ *		want (including from within other parts of the kernel).
++ *	o Common mistakes are avoided (buffer overflow, user space copy
++ *		with irq disabled and so on).
++ *
++ * The Drawback of the new API are :
++ *	o bloat (especially kernel)
++ *	o need to migrate existing drivers to new API
++ * My initial testing shows that the new API adds around 3kB to the kernel
++ * and save between 0 and 5kB from a typical driver.
++ * Also, as all structures and data types are unchanged, the migration is
++ * quite straightforward (but tedious).
++ *
++ * ---
++ *
++ * The new driver API is defined below in this file. User space should
++ * not be aware of what's happening down there...
++ *
++ * A new kernel wrapper is in charge of validating the IOCTLs and calling
++ * the appropriate driver handler. This is implemented in :
++ *	# net/core/wireless.c
++ *
++ * The driver export the list of handlers in :
++ *	# include/linux/netdevice.h (one place)
++ *
++ * The new driver API is available for WIRELESS_EXT >= 13.
++ * Good luck with migration to the new API ;-)
++ */
++
++/* ---------------------- THE IMPLEMENTATION ---------------------- */
++/*
++ * Some of the choice I've made are pretty controversials. Defining an
++ * API is very much weighting compromises. This goes into some of the
++ * details and the thinking behind the implementation.
++ *
++ * Implementation goals :
++ * --------------------
++ * The implementation goals were as follow :
++ *	o Obvious : you should not need a PhD to understand what's happening,
++ *		the benefit is easier maintainance.
++ *	o Flexible : it should accomodate a wide variety of driver
++ *		implementations and be as flexible as the old API.
++ *	o Lean : it should be efficient memory wise to minimise the impact
++ *		on kernel footprint.
++ *	o Transparent to user space : the large number of user space
++ *		applications that use Wireless Extensions should not need
++ *		any modifications.
++ *
++ * Array of functions versus Struct of functions
++ * ---------------------------------------------
++ * 1) Having an array of functions allow the kernel code to access the
++ * handler in a single lookup, which is much more efficient (think hash
++ * table here).
++ * 2) The only drawback is that driver writer may put their handler in
++ * the wrong slot. This is trivial to test (I set the frequency, the
++ * bitrate changes). Once the handler is in the proper slot, it will be
++ * there forever, because the array is only extended at the end.
++ * 3) Backward/forward compatibility : adding new handler just require
++ * extending the array, so you can put newer driver in older kernel
++ * without having to patch the kernel code (and vice versa).
++ *
++ * All handler are of the same generic type
++ * ----------------------------------------
++ * That's a feature !!!
++ * 1) Having a generic handler allow to have generic code, which is more
++ * efficient. If each of the handler was individually typed I would need
++ * to add a big switch in the kernel (== more bloat). This solution is
++ * more scalable, adding new Wireless Extensions doesn't add new code.
++ * 2) You can use the same handler in different slots of the array. For
++ * hardware, it may be more efficient or logical to handle multiple
++ * Wireless Extensions with a single function, and the API allow you to
++ * do that. (An example would be a single record on the card to control
++ * both bitrate and frequency, the handler would read the old record,
++ * modify it according to info->cmd and rewrite it).
++ *
++ * Functions prototype uses union iwreq_data
++ * -----------------------------------------
++ * Some would have prefered functions defined this way :
++ *	static int mydriver_ioctl_setrate(struct net_device *dev, 
++ *					  long rate, int auto)
++ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
++ * can't do it (different hardware may have different notion of what a
++ * valid frequency is), so we don't pretend that we do it.
++ * 2) The above form is not extendable. If I want to add a flag (for
++ * example to distinguish setting max rate and basic rate), I would
++ * break the prototype. Using iwreq_data is more flexible.
++ * 3) Also, the above form is not generic (see above).
++ * 4) I don't expect driver developper using the wrong field of the
++ * union (Doh !), so static typechecking doesn't add much value.
++ * 5) Lastly, you can skip the union by doing :
++ *	static int mydriver_ioctl_setrate(struct net_device *dev,
++ *					  struct iw_request_info *info,
++ *					  struct iw_param *rrq,
++ *					  char *extra)
++ * And then adding the handler in the array like this :
++ *        (iw_handler) mydriver_ioctl_setrate,             // SIOCSIWRATE
++ *
++ * Using functions and not a registry
++ * ----------------------------------
++ * Another implementation option would have been for every instance to
++ * define a registry (a struct containing all the Wireless Extensions)
++ * and only have a function to commit the registry to the hardware.
++ * 1) This approach can be emulated by the current code, but not
++ * vice versa.
++ * 2) Some drivers don't keep any configuration in the driver, for them
++ * adding such a registry would be a significant bloat.
++ * 3) The code to translate from Wireless Extension to native format is
++ * needed anyway, so it would not reduce significantely the amount of code.
++ * 4) The current approach only selectively translate Wireless Extensions
++ * to native format and only selectively set, whereas the registry approach
++ * would require to translate all WE and set all parameters for any single
++ * change.
++ * 5) For many Wireless Extensions, the GET operation return the current
++ * dynamic value, not the value that was set.
++ *
++ * This header is <net/iw_handler.h>
++ * ---------------------------------
++ * 1) This header is kernel space only and should not be exported to
++ * user space. Headers in "include/linux/" are exported, headers in
++ * "include/net/" are not.
++ *
++ * Mixed 32/64 bit issues
++ * ----------------------
++ * The Wireless Extensions are designed to be 64 bit clean, by using only
++ * datatypes with explicit storage size.
++ * There are some issues related to kernel and user space using different
++ * memory model, and in particular 64bit kernel with 32bit user space.
++ * The problem is related to struct iw_point, that contains a pointer
++ * that *may* need to be translated.
++ * This is quite messy. The new API doesn't solve this problem (it can't),
++ * but is a step in the right direction :
++ * 1) Meta data about each ioctl is easily available, so we know what type
++ * of translation is needed.
++ * 2) The move of data between kernel and user space is only done in a single
++ * place in the kernel, so adding specific hooks in there is possible.
++ * 3) In the long term, it allows to move away from using ioctl as the
++ * user space API.
++ *
++ * So many comments and so few code
++ * --------------------------------
++ * That's a feature. Comments won't bloat the resulting kernel binary.
++ */
++
++/***************************** INCLUDES *****************************/
++
++#include <linux/wireless.h>		/* IOCTL user space API */
++
++/***************************** VERSION *****************************/
++/*
++ * This constant is used to know which version of the driver API is
++ * available. Hopefully, this will be pretty stable and no changes
++ * will be needed...
++ * I just plan to increment with each new version.
++ */
++#define IW_HANDLER_VERSION	2
++
++/**************************** CONSTANTS ****************************/
++
++/* Special error message for the driver to indicate that we
++ * should do a commit after return from the iw_handler */
++#define EIWCOMMIT	EINPROGRESS
++
++/* Flags available in struct iw_request_info */
++#define IW_REQUEST_FLAG_NONE	0x0000	/* No flag so far */
++
++/* Type of headers we know about (basically union iwreq_data) */
++#define IW_HEADER_TYPE_NULL	0	/* Not available */
++#define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
++#define IW_HEADER_TYPE_UINT	4	/* __u32 */
++#define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
++#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
++#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
++#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
++
++/* Handling flags */
++/* Most are not implemented. I just use them as a reminder of some
++ * cool features we might need one day ;-) */
++#define IW_DESCR_FLAG_NONE	0x0000	/* Obvious */
++/* Wrapper level flags */
++#define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
++#define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
++#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
++/* Driver level flags */
++#define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
++
++/****************************** TYPES ******************************/
++
++/* ----------------------- WIRELESS HANDLER ----------------------- */
++/*
++ * A wireless handler is just a standard function, that looks like the
++ * ioctl handler.
++ * We also define there how a handler list look like... As the Wireless
++ * Extension space is quite dense, we use a simple array, which is faster
++ * (that's the perfect hash table ;-).
++ */
++
++/*
++ * Meta data about the request passed to the iw_handler.
++ * Most handlers can safely ignore what's in there.
++ * The 'cmd' field might come handy if you want to use the same handler
++ * for multiple command...
++ * This struct is also my long term insurance. I can add new fields here
++ * without breaking the prototype of iw_handler...
++ */
++struct iw_request_info
++{
++	__u16		cmd;		/* Wireless Extension command */
++	__u16		flags;		/* More to come ;-) */
++};
++
++/*
++ * This is how a function handling a Wireless Extension should look
++ * like (both get and set, standard and private).
++ */
++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
++			  union iwreq_data *wrqu, char *extra);
++
++/*
++ * This define all the handler that the driver export.
++ * As you need only one per driver type, please use a static const
++ * shared by all driver instances... Same for the members...
++ * This will be linked from net_device in <linux/netdevice.h>
++ */
++struct iw_handler_def
++{
++	/* Number of handlers defined (more precisely, index of the
++	 * last defined handler + 1) */
++	__u16			num_standard;
++	__u16			num_private;
++	/* Number of private arg description */
++	__u16			num_private_args;
++
++	/* Array of handlers for standard ioctls
++	 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
++	 */
++	iw_handler *		standard;
++
++	/* Array of handlers for private ioctls
++	 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
++	 */
++	iw_handler *		private;
++
++	/* Arguments of private handler. This one is just a list, so you
++	 * can put it in any order you want and should not leave holes...
++	 * We will automatically export that to user space... */
++	struct iw_priv_args *	private_args;
++
++	/* In the long term, get_wireless_stats will move from
++	 * 'struct net_device' to here, to minimise bloat. */
++};
++
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/*
++ * Currently we don't support events, so let's just plan for the
++ * future...
++ */
++
++/*
++ * A Wireless Event.
++ */
++// How do we define short header ? We don't want a flag on length.
++// Probably a flag on event ? Highest bit to zero...
++struct iw_event
++{
++	__u16		length;			/* Lenght of this stuff */
++	__u16		event;			/* Wireless IOCTL */
++	union	iwreq_data	header;		/* IOCTL fixed payload */
++	char		extra[0];		/* Optional IOCTL data */
++};
++
++/* ---------------------- IOCTL DESCRIPTION ---------------------- */
++/*
++ * One of the main goal of the new interface is to deal entirely with
++ * user space/kernel space memory move.
++ * For that, we need to know :
++ *	o if iwreq is a pointer or contain the full data
++ *	o what is the size of the data to copy
++ *
++ * For private IOCTLs, we use the same rules as used by iwpriv and
++ * defined in struct iw_priv_args.
++ *
++ * For standard IOCTLs, things are quite different and we need to
++ * use the stuctures below. Actually, this struct is also more
++ * efficient, but that's another story...
++ */
++
++/*
++ * Describe how a standard IOCTL looks like.
++ */
++struct iw_ioctl_description
++{
++	__u8	header_type;		/* NULL, iw_point or other */
++	__u8	token_type;		/* Future */
++	__u16	token_size;		/* Granularity of payload */
++	__u16	min_tokens;		/* Min acceptable token number */
++	__u16	max_tokens;		/* Max acceptable token number */
++	__u32	flags;			/* Special handling of the request */
++};
++
++/* Need to think of short header translation table. Later. */
++
++/**************************** PROTOTYPES ****************************/
++/*
++ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
++ * Those may be called only within the kernel.
++ */
++
++/* First : function strictly used inside the kernel */
++
++/* Handle /proc/net/wireless, called in net/code/dev.c */
++extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
++				 int length);
++
++/* Handle IOCTLs, called in net/code/dev.c */
++extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
++
++/* Second : functions that may be called by driver modules */
++/* None yet */
++
++#endif	/* _LINUX_WIRELESS_H */
+diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile
+--- linux/net/core-w12/Makefile	Tue Oct 30 15:08:12 2001
++++ linux/net/core/Makefile	Thu Jan 17 11:06:07 2002
+@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d
+ obj-$(CONFIG_NETFILTER) += netfilter.o
+ obj-$(CONFIG_NET_DIVERT) += dv.o
+ obj-$(CONFIG_NET_PROFILE) += profile.o
++obj-$(CONFIG_NET_RADIO) += wireless.o
++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
+ 
+ include $(TOPDIR)/Rules.make
+diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c
+--- linux/net/core-w12/dev.c	Wed Nov  7 14:39:36 2001
++++ linux/net/core/dev.c	Thu Jan 17 11:06:07 2002
+@@ -102,6 +102,7 @@
+ #include <linux/module.h>
+ #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+ #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
++#include <net/iw_handler.h>
+ #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+ #ifdef CONFIG_PLIP
+ extern int plip_init(void);
+@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, 
+ #endif	/* CONFIG_PROC_FS */
+ 
+ 
+-#ifdef WIRELESS_EXT
+-#ifdef CONFIG_PROC_FS
+-
+-/*
+- * Print one entry of /proc/net/wireless
+- * This is a clone of /proc/net/dev (just above)
+- */
+-static int sprintf_wireless_stats(char *buffer, struct net_device *dev)
+-{
+-	/* Get stats from the driver */
+-	struct iw_statistics *stats = (dev->get_wireless_stats ?
+-				       dev->get_wireless_stats(dev) :
+-				       (struct iw_statistics *) NULL);
+-	int size;
+-
+-	if (stats != (struct iw_statistics *) NULL) {
+-		size = sprintf(buffer,
+-			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
+-			       dev->name,
+-			       stats->status,
+-			       stats->qual.qual,
+-			       stats->qual.updated & 1 ? '.' : ' ',
+-			       stats->qual.level,
+-			       stats->qual.updated & 2 ? '.' : ' ',
+-			       stats->qual.noise,
+-			       stats->qual.updated & 4 ? '.' : ' ',
+-			       stats->discard.nwid,
+-			       stats->discard.code,
+-			       stats->discard.fragment,
+-			       stats->discard.retries,
+-			       stats->discard.misc,
+-			       stats->miss.beacon);
+-		stats->qual.updated = 0;
+-	}
+-	else
+-		size = 0;
+-
+-	return size;
+-}
+-
+-/*
+- * Print info for /proc/net/wireless (print all entries)
+- * This is a clone of /proc/net/dev (just above)
+- */
+-static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+-			  int length)
+-{
+-	int		len = 0;
+-	off_t		begin = 0;
+-	off_t		pos = 0;
+-	int		size;
+-	
+-	struct net_device *	dev;
+-
+-	size = sprintf(buffer,
+-		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
+-		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
+-			);
+-	
+-	pos += size;
+-	len += size;
+-
+-	read_lock(&dev_base_lock);
+-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+-		size = sprintf_wireless_stats(buffer + len, dev);
+-		len += size;
+-		pos = begin + len;
+-
+-		if (pos < offset) {
+-			len = 0;
+-			begin = pos;
+-		}
+-		if (pos > offset + length)
+-			break;
+-	}
+-	read_unlock(&dev_base_lock);
+-
+-	*start = buffer + (offset - begin);	/* Start of wanted data */
+-	len -= (offset - begin);		/* Start slop */
+-	if (len > length)
+-		len = length;			/* Ending slop */
+-	if (len < 0)
+-		len = 0;
+-
+-	return len;
+-}
+-#endif	/* CONFIG_PROC_FS */
+-
+-/*
+- *	Allow programatic access to /proc/net/wireless even if /proc
+- *	doesn't exist... Also more efficient...
+- */
+-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
+-{
+-	/* Get stats from the driver */
+-	struct iw_statistics *stats = (dev->get_wireless_stats ?
+-				       dev->get_wireless_stats(dev) :
+-				       (struct iw_statistics *) NULL);
+-
+-	if (stats != (struct iw_statistics *) NULL) {
+-		struct iwreq *	wrq = (struct iwreq *)ifr;
+-
+-		/* Copy statistics to the user buffer */
+-		if(copy_to_user(wrq->u.data.pointer, stats,
+-				sizeof(struct iw_statistics)))
+-			return -EFAULT;
+-
+-		/* Check if we need to clear the update flag */
+-		if(wrq->u.data.flags != 0)
+-			stats->qual.updated = 0;
+-		return(0);
+-	} else
+-		return -EOPNOTSUPP;
+-}
+-#endif	/* WIRELESS_EXT */
+-
+ /**
+  *	netdev_set_master	-	set up master/slave pair
+  *	@slave: slave device
+@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr,
+ 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+ 			return 0;
+ 
+-#ifdef WIRELESS_EXT
+-		case SIOCGIWSTATS:
+-			return dev_iwstats(dev, ifr);
+-#endif	/* WIRELESS_EXT */
+-
+ 		/*
+ 		 *	Unknown or private ioctl
+ 		 */
+@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr,
+ 				return -EOPNOTSUPP;
+ 			}
+ 
+-#ifdef WIRELESS_EXT
+-			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
+-				if (dev->do_ioctl) {
+-					if (!netif_device_present(dev))
+-						return -ENODEV;
+-					return dev->do_ioctl(dev, ifr, cmd);
+-				}
+-				return -EOPNOTSUPP;
+-			}
+-#endif	/* WIRELESS_EXT */
+-
+ 	}
+ 	return -EINVAL;
+ }
+@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar
+ 				}
+ 				dev_load(ifr.ifr_name);
+ 				rtnl_lock();
+-				ret = dev_ifsioc(&ifr, cmd);
++				/* Follow me in net/core/wireless.c */
++				ret = wireless_process_ioctl(&ifr, cmd);
+ 				rtnl_unlock();
+ 				if (!ret && IW_IS_GET(cmd) &&
+ 				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+@@ -2856,6 +2726,7 @@ int __init net_dev_init(void)
+ 	proc_net_create("dev", 0, dev_get_info);
+ 	create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
+ #ifdef WIRELESS_EXT
++	/* Available in net/core/wireless.c */
+ 	proc_net_create("wireless", 0, dev_get_wireless_info);
+ #endif	/* WIRELESS_EXT */
+ #endif	/* CONFIG_PROC_FS */
+diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c
+--- linux/net/core-w12/wireless.c	Wed Dec 31 16:00:00 1969
++++ linux/net/core/wireless.c	Mon Jan 21 11:13:23 2002
+@@ -0,0 +1,733 @@
++/*
++ * This file implement the Wireless Extensions APIs.
++ *
++ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ *
++ * (As all part of the Linux kernel, this file is GPL)
++ */
++
++/************************** DOCUMENTATION **************************/
++/*
++ * API definition :
++ * --------------
++ * See <linux/wireless.h> for details of the APIs and the rest.
++ *
++ * History :
++ * -------
++ *
++ * v1 - 5.12.01 - Jean II
++ *	o Created this file.
++ *
++ * v2 - 13.12.01 - Jean II
++ *	o Move /proc/net/wireless stuff from net/core/dev.c to here
++ *	o Make Wireless Extension IOCTLs go through here
++ *	o Added iw_handler handling ;-)
++ *	o Added standard ioctl description
++ *	o Initial dumb commit strategy based on orinoco.c
++ */
++
++/***************************** INCLUDES *****************************/
++
++#include <asm/uaccess.h>		/* copy_to_user() */
++#include <linux/config.h>		/* Not needed ??? */
++#include <linux/types.h>		/* off_t */
++#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
++
++#include <linux/wireless.h>		/* Pretty obvious */
++#include <net/iw_handler.h>		/* New driver API */
++
++/**************************** CONSTANTS ****************************/
++
++/* This will be turned on later on... */
++#undef WE_STRICT_WRITE		/* Check write buffer size */
++
++/* Debuging stuff */
++#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
++
++/************************* GLOBAL VARIABLES *************************/
++/*
++ * You should not use global variables, because or re-entrancy.
++ * On our case, it's only const, so it's OK...
++ */
++static const struct iw_ioctl_description	standard_ioctl[] = {
++	/* SIOCSIWCOMMIT (internal) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWNAME */
++	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWNWID */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWNWID */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWFREQ */
++	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWFREQ */
++	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWMODE */
++	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWMODE */
++	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWSENS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWSENS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRANGE */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWRANGE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWPRIV */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWPRIV (handled directly by us) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWSTATS */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWSTATS (handled directly by us) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWSPY */
++	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
++	/* SIOCGIWSPY */
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWAP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* SIOCGIWAP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWAPLIST */
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWESSID */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWESSID */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWNICKN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	/* SIOCGIWNICKN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWRATE */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRATE */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRTS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRTS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWFRAG */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWFRAG */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWTXPOW */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWTXPOW */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRETRY */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRETRY */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWENCODE */
++	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
++	/* SIOCGIWENCODE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
++	/* SIOCSIWPOWER */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWPOWER */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++};
++
++/* Size (in bytes) of the various private data types */
++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++
++/************************ COMMON SUBROUTINES ************************/
++/*
++ * Stuff that may be used in various place or doesn't fit in one
++ * of the section below.
++ */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Return the driver handler associated with a specific Wireless Extension.
++ * Called from various place, so make sure it remains efficient.
++ */
++static inline iw_handler get_handler(struct net_device *dev,
++				     unsigned int cmd)
++{
++	unsigned int	index;		/* MUST be unsigned */
++
++	/* Check if we have some wireless handlers defined */
++	if(dev->wireless_handlers == NULL)
++		return NULL;
++
++	/* Try as a standard command */
++	index = cmd - SIOCIWFIRST;
++	if(index < dev->wireless_handlers->num_standard)
++		return dev->wireless_handlers->standard[index];
++
++	/* Try as a private command */
++	index = cmd - SIOCIWFIRSTPRIV;
++	if(index < dev->wireless_handlers->num_private)
++		return dev->wireless_handlers->private[index];
++
++	/* Not found */
++	return NULL;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Get statistics out of the driver
++ */
++static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
++{
++	return (dev->get_wireless_stats ?
++		dev->get_wireless_stats(dev) :
++		(struct iw_statistics *) NULL);
++	/* In the future, get_wireless_stats may move from 'struct net_device'
++	 * to 'struct iw_handler_def', to de-bloat struct net_device.
++	 * Definitely worse a thought... */
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Call the commit handler in the driver
++ * (if exist and if conditions are right)
++ *
++ * Note : our current commit strategy is currently pretty dumb,
++ * but we will be able to improve on that...
++ * The goal is to try to agreagate as many changes as possible
++ * before doing the commit. Drivers that will define a commit handler
++ * are usually those that need a reset after changing parameters, so
++ * we want to minimise the number of reset.
++ * A cool idea is to use a timer : at each "set" command, we re-set the
++ * timer, when the timer eventually fires, we call the driver.
++ * Hopefully, more on that later.
++ *
++ * Also, I'm waiting to see how many people will complain about the
++ * netif_running(dev) test. I'm open on that one...
++ * Hopefully, the driver will remember to do a commit in "open()" ;-)
++ */
++static inline int call_commit_handler(struct net_device *	dev)
++{
++	if((netif_running(dev)) &&
++	   (dev->wireless_handlers->standard[0] != NULL)) {
++		/* Call the commit handler on the driver */
++		return dev->wireless_handlers->standard[0](dev, NULL,
++							   NULL, NULL);
++	} else
++		return 0;		/* Command completed successfully */
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Number of private arguments
++ */
++static inline int get_priv_size(__u16	args)
++{
++	int	num = args & IW_PRIV_SIZE_MASK;
++	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
++
++	return num * priv_type_size[type];
++}
++
++
++/******************** /proc/net/wireless SUPPORT ********************/
++/*
++ * The /proc/net/wireless file is a human readable user-space interface
++ * exporting various wireless specific statistics from the wireless devices.
++ * This is the most popular part of the Wireless Extensions ;-)
++ *
++ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
++ * The content of the file is basically the content of "struct iw_statistics".
++ */
++
++#ifdef CONFIG_PROC_FS
++
++/* ---------------------------------------------------------------- */
++/*
++ * Print one entry (line) of /proc/net/wireless
++ */
++static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
++{
++	/* Get stats from the driver */
++	struct iw_statistics *stats;
++	int size;
++
++	stats = get_wireless_stats(dev);
++	if (stats != (struct iw_statistics *) NULL) {
++		size = sprintf(buffer,
++			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
++			       dev->name,
++			       stats->status,
++			       stats->qual.qual,
++			       stats->qual.updated & 1 ? '.' : ' ',
++			       stats->qual.level,
++			       stats->qual.updated & 2 ? '.' : ' ',
++			       stats->qual.noise,
++			       stats->qual.updated & 4 ? '.' : ' ',
++			       stats->discard.nwid,
++			       stats->discard.code,
++			       stats->discard.fragment,
++			       stats->discard.retries,
++			       stats->discard.misc,
++			       stats->miss.beacon);
++		stats->qual.updated = 0;
++	}
++	else
++		size = 0;
++
++	return size;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Print info for /proc/net/wireless (print all entries)
++ */
++int dev_get_wireless_info(char * buffer, char **start, off_t offset,
++			  int length)
++{
++	int		len = 0;
++	off_t		begin = 0;
++	off_t		pos = 0;
++	int		size;
++	
++	struct net_device *	dev;
++
++	size = sprintf(buffer,
++		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
++		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
++			);
++	
++	pos += size;
++	len += size;
++
++	read_lock(&dev_base_lock);
++	for (dev = dev_base; dev != NULL; dev = dev->next) {
++		size = sprintf_wireless_stats(buffer + len, dev);
++		len += size;
++		pos = begin + len;
++
++		if (pos < offset) {
++			len = 0;
++			begin = pos;
++		}
++		if (pos > offset + length)
++			break;
++	}
++	read_unlock(&dev_base_lock);
++
++	*start = buffer + (offset - begin);	/* Start of wanted data */
++	len -= (offset - begin);		/* Start slop */
++	if (len > length)
++		len = length;			/* Ending slop */
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++#endif	/* CONFIG_PROC_FS */
++
++/************************** IOCTL SUPPORT **************************/
++/*
++ * The original user space API to configure all those Wireless Extensions
++ * is through IOCTLs.
++ * In there, we check if we need to call the new driver API (iw_handler)
++ * or just call the driver ioctl handler.
++ */
++
++/* ---------------------------------------------------------------- */
++/*
++ *	Allow programatic access to /proc/net/wireless even if /proc
++ *	doesn't exist... Also more efficient...
++ */
++static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
++{
++	/* Get stats from the driver */
++	struct iw_statistics *stats;
++
++	stats = get_wireless_stats(dev);
++	if (stats != (struct iw_statistics *) NULL) {
++		struct iwreq *	wrq = (struct iwreq *)ifr;
++
++		/* Copy statistics to the user buffer */
++		if(copy_to_user(wrq->u.data.pointer, stats,
++				sizeof(struct iw_statistics)))
++			return -EFAULT;
++
++		/* Check if we need to clear the update flag */
++		if(wrq->u.data.flags != 0)
++			stats->qual.updated = 0;
++		return 0;
++	} else
++		return -EOPNOTSUPP;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Export the driver private handler definition
++ * They will be picked up by tools like iwpriv...
++ */
++static inline int ioctl_export_private(struct net_device *	dev,
++				       struct ifreq *		ifr)
++{
++	struct iwreq *				iwr = (struct iwreq *) ifr;
++
++	/* Check if the driver has something to export */
++	if((dev->wireless_handlers->num_private_args == 0) ||
++	   (dev->wireless_handlers->private_args == NULL))
++		return -EOPNOTSUPP;
++
++	/* Check NULL pointer */
++	if(iwr->u.data.pointer == NULL)
++		return -EFAULT;
++#ifdef WE_STRICT_WRITE
++	/* Check if there is enough buffer up there */
++	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
++		return -E2BIG;
++#endif	/* WE_STRICT_WRITE */
++
++	/* Set the number of available ioctls. */
++	iwr->u.data.length = dev->wireless_handlers->num_private_args;
++
++	/* Copy structure to the user buffer. */
++	if (copy_to_user(iwr->u.data.pointer,
++			 dev->wireless_handlers->private_args,
++			 sizeof(struct iw_priv_args) * iwr->u.data.length))
++		return -EFAULT;
++
++	return 0;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Wrapper to call a standard Wireless Extension handler.
++ * We do various checks and also take care of moving data between
++ * user space and kernel space.
++ */
++static inline int ioctl_standard_call(struct net_device *	dev,
++				      struct ifreq *		ifr,
++				      unsigned int		cmd,
++				      iw_handler		handler)
++{
++	struct iwreq *				iwr = (struct iwreq *) ifr;
++	const struct iw_ioctl_description *	descr;
++	struct iw_request_info			info;
++	int					ret = -EINVAL;
++
++	/* Get the description of the IOCTL */
++	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
++
++#ifdef WE_IOCTL_DEBUG
++	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
++	       ifr->ifr_name, cmd);
++	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++#endif	/* WE_IOCTL_DEBUG */
++
++	/* Prepare the call */
++	info.cmd = cmd;
++	info.flags = 0;
++
++	/* Check if we have a pointer to user space data or not */
++	if(descr->header_type != IW_HEADER_TYPE_POINT) {
++		/* No extra arguments. Trivial to handle */
++		ret = handler(dev, &info, &(iwr->u), NULL);
++	} else {
++		char *	extra;
++		int	err;
++
++		/* Check what user space is giving us */
++		if(IW_IS_SET(cmd)) {
++			/* Check NULL pointer */
++			if((iwr->u.data.pointer == NULL) &&
++			   (iwr->u.data.length != 0))
++				return -EFAULT;
++			/* Check if number of token fits within bounds */
++			if(iwr->u.data.length > descr->max_tokens)
++				return -E2BIG;
++			if(iwr->u.data.length < descr->min_tokens)
++				return -EINVAL;
++		} else {
++			/* Check NULL pointer */
++			if(iwr->u.data.pointer == NULL)
++				return -EFAULT;
++#ifdef WE_STRICT_WRITE
++			/* Check if there is enough buffer up there */
++			if(iwr->u.data.length < descr->max_tokens)
++				return -E2BIG;
++#endif	/* WE_STRICT_WRITE */
++		}
++
++#ifdef WE_IOCTL_DEBUG
++		printk(KERN_DEBUG "Malloc %d bytes\n",
++		       descr->max_tokens * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++
++		/* Always allocate for max space. Easier, and won't last
++		 * long... */
++		extra = kmalloc(descr->max_tokens * descr->token_size,
++				GFP_KERNEL);
++		if (extra == NULL) {
++			return -ENOMEM;
++		}
++
++		/* If it is a SET, get all the extra data in here */
++		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
++			err = copy_from_user(extra, iwr->u.data.pointer,
++					     iwr->u.data.length *
++					     descr->token_size);
++			if (err) {
++				kfree(extra);
++				return -EFAULT;
++			}
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Got %d bytes\n",
++			       iwr->u.data.length * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Call the handler */
++		ret = handler(dev, &info, &(iwr->u), extra);
++
++		/* If we have something to return to the user */
++		if (!ret && IW_IS_GET(cmd)) {
++			err = copy_to_user(iwr->u.data.pointer, extra,
++					   iwr->u.data.length *
++					   descr->token_size);
++			if (err)
++				ret =  -EFAULT;				   
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Wrote %d bytes\n",
++			       iwr->u.data.length * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Cleanup - I told you it wasn't that long ;-) */
++		kfree(extra);
++	}
++
++	/* Call commit handler if needed and defined */
++	if(ret == -EIWCOMMIT)
++		ret = call_commit_handler(dev);
++
++	/* Here, we will generate the appropriate event if needed */
++
++	return ret;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Wrapper to call a private Wireless Extension handler.
++ * We do various checks and also take care of moving data between
++ * user space and kernel space.
++ * It's not as nice and slimline as the standard wrapper. The cause
++ * is struct iw_priv_args, which was not really designed for the
++ * job we are going here.
++ *
++ * IMPORTANT : This function prevent to set and get data on the same
++ * IOCTL and enforce the SET/GET convention. Not doing it would be
++ * far too hairy...
++ * If you need to set and get data at the same time, please don't use
++ * a iw_handler but process it in your ioctl handler (i.e. use the
++ * old driver API).
++ */
++static inline int ioctl_private_call(struct net_device *	dev,
++				     struct ifreq *		ifr,
++				     unsigned int		cmd,
++				     iw_handler		handler)
++{
++	struct iwreq *			iwr = (struct iwreq *) ifr;
++	struct iw_priv_args *		descr = NULL;
++	struct iw_request_info		info;
++	int				extra_size = 0;
++	int				i;
++	int				ret = -EINVAL;
++
++	/* Get the description of the IOCTL */
++	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
++		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
++			descr = &(dev->wireless_handlers->private_args[i]);
++			break;
++		}
++
++#ifdef WE_IOCTL_DEBUG
++	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
++	       ifr->ifr_name, cmd);
++	if(descr) {
++		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
++		       descr->name, descr->set_args, descr->get_args);
++	}
++#endif	/* WE_IOCTL_DEBUG */
++
++	/* Compute the size of the set/get arguments */
++	if(descr != NULL) {
++		if(IW_IS_SET(cmd)) {
++			/* Size of set arguments */
++			extra_size = get_priv_size(descr->set_args);
++
++			/* Does it fits in iwr ? */
++			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
++			   (extra_size < IFNAMSIZ))
++				extra_size = 0;
++		} else {
++			/* Size of set arguments */
++			extra_size = get_priv_size(descr->get_args);
++
++			/* Does it fits in iwr ? */
++			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
++			   (extra_size < IFNAMSIZ))
++				extra_size = 0;
++		}
++	}
++
++	/* Prepare the call */
++	info.cmd = cmd;
++	info.flags = 0;
++
++	/* Check if we have a pointer to user space data or not. */
++	if(extra_size == 0) {
++		/* No extra arguments. Trivial to handle */
++		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
++	} else {
++		char *	extra;
++		int	err;
++
++		/* Check what user space is giving us */
++		if(IW_IS_SET(cmd)) {
++			/* Check NULL pointer */
++			if((iwr->u.data.pointer == NULL) &&
++			   (iwr->u.data.length != 0))
++				return -EFAULT;
++
++			/* Does it fits within bounds ? */
++			if(iwr->u.data.length > (descr->set_args &
++						 IW_PRIV_SIZE_MASK))
++				return -E2BIG;
++		} else {
++			/* Check NULL pointer */
++			if(iwr->u.data.pointer == NULL)
++				return -EFAULT;
++		}
++
++#ifdef WE_IOCTL_DEBUG
++		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
++#endif	/* WE_IOCTL_DEBUG */
++
++		/* Always allocate for max space. Easier, and won't last
++		 * long... */
++		extra = kmalloc(extra_size, GFP_KERNEL);
++		if (extra == NULL) {
++			return -ENOMEM;
++		}
++
++		/* If it is a SET, get all the extra data in here */
++		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
++			err = copy_from_user(extra, iwr->u.data.pointer,
++					     extra_size);
++			if (err) {
++				kfree(extra);
++				return -EFAULT;
++			}
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Call the handler */
++		ret = handler(dev, &info, &(iwr->u), extra);
++
++		/* If we have something to return to the user */
++		if (!ret && IW_IS_GET(cmd)) {
++			err = copy_to_user(iwr->u.data.pointer, extra,
++					   extra_size);
++			if (err)
++				ret =  -EFAULT;				   
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Wrote %d elem\n",
++			       iwr->u.data.length);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Cleanup - I told you it wasn't that long ;-) */
++		kfree(extra);
++	}
++
++
++	/* Call commit handler if needed and defined */
++	if(ret == -EIWCOMMIT)
++		ret = call_commit_handler(dev);
++
++	return ret;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Main IOCTl dispatcher. Called from the main networking code
++ * (dev_ioctl() in net/core/dev.c).
++ * Check the type of IOCTL and call the appropriate wrapper...
++ */
++int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
++{
++	struct net_device *dev;
++	iw_handler	handler;
++
++	/* Permissions are already checked in dev_ioctl() before calling us.
++	 * The copy_to/from_user() of ifr is also dealt with in there */
++
++	/* Make sure the device exist */
++	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
++		return -ENODEV;
++
++	/* A bunch of special cases, then the generic case...
++	 * Note that 'cmd' is already filtered in dev_ioctl() with
++	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
++	switch(cmd) 
++	{
++		case SIOCGIWSTATS:
++			/* Get Wireless Stats */
++			return dev_iwstats(dev, ifr);
++
++		case SIOCGIWPRIV:
++			/* Check if we have some wireless handlers defined */
++			if(dev->wireless_handlers != NULL) {
++				/* We export to user space the definition of
++				 * the private handler ourselves */
++				return ioctl_export_private(dev, ifr);
++			}
++			// ## Fall-through for old API ##
++		default:
++			/* Generic IOCTL */
++			/* Basic check */
++			if (!netif_device_present(dev))
++				return -ENODEV;
++			/* New driver API : try to find the handler */
++			handler = get_handler(dev, cmd);
++			if(handler != NULL) {
++				/* Standard and private are not the same */
++				if(cmd < SIOCIWFIRSTPRIV)
++					return ioctl_standard_call(dev,
++								   ifr,
++								   cmd,
++								   handler);
++				else
++					return ioctl_private_call(dev,
++								  ifr,
++								  cmd,
++								  handler);
++			}
++			/* Old driver API : call driver ioctl handler */
++			if (dev->do_ioctl) {
++				return dev->do_ioctl(dev, ifr, cmd);
++			}
++			return -EOPNOTSUPP;
++	}
++	/* Not reached */
++	return -EINVAL;
++}
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff
index e69de29bb2..539b160068 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/iw_handlers.w14-5.diff
@@ -0,0 +1,838 @@
+diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h
+--- linux/include/linux-w13/rtnetlink.h	Thu Jun  6 14:44:08 2002
++++ linux/include/linux/rtnetlink.h	Thu Jun  6 15:47:44 2002
+@@ -440,12 +440,14 @@ enum
+ #define IFLA_COST IFLA_COST
+ 	IFLA_PRIORITY,
+ #define IFLA_PRIORITY IFLA_PRIORITY
+-	IFLA_MASTER
++	IFLA_MASTER,
+ #define IFLA_MASTER IFLA_MASTER
++	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
++#define IFLA_WIRELESS IFLA_WIRELESS
+ };
+ 
+ 
+-#define IFLA_MAX IFLA_MASTER
++#define IFLA_MAX IFLA_WIRELESS
+ 
+ #define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+ #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h
+--- linux/include/linux-w13/wireless.h	Thu Jun  6 15:00:28 2002
++++ linux/include/linux/wireless.h	Thu Jun  6 15:47:44 2002
+@@ -1,10 +1,10 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	13	6.12.01
++ * Version :	14	25.1.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _LINUX_WIRELESS_H
+@@ -40,7 +40,7 @@
+  *	# include/linux/netdevice.h (one place)
+  *	# include/linux/proc_fs.h (one place)
+  *
+- * New driver API (2001 -> onward) :
++ * New driver API (2002 -> onward) :
+  * -------------------------------
+  * This file is only concerned with the user space API and common definitions.
+  * The new driver API is defined and documented in :
+@@ -49,6 +49,11 @@
+  * Note as well that /proc/net/wireless implementation has now moved in :
+  *	# include/linux/wireless.c
+  *
++ * Wireless Events (2002 -> onward) :
++ * --------------------------------
++ * Events are defined at the end of this file, and implemented in :
++ *	# include/linux/wireless.c
++ *
+  * Other comments :
+  * --------------
+  * Do not add here things that are redundant with other mechanisms
+@@ -75,7 +80,7 @@
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	13
++#define WIRELESS_EXT	14
+ 
+ /*
+  * Changes :
+@@ -141,6 +146,13 @@
+  *	- Document creation of new driver API.
+  *	- Extract union iwreq_data from struct iwreq (for new driver API).
+  *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
++ *
++ * V13 to V14
++ * ----------
++ *	- Wireless Events support : define struct iw_event
++ *	- Define additional specific event numbers
++ *	- Add "addr" and "param" fields in union iwreq_data
++ *	- AP scanning stuff (SIOCSIWSCAN and friends)
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+@@ -175,6 +187,8 @@
+ #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
+ #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
+ #define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
++#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
++#define SIOCGIWSCAN	0x8B19		/* get scanning results */
+ 
+ /* 802.11 specific support */
+ #define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
+@@ -238,6 +252,15 @@
+ #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
+ #define IW_IS_GET(cmd)	((cmd) & 0x1)
+ 
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/* Those are *NOT* ioctls, do not issue request on them !!! */
++/* Most events use the same identifier as ioctl requests */
++
++#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
++#define IWEVQUAL	0x8C01		/* Quality part of statistics */
++
++#define IWEVFIRST	0x8C00
++
+ /* ------------------------- PRIVATE INFO ------------------------- */
+ /*
+  * The following is used with SIOCGIWPRIV. It allow a driver to define
+@@ -340,6 +363,19 @@
+ #define IW_RETRY_MAX		0x0002	/* Value is a maximum */
+ #define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+ 
++/* Scanning request flags */
++#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
++#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
++#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
++#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
++#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
++#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
++#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
++#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
++#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
++/* Maximum size of returned data */
++#define IW_SCAN_MAX_DATA	4096	/* In bytes */
++
+ /****************************** TYPES ******************************/
+ 
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -466,9 +502,12 @@ union	iwreq_data
+ 
+ 	struct iw_point	encoding;	/* Encoding stuff : tokens */
+ 	struct iw_param	power;		/* PM duration/timeout */
++	struct iw_quality qual;		/* Quality part of statistics */
+ 
+ 	struct sockaddr	ap_addr;	/* Access point address */
++	struct sockaddr	addr;		/* Destination address (hw) */
+ 
++	struct iw_param	param;		/* Other small parameters */
+ 	struct iw_point	data;		/* Other large parameters */
+ };
+ 
+@@ -595,5 +634,36 @@ struct	iw_priv_args
+ 	__u16		get_args;	/* Type and number of args */
+ 	char		name[IFNAMSIZ];	/* Name of the extension */
+ };
++
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/*
++ * Wireless events are carried through the rtnetlink socket to user
++ * space. They are encapsulated in the IFLA_WIRELESS field of
++ * a RTM_NEWLINK message.
++ */
++
++/*
++ * A Wireless Event. Contains basically the same data as the ioctl...
++ */
++struct iw_event
++{
++	__u16		len;			/* Real lenght of this stuff */
++	__u16		cmd;			/* Wireless IOCTL */
++	union iwreq_data	u;		/* IOCTL fixed payload */
++};
++
++/* Size of the Event prefix (including padding and alignement junk) */
++#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
++/* Size of the various events */
++#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
++#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
++#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
++#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point))
++#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
++#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
++#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
++
++/* Note : in the case of iw_point, the extra data will come at the
++ * end of the event */
+ 
+ #endif	/* _LINUX_WIRELESS_H */
+diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h
+--- linux/include/net-w13/iw_handler.h	Thu Jun  6 15:06:16 2002
++++ linux/include/net/iw_handler.h	Thu Jun  6 15:48:06 2002
+@@ -1,10 +1,10 @@
+ /*
+  * This file define the new driver API for Wireless Extensions
+  *
+- * Version :	2	6.12.01
++ * Version :	3	17.1.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _IW_HANDLER_H
+@@ -33,7 +33,7 @@
+  *	o The user space interface is tied to ioctl because of the use
+  *	  copy_to/from_user.
+  *
+- * New driver API (2001 -> onward) :
++ * New driver API (2002 -> onward) :
+  * -------------------------------
+  * The new driver API is just a bunch of standard functions (handlers),
+  * each handling a specific Wireless Extension. The driver just export
+@@ -206,7 +206,18 @@
+  * will be needed...
+  * I just plan to increment with each new version.
+  */
+-#define IW_HANDLER_VERSION	2
++#define IW_HANDLER_VERSION	3
++
++/*
++ * Changes :
++ *
++ * V2 to V3
++ * --------
++ *	- Move event definition in <linux/wireless.h>
++ *	- Add Wireless Event support :
++ *		o wireless_send_event() prototype
++ *		o iwe_stream_add_event/point() inline functions
++ */
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+@@ -225,6 +236,7 @@
+ #define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+ #define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+ #define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
++#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
+ 
+ /* Handling flags */
+ /* Most are not implemented. I just use them as a reminder of some
+@@ -233,7 +245,8 @@
+ /* Wrapper level flags */
+ #define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
+ #define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
+-#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
++#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
++				/* SET : Omit payload from generated iwevent */
+ /* Driver level flags */
+ #define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
+ 
+@@ -303,25 +316,6 @@ struct iw_handler_def
+ 	 * 'struct net_device' to here, to minimise bloat. */
+ };
+ 
+-/* ----------------------- WIRELESS EVENTS ----------------------- */
+-/*
+- * Currently we don't support events, so let's just plan for the
+- * future...
+- */
+-
+-/*
+- * A Wireless Event.
+- */
+-// How do we define short header ? We don't want a flag on length.
+-// Probably a flag on event ? Highest bit to zero...
+-struct iw_event
+-{
+-	__u16		length;			/* Lenght of this stuff */
+-	__u16		event;			/* Wireless IOCTL */
+-	union	iwreq_data	header;		/* IOCTL fixed payload */
+-	char		extra[0];		/* Optional IOCTL data */
+-};
+-
+ /* ---------------------- IOCTL DESCRIPTION ---------------------- */
+ /*
+  * One of the main goal of the new interface is to deal entirely with
+@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * 
+ extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+ 
+ /* Second : functions that may be called by driver modules */
+-/* None yet */
+ 
+-#endif	/* _LINUX_WIRELESS_H */
++/* Send a single event to user space */
++extern void wireless_send_event(struct net_device *	dev,
++				unsigned int		cmd,
++				union iwreq_data *	wrqu,
++				char *			extra);
++
++/* We may need a function to send a stream of events to user space.
++ * More on that later... */
++
++/************************* INLINE FUNTIONS *************************/
++/*
++ * Function that are so simple that it's more efficient inlining them
++ */
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add an Wireless Event to a stream of events.
++ */
++static inline char *
++iwe_stream_add_event(char *	stream,		/* Stream of events */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     int	event_len)	/* Real size of payload */
++{
++	/* Check if it's possible */
++	if((stream + event_len) < ends) {
++		iwe->len = event_len;
++		memcpy(stream, (char *) iwe, event_len);
++		stream += event_len;
++	}
++	return stream;
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add an short Wireless Event containing a pointer to a
++ * stream of events.
++ */
++static inline char *
++iwe_stream_add_point(char *	stream,		/* Stream of events */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     char *	extra)
++{
++	int	event_len = IW_EV_POINT_LEN + iwe->u.data.length;
++	/* Check if it's possible */
++	if((stream + event_len) < ends) {
++		iwe->len = event_len;
++		memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
++		memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
++		stream += event_len;
++	}
++	return stream;
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add a value to a Wireless Event in a stream of events.
++ * Be careful, this one is tricky to use properly :
++ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
++ */
++static inline char *
++iwe_stream_add_value(char *	event,		/* Event in the stream */
++		     char *	value,		/* Value in event */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     int	event_len)	/* Real size of payload */
++{
++	/* Don't duplicate LCP */
++	event_len -= IW_EV_LCP_LEN;
++
++	/* Check if it's possible */
++	if((value + event_len) < ends) {
++		/* Add new value */
++		memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
++		value += event_len;
++		/* Patch LCP */
++		iwe->len = value - event;
++		memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
++	}
++	return value;
++}
++
++#endif	/* _IW_HANDLER_H */
+diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c
+--- linux/net/netsyms-w13.c	Thu Jun  6 15:46:34 2002
++++ linux/net/netsyms.c	Thu Jun  6 15:47:44 2002
+@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf);
+ EXPORT_SYMBOL(net_call_rx_atomic);
+ EXPORT_SYMBOL(softnet_data);
+ 
++#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
++/* Don't include the whole header mess for a single function */
++extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra);
++EXPORT_SYMBOL(wireless_send_event);
++#endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
++
+ #endif  /* CONFIG_NET */
+diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c
+--- linux/net/core/wireless-w13.c	Thu Jun  6 15:46:45 2002
++++ linux/net/core/wireless.c	Thu Jun  6 15:48:06 2002
+@@ -2,7 +2,7 @@
+  * This file implement the Wireless Extensions APIs.
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+  *
+  * (As all part of the Linux kernel, this file is GPL)
+  */
+@@ -25,6 +25,16 @@
+  *	o Added iw_handler handling ;-)
+  *	o Added standard ioctl description
+  *	o Initial dumb commit strategy based on orinoco.c
++ *
++ * v3 - 19.12.01 - Jean II
++ *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
++ *	o Add event dispatcher function
++ *	o Add event description
++ *	o Propagate events as rtnetlink IFLA_WIRELESS option
++ *	o Generate event on selected SET requests
++ *
++ * v4 - 18.04.01 - Jean II
++ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+  */
+ 
+ /***************************** INCLUDES *****************************/
+@@ -33,6 +43,7 @@
+ #include <linux/config.h>		/* Not needed ??? */
+ #include <linux/types.h>		/* off_t */
+ #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
++#include <linux/rtnetlink.h>		/* rtnetlink stuff */
+ 
+ #include <linux/wireless.h>		/* Pretty obvious */
+ #include <net/iw_handler.h>		/* New driver API */
+@@ -44,14 +55,23 @@
+ 
+ /* Debuging stuff */
+ #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
++#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
++
++/* Options */
++#define WE_EVENT_NETLINK	/* Propagate events using rtnetlink */
++#define WE_SET_EVENT		/* Generate an event on some set commands */
+ 
+ /************************* GLOBAL VARIABLES *************************/
+ /*
+  * You should not use global variables, because or re-entrancy.
+  * On our case, it's only const, so it's OK...
+  */
++/*
++ * Meta-data about all the standard Wireless Extension request we
++ * know about.
++ */
+ static const struct iw_ioctl_description	standard_ioctl[] = {
+-	/* SIOCSIWCOMMIT (internal) */
++	/* SIOCSIWCOMMIT */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* SIOCGIWNAME */
+ 	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+@@ -99,18 +119,18 @@ static const struct iw_ioctl_description
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* SIOCGIWAPLIST */
+ 	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
+-	/* -- hole -- */
+-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+-	/* -- hole -- */
+-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWSCAN */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWSCAN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
+ 	/* SIOCSIWESSID */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
+ 	/* SIOCGIWESSID */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
+ 	/* SIOCSIWNICKN */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+ 	/* SIOCGIWNICKN */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+ 	/* -- hole -- */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* -- hole -- */
+@@ -136,7 +156,7 @@ static const struct iw_ioctl_description
+ 	/* SIOCGIWRETRY */
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ 	/* SIOCSIWENCODE */
+-	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+ 	/* SIOCGIWENCODE */
+ 	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
+ 	/* SIOCSIWPOWER */
+@@ -144,9 +164,38 @@ static const struct iw_ioctl_description
+ 	/* SIOCGIWPOWER */
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ };
++static const int standard_ioctl_num = (sizeof(standard_ioctl) /
++				       sizeof(struct iw_ioctl_description));
++
++/*
++ * Meta-data about all the additional standard Wireless Extension events
++ * we know about.
++ */
++static const struct iw_ioctl_description	standard_event[] = {
++	/* IWEVTXDROP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* IWEVQUAL */
++	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
++};
++static const int standard_event_num = (sizeof(standard_event) /
++				       sizeof(struct iw_ioctl_description));
+ 
+ /* Size (in bytes) of the various private data types */
+-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++
++/* Size (in bytes) of various events */
++static const int event_type_size[] = {
++	IW_EV_LCP_LEN,
++	0,
++	IW_EV_CHAR_LEN,
++	0,
++	IW_EV_UINT_LEN,
++	IW_EV_FREQ_LEN,
++	IW_EV_POINT_LEN,		/* Without variable payload */
++	IW_EV_PARAM_LEN,
++	IW_EV_ADDR_LEN,
++	IW_EV_QUAL_LEN,
++};
+ 
+ /************************ COMMON SUBROUTINES ************************/
+ /*
+@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4,
+ static inline iw_handler get_handler(struct net_device *dev,
+ 				     unsigned int cmd)
+ {
+-	unsigned int	index;		/* MUST be unsigned */
++	/* Don't "optimise" the following variable, it will crash */
++	unsigned int	index;		/* *MUST* be unsigned */
+ 
+ 	/* Check if we have some wireless handlers defined */
+ 	if(dev->wireless_handlers == NULL)
+@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats
+ 			       stats->status,
+ 			       stats->qual.qual,
+ 			       stats->qual.updated & 1 ? '.' : ' ',
+-			       stats->qual.level,
++			       ((__u8) stats->qual.level),
+ 			       stats->qual.updated & 2 ? '.' : ' ',
+-			       stats->qual.noise,
++			       ((__u8) stats->qual.noise),
+ 			       stats->qual.updated & 4 ? '.' : ' ',
+ 			       stats->discard.nwid,
+ 			       stats->discard.code,
+@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st
+ 	int					ret = -EINVAL;
+ 
+ 	/* Get the description of the IOCTL */
++	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
++		return -EOPNOTSUPP;
+ 	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+ 
+ #ifdef WE_IOCTL_DEBUG
+-	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
++	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
+ 	       ifr->ifr_name, cmd);
+-	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 	/* Prepare the call */
+@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st
+ 
+ 	/* Check if we have a pointer to user space data or not */
+ 	if(descr->header_type != IW_HEADER_TYPE_POINT) {
++
+ 		/* No extra arguments. Trivial to handle */
+ 		ret = handler(dev, &info, &(iwr->u), NULL);
++
++#ifdef WE_SET_EVENT
++		/* Generate an event to notify listeners of the change */
++		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
++		   ((ret == 0) || (ret == -EIWCOMMIT)))
++			wireless_send_event(dev, cmd, &(iwr->u), NULL);
++#endif	/* WE_SET_EVENT */
+ 	} else {
+ 		char *	extra;
+ 		int	err;
+@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-		printk(KERN_DEBUG "Malloc %d bytes\n",
+-		       descr->max_tokens * descr->token_size);
++		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
++		       dev->name, descr->max_tokens * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 		/* Always allocate for max space. Easier, and won't last
+@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st
+ 				return -EFAULT;
+ 			}
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Got %d bytes\n",
++			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
++			       dev->name,
+ 			       iwr->u.data.length * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st
+ 			if (err)
+ 				ret =  -EFAULT;				   
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Wrote %d bytes\n",
++			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
++			       dev->name,
+ 			       iwr->u.data.length * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
++#ifdef WE_SET_EVENT
++		/* Generate an event to notify listeners of the change */
++		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
++		   ((ret == 0) || (ret == -EIWCOMMIT))) {
++			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
++				/* If the event is restricted, don't
++				 * export the payload */
++				wireless_send_event(dev, cmd, &(iwr->u), NULL);
++			else
++				wireless_send_event(dev, cmd, &(iwr->u),
++						    extra);
++		}
++#endif	/* WE_SET_EVENT */
++
+ 		/* Cleanup - I told you it wasn't that long ;-) */
+ 		kfree(extra);
+ 	}
+@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
++	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
+ 	       ifr->ifr_name, cmd);
+ 	if(descr) {
+-		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
+-		       descr->name, descr->set_args, descr->get_args);
++		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
++		       dev->name, descr->name,
++		       descr->set_args, descr->get_args);
+ 	}
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
++		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
++		       dev->name, extra_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 		/* Always allocate for max space. Easier, and won't last
+@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str
+ 				return -EFAULT;
+ 			}
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
++			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
++			       dev->name, iwr->u.data.length);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
+@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str
+ 			if (err)
+ 				ret =  -EFAULT;				   
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Wrote %d elem\n",
+-			       iwr->u.data.length);
++			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
++			       dev->name, iwr->u.data.length);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
+@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq 
+ 	}
+ 	/* Not reached */
+ 	return -EINVAL;
++}
++
++/************************* EVENT PROCESSING *************************/
++/*
++ * Process events generated by the wireless layer or the driver.
++ * Most often, the event will be propagated through rtnetlink
++ */
++
++#ifdef WE_EVENT_NETLINK
++/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
++ * It is declared in <linux/rtnetlink.h> */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Fill a rtnetlink message with our event data.
++ * Note that we propage only the specified event and don't dump the
++ * current wireless config. Dumping the wireless config is far too
++ * expensive (for each parameter, the driver need to query the hardware).
++ */
++static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
++					struct net_device *	dev,
++					int			type,
++					char *			event,
++					int			event_len)
++{
++	struct ifinfomsg *r;
++	struct nlmsghdr  *nlh;
++	unsigned char	 *b = skb->tail;
++
++	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
++	r = NLMSG_DATA(nlh);
++	r->ifi_family = AF_UNSPEC;
++	r->ifi_type = dev->type;
++	r->ifi_index = dev->ifindex;
++	r->ifi_flags = dev->flags;
++	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
++
++	/* Add the wireless events in the netlink packet */
++	RTA_PUT(skb, IFLA_WIRELESS,
++		event_len, event);
++
++	nlh->nlmsg_len = skb->tail - b;
++	return skb->len;
++
++nlmsg_failure:
++rtattr_failure:
++	skb_trim(skb, b - skb->data);
++	return -1;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Create and broadcast and send it on the standard rtnetlink socket
++ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
++ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
++ * within a RTM_NEWLINK event.
++ */
++static inline void rtmsg_iwinfo(struct net_device *	dev,
++				char *			event,
++				int			event_len)
++{
++	struct sk_buff *skb;
++	int size = NLMSG_GOODSIZE;
++
++	skb = alloc_skb(size, GFP_ATOMIC);
++	if (!skb)
++		return;
++
++	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
++				  event, event_len) < 0) {
++		kfree_skb(skb);
++		return;
++	}
++	NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
++	netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
++}
++#endif	/* WE_EVENT_NETLINK */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Main event dispatcher. Called from other parts and drivers.
++ * Send the event on the apropriate channels.
++ * May be called from interrupt context.
++ */
++void wireless_send_event(struct net_device *	dev,
++			 unsigned int		cmd,
++			 union iwreq_data *	wrqu,
++			 char *			extra)
++{
++	const struct iw_ioctl_description *	descr = NULL;
++	int extra_len = 0;
++	struct iw_event  *event;		/* Mallocated whole event */
++	int event_len;				/* Its size */
++	int hdr_len;				/* Size of the event header */
++	/* Don't "optimise" the following variable, it will crash */
++	unsigned	cmd_index;		/* *MUST* be unsigned */
++
++	/* Get the description of the IOCTL */
++	if(cmd <= SIOCIWLAST) {
++		cmd_index = cmd - SIOCIWFIRST;
++		if(cmd_index < standard_ioctl_num)
++			descr = &(standard_ioctl[cmd_index]);
++	} else {
++		cmd_index = cmd - IWEVFIRST;
++		if(cmd_index < standard_event_num)
++			descr = &(standard_event[cmd_index]);
++	}
++	/* Don't accept unknown events */
++	if(descr == NULL) {
++		/* Note : we don't return an error to the driver, because
++		 * the driver would not know what to do about it. It can't
++		 * return an error to the user, because the event is not
++		 * initiated by a user request.
++		 * The best the driver could do is to log an error message.
++		 * We will do it ourselves instead...
++		 */
++	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
++		       dev->name, cmd);
++		return;
++	}
++#ifdef WE_EVENT_DEBUG
++	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
++	       dev->name, cmd);
++	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++#endif	/* WE_EVENT_DEBUG */
++
++	/* Check extra parameters and set extra_len */
++	if(descr->header_type == IW_HEADER_TYPE_POINT) {
++		/* Check if number of token fits within bounds */
++		if(wrqu->data.length > descr->max_tokens) {
++		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
++			return;
++		}
++		if(wrqu->data.length < descr->min_tokens) {
++		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
++			return;
++		}
++		/* Calculate extra_len - extra is NULL for restricted events */
++		if(extra != NULL)
++			extra_len = wrqu->data.length * descr->token_size;
++#ifdef WE_EVENT_DEBUG
++		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
++#endif	/* WE_EVENT_DEBUG */
++	}
++
++	/* Total length of the event */
++	hdr_len = event_type_size[descr->header_type];
++	event_len = hdr_len + extra_len;
++
++#ifdef WE_EVENT_DEBUG
++	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
++#endif	/* WE_EVENT_DEBUG */
++
++	/* Create temporary buffer to hold the event */
++	event = kmalloc(event_len, GFP_ATOMIC);
++	if(event == NULL)
++		return;
++
++	/* Fill event */
++	event->len = event_len;
++	event->cmd = cmd;
++	memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
++	if(extra != NULL)
++		memcpy(((char *) event) + hdr_len, extra, extra_len);
++
++#ifdef WE_EVENT_NETLINK
++	/* rtnetlink event channel */
++	rtmsg_iwinfo(dev, (char *) event, event_len);
++#endif	/* WE_EVENT_NETLINK */
++
++	/* Cleanup */
++	kfree(event);
++
++	return;		/* Always success, I guess ;-) */
+ }
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch
index e69de29bb2..93a80bae3c 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keyboard-ctrl+alt.patch
@@ -0,0 +1,79 @@
+
+#
+# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/char/corgi_rawmap.h~keyboard-ctrl+alt	2003-09-15 14:30:08.000000000 +0200
++++ linux/drivers/char/corgi_rawmap.h	2003-09-16 00:45:39.000000000 +0200
+@@ -55,7 +55,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ static unsigned char rawkeytable_table_NormalUpper[(NR_KEYCODES+1)] = {
+@@ -66,7 +66,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ static unsigned char rawkeytable_table_2ndLower[(NR_KEYCODES+1)] = {
+@@ -77,7 +77,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ static unsigned char rawkeytable_table_2ndUpper[(NR_KEYCODES+1)] = {
+@@ -88,7 +88,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_PRINTSCREEN, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ static unsigned char rawkeytable_table_NumlockLower[(NR_KEYCODES+1)] = {
+@@ -99,7 +99,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ static unsigned char rawkeytable_table_NumlockUpper[(NR_KEYCODES+1)] = {
+@@ -110,7 +110,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ static unsigned char rawkeytable_table_Num2ndLower[(NR_KEYCODES+1)] = {
+@@ -121,7 +121,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_C, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ static unsigned char rawkeytable_table_Num2ndUpper[(NR_KEYCODES+1)] = {
+@@ -132,7 +132,7 @@
+ 	SLKEY_ACTIVITY, SLKEY_W, SLKEY_S, SLKEY_F, SLKEY_V, SLKEY_H, SLKEY_M, SLKEY_L, KEY_IGN, SLKEY_RSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_CONTACTS, SLKEY_A, SLKEY_D, SLKEY_PRINTSCREEN, SLKEY_B, SLKEY_N, SLKEY_PERIOD, KEY_IGN, SLKEY_ENTER, KEY_IGN, SLKEY_LSHIFT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_MAIL, SLKEY_Z, SLKEY_X, SLKEY_MINUS, SLKEY_SPACE, SLKEY_COMMA, KEY_IGN, SLKEY_UP, KEY_IGN, KEY_IGN, KEY_IGN, SLKEY_2ND, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+-	SLKEY_HOME, SLKEY_KANA, SLKEY_ZENHAN, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
++	SLKEY_HOME, SLKEY_LCONTROL, SLKEY_LALT, SLKEY_F9, SLKEY_F4, SLKEY_F2, SLKEY_LEFT, SLKEY_DOWN, SLKEY_RIGHT, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN,
+ 	SLKEY_OFF, SLKEY_EXSELECT, SLKEY_EXCANCEL, SLKEY_EXJOGDOWN, SLKEY_EXJOGUP, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN, KEY_IGN};
+ 
+ 
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch
index e69de29bb2..a58dd13fbd 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/keymap-more-sane.patch
@@ -0,0 +1,23 @@
+--- linux/drivers/char/corgi_keymap.map~keymap-more-sane	2003-08-30 01:05:14.000000000 +0200
++++ linux/drivers/char/corgi_keymap.map	2003-09-03 20:44:27.000000000 +0200
+@@ -71,9 +71,11 @@
+ # (Cancel:34) F9 -> Escape
+ keycode 34 = Escape
+ keycode 35 = Left
++	alt keycode 35 = Decr_Console
+ keycode 36 = Up
+ keycode 37 = Down
+ keycode 38 = Right
++	alt keycode 38 = Incr_Console
+ # (OK:39) F4 -> Return 
+ keycode 39 = Return
+ keycode 40 = 
+@@ -100,7 +102,7 @@
+ keycode 60 = Shift_Lock
+ keycode 61 = at
+ keycode 62 = question
+-keycode 63 = comma slash
++keycode 63 = slash comma
+ 	alt keycode 63 = less
+ keycode 64 = period question
+ 	alt keycode 64 = greater
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch
index e69de29bb2..c006684f23 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/logo.patch
@@ -0,0 +1,2598 @@
+--- linux/drivers/video/fbcon.c	2003-02-27 21:47:36.000000000 -0600
++++ linux.new/drivers/video/fbcon.c	2003-02-27 18:39:39.000000000 -0600
+@@ -126,8 +126,8 @@
+ #define LOGO_H			(320-16)
+ #define LOGO_W			240
+ #else
+-#define LOGO_H			80
+-#define LOGO_W			80
++#define LOGO_H			52
++#define LOGO_W			240
+ #endif
+ #define LOGO_LINE	(LOGO_W/8)
+ #if defined(CONFIG_SHARP_LOGO_SCREEN)
+--- linux/include/linux/linux_logo.h	2001-06-11 21:15:27.000000000 -0500
++++ linux.new/include/linux/linux_logo.h	2003-02-27 15:58:15.000000000 -0600
+@@ -1,4 +1,4 @@
+-/* $Id$
++/* linux_logo.h created with fblogo, 2002/12/29 02:43:36
+  * include/linux/linux_logo.h: This is a linux logo
+  *                             to be displayed on boot.
+  *
+@@ -7,907 +7,1673 @@
+  *
+  * You can put anything here, but:
+  * LINUX_LOGO_COLORS has to be less than 224
+- * image size has to be 80x80
+- * values have to start from 0x20
+- * (i.e. RGB(linux_logo_red[0],
+- *           linux_logo_green[0],
+- *           linux_logo_blue[0]) is color 0x20)
+- * BW image has to be 80x80 as well, with MS bit
+- * on the left
+- * Serial_console ascii image can be any size,
+- * but should contain %s to display the version
++ * Generated by fblogo version 0.5.0
++ *
++ *
++ * Remember to modify drivers/video/fbcon.c:
++ * Change "#define LOGO_H 80" to "#define LOGO_H 52"
++ * Change "#define LOGO_W 80" to "#define LOGO_W 240"
+  */
+ 
+ #ifndef __HAVE_ARCH_LINUX_LOGO
+-#define LINUX_LOGO_COLORS	187
++#define LINUX_LOGO_COLORS 223
+ #endif
+-
+ #ifdef INCLUDE_LINUX_LOGO_DATA
+-
+ #ifndef __HAVE_ARCH_LINUX_LOGO
+-
+ unsigned char linux_logo_red[] __initdata = {
+-    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+-    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+-    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+-    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+-    0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+-    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+-    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
+-    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+-    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+-    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+-    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+-    0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
+-    0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
+-    0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
+-    0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
+-    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x12,
+-    0x4a, 0x8e, 0xf2, 0xf6, 0xf6, 0xee, 0xb5, 0xe4,
+-    0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16,
+-    0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
+-    0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae,
+-    0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf,
+-    0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82,
+-    0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52,
+-    0x59, 0x64, 0x5e,
++  0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, 
++  0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, 
++  0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, 
++  0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, 
++  0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, 
++  0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, 
++  0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, 
++  0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x32, 0x7E, 
++  0x3A, 0x16, 0x02, 0x02, 0x06, 0x1F, 0x02, 0x02, 
++  0x06, 0x02, 0x22, 0x3A, 0x35, 0x16, 0x0A, 0x02, 
++  0x2A, 0x3E, 0x39, 0x32, 0x2A, 0x1E, 0x16, 0x06, 
++  0x22, 0x22, 0x1E, 0x16, 0x6E, 0x82, 0x6E, 0x2E, 
++  0x1E, 0x2E, 0x1E, 0x0A, 0x3A, 0xDA, 0xFE, 0xFA, 
++  0xFA, 0xE2, 0x6A, 0x3A, 0x1A, 0xFA, 0xF6, 0x9E, 
++  0x02, 0x6E, 0xFE, 0xF6, 0x3E, 0x66, 0x52, 0x1B, 
++  0xD6, 0x5A, 0xEE, 0xC6, 0x72, 0x36, 0x22, 0x1E, 
++  0x02, 0x96, 0xF6, 0xDE, 0xA2, 0xD6, 0x39, 0x0E, 
++  0xAA, 0x52, 0x5A, 0xD2, 0xDE, 0x61, 0x46, 0xDE, 
++  0x7A, 0x57, 0x9E, 0xBA, 0xB6, 0x4A, 0x5A, 0xA6, 
++  0x96, 0x23, 0x1E, 0x12, 0x9A, 0x4E, 0x76, 0xAE, 
++  0x2E, 0xBE, 0x86, 0x48, 0xA6, 0x52, 0x06, 0x2E, 
++  0x56, 0x13, 0x2A, 0x4A, 0x36, 0x56, 0x2E, 0x1E, 
++  0x46, 0x3A, 0x66, 0x02, 0x3D, 0x3E, 0x2E, 0x3E, 
++  0x4A, 0x32, 0x52, 0x72, 0x76, 0x67, 0x68, 0x5A, 
++  0x3A, 0x1A, 0x0E, 0x2E, 0x4E, 0x02, 0x3E, 0x0A, 
++  0x28, 0x42, 0x10, 0x26, 0x8E, 0x0A, 0x86, 0xC2, 
++  0x02, 0x6E, 0x92, 0x02, 0x42, 0x02, 0xBE, 0x4E, 
++  0x02, 0x22, 0x02, 0x3E, 0x3A, 0x32
+ };
+ 
+ unsigned char linux_logo_green[] __initdata = {
+-    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+-    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+-    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+-    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+-    0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+-    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+-    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
+-    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+-    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+-    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+-    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+-    0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
+-    0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
+-    0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
+-    0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
+-    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x0e,
+-    0x36, 0x86, 0xba, 0xbe, 0xe6, 0xcc, 0x8e, 0xb8,
+-    0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12,
+-    0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
+-    0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87,
+-    0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76,
+-    0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62,
+-    0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e,
+-    0x51, 0x52, 0x56,
++  0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, 
++  0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, 
++  0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, 
++  0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, 
++  0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, 
++  0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, 
++  0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, 
++  0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x2E, 0x7E, 
++  0x3A, 0x3E, 0x6A, 0xA2, 0x92, 0x30, 0x95, 0x76, 
++  0x4E, 0x86, 0x36, 0x7E, 0x9A, 0x6E, 0x42, 0x56, 
++  0x5A, 0xC2, 0xBE, 0xB2, 0xAA, 0x9A, 0x63, 0x1E, 
++  0xA2, 0x9E, 0x96, 0x5A, 0x3A, 0x42, 0x4A, 0x52, 
++  0x91, 0x46, 0x4E, 0x62, 0x22, 0x4A, 0x6E, 0x86, 
++  0x92, 0x9A, 0x52, 0x4A, 0x76, 0x7A, 0x9E, 0x76, 
++  0x62, 0x32, 0x5E, 0xAE, 0x3E, 0x66, 0x52, 0x81, 
++  0xA6, 0x5A, 0xEE, 0xC6, 0x72, 0x5C, 0x6A, 0x8A, 
++  0x36, 0x3E, 0xBA, 0xBA, 0xA2, 0xD6, 0xAA, 0x4E, 
++  0x8A, 0x4E, 0x5A, 0xD2, 0xDE, 0x64, 0x32, 0x9A, 
++  0x5E, 0x57, 0x9E, 0xBA, 0xB6, 0x52, 0x62, 0xA6, 
++  0x9A, 0x47, 0x3E, 0x56, 0x02, 0x1A, 0x76, 0xAE, 
++  0x4A, 0x02, 0x02, 0x38, 0x02, 0x4A, 0x46, 0x86, 
++  0x1E, 0x2E, 0x7A, 0xD2, 0x5E, 0x26, 0x92, 0x62, 
++  0xCA, 0x42, 0x66, 0x26, 0x67, 0xB6, 0x62, 0x92, 
++  0x9E, 0x72, 0xB2, 0xF2, 0xFE, 0xDE, 0xFE, 0xFE, 
++  0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x8A, 0x2A, 
++  0x42, 0x52, 0x6A, 0x26, 0x8E, 0x26, 0x86, 0xC2, 
++  0xE2, 0x6E, 0x92, 0xBE, 0x42, 0xC6, 0xBE, 0x4E, 
++  0xEE, 0x5A, 0xEA, 0x3E, 0x4A, 0x32
+ };
+ 
+ unsigned char linux_logo_blue[] __initdata = {
+-    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+-    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+-    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
+-    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+-    0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+-    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+-    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
+-    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+-    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+-    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+-    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+-    0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
+-    0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
+-    0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
+-    0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
+-    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x06,
+-    0x0e, 0x6a, 0x0e, 0x0e, 0xbe, 0x5b, 0x2c, 0x3e,
+-    0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06,
+-    0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
+-    0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32,
+-    0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06,
+-    0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e,
+-    0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22,
+-    0x42, 0x34, 0x42,
++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, 
++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, 
++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, 
++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, 
++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, 
++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, 
++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, 
++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x1A, 0x06, 
++ 0x1A, 0x2A, 0x36, 0x52, 0x46, 0x23, 0x4D, 0x3E, 
++ 0x2A, 0x42, 0x2A, 0x5A, 0x69, 0x42, 0x26, 0x2E, 
++ 0x42, 0x7E, 0x7C, 0x72, 0x6A, 0x5E, 0x3B, 0x12, 
++ 0x62, 0x5E, 0x5A, 0x36, 0x26, 0x1E, 0x26, 0x42, 
++ 0x56, 0x3A, 0x36, 0x36, 0x1E, 0x2E, 0x2A, 0x22, 
++ 0x22, 0x1A, 0x16, 0x42, 0x46, 0x26, 0x1E, 0x12, 
++ 0x32, 0x2A, 0x2E, 0x16, 0x2A, 0x1A, 0x2E, 0x4E, 
++ 0x12, 0x22, 0x02, 0x02, 0x12, 0x4A, 0x46, 0x52, 
++ 0x1E, 0x1E, 0x16, 0x0E, 0x02, 0x02, 0x6F, 0x2E, 
++ 0x0E, 0x1A, 0x06, 0x02, 0x02, 0x04, 0x22, 0x16, 
++ 0x0E, 0x12, 0x02, 0x02, 0x02, 0x0A, 0x5A, 0x02, 
++ 0x02, 0x1B, 0x2E, 0x32, 0x02, 0x02, 0x02, 0x02, 
++ 0x16, 0x02, 0x02, 0x10, 0x02, 0x02, 0x26, 0x5A, 
++ 0x02, 0x1F, 0x52, 0x8E, 0x22, 0x02, 0x5E, 0x3E, 
++ 0x86, 0x0E, 0x16, 0x16, 0x52, 0x7A, 0x4A, 0x66, 
++ 0x72, 0x52, 0x82, 0xB2, 0xBA, 0xA4, 0xB2, 0xAA, 
++ 0x9E, 0x8E, 0x88, 0x96, 0xA6, 0x82, 0x62, 0x1A, 
++ 0x34, 0x4A, 0x31, 0x16, 0x02, 0x1A, 0x02, 0x02, 
++ 0x72, 0x02, 0x02, 0x5E, 0x1A, 0x62, 0x02, 0x0E, 
++ 0x76, 0x1E, 0x76, 0x1E, 0x0A, 0x02
+ };
+ 
+ unsigned char linux_logo[] __initdata = {
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+-    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+-    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+-    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+-    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+-    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+-    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+-    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+-    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+-    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
+-    0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+-    0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
+-    0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
+-    0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+-    0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+-    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+-    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+-    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+-    0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
+-    0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+-    0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
+-    0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+-    0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
+-    0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
+-    0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
+-    0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
+-    0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
+-    0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
+-    0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
+-    0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
+-    0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+-    0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+-    0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
+-    0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+-    0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
+-    0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
+-    0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
+-    0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
+-    0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
+-    0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+-    0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
+-    0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
+-    0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
+-    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+-    0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
+-    0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
+-    0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
+-    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+-    0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
+-    0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
+-    0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
+-    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
+-    0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
+-    0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
+-    0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
+-    0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+-    0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
+-    0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
+-    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
+-    0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
+-    0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
+-    0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+-    0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
+-    0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
+-    0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
+-    0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
+-    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+-    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
+-    0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+-    0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+-    0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
+-    0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
+-    0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
+-    0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
+-    0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
+-    0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
+-    0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
+-    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
+-    0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
+-    0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
+-    0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
+-    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
+-    0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
+-    0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
+-    0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
+-    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
+-    0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
+-    0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
+-    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
+-    0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
+-    0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
+-    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
+-    0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
+-    0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
+-    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
+-    0x36, 0x24, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
+-    0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
+-    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
+-    0x36, 0x3a, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x9b, 0x52, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
+-    0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
+-    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
+-    0x23, 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x47, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
+-    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+-    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
+-    0x2e, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x99, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
+-    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+-    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
+-    0x54, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+-    0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
+-    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
+-    0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21,
+-    0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
+-    0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x52, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x21,
+-    0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
+-    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x22,
+-    0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
+-    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23,
+-    0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
+-    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22,
+-    0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+-    0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
+-    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+-    0x24, 0x27, 0x9f, 0x24, 0x25, 0x28, 0x21, 0x36,
+-    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+-    0x39, 0x4d, 0xa0, 0x84, 0x81, 0x57, 0x21, 0x39,
+-    0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28,
+-    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+-    0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+-    0x2d, 0xa1, 0x7a, 0xa2, 0xa3, 0xa3, 0x7f, 0x22,
+-    0x51, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0xa4, 0xa5, 0xa5, 0xa6, 0x61,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+-    0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+-    0x4d, 0x91, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0x5a,
+-    0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0xa7, 0xa8, 0x69, 0x66, 0xa9,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+-    0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
+-    0x60, 0x85, 0xab, 0xac, 0xa3, 0xa3, 0xa3, 0x82,
+-    0x86, 0x36, 0x32, 0x3f, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0xad, 0xa2, 0xa8, 0xae, 0xaf,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
+-    0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90,
+-    0x8b, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0x5d, 0xb1, 0x36, 0x24, 0x53, 0x9b, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
+-    0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
+-    0x7b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80,
+-    0x9f, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b,
+-    0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa2, 0xa2, 0xac,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x4b,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63,
+-    0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64,
+-    0xa2, 0xa2, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30,
+-    0x44, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85,
+-    0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa2, 0xa3,
+-    0xa3, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36,
+-    0x2d, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe,
+-    0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa2, 0xc1, 0x37, 0x35, 0x26, 0x23,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36,
+-    0x24, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b,
+-    0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa2, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27,
+-    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa8, 0x89, 0x9f, 0x36, 0x36,
+-    0x32, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa2, 0xac,
+-    0xa2, 0x64, 0x64, 0xa2, 0xa2, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x5d, 0xc3, 0x2c,
+-    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x57, 0x27, 0x4d,
+-    0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x99, 0x34, 0x9f, 0xb9, 0x7a, 0x7b, 0xa2, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xc2,
+-    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa8, 0x5f, 0x92, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
+-    0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0xa2, 0xc0,
+-    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+-    0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x89, 0x45,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
+-    0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0xbe, 0xc3,
+-    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x33, 0xc4, 0x63, 0xbe, 0xa2, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x72, 0x81, 0xc5,
+-    0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
+-    0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa2, 0xab, 0x8b, 0xb0, 0x2c,
+-    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+-    0x35, 0x96, 0x75, 0xab, 0xa2, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0x81, 0xb9,
+-    0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
+-    0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30,
+-    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+-    0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa2, 0xa2,
+-    0xac, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x7b, 0x7a, 0xc7,
+-    0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
+-    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x64, 0x64,
+-    0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b,
+-    0x76, 0x7b, 0x64, 0x64, 0xa2, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x76, 0x85, 0xb9,
+-    0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa2, 0xa3,
+-    0xa3, 0xa3, 0xac, 0xa2, 0x64, 0x76, 0xbe, 0x8b,
+-    0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+-    0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90,
+-    0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa2,
+-    0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc,
+-    0x79, 0x9f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64,
+-    0xac, 0xa2, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96,
+-    0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f,
+-    0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d,
+-    0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd,
+-    0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+-    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+-    0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76,
+-    0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34,
+-    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+-    0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74,
+-    0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79,
+-    0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
+-    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
+-    0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e,
+-    0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a,
+-    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+-    0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1,
+-    0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3,
+-    0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+-    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+-    0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7,
+-    0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+-    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
+-    0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51,
+-    0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+-    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+-    0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80,
+-    0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+-    0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33,
+-    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8,
+-    0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+-    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+-    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+-    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+-    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x33, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x61, 0x62, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x35, 0x61, 0x63, 0x64, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x65, 0x66, 0x66, 0x67, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B,
++  0x3B, 0x68, 0x64, 0x69, 0x62, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x22, 0x23, 0x23, 0x55, 0x6A, 0x6B,
++  0x6C, 0x6D, 0x6E, 0x6F, 0x6F, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x22, 0x23, 0x35, 0x33, 0x3B, 0x70, 0x71, 0x72,
++  0x73, 0x74, 0x75, 0x76, 0x77, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x23, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x55,
++  0x2B, 0x34, 0x34, 0x42, 0x70, 0x71, 0x73, 0x78,
++  0x78, 0x78, 0x79, 0x7A, 0x7B, 0x34, 0x22, 0x21,
++  0x55, 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x3B, 0x7C, 0x7D, 0x7E, 0x34, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x35, 0x3B, 0x4C, 0x3C,
++  0x42, 0x3F, 0x56, 0x7F, 0x71, 0x74, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x79, 0x80, 0x81, 0x3C, 0x82,
++  0x83, 0x62, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
++  0x3B, 0x21, 0x55, 0x55, 0x2B, 0x34, 0x39, 0x3F,
++  0x2A, 0x57, 0x8B, 0x72, 0x74, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x75, 0x8C, 0x6F, 0x63,
++  0x63, 0x66, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x84, 0x85, 0x86, 0x8D, 0x88, 0x8E, 0x8F, 0x5E,
++  0x3C, 0x34, 0x3B, 0x34, 0x3F, 0x2A, 0x58, 0x57,
++  0x52, 0x46, 0x6C, 0x73, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x6E, 0x69,
++  0x69, 0x90, 0x34, 0x33, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x91, 0x92, 0x8D, 0x87, 0x8E, 0x93, 0x8A, 0x35,
++  0x94, 0x95, 0x96, 0x56, 0x32, 0x32, 0x52, 0x5C,
++  0x4D, 0x82, 0x72, 0x78, 0x78, 0x78, 0x78, 0x79,
++  0x97, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D, 0x6F,
++  0x62, 0x65, 0x34, 0x4C, 0x33, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
++  0x91, 0x86, 0x87, 0x88, 0x93, 0x98, 0x60, 0x3F,
++  0x99, 0x9A, 0x9A, 0x9B, 0x9C, 0x57, 0x5C, 0x36,
++  0x9D, 0x9E, 0x6D, 0x78, 0x78, 0x78, 0x97, 0x6E,
++  0x9F, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80, 0xA0,
++  0x61, 0x51, 0x51, 0x3C, 0x4C, 0x55, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x3B, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C,
++  0xA1, 0x8D, 0x88, 0x8E, 0xA2, 0xA3, 0x94, 0x42,
++  0x51, 0xA4, 0x9A, 0x9A, 0x9A, 0xA5, 0x9C, 0x2A,
++  0xA6, 0x74, 0x8C, 0x75, 0x97, 0xA7, 0x76, 0x75,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6E,
++  0x46, 0x52, 0x56, 0x3F, 0x42, 0x34, 0x33, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x22,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x3A,
++  0x5A, 0x53, 0x53, 0x29, 0x43, 0x50, 0x53, 0x5A,
++  0x5A, 0x29, 0x5A, 0x43, 0x53, 0x5D, 0x44, 0x2A,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
++  0x7D, 0x87, 0x8E, 0x93, 0xA8, 0xA9, 0xAA, 0x2A,
++  0x57, 0x94, 0xA4, 0x9B, 0xAB, 0xAC, 0x9A, 0x9B,
++  0xAD, 0x76, 0x79, 0x78, 0x75, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D,
++  0x46, 0x5C, 0x57, 0x56, 0x51, 0x42, 0x4C, 0x55,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x27,
++  0x29, 0x2A, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x30,
++  0x59, 0x3D, 0x3D, 0x3D, 0x27, 0x27, 0x26, 0x5D,
++  0x27, 0x27, 0x54, 0x37, 0x2E, 0x4A, 0x36, 0x2B,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0xAE, 0x88, 0xAF, 0xB0, 0xAA, 0x2A, 0x39, 0x34,
++  0x4C, 0x5C, 0x58, 0xB1, 0xB2, 0xB3, 0xAB, 0xA5,
++  0x9A, 0xB4, 0xB5, 0x8C, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80,
++  0xB6, 0x38, 0x5C, 0x57, 0x56, 0x3F, 0x42, 0x3B,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x32,
++  0x31, 0x2C, 0x26, 0x2C, 0x33, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34,
++  0x32, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x33,
++  0x33, 0x55, 0x55, 0x55, 0x23, 0x23, 0x35, 0x23,
++  0x23, 0x35, 0x2B, 0x4E, 0x4F, 0x2A, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x55, 0x38, 0x25,
++  0x2C, 0x52, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x55, 0x8A, 0x8F, 0x39, 0x34, 0x3C, 0x57, 0x32,
++  0x46, 0x42, 0x52, 0x4A, 0x51, 0xAA, 0xB7, 0xB3,
++  0xAB, 0xAC, 0xAC, 0xB8, 0xB9, 0x79, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A,
++  0xBA, 0x70, 0x7B, 0xBB, 0x82, 0x56, 0x3F, 0x34,
++  0x4C, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x36,
++  0x2D, 0x37, 0x38, 0x2A, 0x2B, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x39, 0x3A, 0x2C, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x24, 0x3D,
++  0x3E, 0x25, 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x33, 0x29, 0x26, 0x2A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x54, 0x3E, 0x28,
++  0x28, 0x59, 0x59, 0x48, 0x51, 0x3F, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x2B, 0x56, 0x4D, 0x29, 0x5B, 0x34,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x55, 0x60, 0x3F, 0x42, 0x51, 0x32, 0x52,
++  0x40, 0x38, 0x40, 0x46, 0x42, 0xBC, 0xBD, 0xBE,
++  0xBF, 0x9B, 0xAB, 0x9B, 0xC0, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
++  0xA7, 0x63, 0x63, 0x66, 0x6F, 0x58, 0x56, 0x39,
++  0x34, 0x2B, 0x23, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x2F,
++  0x3D, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x40, 0x41, 0x3B, 0x21,
++  0x21, 0x22, 0x42, 0x38, 0x43, 0x44, 0x3A, 0x45,
++  0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x46, 0x30, 0x47,
++  0x2A, 0x48, 0x48, 0x21, 0x21, 0x21, 0x21, 0x22,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x4D, 0x44, 0x2A, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x50, 0x4A, 0x57, 0x35,
++  0x35, 0x2B, 0x56, 0x27, 0x4B, 0x5D, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x3B, 0x52, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x38,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x3C, 0x42, 0x21, 0x33, 0x24, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x33, 0x38, 0x59, 0x37, 0x27, 0x27, 0x4A, 0x47,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x23, 0x4C, 0x4C, 0x2A, 0x56, 0x46, 0x31,
++  0x4D, 0x36, 0x50, 0x5A, 0x35, 0xC1, 0xC1, 0xC2,
++  0xC3, 0xB7, 0xB3, 0xBE, 0x76, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
++  0x6D, 0x62, 0x69, 0x6F, 0x58, 0x46, 0x32, 0x2A,
++  0x39, 0x34, 0x35, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x49,
++  0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x23, 0x29, 0x48, 0x22,
++  0x42, 0x3A, 0x4A, 0x49, 0x4B, 0x2E, 0x4B, 0x3E,
++  0x4A, 0x2C, 0x34, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x30, 0x40, 0x22,
++  0x21, 0x32, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x39,
++  0x36, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22,
++  0x31, 0x4F, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x31, 0x59, 0x2A, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x55, 0x27, 0x24, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4C, 0x44, 0x27, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x2A, 0x26, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3A,
++  0x40, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, 0x49,
++  0x35, 0x21, 0x21, 0x21, 0x21, 0x22, 0x58, 0x25,
++  0x5A, 0x57, 0x21, 0x4C, 0x3D, 0x34, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38,
++  0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x3A, 0x4B, 0x53, 0x56, 0x55, 0x33, 0x42, 0x56,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x55, 0x4C, 0x42, 0x2A, 0x57, 0x5C, 0x38,
++  0x36, 0x47, 0x5A, 0xB6, 0x77, 0xC4, 0xC1, 0xC1,
++  0xC4, 0xC5, 0xB7, 0xB9, 0x79, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
++  0x97, 0xC6, 0x68, 0x57, 0x4D, 0x38, 0x46, 0x32,
++  0x51, 0x42, 0x2B, 0x35, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x2D, 0x38,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x3C,
++  0x47, 0x4F, 0x50, 0x51, 0x3F, 0x44, 0x42, 0x34,
++  0x52, 0x53, 0x28, 0x2A, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x48, 0x54, 0x33, 0x21,
++  0x23, 0x3A, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x2A,
++  0x26, 0x33, 0x21, 0x21, 0x21, 0x21, 0x23, 0x45,
++  0x37, 0x3D, 0x41, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x31,
++  0x59, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x28, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x27, 0x5B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x54, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B,
++  0x46, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x49,
++  0x2B, 0x21, 0x21, 0x21, 0x23, 0x40, 0x43, 0x32,
++  0x35, 0x21, 0x21, 0x33, 0x28, 0x4C, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x4F,
++  0x5B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x50,
++  0x44, 0x39, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x3B, 0x34, 0x3F, 0x58, 0x46, 0x40, 0x36,
++  0x50, 0x41, 0x4D, 0xC7, 0x65, 0xC2, 0xC1, 0xC1,
++  0xC8, 0xBF, 0xB1, 0x97, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79,
++  0x80, 0xC9, 0x36, 0x50, 0x36, 0x38, 0x31, 0x32,
++  0x56, 0x39, 0x34, 0x33, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x2B, 0x3D, 0x28, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x4D,
++  0x55, 0x2B, 0x21, 0x21, 0x2B, 0x28, 0x3B, 0x21,
++  0x21, 0x22, 0x52, 0x27, 0x56, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x2A, 0x30, 0x3F, 0x21, 0x22,
++  0x57, 0x44, 0x58, 0x21, 0x21, 0x21, 0x21, 0x56,
++  0x37, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x56, 0x3E,
++  0x36, 0x2A, 0x59, 0x23, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x50, 0x3D,
++  0x42, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x40, 0x5A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x56, 0x49, 0x24, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x42, 0x54, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x59,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x4A,
++  0x51, 0x21, 0x21, 0x33, 0x47, 0x47, 0x33, 0x21,
++  0x21, 0x21, 0x21, 0x55, 0x27, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x4B,
++  0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34, 0x44,
++  0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x33, 0x4C, 0x3C, 0x51, 0x57, 0x5C, 0x38, 0x38,
++  0x9D, 0xCA, 0x61, 0xCB, 0xCC, 0xCD, 0xC4, 0xC8,
++  0xA4, 0x9C, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79,
++  0x7A, 0x7F, 0x41, 0x29, 0x47, 0x38, 0x40, 0x57,
++  0x32, 0x51, 0x42, 0x2B, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x57, 0x49, 0x32, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57, 0x27,
++  0x35, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x2A, 0x21,
++  0x21, 0x21, 0x21, 0x56, 0x54, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x4C, 0x2E, 0x5A, 0x23, 0x55, 0x5B,
++  0x49, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x21, 0x32,
++  0x3E, 0x3B, 0x21, 0x21, 0x21, 0x35, 0x54, 0x53,
++  0x23, 0x55, 0x4F, 0x55, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x25, 0x44, 0x42,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x41, 0x46, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x53, 0x2F, 0x2A, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x32, 0x28, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x59, 0x5B,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54,
++  0x57, 0x21, 0x35, 0x53, 0x47, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x44, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x41, 0x43,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3F, 0x29,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x55, 0x4C, 0x3F, 0x2A, 0x46, 0x31, 0x36, 0x46,
++  0x71, 0x97, 0xCE, 0xCB, 0xCF, 0xA4, 0x9C, 0xA4,
++  0xAD, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x8C,
++  0x7A, 0xA7, 0x36, 0x50, 0x3A, 0x36, 0x38, 0x52,
++  0x32, 0x2A, 0x3F, 0x2B, 0x22, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x22, 0x5A, 0x5A, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x28,
++  0x35, 0x21, 0x21, 0x21, 0x55, 0x30, 0x56, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x5B, 0x45, 0x21, 0x21,
++  0x21, 0x21, 0x2B, 0x2E, 0x25, 0x47, 0x3D, 0x2D,
++  0x25, 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39,
++  0x44, 0x55, 0x21, 0x21, 0x21, 0x46, 0x59, 0x3B,
++  0x21, 0x23, 0x30, 0x34, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x2A, 0x28, 0x4E, 0x42, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x3C, 0x3D, 0x42, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x51, 0x4B, 0x49, 0x39, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x5C, 0x25, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x4B, 0x3B,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54,
++  0x56, 0x21, 0x5B, 0x3A, 0x35, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x51, 0x59, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x2D, 0x42,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x2B, 0x3C, 0x39, 0x56, 0x46, 0x40, 0x36, 0xB6,
++  0x73, 0x82, 0xCB, 0xD0, 0x75, 0xD1, 0xD2, 0xD1,
++  0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x74, 0xCE,
++  0x9E, 0x6E, 0xD3, 0xC6, 0x6F, 0x81, 0x38, 0x5C,
++  0x52, 0x58, 0x39, 0x4C, 0x35, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x4C, 0x4A, 0x40, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x3A,
++  0x21, 0x21, 0x21, 0x21, 0x55, 0x27, 0x3F, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x3B, 0x21,
++  0x21, 0x21, 0x42, 0x2E, 0x2D, 0x2D, 0x26, 0x46,
++  0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51,
++  0x44, 0x55, 0x21, 0x21, 0x35, 0x25, 0x40, 0x21,
++  0x21, 0x22, 0x4E, 0x58, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x39, 0x59, 0x38, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x56, 0x59, 0x23, 0x21, 0x21, 0x21,
++  0x21, 0x4C, 0x54, 0x5B, 0x59, 0x4C, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x57, 0x3A, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x4D, 0x49, 0x26, 0x23,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x53,
++  0x32, 0x51, 0x27, 0x42, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x42, 0x25, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x24, 0x37, 0x3E, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x48,
++  0x48, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x3B, 0x39, 0x3F, 0x32, 0x5C, 0x38, 0x47, 0xD4,
++  0x7A, 0xC7, 0xCB, 0xD0, 0x74, 0x80, 0x8C, 0x9F,
++  0x80, 0x79, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x73, 0x72, 0xD5, 0xCA, 0x61, 0xD3, 0x40, 0x5C,
++  0x46, 0x58, 0x51, 0x42, 0x33, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x39, 0x4B, 0x58, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x2A, 0x3D, 0x51,
++  0x21, 0x21, 0x21, 0x21, 0x55, 0x28, 0x42, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x47, 0x52, 0x21,
++  0x21, 0x21, 0x58, 0x59, 0x42, 0x3C, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57,
++  0x4E, 0x23, 0x21, 0x22, 0x4D, 0x54, 0x35, 0x21,
++  0x21, 0x21, 0x5A, 0x46, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x56, 0x59, 0x36, 0x35, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x36, 0x5B, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x53, 0x48, 0x3F, 0x27, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x24, 0x47, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x22, 0x40, 0x27, 0x29, 0x29, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47,
++  0x40, 0x41, 0x5C, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x39, 0x41, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x32, 0x26, 0x47, 0x28, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
++  0x53, 0x28, 0x36, 0x42, 0x23, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x4C, 0x39, 0x58, 0x32, 0x31, 0x38, 0x47, 0xD4,
++  0xCF, 0xD0, 0x6C, 0x9E, 0xD6, 0x6B, 0xD7, 0xD8,
++  0xD7, 0x6B, 0xCF, 0x7B, 0x80, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x74, 0x72, 0xD0, 0xA6, 0x70, 0x51,
++  0x46, 0x56, 0x51, 0x42, 0x55, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x5C, 0x27, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x32, 0x37, 0x54, 0x33,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x2A, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x2C, 0x21,
++  0x21, 0x21, 0x47, 0x36, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52,
++  0x54, 0x23, 0x21, 0x24, 0x4F, 0x46, 0x21, 0x21,
++  0x21, 0x21, 0x38, 0x2C, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x42, 0x55, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x45, 0x54, 0x56, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x53, 0x24, 0x21, 0x21, 0x21, 0x21,
++  0x46, 0x5D, 0x4C, 0x52, 0x4E, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x31, 0x48, 0x22, 0x21, 0x21,
++  0x21, 0x22, 0x46, 0x54, 0x3B, 0x45, 0x29, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47,
++  0x28, 0x28, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x51, 0x41, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x56, 0x54, 0x39, 0x56, 0x28, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x34, 0x50, 0x30, 0x4E, 0x40, 0x34, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x4C, 0x39, 0x58, 0x52, 0x5C, 0x38, 0x47, 0x9D,
++  0xC9, 0xD9, 0xDA, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC,
++  0xDC, 0xDC, 0xDC, 0xDD, 0x6B, 0x7B, 0x75, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x74, 0x71, 0xD0, 0x3F,
++  0x52, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x47, 0x3A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x35, 0x45, 0x4A, 0x2C, 0x3B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x30, 0x56, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x58, 0x29, 0x21,
++  0x21, 0x21, 0x53, 0x3F, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31,
++  0x43, 0x22, 0x3B, 0x28, 0x48, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x56, 0x25, 0x35, 0x21, 0x21, 0x21,
++  0x39, 0x54, 0x34, 0x21, 0x21, 0x21, 0x35, 0x3A,
++  0x30, 0x57, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0x39, 0x21, 0x21,
++  0x21, 0x35, 0x25, 0x3F, 0x21, 0x21, 0x21, 0x56,
++  0x30, 0x58, 0x21, 0x24, 0x43, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4D, 0x29, 0x22, 0x21, 0x21,
++  0x22, 0x32, 0x26, 0x42, 0x21, 0x46, 0x2C, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x48,
++  0x2E, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x56, 0x28, 0x35, 0x21, 0x21,
++  0x21, 0x3F, 0x27, 0x32, 0x21, 0x51, 0x25, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x22, 0x39, 0x38, 0x25, 0x54, 0x50,
++  0x58, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x4C, 0x3F, 0x56, 0x52, 0x31, 0x4D, 0x47, 0x39,
++  0xD8, 0xDC, 0xDC, 0xDC, 0xDE, 0xDF, 0xDF, 0xDF,
++  0xDF, 0xDF, 0xDE, 0xDE, 0xDC, 0xDD, 0xD6, 0x97,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x97, 0x56,
++  0x46, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x38, 0x29, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x35, 0x5B, 0x3D, 0x40, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x3F, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21,
++  0x21, 0x22, 0x5D, 0x34, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x5B,
++  0x2C, 0x33, 0x29, 0x28, 0x3B, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x34, 0x59, 0x3C, 0x21, 0x21, 0x2B,
++  0x53, 0x36, 0x22, 0x21, 0x21, 0x34, 0x5A, 0x28,
++  0x3F, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x40, 0x41, 0x23, 0x21,
++  0x21, 0x3B, 0x28, 0x2B, 0x21, 0x21, 0x2A, 0x44,
++  0x38, 0x22, 0x21, 0x24, 0x50, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x50, 0x25, 0x23, 0x21, 0x23,
++  0x45, 0x5D, 0x52, 0x21, 0x21, 0x40, 0x50, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x50,
++  0x2D, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x46, 0x30, 0x33, 0x21, 0x22,
++  0x24, 0x4E, 0x45, 0x22, 0x21, 0x58, 0x25, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x48,
++  0x27, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x34, 0x3F, 0x58, 0x57, 0x31, 0x4D, 0x47, 0x56,
++  0xDB, 0xDC, 0xDE, 0xE0, 0xE1, 0xE2, 0xE2, 0xE2,
++  0xE2, 0xE2, 0xE1, 0xE3, 0xE4, 0xDE, 0xDC, 0x6B,
++  0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0xA7, 0x38,
++  0x46, 0x56, 0x2A, 0x39, 0x3B, 0x23, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x32, 0x44, 0x34, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3F,
++  0x4D, 0x41, 0x29, 0x42, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x46, 0x34,
++  0x2B, 0x55, 0x55, 0x2B, 0x56, 0x59, 0x36, 0x21,
++  0x21, 0x22, 0x59, 0x2B, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x55, 0x5C, 0x21, 0x21, 0x21, 0x40,
++  0x50, 0x4D, 0x4F, 0x32, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x55, 0x44, 0x31, 0x22, 0x3B, 0x5A,
++  0x41, 0x55, 0x21, 0x35, 0x57, 0x4A, 0x2E, 0x48,
++  0x57, 0x32, 0x3F, 0x55, 0x35, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x25, 0x47, 0x22, 0x21,
++  0x21, 0x4C, 0x28, 0x35, 0x21, 0x34, 0x30, 0x3A,
++  0x23, 0x21, 0x21, 0x58, 0x3A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4D, 0x4E, 0x35, 0x33, 0x48,
++  0x44, 0x56, 0x21, 0x21, 0x21, 0x58, 0x41, 0x23,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x29,
++  0x4A, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x32, 0x44, 0x2B, 0x23, 0x45,
++  0x3D, 0x31, 0x22, 0x21, 0x21, 0x4C, 0x27, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x53, 0x53, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x34, 0x3F, 0x58, 0x57, 0x40, 0x38, 0x47, 0xD4,
++  0xDC, 0xDE, 0xE0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE1, 0xDF, 0xDC,
++  0xE6, 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x2A, 0x40,
++  0x46, 0x58, 0x2A, 0x42, 0x34, 0x34, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x2B, 0x54, 0x5A, 0x34, 0x23,
++  0x35, 0x23, 0x35, 0x33, 0x2B, 0x24, 0x54, 0x4B,
++  0x59, 0x5C, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B, 0x44, 0x59,
++  0x27, 0x26, 0x26, 0x4A, 0x3E, 0x41, 0x55, 0x21,
++  0x21, 0x22, 0x41, 0x39, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x34, 0x53, 0x4D, 0x21, 0x21, 0x21, 0x5C,
++  0x4B, 0x4F, 0x40, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x48, 0x30, 0x50, 0x26, 0x54,
++  0x34, 0x21, 0x55, 0x4E, 0x2D, 0x2F, 0x4F, 0x37,
++  0x3E, 0x4B, 0x4B, 0x30, 0x27, 0x53, 0x2C, 0x57,
++  0x42, 0x4C, 0x55, 0x22, 0x22, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x39, 0x4A, 0x3F, 0x21, 0x21,
++  0x21, 0x55, 0x53, 0x55, 0x2A, 0x26, 0x54, 0x33,
++  0x21, 0x21, 0x21, 0x51, 0x54, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x51, 0x3D, 0x46, 0x5A, 0x4F,
++  0x52, 0x21, 0x21, 0x21, 0x21, 0x22, 0x27, 0x31,
++  0x33, 0x23, 0x42, 0x4C, 0x21, 0x21, 0x21, 0x5B,
++  0x54, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3B, 0x44, 0x45, 0x48, 0x4B,
++  0x38, 0x22, 0x21, 0x21, 0x21, 0x21, 0x53, 0x48,
++  0x33, 0x23, 0x34, 0x3C, 0x22, 0x57, 0x4D, 0x33,
++  0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x34, 0x40,
++  0x44, 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x3B, 0x42, 0x2A, 0x57, 0x31, 0x38, 0x5C, 0xD8,
++  0xDC, 0xE4, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE0,
++  0xDE, 0xCA, 0x9F, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x80, 0x76, 0x57, 0x5C,
++  0x31, 0x6E, 0x34, 0x3C, 0xC9, 0x3B, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x33, 0x5B, 0x30, 0x25,
++  0x5D, 0x5A, 0x53, 0x27, 0x26, 0x59, 0x36, 0x56,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x3D, 0x2A, 0x55,
++  0x42, 0x51, 0x56, 0x24, 0x2A, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x45, 0x53, 0x3B, 0x22, 0x22, 0x35,
++  0x46, 0x59, 0x54, 0x55, 0x21, 0x21, 0x21, 0x31,
++  0x2D, 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x33, 0x50, 0x5D, 0x45, 0x55,
++  0x21, 0x21, 0x34, 0x4F, 0x29, 0x58, 0x33, 0x4C,
++  0x39, 0x3C, 0x2A, 0x40, 0x48, 0x54, 0x3D, 0x3D,
++  0x37, 0x4A, 0x59, 0x29, 0x5B, 0x36, 0x52, 0x2A,
++  0x42, 0x3C, 0x32, 0x30, 0x41, 0x35, 0x21, 0x21,
++  0x21, 0x33, 0x41, 0x26, 0x4B, 0x5A, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x3E, 0x41, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x41, 0x49, 0x30, 0x32,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x4F,
++  0x5D, 0x41, 0x27, 0x58, 0x21, 0x21, 0x21, 0x5B,
++  0x41, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x47, 0x49, 0x4F, 0x5C,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, 0x4A,
++  0x28, 0x43, 0x27, 0x5C, 0x35, 0x25, 0x49, 0x5B,
++  0x58, 0x52, 0x5C, 0x38, 0x48, 0x41, 0x4A, 0x4B,
++  0x50, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x3B, 0x3C, 0x2A, 0x32, 0x5C, 0x40, 0x32, 0xDD,
++  0xDC, 0xE3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE1, 0xE0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x80, 0xE7, 0x58, 0x52,
++  0x5C, 0x67, 0xE7, 0x6C, 0xE8, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x23, 0x39, 0x5C,
++  0x29, 0x5A, 0x4D, 0x5C, 0x2A, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x42, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x33, 0x27, 0x30, 0x5A, 0x2C, 0x25,
++  0x4B, 0x50, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x2C, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4C, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x55, 0x2B,
++  0x39, 0x32, 0x4D, 0x29, 0x26, 0x3D, 0x2D, 0x2D,
++  0x4B, 0x4B, 0x2F, 0x30, 0x42, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x3B, 0x29, 0x2C, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x50, 0x4D, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x32, 0x3B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51,
++  0x48, 0x45, 0x34, 0x21, 0x21, 0x21, 0x21, 0x38,
++  0x44, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0x32, 0x34, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3C,
++  0x5B, 0x4D, 0x42, 0x21, 0x21, 0x34, 0x4D, 0x47,
++  0x5A, 0x5D, 0x27, 0x4E, 0x25, 0x3A, 0x5C, 0x42,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x2B, 0x34, 0x51, 0x56, 0x46, 0x40, 0xE9, 0xDA,
++  0xDD, 0xE1, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE2, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x76, 0xD3, 0x67, 0x39,
++  0x3C, 0xCF, 0xD5, 0x9F, 0x3B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x2B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x53, 0x44, 0x3D, 0x43,
++  0x57, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x35, 0x55, 0x3F, 0x2A,
++  0x57, 0x24, 0x3F, 0x3B, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
++  0x3C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x55, 0x4C, 0x3F, 0x58, 0x46, 0x31, 0x8B, 0xAD,
++  0xCC, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x97, 0x35, 0x6E, 0xC6, 0x82,
++  0xA6, 0x73, 0x75, 0xBA, 0x2B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x34, 0x44, 0x3B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x33, 0x34, 0xEB, 0x34, 0x57, 0x5C, 0x4C, 0xA4,
++  0xEC, 0x64, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0x83, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x80, 0xED, 0xCF, 0xCE, 0x78, 0x78,
++  0x78, 0x7A, 0x6D, 0x34, 0x22, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x55, 0x25, 0x55, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x34, 0xEE, 0xEF, 0x5F, 0x96, 0x23, 0xB3,
++  0xBF, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x9F, 0x78, 0x78, 0x78, 0x78,
++  0x80, 0x9F, 0x65, 0x33, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x55, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x4C, 0xF1, 0xA5, 0xAC, 0xAB, 0x60, 0xB3,
++  0xB3, 0xF2, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xF3, 0x6D, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x80, 0x61, 0x34, 0x23, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5E,
++  0x4C, 0x3B, 0xF4, 0xA5, 0x9B, 0x9B, 0xB4, 0xEF,
++  0xEF, 0xBF, 0xAD, 0xF5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0x67, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80,
++  0xA7, 0x3F, 0x55, 0x22, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5F,
++  0x9B, 0xD2, 0x3C, 0xB7, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xF0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x82,
++  0x34, 0x3B, 0x33, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x5D, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x60,
++  0xAB, 0xA5, 0xB8, 0xB1, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xF6, 0xB7, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0x67, 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x80, 0x9F, 0xBA, 0x42,
++  0x4C, 0x2B, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
++  0xF2, 0x9B, 0x9B, 0xB4, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB4, 0x5F, 0x63, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF5,
++  0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x80, 0x6D, 0x65, 0x3C, 0x34,
++  0x3B, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0xF7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF8, 0x68,
++  0x7A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x80, 0x97, 0x82, 0x39, 0x39, 0x34, 0x3B,
++  0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x3B, 0xB8, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xF6, 0xB2, 0xF9, 0xFA, 0xFA, 0xFA,
++  0xFA, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0x6F, 0x97,
++  0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x8C, 0x61, 0x39, 0x2A, 0x3F, 0x3C, 0x4C, 0x55,
++  0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x31, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0xFB, 0xF6, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB3, 0xB2, 0xF9, 0xF3, 0xF3, 0xF3,
++  0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0x90, 0x6D, 0x97,
++  0x8C, 0x6D, 0x76, 0xBB, 0xC6, 0xB9, 0xC0, 0xFC,
++  0xAD, 0xFB, 0x2A, 0x58, 0x42, 0x4C, 0x55, 0x33,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x33, 0xD2, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB4, 0xB8, 0xEB, 0xE8, 0x7F, 0xD6,
++  0xD6, 0xD6, 0xD6, 0x9D, 0x9D, 0x52, 0xEB, 0x5F,
++  0x5F, 0x5F, 0xF2, 0xA4, 0xBF, 0xBF, 0xB4, 0xBF,
++  0xEE, 0x56, 0x2A, 0x42, 0x4C, 0x2B, 0x33, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x4C, 0xBE, 0xF6, 0xEF, 0xEF, 0xEF,
++  0xF6, 0xB4, 0xB2, 0xF1, 0x3C, 0x56, 0x46, 0x5C,
++  0x31, 0x38, 0x40, 0x40, 0x4D, 0x4D, 0xB8, 0xAC,
++  0xBF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xB4,
++  0xB1, 0x39, 0x39, 0x3B, 0x2B, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3B, 0xAD, 0xA4, 0xBF, 0xBF,
++  0xB7, 0xB2, 0xEE, 0x5E, 0x39, 0x51, 0x2A, 0x32,
++  0x52, 0x46, 0x5C, 0x31, 0x31, 0x2A, 0xA5, 0xEF,
++  0xFD, 0xB4, 0xEF, 0xF6, 0xF6, 0xEF, 0xF6, 0xB2,
++  0x3F, 0x34, 0x2B, 0x55, 0x23, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0xEB, 0xF7, 0xAA,
++  0xAA, 0xF7, 0xEB, 0x55, 0x3B, 0x3C, 0x39, 0x51,
++  0x2A, 0x56, 0x32, 0x57, 0x57, 0x2A, 0x96, 0x3C,
++  0x2A, 0xEE, 0xEF, 0x5F, 0xD2, 0xEF, 0xB4, 0xAA,
++  0x42, 0x55, 0x35, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3B,
++  0x3B, 0x35, 0x21, 0x23, 0x33, 0x3B, 0x4C, 0x3C,
++  0x39, 0x3F, 0x51, 0x2A, 0x51, 0x51, 0x58, 0x32,
++  0x56, 0xF4, 0xB1, 0x42, 0x3C, 0xF2, 0x9C, 0x3F,
++  0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x33, 0x55,
++  0x3B, 0x4C, 0x4C, 0x3C, 0x42, 0x42, 0x3C, 0x34,
++  0x34, 0x3F, 0x4C, 0x3B, 0x4C, 0x3B, 0x3C, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x35, 0x33, 0x55, 0x33, 0x33, 0x33, 0x55, 0x2B,
++  0x2B, 0x35, 0x35, 0x35, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
+ };
+ 
+ #endif /* !__HAVE_ARCH_LINUX_LOGO */
+@@ -994,7 +1760,7 @@
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+ 
+ #endif /* !__HAVE_ARCH_LINUX_LOGOBW */
+@@ -1401,7 +2167,7 @@
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ 
+ #endif /* !__HAVE_ARCH_LINUX_LOGO16 */
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch
index e69de29bb2..4daeaa11be 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/mkdep.patch
@@ -0,0 +1,16 @@
+
+#
+# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/Makefile~mkdep	2003-12-19 09:36:51.000000000 -0800
++++ linux/Makefile	2003-12-19 09:57:44.000000000 -0800
+@@ -458,7 +458,7 @@
+ 
+ dep-files: scripts/mkdep archdep include/linux/version.h
+ 	scripts/mkdep -- init/*.c > .depend
+-	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
++	$(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)
+ 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
+ ifdef CONFIG_MODVERSIONS
+ 	$(MAKE) update-modverfile
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch
index e69de29bb2..1cde717bb4 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/swap-performance.patch
@@ -0,0 +1,19 @@
+*** ../linux/mm/swap.c	Tue Jan 14 14:54:41 2003
+--- linux/mm/swap.c	Sun Sep 28 21:34:25 2003
+***************
+*** 32,38 ****
+  int page_cluster;
+  
+  pager_daemon_t pager_daemon = {
+! 	512,	/* base number for calculating the number of tries */
+  	SWAP_CLUSTER_MAX,	/* minimum number of tries */
+  	8,	/* do swap I/O in clusters of this size */
+  };
+--- 32,38 ----
+  int page_cluster;
+  
+  pager_daemon_t pager_daemon = {
+! 	128,	/* base number for calculating the number of tries */
+  	SWAP_CLUSTER_MAX,	/* minimum number of tries */
+  	8,	/* do swap I/O in clusters of this size */
+  };
diff --git a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch
index e69de29bb2..c9296cf224 100644
--- a/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch
+++ b/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/usb-storage.patch
@@ -0,0 +1,3433 @@
+diff -Nur linux-2.4.18/drivers/usb/device/bi/sa1100.c linux-2.4.18-usb-storage/drivers/usb/device/bi/sa1100.c
+--- linux-2.4.18/drivers/usb/device/bi/sa1100.c	2003-05-13 13:18:44.000000000 +0400
++++ linux-2.4.18-usb-storage/drivers/usb/device/bi/sa1100.c	2004-03-01 07:20:38.000000000 +0300
+@@ -440,6 +440,7 @@
+                                         udc_interrupts, *(UDCSR), *(UDCCS0), *(UDCAR));
+ 
+ 			usbd_device_event (udc_device, DEVICE_RESET, 0);
++			usbd_device_event (udc_device, DEVICE_ADDRESS_ASSIGNED,0);
+ 		}
+ 
+ 		if (status & UDCSR_SUSIR) {
+diff -Nur linux-2.4.18/drivers/usb/device/Config.in linux-2.4.18-usb-storage/drivers/usb/device/Config.in
+--- linux-2.4.18/drivers/usb/device/Config.in	2003-05-13 13:18:45.000000000 +0400
++++ linux-2.4.18-usb-storage/drivers/usb/device/Config.in	2003-11-07 05:35:14.000000000 +0300
+@@ -34,6 +34,7 @@
+    comment 'USB Device functions'
+    source drivers/usb/device/net_fd/Config.in
+    source drivers/usb/device/serial_fd/Config.in
++   source drivers/usb/device/storage_fd/Config.in
+ 	
+    comment 'USB Device bus interfaces'
+    source drivers/usb/device/bi/Config.in
+diff -Nur linux-2.4.18/drivers/usb/device/Makefile linux-2.4.18-usb-storage/drivers/usb/device/Makefile
+--- linux-2.4.18/drivers/usb/device/Makefile	2003-05-13 13:18:45.000000000 +0400
++++ linux-2.4.18-usb-storage/drivers/usb/device/Makefile	2003-11-07 05:35:01.000000000 +0300
+@@ -20,6 +20,7 @@
+ 
+ subdir-$(CONFIG_USBD_NET) += net_fd
+ subdir-$(CONFIG_USBD_SERIAL) += serial_fd
++subdir-$(CONFIG_USBD_STORAGE) += storage_fd
+ 
+ #subdir-$(CONFIG_USBD_GENERIC_BUS) += gen_bi
+ #subdir-$(CONFIG_USBD_L7205_BUS) += l7205_bi
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Config.help linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.help
+--- linux-2.4.18/drivers/usb/device/storage_fd/Config.help	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.help	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,55 @@
++CONFIG_USBD_STORAGE
++  Enable the generic mass storage function driver. This function is
++  used emulating a Linux block driver.
++
++CONFIG_USBD_STORAGE_VENDORID
++  Optionally specify the mass storage USB Device Vendor ID. The top
++  level Vendor ID will be used if this is not specified.
++
++CONFIG_USBD_STORAGE_PRODUCTID
++  Optionally specify the mass storage USB Device Product ID. The top
++  level Vendor ID will be used if this is not specified.
++
++CONFIG_USBD_STORAGE_OUT_ENDPOINT
++  Specify the preferred OUT (received data) endpoint number. This is a
++  number from 0-15 and must be allowed by the bus interface device.
++
++  Some devices such as the SA-1110 or L7205/L7210 may override this
++  value with a fixed value.
++
++CONFIG_USBD_STORAGE_IN_ENDPOINT
++  Specify the preferred IN (transmit data) endpoint number. This is a
++  number from 0-15 and must be allowed by the bus interface device.
++
++  Some devices such as the SA-1110 or L7205/L7210 may override this
++  value with a fixed value.
++
++CONFIG_USBD_STORAGE_INT_ENDPOINT
++  Specify the preferred INT (interrupt) endpoint number. This is a
++  number from 0-15 and must be allowed by the bus interface device.
++
++  Some devices such as the L7205/L7210 may override this value with a
++  fixed value. Others such as the SA-1110 do not allow an interrupt
++  value.
++
++CONFIG_USBD_STORAGE_OUT_PKTSIZE
++  Specify the maximum packet size for the OUT endpoint. This allowable
++  values are normally 16, 32 and 64. 
++
++  Some devices such as the Linkup L7205/L7210 may override this value
++  with a lower maximum value (such as 32).
++
++CONFIG_USBD_STORAGE_IN_PKTSIZE
++  Specify the maximum packet size for the IN endpoint. This allowable
++  values are normally 16, 32 and 64. 
++
++  Some devices such as the Linkup L7205/L7210 may override this value
++  with a lower maximum value (such as 32).
++
++CONFIG_USBD_STORAGE_INT_PKTSIZE
++  Specify the maximum packet size for the INT endpoint. This allowable
++  values are normally 8 and 16. Some bus interface devices may not
++  support all values.
++
++CONFIG_USBD_STORAGE_DEF_DEVICE_NAME
++  Specify the default block device name to used on mass storage.
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Config.in linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.in
+--- linux-2.4.18/drivers/usb/device/storage_fd/Config.in	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Config.in	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,29 @@
++#
++#  Generic Mass Storage Function Driver
++#
++# Copyright (c) 2003 Communication Technology Inc.
++# Copyright (C) 2001 Lineo, Inc.
++# Copyright (C) 2001 Hewlett-Packard Co.
++mainmenu_option next_comment
++comment "Mass Storage Function"
++
++dep_tristate '  Mass Storage Function Driver' CONFIG_USBD_STORAGE $CONFIG_USBD
++if [ "$CONFIG_USBD_STORAGE" = "y" -o "$CONFIG_USBD_STORAGE" = "m" ]; then
++   hex     ' Overide VendorID (hex value)' CONFIG_USBD_STORAGE_VENDORID "0000"
++   hex     ' Overide ProductID (hex value)' CONFIG_USBD_STORAGE_PRODUCTID "0000"
++
++   # allow setting of endpoint configurations for some architectures
++   int     '    OUT Endpoint (0-15)' CONFIG_USBD_STORAGE_OUT_ENDPOINT "1"
++   int     '   OUT PacketSize (16, 32, 64)' CONFIG_USBD_STORAGE_OUT_PKTSIZE "64"
++   int     '    IN  Endpoint (0-15)' CONFIG_USBD_STORAGE_IN_ENDPOINT "2"
++   int     '   IN  PacketSize (16, 32, 64)' CONFIG_USBD_STORAGE_IN_PKTSIZE "64"
++
++   if [ ! "$CONFIG_ARCH_SA1100" = "y" -a ! "$CONFIG_ARCH_L7200" = "y" ]; then
++      int  '    INT Endpoint (0-15)' CONFIG_USBD_STORAGE_INT_ENDPOINT "3"
++      int  '   INT PacketSize (8, 16)' CONFIG_USBD_STORAGE_INT_PKTSIZE "16"
++   fi
++
++   string  '   Default Mass Storage device name' CONFIG_USBD_STORAGE_DEF_DEVICE_NAME ""
++fi
++
++endmenu
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/Makefile linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Makefile
+--- linux-2.4.18/drivers/usb/device/storage_fd/Makefile	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/Makefile	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,58 @@
++#
++# SA1100 Function driver for a network USB Device
++#
++# Copyright (C) 2001 Lineo, Inc.
++# Copyright (C) 2001 Hewlett-Packard Co.
++
++
++O_TARGET	:= storage_fd_drv.o
++list-multi	:= storage_fd.o
++
++storage_fd-objs	:= storage-fd.o storageproto.o schedule_task.o # netproto.o crc32.o 
++
++# Object file lists.
++
++obj-y		:=
++obj-m		:=
++obj-n		:=
++obj-		:=
++
++# Each configuration option enables a list of files.
++
++obj-$(CONFIG_USBD_STORAGE)   += storage_fd.o
++
++# Extract lists of the multi-part drivers.
++# The 'int-*' lists are the intermediate files used to build the multi's.
++
++multi-y		:= $(filter $(list-multi), $(obj-y))
++multi-m		:= $(filter $(list-multi), $(obj-m))
++int-y		:= $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs)))
++int-m		:= $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs)))
++
++# Files that are both resident and modular: remove from modular.
++
++obj-m		:= $(filter-out $(obj-y), $(obj-m))
++int-m		:= $(filter-out $(int-y), $(int-m))
++
++# Translate to Rules.make lists.
++
++O_OBJS		:= $(filter-out $(export-objs), $(obj-y))
++OX_OBJS		:= $(filter     $(export-objs), $(obj-y))
++M_OBJS		:= $(sort $(filter-out $(export-objs), $(obj-m)))
++MX_OBJS		:= $(sort $(filter     $(export-objs), $(obj-m)))
++MI_OBJS		:= $(sort $(filter-out $(export-objs), $(int-m)))
++MIX_OBJS	:= $(sort $(filter     $(export-objs), $(int-m)))
++
++# The global Rules.make.
++
++include $(TOPDIR)/Rules.make
++
++# Link rules for multi-part drivers.
++
++storage_fd.o: $(storage_fd-objs)
++	$(LD) -r -o $@ $(storage_fd-objs)
++
++# dependencies:
++
++storage-fd.o: ../usbd.h ../usbd-bus.h ../usbd-func.h
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.c
+--- linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.c	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,230 @@
++/*
++ * linux/drivers/usb/device/storage_fd/schedule_task.c - schedule task library
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/******************************************************************************
++** Include File
++******************************************************************************/
++#include <linux/config.h>
++#include <linux/fs.h>
++#include <linux/string.h>
++#include <linux/mm.h>
++#include <linux/dcache.h>
++#include <linux/init.h>
++#include <linux/quotaops.h>
++#include <linux/slab.h>
++#include <linux/cache.h>
++#include <linux/swap.h>
++#include <linux/swapctl.h>
++#include <linux/prefetch.h>
++#include <linux/locks.h>
++#include <asm/uaccess.h>
++
++#include "schedule_task.h"
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++#define TASK_DESC_NUM   (512)
++
++/******************************************************************************
++** Structure Define
++******************************************************************************/
++
++/**************************************
++** TASK_DESC
++**************************************/
++typedef struct _TASK_DESC{
++    struct _TASK_DESC*  next;
++    SCHEDULE_TASK_FUNC  task_entry;
++    int                 task_param1;
++    int                 task_param2;
++    int                 task_param3;
++    int                 task_param4;
++    int                 task_param5;
++    char*               file;
++    int                 line;
++} TASK_DESC;
++
++/**************************************
++** OS_WRP_TASK_DATA
++**************************************/
++typedef struct{
++    volatile TASK_DESC* read_desc;
++    volatile TASK_DESC* write_desc;
++    TASK_DESC           desc_pool[TASK_DESC_NUM];
++    spinlock_t          spin_lock;
++    struct tq_struct    task_que;
++    unsigned long       use_num;
++    unsigned long       max_num;
++} TASK_DATA;
++
++/******************************************************************************
++** Variable Declaration
++******************************************************************************/
++static TASK_DATA    TaskData;
++
++/******************************************************************************
++** Local Function Prototype
++******************************************************************************/
++static void task_entry(void*);
++
++/******************************************************************************
++** Global Function
++******************************************************************************/
++void schedule_task_init(void)
++{
++    int i;
++    
++    /* 0 clear */
++    memset(&TaskData, 0x00, sizeof(TaskData));
++    
++    /* Read/write pointer initialize */
++    TaskData.read_desc = TaskData.write_desc = &TaskData.desc_pool[0];
++    
++    /* Ling buffer initialize */
++    for(i=0; i<(TASK_DESC_NUM-1); i++){
++        TaskData.desc_pool[i].next = &TaskData.desc_pool[i+1];
++    }
++    TaskData.desc_pool[i].next = &TaskData.desc_pool[0];
++    
++    /* Spin lock initialize */
++    spin_lock_init(&TaskData.spin_lock);
++    
++    /* Task queue initialize */
++    PREPARE_TQUEUE(&TaskData.task_que, task_entry, &TaskData);
++    
++    return;
++}
++
++int schedule_task_register(SCHEDULE_TASK_FUNC entry, int param1, int param2,
++                           int param3, int param4, int param5)
++{
++    unsigned long   flags = 0;
++    
++    spin_lock_irqsave(&TaskData.spin_lock, flags);
++    
++    /* Free descriptor check */
++    if(TaskData.write_desc->next == TaskData.read_desc){
++        printk(KERN_INFO "storage_fd: schedule task no descriptor.\n");
++        spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++        return -1;
++    }
++    
++    /* Descriptor set */
++    TaskData.write_desc->task_entry  = entry;
++    TaskData.write_desc->task_param1 = param1;
++    TaskData.write_desc->task_param2 = param2;
++    TaskData.write_desc->task_param3 = param3;
++    TaskData.write_desc->task_param4 = param4;
++    TaskData.write_desc->task_param5 = param5;
++    
++    /* Pointer update */
++    TaskData.write_desc = TaskData.write_desc->next;
++    
++    /* Statistics set */
++    TaskData.use_num++;
++    if(TaskData.use_num > TaskData.max_num){
++        TaskData.max_num = TaskData.use_num;
++    }
++    
++    spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++    
++    /* Task queue register */
++    schedule_task(&TaskData.task_que);
++    
++    return 0;
++}
++
++void schedule_task_all_unregister(void)
++{
++    unsigned long   flags = 0;
++    
++    spin_lock_irqsave(&TaskData.spin_lock, flags);
++    TaskData.read_desc = TaskData.write_desc;
++    TaskData.use_num = 0;
++    spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++}
++
++ssize_t schedule_task_proc_read(struct file* file, char* buf, size_t count,
++                                loff_t* pos)
++{
++    char    string[1024];
++    int     len = 0;
++
++    len += sprintf(string + len, "Schedule task max num:0x%d\n",
++            TASK_DESC_NUM);
++
++    len += sprintf(string + len, "Schedule task use num:0x%ld\n",
++            TaskData.use_num);
++
++    len += sprintf(string + len, "Schedule task max use num:0x%ld\n",
++            TaskData.max_num);
++    
++    *pos += len;
++    if(len > count){
++        len = -EINVAL;
++    }
++    else
++    if(len > 0 && copy_to_user(buf, string, len)) {
++        len = -EFAULT;
++    }
++
++    return len;
++}
++
++/******************************************************************************
++** Local Function
++******************************************************************************/
++static void task_entry(void* data)
++{
++    int                 cond;
++    unsigned long       flags = 0;
++    volatile TASK_DESC* desc;
++    
++    for(;;){
++        
++        spin_lock_irqsave(&TaskData.spin_lock, flags);
++        desc = TaskData.read_desc;
++        cond = (TaskData.read_desc == TaskData.write_desc);
++        spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++        
++        if(cond) break;
++        
++        /* Task call */
++        desc->task_entry(desc->task_param1, desc->task_param2,
++                      desc->task_param3, desc->task_param4, desc->task_param5);
++        
++        spin_lock_irqsave(&TaskData.spin_lock, flags);
++        
++        /* Pointer update */
++        TaskData.read_desc = TaskData.read_desc->next;
++        
++        /* Statistics set */
++        TaskData.use_num--;
++        
++        spin_unlock_irqrestore(&TaskData.spin_lock, flags);
++    }
++    
++    return;
++}
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.h linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.h
+--- linux-2.4.18/drivers/usb/device/storage_fd/schedule_task.h	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/schedule_task.h	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,41 @@
++/*
++ * linux/drivers/usb/device/storage_fd/schedule_task.h - schedule task library header
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _SCHEDULE_TASK_H_
++#define _SCHEDULE_TASK_H_
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++typedef int (*SCHEDULE_TASK_FUNC)(int, int, int, int, int);
++
++/******************************************************************************
++** Global Function Prototype
++******************************************************************************/
++void    schedule_task_init(void);
++int     schedule_task_register(SCHEDULE_TASK_FUNC, int, int, int, int, int);
++void    schedule_task_all_unregister(void);
++ssize_t schedule_task_proc_read(struct file*, char*, size_t, loff_t*);
++
++#endif  /* _SCHEDULE_TASK_H_ */
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storage-fd.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storage-fd.c
+--- linux-2.4.18/drivers/usb/device/storage_fd/storage-fd.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storage-fd.c	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,865 @@
++/*
++ * linux/drivers/usb/device/storage_fd/storage-fd.c - mass storage function driver
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ * Based on
++ *
++ * linux/drivers/usbd/net_fd/net-fd.c - network function driver
++ *
++ * Copyright (c) 2000, 2001, 2002 Lineo
++ * Copyright (c) 2001 Hewlett Packard
++ *
++ * By: 
++ *      Stuart Lynne <sl@lineo.com>, 
++ *      Tom Rushworth <tbr@lineo.com>, 
++ *      Bruce Balden <balden@lineo.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/******************************************************************************
++** Include File
++******************************************************************************/
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include "../usbd-export.h"
++#include "../usbd-build.h"
++#include "../usbd-module.h"
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/string.h>
++#include <linux/atmdev.h>
++#include <linux/pkt_sched.h>
++#include <linux/delay.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <net/arp.h>
++
++#include <linux/autoconf.h>
++
++#include "../usbd.h"
++#include "../usbd-func.h"
++#include "../usbd-bus.h"
++#include "../usbd-inline.h"
++#include "../usbd-arch.h"
++#include "../hotplug.h"
++
++#include "schedule_task.h"
++#include "storageproto.h"
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++
++/**************************************
++** Module Information
++**************************************/
++
++MODULE_AUTHOR("Shunnosuke kabata");
++MODULE_DESCRIPTION("USB Device Mass Storage Function");
++USBD_MODULE_INFO("storage_fd 0.1");
++
++/**************************************
++** Configration Check
++**************************************/
++
++#if !defined (CONFIG_USBD_VENDORID) && !defined(CONFIG_USBD_STORAGE_VENDORID)
++#error No Vendor ID
++#endif
++#if !defined (CONFIG_USBD_PRODUCTID) && !defined(CONFIG_USBD_STORAGE_PRODUCTID)
++#error No Product ID
++#endif
++
++#if defined(CONFIG_USBD_STORAGE_VENDORID) && (CONFIG_USBD_STORAGE_VENDORID > 0)
++#undef CONFIG_USBD_VENDORID
++#define CONFIG_USBD_VENDORID    CONFIG_USBD_STORAGE_VENDORID
++#endif
++
++#if defined(CONFIG_USBD_STORAGE_PRODUCTID) && (CONFIG_USBD_STORAGE_PRODUCTID > 0)
++#undef CONFIG_USBD_PRODUCTID
++#define CONFIG_USBD_PRODUCTID   CONFIG_USBD_STORAGE_PRODUCTID
++#endif
++
++#ifndef CONFIG_USBD_MAXPOWER
++#define CONFIG_USBD_MAXPOWER            0
++#endif
++
++#ifndef CONFIG_USBD_MANUFACTURER
++#define CONFIG_USBD_MANUFACTURER        "Sharp"
++#endif
++
++#define MAXTRANSFER                     (512)
++
++#ifndef CONFIG_USBD_VENDORID
++#error "CONFIG_USBD_VENDORID not defined"
++#endif
++
++#ifndef CONFIG_USBD_PRODUCTID
++#error "CONFIG_USBD_PRODUCTID not defined"
++#endif
++
++#ifndef CONFIG_USBD_PRODUCT_NAME
++#define CONFIG_USBD_PRODUCT_NAME        "Linux Mass Storage Driver"
++#endif
++
++#ifndef CONFIG_USBD_SERIAL_NUMBER_STR
++#define CONFIG_USBD_SERIAL_NUMBER_STR   ""
++#endif
++
++/*
++ * USB 2.0 spec does not mention it, but MaxPower is expected to be at least one 
++ * and is tested for in USB configuration tests.
++ */
++
++#ifdef CONFIG_USBD_SELFPOWERED
++#define BMATTRIBUTE BMATTRIBUTE_RESERVED | BMATTRIBUTE_SELF_POWERED
++#define BMAXPOWER   1
++#else
++#define BMATTRIBUTE BMATTRIBUTE_RESERVED
++#define BMAXPOWER   CONFIG_USBD_MAXPOWER
++#endif
++
++/*
++ * setup some default values for pktsizes and endpoint addresses.
++ */
++
++#ifndef CONFIG_USBD_STORAGE_OUT_PKTSIZE
++#define CONFIG_USBD_STORAGE_OUT_PKTSIZE     64
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_IN_PKTSIZE
++#define CONFIG_USBD_STORAGE_IN_PKTSIZE      64
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_INT_PKTSIZE
++#define CONFIG_USBD_STORAGE_INT_PKTSIZE     16
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_OUT_ENDPOINT
++#define CONFIG_USBD_STORAGE_OUT_ENDPOINT    1
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_IN_ENDPOINT
++#define CONFIG_USBD_STORAGE_IN_ENDPOINT     2
++#endif
++
++#ifndef CONFIG_USBD_STORAGE_INT_ENDPOINT
++#define CONFIG_USBD_STORAGE_INT_ENDPOINT    3
++#endif
++
++/*
++ * check for architecture specific endpoint configurations
++ */
++
++#if defined(ABS_OUT_ADDR)
++    //#warning
++    //#warning USING ABS ENDPOINT OUT ADDRESS
++    #undef CONFIG_USBD_STORAGE_OUT_ENDPOINT
++
++    #if ABS_OUT_ADDR > 0
++        #define CONFIG_USBD_STORAGE_OUT_ENDPOINT    ABS_OUT_ADDR
++    #endif
++
++#elif defined(MAX_OUT_ADDR) && defined(CONFIG_USBD_STORAGE_OUT_ENDPOINT) && (CONFIG_USBD_STORAGE_OUT_ENDPOINT > MAX_OUT_ADDR)
++    //#warning
++    //#warning USING DEFAULT ENDPOINT OUT ADDRESS
++    #undef CONFIG_USBD_STORAGE_OUT_ENDPOINT
++    #define CONFIG_USBD_STORAGE_OUT_ENDPOINT        DFL_OUT_ADDR
++
++#endif  /* elif */
++
++#if defined(ABS_IN_ADDR)
++    //#warning
++    //#warning USING ABS ENDPOINT IN ADDRESS
++    #undef CONFIG_USBD_STORAGE_IN_ENDPOINT
++
++    #if ABS_IN_ADDR > 0
++        #define CONFIG_USBD_STORAGE_IN_ENDPOINT     ABS_IN_ADDR
++    #endif
++
++#elif defined(MAX_IN_ADDR) && defined(CONFIG_USBD_STORAGE_IN_ENDPOINT) && (CONFIG_USBD_STORAGE_IN_ENDPOINT > MAX_IN_ADDR)
++    //#warning
++    //#warning USING DEFAULT ENDPOINT IN ADDRESS
++    #undef CONFIG_USBD_STORAGE_IN_ENDPOINT
++    #define CONFIG_USBD_STORAGE_IN_ENDPOINT         DFL_IN_ADDR
++
++#endif  /* elif */
++
++#if defined(ABS_INT_ADDR)
++    //#warning
++    //#warning USING ABS ENDPOINT INT ADDRESS
++    #undef CONFIG_USBD_STORAGE_INT_ENDPOINT
++
++    #if ABS_INT_ADDR
++        #define CONFIG_USBD_STORAGE_INT_ENDPOINT    ABS_INT_ADDR
++    #endif
++
++#elif defined(MAX_INT_ADDR) && defined(CONFIG_USBD_STORAGE_INT_ENDPOINT) && (CONFIG_USBD_STORAGE_INT_ENDPOINT > MAX_INT_ADDR)
++    //#warning
++    //#warning USING DEFAULT ENDPOINT INT ADDRESS
++    #undef CONFIG_USBD_STORAGE_INT_ENDPOINT
++    #define CONFIG_USBD_STORAGE_INT_ENDPOINT        DFL_INT_ADDR
++
++#endif  /* elif */
++
++#if defined(MAX_OUT_PKTSIZE) && defined(CONFIG_USBD_STORAGE_OUT_PKTSIZE) && CONFIG_USBD_STORAGE_OUT_PKTSIZE > MAX_OUT_PKTSIZE
++    //#warning
++    //#warning OVERIDING ENDPOINT OUT PKTSIZE 
++    #undef CONFIG_USBD_STORAGE_OUT_PKTSIZE
++    #define CONFIG_USBD_STORAGE_OUT_PKTSIZE         MAX_OUT_PKTSIZE
++#endif
++
++#if defined(MAX_IN_PKTSIZE) && defined(CONFIG_USBD_STORAGE_IN_PKTSIZE) && CONFIG_USBD_STORAGE_IN_PKTSIZE > MAX_IN_PKTSIZE
++    //#warning
++    //#warning OVERIDING ENDPOINT IN PKTSIZE 
++    #undef CONFIG_USBD_STORAGE_IN_PKTSIZE
++    #define CONFIG_USBD_STORAGE_IN_PKTSIZE          MAX_IN_PKTSIZE
++#endif
++
++#if defined(MAX_INT_PKTSIZE) && defined(CONFIG_USBD_STORAGE_INT_PKTSIZE) && CONFIG_USBD_STORAGE_INT_PKTSIZE > MAX_INT_PKTSIZE
++    //#warning
++    //#warning OVERIDING ENDPOINT INT PKTSIZE
++    #undef CONFIG_USBD_STORAGE_INT_PKTSIZE
++    #define CONFIG_USBD_STORAGE_INT_PKTSIZE         MAX_INT_PKTSIZE
++#endif
++
++/******************************************************************************
++** Variable Declaration
++******************************************************************************/
++
++/**************************************
++** Module Parameters
++**************************************/
++
++static u32  vendor_id;
++static u32  product_id;
++static int  out_pkt_sz = CONFIG_USBD_STORAGE_OUT_PKTSIZE;
++static int  in_pkt_sz  = CONFIG_USBD_STORAGE_IN_PKTSIZE;
++
++MODULE_PARM(vendor_id, "i");
++MODULE_PARM(product_id, "i");
++MODULE_PARM(out_pkt_sz, "i");
++MODULE_PARM(in_pkt_sz, "i");
++
++MODULE_PARM_DESC(vendor_id, "vendor id");
++MODULE_PARM_DESC(product_id, "product id");
++
++/**************************************
++** Mass Storage Configuration
++**************************************/
++
++/*
++ * Data Interface Alternate 1 endpoints
++ */
++static __initdata struct usb_endpoint_description StorageAlt1Endpoints[] = {
++    {
++        bEndpointAddress:CONFIG_USBD_STORAGE_OUT_ENDPOINT,
++        bmAttributes:BULK,
++        wMaxPacketSize:CONFIG_USBD_STORAGE_OUT_PKTSIZE,
++        bInterval:0,
++        direction:OUT,
++        transferSize:MAXTRANSFER,
++    },
++
++    {
++        bEndpointAddress:CONFIG_USBD_STORAGE_IN_ENDPOINT,
++        bmAttributes:BULK,
++        wMaxPacketSize:CONFIG_USBD_STORAGE_IN_PKTSIZE,
++        bInterval:0,
++        direction:IN,
++        transferSize:MAXTRANSFER,
++    },
++
++#if defined(CONFIG_USBD_STORAGE_INT_ENDPOINT) && (CONFIG_USBD_STORAGE_INT_ENDPOINT > 0)
++    {
++        bEndpointAddress:CONFIG_USBD_STORAGE_INT_ENDPOINT,
++        bmAttributes:INTERRUPT,
++        wMaxPacketSize:CONFIG_USBD_STORAGE_INT_PKTSIZE,
++        bInterval:10,
++        direction:IN,
++        transferSize:CONFIG_USBD_STORAGE_INT_PKTSIZE,
++    },
++#endif
++};
++
++
++/*
++ * Data Interface Alternate description(s)
++ */
++static __initdata struct usb_alternate_description StorageAlternateDescriptions[] = {
++    {
++        #if defined(CONFIG_USBD_STORAGE_NO_STRINGS)
++        iInterface:"",
++        #else
++        iInterface:"Mass Storage Interface",
++        #endif
++        bAlternateSetting:0,
++        classes:0,
++        class_list:NULL,
++        endpoints:sizeof (StorageAlt1Endpoints) / sizeof (struct usb_endpoint_description),
++        endpoint_list:StorageAlt1Endpoints,
++    },
++};
++
++/*
++ * Interface description(s)
++ */
++static __initdata struct usb_interface_description StorageInterfaces[] = {
++    {
++        #if defined(CONFIG_USBD_STORAGE_NO_STRINGS)
++        iInterface:"",
++        #else
++        iInterface:"Mass Storage Interface",
++        #endif
++        bInterfaceClass:MASS_STORAGE_CLASS,
++        bInterfaceSubClass:MASS_STORAGE_SUBCLASS_SCSI,
++        bInterfaceProtocol:MASS_STORAGE_PROTO_BULK_ONLY,
++        alternates:sizeof (StorageAlternateDescriptions) / sizeof (struct usb_alternate_description),
++        alternate_list:StorageAlternateDescriptions,
++    },
++};
++
++/******************************************************************************
++** USB Configuration
++******************************************************************************/
++
++/*
++ * Configuration description(s)
++ */
++struct __initdata usb_configuration_description StorageDescription[] = {
++    {
++        #if defined(CONFIG_USBD_STORAGE_NO_STRINGS)
++        iConfiguration:"",
++        #else
++        iConfiguration:"Mass Storage Configuration",
++        #endif
++        bmAttributes:BMATTRIBUTE,
++        bMaxPower:BMAXPOWER,
++        interfaces:sizeof (StorageInterfaces) / sizeof (struct usb_interface_description),
++        interface_list:StorageInterfaces,
++    },
++};
++
++/*
++ * Device Description
++ */
++struct __initdata usb_device_description StorageDeviceDescription = {
++    bDeviceClass:0,
++    bDeviceSubClass:0,  // XXX
++    bDeviceProtocol:0,  // XXX
++    idVendor:CONFIG_USBD_VENDORID,
++    idProduct:CONFIG_USBD_PRODUCTID,
++    iManufacturer:CONFIG_USBD_MANUFACTURER,
++    iProduct:CONFIG_USBD_PRODUCT_NAME,
++    iSerialNumber:CONFIG_USBD_SERIAL_NUMBER_STR,
++};
++
++/**************************************
++** Other Variable
++**************************************/
++static int              storage_exit_flag = 0;
++static pid_t            storage_pid = 0;
++static struct semaphore storage_sem;
++struct timer_list       storage_usb_event_tim;
++
++
++/******************************************************************************
++** Global Function
++******************************************************************************/
++
++void storage_urb_send(struct usb_device_instance* device, void* buffer,
++                      int length)
++{
++    int         port = 0;
++    struct urb* urb;
++
++    if(!(urb = usbd_alloc_urb(device,
++                              device->function_instance_array + port,
++                              CONFIG_USBD_STORAGE_IN_ENDPOINT,
++                              length + 5 + in_pkt_sz))){
++        printk(KERN_INFO "storage_fd: usbd_alloc_urb failed. length '%d'.\n", length);
++        return;
++    }
++
++    if(buffer){
++        memcpy(urb->buffer, buffer, length);
++    }
++    else{
++        memset(urb->buffer, 0x00, length);
++    }
++    urb->actual_length = length;
++
++    if(usbd_send_urb(urb)){
++        printk(KERN_INFO "storage_fd: usbd_send_urb failed.\n");
++        usbd_dealloc_urb(urb);
++        return;
++    }
++
++    return;
++}
++
++/******************************************************************************
++** Local Function
++******************************************************************************/
++
++/**************************************
++** Called when a USB Device is created or destroyed
++**************************************/
++
++static int storage_thread(void *_c)
++{
++    siginfo_t           info;
++    unsigned long       signr;
++    char                buff[32];
++
++    /* current status set */
++    daemonize();
++
++    /* PID set */
++    storage_pid = current->pid;
++
++    /* thread name set */
++    sprintf(current->comm, STORAGE_THREAD_NAME);
++    (current)->nice = 10;
++
++    /* signal register */
++    spin_lock_irq(&current->sigmask_lock);
++    siginitsetinv(&current->blocked,
++                  sigmask(SIGUSR1) | sigmask(SIGHUP) | sigmask(SIGKILL) |
++                  sigmask(SIGSTOP) | sigmask(SIGCONT) | sigmask(SIGTERM) |
++                  sigmask(SIGALRM));
++    recalc_sigpending(current);
++    spin_unlock_irq(&current->sigmask_lock);
++
++    /* media open */
++    schedule_task_register(
++        (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_STORAGE,
++        0, 0, 0, 0);
++
++    /* thread active indicate */
++    sprintf(buff, "%d\n", storage_pid);
++    hotplug("usbdstorage", buff, "active");
++
++    for(;;){
++        set_current_state(TASK_INTERRUPTIBLE);
++
++        if (!signal_pending(current)) {
++            schedule();
++            continue;
++        }
++
++        spin_lock_irq(&current->sigmask_lock);
++        signr = dequeue_signal(&current->blocked, &info);
++        spin_unlock_irq(&current->sigmask_lock);
++
++        switch(signr) {
++        case SIGHUP:
++            /* media signal indicate */
++            schedule_task_register(
++                (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_STORAGE,
++                0, 0, 0, 0);
++
++            DBG_STORAGE_FD(KERN_INFO "storage_fd: signal receive 'SIGHUP'.\n");
++            break;
++
++        default:
++            DBG_STORAGE_FD(KERN_INFO "storage_fd: signal receive '%ld'\n", signr);
++            break;
++        }
++
++        if(storage_exit_flag) break;
++    }
++    /* current status set */
++    current->state = TASK_RUNNING;
++
++    /* PID clear */
++    storage_pid = 0;
++
++    /* thread inactive indicate */
++    hotplug("usbdstorage", buff, "inactive");
++
++    up(&storage_sem);
++
++    return 0;
++}
++
++static void storage_function_init(struct usb_bus_instance* bus,
++                              struct usb_device_instance* device,
++                              struct usb_function_driver* function_driver)
++{
++    /* schedule task init */
++    schedule_task_init();
++
++    /* storage protocol initialize */
++    storageproto_init();
++
++    /* semaphore init */
++    sema_init(&storage_sem, 0);
++
++    /* timer initialize */
++    init_timer(&storage_usb_event_tim);
++
++    /* thread create */
++    storage_pid = kernel_thread(storage_thread, NULL, 0);
++
++    return;
++}
++
++static void storage_function_exit(struct usb_device_instance* device)
++{
++    /* thread kill */
++    storage_exit_flag = 1;
++    kill_proc(storage_pid, SIGKILL, 1);
++    down(&storage_sem);
++
++    /* delete timer */
++    del_timer(&storage_usb_event_tim);
++
++    /* storage protocol exit */
++    storageproto_exit();
++
++    /* schedule task delete */
++    schedule_task_all_unregister();
++
++    return;
++}
++
++
++/**************************************
++** Called to handle USB Events
++**************************************/
++
++static void storage_usb_event_delay_timeout(unsigned long param)
++{
++    /* media signal indicate */
++    schedule_task_register(
++        (SCHEDULE_TASK_FUNC)storageproto_usb_status_check, (int)param,
++        0, 0, 0, 0);
++
++    return;
++}
++
++/*
++ * storage_event - process a device event
++ * @device: usb device 
++ * @event: the event that happened
++ *
++ * Called by the usb device core layer to respond to various USB events.
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++void storage_event(struct usb_device_instance* device,
++                   usb_device_event_t event, int data)
++{
++#if 0
++    static struct {
++        usb_device_event_t  event;
++        char*               string;
++    } eventAnal[] = {
++        {DEVICE_UNKNOWN,            "DEVICE_UNKNOWN"},
++        {DEVICE_INIT,               "DEVICE_INIT"},
++        {DEVICE_CREATE,             "DEVICE_CREATE"},
++        {DEVICE_HUB_CONFIGURED,     "DEVICE_HUB_CONFIGURED"},
++        {DEVICE_RESET,              "DEVICE_RESET"},
++        {DEVICE_ADDRESS_ASSIGNED,   "DEVICE_ADDRESS_ASSIGNED"},
++        {DEVICE_CONFIGURED,         "DEVICE_CONFIGURED"},
++        {DEVICE_SET_INTERFACE,      "DEVICE_SET_INTERFACE"},
++        {DEVICE_SET_FEATURE,        "DEVICE_SET_FEATURE"},
++        {DEVICE_CLEAR_FEATURE,      "DEVICE_CLEAR_FEATURE"},
++        {DEVICE_DE_CONFIGURED,      "DEVICE_DE_CONFIGURED"},
++        {DEVICE_BUS_INACTIVE,       "DEVICE_BUS_INACTIVE"},
++        {DEVICE_BUS_ACTIVITY,       "DEVICE_BUS_ACTIVITY"},
++        {DEVICE_POWER_INTERRUPTION, "DEVICE_POWER_INTERRUPTION"},
++        {DEVICE_HUB_RESET,          "DEVICE_HUB_RESET"},
++        {DEVICE_DESTROY,            "DEVICE_DESTROY"},
++        {DEVICE_FUNCTION_PRIVATE,   "DEVICE_FUNCTION_PRIVATE"}
++    };
++    int i;
++
++    for(i=0; i<(sizeof(eventAnal)/sizeof(eventAnal[0])); i++){
++        if(event == eventAnal[i].event){
++            DBG_STORAGE_FD(KERN_INFO "storage_fd: event receive '%s'.\n",
++                eventAnal[i].string);
++            break;
++        }
++    }
++    if(i == (sizeof(eventAnal)/sizeof(eventAnal[0]))){
++        DBG_STORAGE_FD(KERN_INFO "storage_fd: unknown event receive.\n");
++    }
++#endif
++
++    switch(event){
++    case DEVICE_ADDRESS_ASSIGNED:
++        {
++        static int  Is1stCheck = 1;
++        if(Is1stCheck){
++            Is1stCheck = 0;
++
++            /* delay timer set */
++            del_timer(&storage_usb_event_tim);
++            storage_usb_event_tim.expires  = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000);
++            storage_usb_event_tim.data     = USB_DISCONNECT;
++            storage_usb_event_tim.function = storage_usb_event_delay_timeout;
++            add_timer(&storage_usb_event_tim);
++            break;
++        }
++        }
++    case DEVICE_BUS_ACTIVITY:
++        /* delay timer set */
++        del_timer(&storage_usb_event_tim);
++        storage_usb_event_tim.expires  = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000);
++        storage_usb_event_tim.data     = USB_CONNECT;
++        storage_usb_event_tim.function = storage_usb_event_delay_timeout;
++        add_timer(&storage_usb_event_tim);
++        break;
++
++    case DEVICE_BUS_INACTIVE:
++        /* delay timer set */
++        del_timer(&storage_usb_event_tim);
++        storage_usb_event_tim.expires  = jiffies + ((USB_EVENT_DELAY_TIM * HZ) / 1000);
++        storage_usb_event_tim.data     = USB_DISCONNECT;
++        storage_usb_event_tim.function = storage_usb_event_delay_timeout;
++        add_timer(&storage_usb_event_tim);
++        break;
++
++    case DEVICE_RESET:
++        schedule_task_register(
++            (SCHEDULE_TASK_FUNC)storageproto_usb_reset_ind,
++            0, 0, 0, 0, 0);
++        break;
++
++    default:
++        break;
++    }
++
++    return;
++}
++
++/*
++ * storage_recv_setup - called with a control URB 
++ * @urb - pointer to struct urb
++ *
++ * Check if this is a setup packet, process the device request, put results
++ * back into the urb and return zero or non-zero to indicate success (DATA)
++ * or failure (STALL).
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++int storage_recv_setup(struct urb* urb)
++{
++    return 0;
++}
++
++/*
++ * storage_recv_urb - called with a received URB 
++ * @urb - pointer to struct urb
++ *
++ * Return non-zero if we failed and urb is still valid (not disposed)
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++int storage_recv_urb(struct urb* urb)
++{
++    int                             port = 0;   // XXX compound device
++    struct usb_device_instance*     device;
++    struct usb_function_instance*   function;
++
++    if(!urb || !(device = urb->device) ||
++       !(function = device->function_instance_array + port)){
++        return -EINVAL;
++    }
++
++    if(urb->status != RECV_OK){
++        return -EINVAL;
++    }
++
++    /* URB urb_analysis */
++    schedule_task_register(
++        (SCHEDULE_TASK_FUNC)storageproto_urb_analysis, (int)urb,
++        0, 0, 0, 0);
++
++    return 0;
++}
++
++/*
++ * storage_urb_sent - called to indicate URB transmit finished
++ * @urb: pointer to struct urb
++ * @rc: result
++ *
++ * The usb device core layer will use this to let us know when an URB has
++ * been finished with.
++ *
++ * This routine IS called at interrupt time. Please use the usual precautions.
++ *
++ */
++int storage_urb_sent(struct urb* urb, int rc)
++{
++    int                             port = 0;   // XXX compound device
++    struct usb_device_instance*     device;
++    struct usb_function_instance*   function;
++
++    if(!urb || !(device = urb->device) ||
++       !(function = device->function_instance_array + port)){
++        return -EINVAL;
++    }
++
++    usbd_dealloc_urb (urb);
++
++    return 0;
++}
++
++/**************************************
++** Proc file system
++**************************************/
++
++static ssize_t storage_proc_read(struct file* file, char* buf, size_t count,
++                                 loff_t* pos)
++{
++    int len = 0, ret;
++
++    if(*pos > 0) return 0;
++
++    if((ret = storageproto_proc_read(file, buf + len, count - len, pos)) < 0){
++        return ret;
++    }
++    len += ret;
++
++    if((ret = schedule_task_proc_read(file, buf + len, count - len, pos)) < 0){
++        return ret;
++    }
++    len += ret;
++
++    return len;
++}
++
++static struct file_operations StorageProcOps = {
++    read:storage_proc_read,
++};
++
++/**************************************
++** Module init and exit
++**************************************/
++
++struct usb_function_operations StorageFunctionOps = {
++    event:storage_event,
++    recv_urb:storage_recv_urb,
++    recv_setup:storage_recv_setup,
++    urb_sent:storage_urb_sent,
++    function_init:storage_function_init,
++    function_exit:storage_function_exit,
++};
++
++struct usb_function_driver StorageFunctionDriver = {
++    name:"Mass Storage",
++    ops:&StorageFunctionOps,
++    device_description:&StorageDeviceDescription,
++    configurations:sizeof (StorageDescription) / sizeof (struct usb_configuration_description),
++    configuration_description:StorageDescription,
++    this_module:THIS_MODULE,
++};
++
++/*
++ * net_modinit - module init
++ *
++ */
++static int __init net_modinit(void)
++{
++    struct proc_dir_entry*  proc_entry;
++
++    printk(KERN_INFO "storage_fd: %s (OUT=%d,IN=%d)\n",
++        __usbd_module_info, out_pkt_sz, in_pkt_sz);
++
++    printk(KERN_INFO "storage_fd: vendorID: %x productID: %x\n",
++        CONFIG_USBD_VENDORID, CONFIG_USBD_PRODUCTID);
++
++    // verify pkt sizes not too small
++    if (out_pkt_sz < 3 || in_pkt_sz < 3){
++        printk(KERN_INFO "storage_fd: Rx pkt size %d or Tx pkt size %d too small\n",
++            out_pkt_sz, in_pkt_sz);
++        return (-EINVAL);
++    }
++
++    if(vendor_id){
++        StorageDeviceDescription.idVendor = vendor_id;
++    }
++    if(product_id){
++        StorageDeviceDescription.idProduct = product_id;
++    }
++
++    // register us with the usb device support layer
++    if(usbd_register_function(&StorageFunctionDriver)){
++        printk(KERN_INFO "storage_fd: usbd_register_function failed.\n");
++        return -EINVAL;
++    }
++
++    // create proc entry
++    if ((proc_entry = create_proc_entry("usb-storage", 0, 0)) == NULL) {
++        usbd_deregister_function (&StorageFunctionDriver);
++        printk(KERN_INFO "storage_fd: create_proc_entry failed.\n");
++        return -ENOMEM;
++    }
++    proc_entry->proc_fops = &StorageProcOps;
++
++    return 0;
++}
++
++/*
++ * function_exit - module cleanup
++ *
++ */
++static void __exit net_modexit (void)
++{
++    // de-register us with the usb device support layer
++    usbd_deregister_function (&StorageFunctionDriver);
++
++    // remove proc entry
++    remove_proc_entry("usb-storage", NULL);
++
++    return;
++}
++
++module_init (net_modinit);
++module_exit (net_modexit);
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storageproto.c linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.c
+--- linux-2.4.18/drivers/usb/device/storage_fd/storageproto.c	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.c	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,1505 @@
++/*
++ * linux/drivers/usb/device/storage_fd/storageproto.c - mass storage protocol library
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/******************************************************************************
++** Include File
++******************************************************************************/
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include "../usbd-export.h"
++#include "../usbd-build.h"
++#include "../usbd-module.h"
++
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/etherdevice.h>
++#include <linux/rtnetlink.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/timer.h>
++#include <linux/string.h>
++#include <linux/atmdev.h>
++#include <linux/pkt_sched.h>
++#include <linux/delay.h>
++#include <linux/blkdev.h>
++#include <linux/file.h>
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <net/arp.h>
++
++#include <linux/autoconf.h>
++
++#include "../usbd.h"
++#include "../usbd-func.h"
++#include "../usbd-bus.h"
++#include "../usbd-inline.h"
++#include "../usbd-arch.h"
++#include "../hotplug.h"
++
++#include "schedule_task.h"
++#include "storageproto.h"
++
++/******************************************************************************
++** macro define
++******************************************************************************/
++
++#define DEVICE_BLOCK_SIZE       512
++
++#define BLOCK_BUFFER_SIZE       (1024 * 64)
++
++#define DEF_NUMBER_OF_HEADS     0x10
++#define DEF_SECTORS_PER_TRACK   0x20
++
++/******************************************************************************
++** Structure Define
++******************************************************************************/
++
++typedef struct{
++    unsigned char   scsi_command;
++    unsigned char*  command_name;
++    void            (*scsi_func)(struct usb_device_instance*,
++                                 COMMAND_BLOCK_WRAPPER*);
++} SCSI_ANALYSIS_TBL;
++
++typedef struct{
++    unsigned char   scsi_command;
++    unsigned char*  command_name;
++    void            (*bulkout_func)(struct usb_device_instance*,
++                                    void*, int);
++} SCSI_BULKOUT_ANALYSIS_TBL;
++
++/******************************************************************************
++** Variable Declaration
++******************************************************************************/
++
++/**************************************
++** Module Parameters
++**************************************/
++
++static char*    storage_device = CONFIG_USBD_STORAGE_DEF_DEVICE_NAME;
++MODULE_PARM(storage_device, "s");
++
++/**************************************
++** Device Information
++**************************************/
++
++static struct file*     DeviceFile      = NULL;
++static int              DeviceSize      = 0;
++static int              DeviceBlockSize = DEVICE_BLOCK_SIZE;
++static int              DeviceWrProtect = WR_PROTECT_OFF;
++
++/**************************************
++** Status
++**************************************/
++
++static int  StorageStatus  = STORAGE_IDLE;
++static int  UsbStatus      = USB_DISCONNECT;
++static int  MediaStatus    = MEDIA_EJECT;
++static int  MediaChange    = MEDIA_CHANGE_OFF;
++
++/**************************************
++** Keep Information
++**************************************/
++
++static SCSI_REQUEST_SENSE_DATA  RequestSenseData;
++static COMMAND_BLOCK_WRAPPER    KeepCBW;
++static unsigned long            BulkOutLength = 0;
++static unsigned char            BlockBuffer[BLOCK_BUFFER_SIZE];
++
++/**************************************
++** Statistics
++**************************************/
++static unsigned long    StatMaxBulkInSize  = 0;
++static unsigned long    StatMaxBulkOutSize = 0;
++static unsigned long    StatDevWriteError  = 0;
++static unsigned long    StatDevReadError   = 0;
++static unsigned long    StatDevFlushError  = 0;
++static unsigned long    StatWriteTimout    = 0;
++static unsigned long    StatMaxWriteTime   = 0;
++
++/**************************************
++** Timer
++**************************************/
++static struct timer_list    BulkOutTim;
++static struct timer_list    MediaCheckTim;
++
++/******************************************************************************
++** Local Function
++******************************************************************************/
++
++static void storage_bulkout_timeout(unsigned long param)
++{
++    /* statistics update */
++    StatWriteTimout++;
++    printk(KERN_INFO "storage_fd: write bulk out timeout. length '%ld/%ld'.\n",
++        BulkOutLength, KeepCBW.dCBWDataTransferLength);
++
++    return;
++}
++
++static void media_check_timeout(unsigned long param)
++{
++    /* media check */
++    schedule_task_register(
++        (SCHEDULE_TASK_FUNC)storageproto_media_status_check, CONTEXT_TIMER,
++        0, 0, 0, 0);
++
++    return;
++}
++
++static void request_sense_data_set(unsigned char sense_key, unsigned char asc,
++                                   unsigned char ascq, unsigned long info)
++{
++    /*
++     * set REQUEST SENSE DATA
++     */
++
++    memset(&RequestSenseData, 0x00, sizeof(RequestSenseData));
++
++    RequestSenseData.ErrorCode                    = 0x70;
++    RequestSenseData.Valid                        = (info) ? 1 : 0;
++    RequestSenseData.SenseKey                     = sense_key;
++    memcpy(RequestSenseData.Information, &info, sizeof(info));
++    RequestSenseData.AdditionalSenseLength        = 0x0a;
++    RequestSenseData.AdditionalSenseCode          = asc;
++    RequestSenseData.AdditionalSenseCodeQualifier = ascq;
++
++    return;
++}
++
++static void scsi_inquiry_analysis(struct usb_device_instance* device,
++                                  COMMAND_BLOCK_WRAPPER* cbw)
++{
++    SCSI_INQUIRY_DATA       data;
++    COMMAND_STATUS_WRAPPER  csw;
++    unsigned long           data_len;
++
++    /*
++     * data transport
++     */
++
++    memset(&data, 0x00, sizeof(data));
++
++    data.PeripheralDeviceType = 0x00;
++    data.RMB                  = 1;
++    data.ResponseDataFormat   = 0x01;
++    data.AdditionalLength     = 0x1f;
++    strncpy(data.VendorInformation, CONFIG_USBD_MANUFACTURER,
++            sizeof(data.VendorInformation));
++    strncpy(data.ProductIdentification, CONFIG_USBD_PRODUCT_NAME,
++            sizeof(data.ProductIdentification));
++    strncpy(data.ProductRevisionLevel, PRODUCT_REVISION_LEVEL,
++            sizeof(data.ProductRevisionLevel));
++
++    data_len = sizeof(data);
++    if(cbw->dCBWDataTransferLength < data_len){
++        data_len = cbw->dCBWDataTransferLength;
++    }
++
++    storage_urb_send(device, &data, data_len);
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++    csw.bCSWStatus      = 0;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_read_format_capacity_analysis(struct usb_device_instance* device,
++                                               COMMAND_BLOCK_WRAPPER* cbw)
++{
++    SCSI_READ_FORMAT_CAPACITY_DATA  data;
++    COMMAND_STATUS_WRAPPER          csw;
++    unsigned long                   block_num, data_len;
++    unsigned short                  block_len;
++
++    /*
++     * data transport
++     */
++
++    block_num = 0xffffffff;
++    block_len = (unsigned short)DeviceBlockSize;
++    block_num = htonl(block_num);
++    block_len = htons(block_len);
++
++    memset(&data, 0x00, sizeof(data));
++
++    data.CapacityListHeader.CapacityListLength =
++        sizeof(data.CurrentMaximumCapacityDescriptor);
++    memcpy(data.CurrentMaximumCapacityDescriptor.NumberofBlocks, &block_num,
++           sizeof(block_num));
++    data.CurrentMaximumCapacityDescriptor.DescriptorCode = 0x03;
++    memcpy(data.CurrentMaximumCapacityDescriptor.BlockLength + 1, &block_len,
++           sizeof(block_len));
++
++    data_len = sizeof(data);
++    if(cbw->dCBWDataTransferLength < data_len){
++        data_len = cbw->dCBWDataTransferLength;
++    }
++
++    storage_urb_send(device, &data, data_len);
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++    csw.bCSWStatus      = 0;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_read_capacity_analysis(struct usb_device_instance* device,
++                                        COMMAND_BLOCK_WRAPPER* cbw)
++{
++    SCSI_READ_CAPACITY_DATA data;
++    COMMAND_STATUS_WRAPPER  csw;
++    unsigned char           data_len, status = 0;
++
++    if(DeviceFile == NULL){
++        /* 0 clear */
++        memset(&data, 0x00, sizeof(data));
++
++        /* data length set */
++        data_len = cbw->dCBWDataTransferLength;
++
++        /* status set */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++    }
++    else
++    if(MediaChange == MEDIA_CHANGE_ON){
++        /* 0 clear */
++        memset(&data, 0x00, sizeof(data));
++
++        /* data length set */
++        data_len = cbw->dCBWDataTransferLength;
++
++        /* status set */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++        /* media change flag off */
++        MediaChange = MEDIA_CHANGE_OFF;
++    }
++    else{
++        unsigned long   last_lba, block_len;
++
++        /* 0 clear */
++        memset(&data, 0x00, sizeof(data));
++
++        /* data set */
++        last_lba  = (DeviceSize / DeviceBlockSize) - 1;
++        block_len = DeviceBlockSize;
++        last_lba  = htonl(last_lba);
++        block_len = htonl(block_len);
++
++        memcpy(data.LastLogicalBlockAddress, &last_lba, sizeof(last_lba));
++        memcpy(data.BlockLengthInBytes, &block_len, sizeof(block_len));
++
++        /* data length set */
++        data_len = sizeof(data);
++
++        /* status set */
++        status = 0;
++    }
++
++    /*
++     * data transport
++     */
++
++    if(cbw->dCBWDataTransferLength < data_len){
++        data_len = cbw->dCBWDataTransferLength;
++    }
++
++    storage_urb_send(device, &data, data_len);
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++    csw.bCSWStatus      = status;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_request_sense_analysis(struct usb_device_instance* device,
++                                        COMMAND_BLOCK_WRAPPER* cbw)
++{
++    COMMAND_STATUS_WRAPPER  csw;
++    unsigned long           data_len;
++
++    /*
++     * data transport
++     */
++
++    data_len = sizeof(RequestSenseData);
++    if(cbw->dCBWDataTransferLength < data_len){
++        data_len = cbw->dCBWDataTransferLength;
++    }
++
++    storage_urb_send(device, &RequestSenseData, data_len);
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++    csw.bCSWStatus      = 0;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_read_10_analysis(struct usb_device_instance* device,
++                                  COMMAND_BLOCK_WRAPPER* cbw)
++{
++    SCSI_READ_10_COMMAND*   command = (SCSI_READ_10_COMMAND*)cbw->CBWCB;
++    COMMAND_STATUS_WRAPPER  csw;
++    unsigned char           status = 0;
++    unsigned short          len;
++    unsigned long           lba, size, offset;
++
++    memcpy(&lba, command->LogicalBlockAddress, sizeof(lba));
++    memcpy(&len, command->TransferLength, sizeof(len));
++    lba    = ntohl(lba);
++    len    = ntohs(len);
++    offset = lba * DeviceBlockSize;
++    size   = cbw->dCBWDataTransferLength;
++
++    if(DeviceFile == NULL){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++
++        /*
++         * data transport
++         */
++
++        storage_urb_send(device, NULL, size);
++    }
++    else
++    if(MediaChange == MEDIA_CHANGE_ON){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++        /* media change flag off */
++        MediaChange = MEDIA_CHANGE_OFF;
++
++        /*
++         * data transport
++         */
++
++        storage_urb_send(device, NULL, size);
++    }
++    else{
++        unsigned long   count, read_size;
++
++        /*
++         * data transport
++         */
++
++        /* device seek */
++        DeviceFile->f_op->llseek(DeviceFile, offset, 0);
++
++        /* device read */
++        for(count = size; count; count -= read_size){
++            read_size = (count > sizeof(BlockBuffer)) ?
++                            sizeof(BlockBuffer) : count;
++            if(DeviceFile &&
++               DeviceFile->f_op->read(DeviceFile, BlockBuffer, read_size,
++                                      &DeviceFile->f_pos) != read_size){
++
++                /* command fail */
++                status = 1;
++
++                /* error code save REQUEST SENSE */
++                request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++
++                /* statistics update */
++                StatDevReadError++;
++                printk(KERN_INFO "storage_fd: device read error. length '%ld'.\n", read_size);
++            }
++
++            storage_urb_send(device, BlockBuffer, read_size);
++        }
++    }
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength - size;
++    csw.bCSWStatus      = status;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_mode_sense_analysis(struct usb_device_instance* device,
++                                     COMMAND_BLOCK_WRAPPER* cbw)
++{
++    static READ_WRITE_ERROR_RECOVERY_PAGE           page_01 = {
++        PageCode:0x01,
++        PageLength:0x0A,
++        ReadRetryCount:0x03,
++        WriteRetryCount:0x80,
++    };
++    static FLEXIBLE_DISK_PAGE                       page_05 = {
++        PageCode:0x05,
++        PageLength:0x1E,
++        TransferRate:{0x00, 0xFA},
++        NumberofHeads:0xA0,
++        SectorsperTrack:0x00,
++        DataBytesperSector:{0x02, 0x00},
++        NumberofCylinders:{0x00, 0x00},
++        MotorOnDelay:0x05,
++        MotorOffDelay:0x1E,
++        MediumRotationRate:{0x01, 0x68},
++    };
++    static REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE page_1b = {
++        PageCode:0x1B,
++        PageLength:0x0A,
++        TLUN:0x01,
++    };
++    static TIMER_AND_PROTECT_PAGE                   page_1c = {
++        PageCode:0x1c,
++        PageLength:0x06,
++        InactivityTimeMultiplier:0x0A,
++    };
++
++
++    SCSI_MODE_SENSE_COMMAND*    command = (SCSI_MODE_SENSE_COMMAND*)cbw->CBWCB;
++    SCSI_MODE_SENSE_DATA        data;
++    COMMAND_STATUS_WRAPPER      csw;
++    unsigned char               data_len, status = 0;
++    unsigned short              cylinder, sector;
++    unsigned long               size;
++
++    /*
++     * data transport
++     */
++
++    memset(&data, 0x00, sizeof(data));
++
++    /* set write protect */
++    data.ModeParameterHeader.WP = DeviceWrProtect;
++
++    /* set Flexible Disk Page */
++    if(DeviceFile == NULL){
++        sector   = (unsigned short)DeviceBlockSize;
++        cylinder = 0;
++        sector   = htons(sector);
++        cylinder = htons(cylinder);
++
++        page_05.NumberofHeads      = 0;
++        page_05.SectorsperTrack    = 0;
++        memcpy(page_05.DataBytesperSector, &sector, sizeof(sector));
++        memcpy(page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++    }
++    else{
++        sector   = (unsigned short)DeviceBlockSize;
++        size     = DEF_NUMBER_OF_HEADS * DEF_SECTORS_PER_TRACK * sector;
++        cylinder = DeviceSize / size;
++        sector   = htons(sector);
++        cylinder = htons(cylinder);
++
++        page_05.NumberofHeads      = DEF_NUMBER_OF_HEADS;
++        page_05.SectorsperTrack    = DEF_SECTORS_PER_TRACK;
++        memcpy(page_05.DataBytesperSector, &sector, sizeof(sector));
++        memcpy(page_05.NumberofCylinders, &cylinder, sizeof(cylinder));
++    }
++
++    if(command->PC == 0 && command->PageCode == 0x01){
++        data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_01);
++        data.ModeParameterHeader.ModeDataLength = data_len - 1;
++        memcpy(&data.ModePages, &page_01, sizeof(page_01));
++    }
++    else
++    if(command->PC == 0 && command->PageCode == 0x05){
++        data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_05);
++        data.ModeParameterHeader.ModeDataLength = data_len - 1;
++        memcpy(&data.ModePages, &page_05, sizeof(page_05));
++    }
++    else
++    if(command->PC == 0 && command->PageCode == 0x1b){
++        data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1b);
++        data.ModeParameterHeader.ModeDataLength = data_len - 1;
++        memcpy(&data.ModePages, &page_1b, sizeof(page_1b));
++    }
++    else
++    if(command->PC == 0 && command->PageCode == 0x1c){
++        data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(page_1c);
++        data.ModeParameterHeader.ModeDataLength = data_len - 1;
++        memcpy(&data.ModePages, &page_1c, sizeof(page_1c));
++    }
++    else
++    if(command->PC == 0 && command->PageCode == 0x3f){
++        data_len = sizeof(MODE_PARAMETER_HEADER) + sizeof(MODE_ALL_PAGES);
++        data.ModeParameterHeader.ModeDataLength = data_len - 1;
++        memcpy(&data.ModePages.ModeAllPages.ReadWriteErrorRecoveryPage,
++               &page_01, sizeof(page_01));
++        memcpy(&data.ModePages.ModeAllPages.FlexibleDiskPage,
++               &page_05, sizeof(page_05));
++        memcpy(&data.ModePages.ModeAllPages.RemovableBlockAccessCapabilitiesPage,
++               &page_1b, sizeof(page_1b));
++        memcpy(&data.ModePages.ModeAllPages.TimerAndProtectPage,
++               &page_1c, sizeof(page_1c));
++    }
++    else{
++        /* command fail */
++        status = 1;
++        data_len = cbw->dCBWDataTransferLength;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x05, 0x24, 0x00, 0x00);
++    }
++
++    if(cbw->dCBWDataTransferLength < data_len){
++        data_len = cbw->dCBWDataTransferLength;
++    }
++
++    storage_urb_send(device, &data, data_len);
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++    csw.bCSWStatus      = status;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_test_unit_ready_analysis(struct usb_device_instance* device,
++                                          COMMAND_BLOCK_WRAPPER* cbw)
++{
++    COMMAND_STATUS_WRAPPER      csw;
++    unsigned char               status = 0;
++
++    if(DeviceFile == NULL){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++    }
++    else
++    if(MediaChange == MEDIA_CHANGE_ON){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++        /* media change flag off */
++        MediaChange = MEDIA_CHANGE_OFF;
++    }
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++    csw.bCSWStatus      = status;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_prevent_allow_medium_removal_analysis(struct usb_device_instance* device,
++                                                       COMMAND_BLOCK_WRAPPER* cbw)
++{
++    SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND*  command = (SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND*)cbw->CBWCB;
++    COMMAND_STATUS_WRAPPER                      csw;
++    unsigned char                               status = 0;
++
++    if(command->Prevent){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x05, 0x24, 0x00, 0x00);
++    }
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++    csw.bCSWStatus      = status;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_start_stop_analysis(struct usb_device_instance* device,
++                                     COMMAND_BLOCK_WRAPPER* cbw)
++{
++    SCSI_START_STOP_COMMAND*    command = (SCSI_START_STOP_COMMAND*)cbw->CBWCB;
++    COMMAND_STATUS_WRAPPER      csw;
++    unsigned char               status = 0;
++
++    if(DeviceFile == NULL){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++    }
++    else
++    if(MediaChange == MEDIA_CHANGE_ON){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++        /* media change flag off */
++        MediaChange = MEDIA_CHANGE_OFF;
++    }
++    else
++    if(command->Start && command->LoEj){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x05, 0x24, 0x00, 0x00);
++    }
++
++    /* device buffer flush */
++    if(DeviceFile && DeviceFile->f_op->ioctl(DeviceFile->f_dentry->d_inode,
++                                             DeviceFile, BLKFLSBUF, 0) != 0){
++        /* statistics update */
++        StatDevFlushError++;
++        printk(KERN_INFO "storage_fd: device flush error.\n");
++    }
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++    csw.bCSWStatus      = status;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_write_10_analysis(struct usb_device_instance* device,
++                                   COMMAND_BLOCK_WRAPPER* cbw)
++{
++    /* status set */
++    BulkOutLength = 0;
++    StorageStatus = STORAGE_BULKOUT;
++
++    /* timer set */
++    del_timer(&BulkOutTim);
++    BulkOutTim.expires  = jiffies + ((WR_BULKOUT_CHK_TIM * HZ) / 1000);
++    BulkOutTim.data     = 0;
++    BulkOutTim.function = storage_bulkout_timeout;
++    add_timer(&BulkOutTim);
++
++    return;
++}
++
++static void scsi_verify_analysis(struct usb_device_instance* device,
++                                 COMMAND_BLOCK_WRAPPER* cbw)
++{
++    COMMAND_STATUS_WRAPPER      csw;
++    unsigned char               status = 0;
++
++    if(DeviceFile == NULL){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++    }
++    else
++    if(MediaChange == MEDIA_CHANGE_ON){
++        /* command fail */
++        status = 1;
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++        /* media change flag off */
++        MediaChange = MEDIA_CHANGE_OFF;
++    }
++
++    /*
++     * status transport
++     */
++
++    memset(&csw, 0x00, sizeof(csw));
++
++    csw.dCSWSignature   = CSW_SIGNATURE;
++    csw.dCSWTag         = cbw->dCBWTag;
++    csw.dCSWDataResidue = cbw->dCBWDataTransferLength;
++    csw.bCSWStatus      = status;
++
++    storage_urb_send(device, &csw, sizeof(csw));
++
++    return;
++}
++
++static void scsi_unsupport_analysis(struct usb_device_instance* device,
++                                    COMMAND_BLOCK_WRAPPER* cbw)
++{
++    COMMAND_STATUS_WRAPPER csw;
++    unsigned char          data_len = 0;
++
++    if(((cbw->bmCBWFlags & 0x80) == 0x00) && (cbw->dCBWDataTransferLength)){
++        /* BLKOUT */
++
++        /* status set */
++        BulkOutLength = 0;
++        StorageStatus = STORAGE_BULKOUT;
++    }
++    else{
++        /* BLKIN */
++
++        if(cbw->dCBWDataTransferLength){
++            data_len = cbw->dCBWDataTransferLength;
++            storage_urb_send(device, NULL, data_len);
++        }
++
++        /*
++         * status transport
++         */
++
++        memset(&csw, 0x00, sizeof(csw));
++
++        csw.dCSWSignature   = CSW_SIGNATURE;
++        csw.dCSWTag         = cbw->dCBWTag;
++        csw.dCSWDataResidue = cbw->dCBWDataTransferLength - data_len;
++        csw.bCSWStatus      = 0x01;
++        storage_urb_send(device, &csw, sizeof(csw));
++
++    }
++
++    /* error code save REQUEST SENSE */
++    request_sense_data_set(0x05, 0x20, 0x00, 0x00);
++
++    return;
++}
++
++static void scsi_bulkout_write_10_analysis(struct usb_device_instance* device,
++                                           void* buffer, int length)
++{
++    COMMAND_STATUS_WRAPPER  csw;
++    unsigned char           status = 0;
++    unsigned long           buff_used_len, buff_offset;
++    unsigned long           s_tick, e_tick, wr_tick;
++
++    buff_offset = BulkOutLength % sizeof(BlockBuffer);
++
++    memcpy(BlockBuffer + buff_offset, buffer, length);
++    BulkOutLength += length;
++
++    buff_used_len = BulkOutLength % sizeof(BlockBuffer);
++    if(buff_used_len == 0) buff_used_len = sizeof(BlockBuffer);
++
++    /* delete timer */
++    if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++        del_timer(&BulkOutTim);
++    }
++
++    if(buff_used_len >= sizeof(BlockBuffer) ||
++       BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++
++        /* buffer full */
++        SCSI_WRITE_10_COMMAND*  command = (SCSI_WRITE_10_COMMAND*)&KeepCBW.CBWCB;
++        unsigned short          len;
++        unsigned long           lba, offset;
++
++        memcpy(&lba, command->LogicalBlockAddress, sizeof(lba));
++        memcpy(&len, command->TransferLength, sizeof(len));
++        lba = ntohl(lba);
++        len = ntohs(len);
++
++        offset = (lba * DeviceBlockSize) +
++                 (sizeof(BlockBuffer) * ((BulkOutLength - 1) / sizeof(BlockBuffer)));
++
++        /* device check */
++        if(DeviceFile &&
++           MediaChange != MEDIA_CHANGE_ON &&
++           DeviceWrProtect != WR_PROTECT_ON){
++
++            /* write before jiffies get */
++            s_tick = jiffies;
++
++            /* device seek */
++            DeviceFile->f_op->llseek(DeviceFile, offset, 0);
++
++            /* device write */
++            if(DeviceFile->f_op->write(DeviceFile, BlockBuffer, buff_used_len,
++                                       &DeviceFile->f_pos) != buff_used_len){
++                /* statistics update */
++                StatDevWriteError++;
++                printk(KERN_INFO "storage_fd: device write error. length '%ld'.\n", buff_used_len);
++            }
++
++            /* write after jiffies get */
++            e_tick = jiffies;
++
++            /* statistics update */
++            wr_tick = e_tick - s_tick;
++            if(wr_tick > StatMaxWriteTime){
++                StatMaxWriteTime = wr_tick;
++            }
++        }
++    }
++
++    if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++        if(DeviceFile == NULL){
++            /* command fail */
++            status = 1;
++
++            /* error code save REQUEST SENSE */
++            request_sense_data_set(0x02, 0x3a, 0x00, 0x00);
++        }
++        else
++        if(MediaChange == MEDIA_CHANGE_ON){
++            /* command fail */
++            status = 1;
++
++            /* error code save REQUEST SENSE */
++            request_sense_data_set(0x06, 0x28, 0x00, 0x00);
++
++            /* media change flag off */
++            MediaChange = MEDIA_CHANGE_OFF;
++        }
++        else
++        if(DeviceWrProtect == WR_PROTECT_ON){
++            /* command fail */
++            status = 1;
++
++            /* error code save REQUEST SENSE */
++            request_sense_data_set(0x07, 0x27, 0x00, 0x00);
++
++            /* media change flag off */
++            MediaChange = MEDIA_CHANGE_OFF;
++        }
++
++        /*
++         * status transport
++         */
++
++        memset(&csw, 0x00, sizeof(csw));
++
++        csw.dCSWSignature   = CSW_SIGNATURE;
++        csw.dCSWTag         = KeepCBW.dCBWTag;
++        csw.dCSWDataResidue = KeepCBW.dCBWDataTransferLength - BulkOutLength;
++        csw.bCSWStatus      = status;
++
++        storage_urb_send(device, &csw, sizeof(csw));
++
++        /* status reset */
++        BulkOutLength = 0;
++        StorageStatus = STORAGE_IDLE;
++
++        /* flush before jiffies get */
++        s_tick = jiffies;
++
++        /* device buffer flush */
++        if(DeviceFile && DeviceFile->f_op->ioctl(DeviceFile->f_dentry->d_inode,
++                                                 DeviceFile, BLKFLSBUF, 0) != 0){
++            /* statistics update */
++            StatDevFlushError++;
++            printk(KERN_INFO "storage_fd: device flush error.\n");
++        }
++
++        /* flush after jiffies get */
++        e_tick = jiffies;
++
++        /* statistics update */
++        wr_tick = e_tick - s_tick;
++        if(wr_tick > StatMaxWriteTime){
++            StatMaxWriteTime = wr_tick;
++        }
++
++    }
++
++    return;
++}
++
++static void scsi_bulkout_unsupport_analysis(struct usb_device_instance* device,
++                                            void* buffer, int length)
++{
++    COMMAND_STATUS_WRAPPER  csw;
++
++    BulkOutLength += length;
++
++    if(BulkOutLength >= KeepCBW.dCBWDataTransferLength){
++        /*
++         * status transport
++         */
++
++        memset(&csw, 0x00, sizeof(csw));
++
++        csw.dCSWSignature   = CSW_SIGNATURE;
++        csw.dCSWTag         = KeepCBW.dCBWTag;
++        csw.dCSWDataResidue = KeepCBW.dCBWDataTransferLength - BulkOutLength;
++        csw.bCSWStatus      = 1;
++
++        storage_urb_send(device, &csw, sizeof(csw));
++
++        /* error code save REQUEST SENSE */
++        request_sense_data_set(0x05, 0x20, 0x00, 0x00);
++
++        /* status reset */
++        BulkOutLength = 0;
++        StorageStatus = STORAGE_IDLE;
++    }
++
++    return;
++}
++
++/******************************************************************************
++** Global Function
++******************************************************************************/
++
++static SCSI_ANALYSIS_TBL    ScsiAnalysisTbl[] = {
++    {SCSI_FORMAT_UNT,                   "SCSI_FORMAT_UNT",                   NULL},
++    {SCSI_INQUIRY,                      "SCSI_INQUIRY",                      scsi_inquiry_analysis},
++    {SCSI_START_STOP,                   "SCSI_START_STOP",                   scsi_start_stop_analysis},
++    {SCSI_MODE_SELECT,                  "SCSI_MODE_SELECT",                  NULL},
++    {SCSI_MODE_SENSE,                   "SCSI_MODE_SENSE",                   scsi_mode_sense_analysis},
++    {SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL, "SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL", scsi_prevent_allow_medium_removal_analysis},
++    {SCSI_READ_10,                      "SCSI_READ_10",                      scsi_read_10_analysis},
++    {SCSI_READ_12,                      "SCSI_READ_12",                      NULL},
++    {SCSI_READ_CAPACITY,                "SCSI_READ_CAPACITY",                scsi_read_capacity_analysis},
++    {SCSI_READ_FORMAT_CAPACITY,         "SCSI_READ_FORMAT_CAPACITY",         scsi_read_format_capacity_analysis},
++    {SCSI_REQUEST_SENSE,                "SCSI_REQUEST_SENSE",                scsi_request_sense_analysis},
++    {SCSI_REZERO_UNIT,                  "SCSI_REZERO_UNIT",                  NULL},
++    {SCSI_SEEK_10,                      "SCSI_SEEK_10",                      NULL},
++    {SCSI_SEND_DIAGNOSTIC,              "SCSI_SEND_DIAGNOSTIC",              NULL},
++    {SCSI_TEST_UNIT_READY,              "SCSI_TEST_UNIT_READY",              scsi_test_unit_ready_analysis},
++    {SCSI_VERIFY,                       "SCSI_VERIFY",                       scsi_verify_analysis},
++    {SCSI_WRITE_10,                     "SCSI_WRITE_10",                     scsi_write_10_analysis},
++    {SCSI_WRITE_12,                     "SCSI_WRITE_12",                     NULL},
++    {SCSI_WRITE_AND_VERIFY,             "SCSI_WRITE_AND_VERIFY",             NULL}
++};
++
++static SCSI_BULKOUT_ANALYSIS_TBL    ScsiBlkOutAnalysisTbl[] = {
++    {SCSI_WRITE_10,                     "SCSI_WRITE_10",                     scsi_bulkout_write_10_analysis},
++};
++
++void storageproto_urb_analysis(struct urb* urb)
++{
++    COMMAND_BLOCK_WRAPPER*  cbw = (COMMAND_BLOCK_WRAPPER*)urb->buffer;
++    int                     i;
++
++    /* status BLKOUT check */
++    if(StorageStatus == STORAGE_BULKOUT){
++        for(i = 0;
++            i < sizeof(ScsiBlkOutAnalysisTbl) / sizeof(SCSI_ANALYSIS_TBL);
++            i++){
++            if(ScsiBlkOutAnalysisTbl[i].scsi_command == KeepCBW.CBWCB[0]){
++                if(ScsiBlkOutAnalysisTbl[i].bulkout_func){
++                    ScsiBlkOutAnalysisTbl[i].bulkout_func(urb->device,
++                                                          urb->buffer,
++                                                          urb->actual_length);
++                    goto RETURN_LABEL;
++                }
++                break;
++            }
++        }
++        scsi_bulkout_unsupport_analysis(urb->device, urb->buffer, urb->actual_length);
++        goto RETURN_LABEL;
++    }
++
++    /* signature check */
++    if(cbw->dCBWSignature != CBW_SIGNATURE){
++        printk(KERN_INFO "storage_fd: signature error. '0x%08lx'.\n",
++            cbw->dCBWSignature);
++        goto RETURN_LABEL;
++    }
++
++    /* statistics set */
++    if(cbw->dCBWDataTransferLength){
++        if(((cbw->bmCBWFlags & 0x80) == 0x00) && (cbw->dCBWDataTransferLength)){
++            /* BULK OUT */
++            if(StatMaxBulkOutSize < cbw->dCBWDataTransferLength){
++                StatMaxBulkOutSize = cbw->dCBWDataTransferLength;
++            }
++        }
++        else{
++            /* BULK IN */
++            if(StatMaxBulkInSize < cbw->dCBWDataTransferLength){
++                StatMaxBulkInSize = cbw->dCBWDataTransferLength;
++            }
++        }
++    }
++
++    /* save CBW and set storage status */
++    memcpy(&KeepCBW, cbw, sizeof(KeepCBW));
++
++    /* UFI command analysis */
++    for(i = 0; i < sizeof(ScsiAnalysisTbl) / sizeof(SCSI_ANALYSIS_TBL); i++){
++        if(ScsiAnalysisTbl[i].scsi_command == cbw->CBWCB[0]){
++            if(ScsiAnalysisTbl[i].scsi_func){
++                ScsiAnalysisTbl[i].scsi_func(urb->device, cbw);
++                goto RETURN_LABEL;
++            }
++            break;
++        }
++    }
++
++    scsi_unsupport_analysis(urb->device, cbw);
++    printk(KERN_INFO "storage_fd: SCSI command error. '0x%02x'.\n",
++        cbw->CBWCB[0]);
++    goto RETURN_LABEL;
++
++RETURN_LABEL:
++
++    /* URB free */
++    usbd_recycle_urb(urb);
++
++    return;
++}
++
++int storageproto_device_open_check(void)
++{
++    struct file*    file;
++    struct inode*   inode;
++    kdev_t          dev;
++    int             read_org;
++
++    /* device already open check */
++    if(DeviceFile){
++        storageproto_device_close();
++    }
++
++    /* device open */
++    file = filp_open(storage_device, O_RDWR, 0000);
++    if(IS_ERR(file)){
++        file = filp_open(storage_device, O_RDONLY, 0000);
++        if(IS_ERR(file)){
++            storageproto_device_close();
++            return MEDIA_EJECT;
++        }
++        DeviceWrProtect = WR_PROTECT_ON;
++    }
++
++    file->f_op->llseek(file, 0, 0);
++    if(file->f_op->read(file, (void*)&read_org, sizeof(read_org), &file->f_pos)
++                        != sizeof(read_org)){
++        filp_close(file, NULL);
++        storageproto_device_close();
++        return MEDIA_EJECT;
++    }
++
++    /* struct file pointer save */
++    DeviceFile = file;
++
++    /* device information */
++    inode = file->f_dentry->d_inode;
++    dev = inode->i_rdev;
++
++    if (blk_size[MAJOR(dev)]){
++        DeviceSize = blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS;
++    }
++    else{
++        DeviceSize = INT_MAX << BLOCK_SIZE_BITS;
++    }
++
++    if(blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]){
++        DeviceBlockSize = DEVICE_BLOCK_SIZE;
++    }
++    else{
++        DeviceBlockSize = DEVICE_BLOCK_SIZE;
++    }
++
++    return MEDIA_INSERT;
++}
++
++void storageproto_device_close(void)
++{
++    if(DeviceFile){
++        filp_close(DeviceFile, NULL);
++        DeviceFile      = NULL;
++        DeviceSize      = 0;
++        DeviceBlockSize = DEVICE_BLOCK_SIZE;
++        DeviceWrProtect = WR_PROTECT_OFF;
++    }
++
++    return;
++}
++
++void storageproto_usb_status_check(int status)
++{
++    static int  Is1stCheck = 1;
++
++    /* USB status check */
++    if(Is1stCheck){
++        Is1stCheck = 0;
++    }
++    else{
++        if(UsbStatus == status) goto RETURN_LABEL;
++    }
++
++    /* set status */
++    UsbStatus = status;
++
++    switch(UsbStatus){
++    case USB_CONNECT:
++        /* media status check */
++        storageproto_media_status_check(CONTEXT_SCHEDULE);
++
++        switch(MediaStatus){
++        case MEDIA_EJECT:
++            break;
++
++        case MEDIA_INSERT:
++            hotplug("usbdstorage", storage_device, "umount");
++            break;
++
++        default:
++            break;
++        }
++        hotplug("usbdstorage", storage_device, "connect");
++        break;
++
++    case USB_DISCONNECT:
++        /* device close */
++        storageproto_device_close();
++
++        switch(MediaStatus){
++        case MEDIA_EJECT:
++            break;
++
++        case MEDIA_INSERT:
++            hotplug("usbdstorage", storage_device, "mount");
++            break;
++
++        default:
++            break;
++        }
++        hotplug("usbdstorage", storage_device, "disconnect");
++        break;
++
++    default:
++        break;
++    }
++
++RETURN_LABEL:
++    DBG_STORAGE_FD(KERN_INFO "storage_fd: USB check '%s' '%s' 'file:%p'.\n",
++        (UsbStatus) ? "USB_CONNECT" : "USB_DISCONNECT",
++        (MediaStatus) ? "MEDIA_INSERT" : "MEDIA_EJECT", DeviceFile);
++
++    return;
++}
++
++void storageproto_media_status_check(int call_context)
++{
++    static unsigned long    RetryCount = 0;
++    int status;
++
++    /* media open check */
++    status = storageproto_device_open_check();
++
++    /* media status check retry */
++    if(status == MEDIA_EJECT){
++        switch(call_context){
++        case CONTEXT_STORAGE:
++
++            /* retry counter init */
++            RetryCount = 0;
++
++            /* timer set */
++            del_timer(&MediaCheckTim);
++            MediaCheckTim.expires  = jiffies + ((MEDIA_CHECK_TIM * HZ) / 1000);
++            MediaCheckTim.data     = 0;
++            MediaCheckTim.function = media_check_timeout;
++            add_timer(&MediaCheckTim);
++
++            break;
++
++        case CONTEXT_TIMER:
++
++            /* retry counter update */
++            RetryCount++;
++
++            /* retry counter check */
++            if(RetryCount >= MEDIA_CHECK_RETRY) break;
++
++            /* timer set */
++            del_timer(&MediaCheckTim);
++            MediaCheckTim.expires  = jiffies + ((MEDIA_CHECK_TIM * HZ) / 1000);
++            MediaCheckTim.data     = 0;
++            MediaCheckTim.function = media_check_timeout;
++            add_timer(&MediaCheckTim);
++
++            break;
++
++        default:
++            break;
++        }
++    }
++    else
++    if(status == MEDIA_INSERT){
++        /* delete timer */
++        del_timer(&MediaCheckTim);
++    }
++
++    /* media status check */
++    if(status == MediaStatus){
++        if(UsbStatus == USB_DISCONNECT){
++            storageproto_device_close();
++        }
++        if(MediaStatus == MEDIA_INSERT){
++            if(call_context == CONTEXT_STORAGE || call_context == CONTEXT_TIMER){
++                MediaChange = MEDIA_CHANGE_ON;
++            }
++        }
++        goto RETURN_LABEL;
++    }
++
++    /* set status */
++    MediaStatus = status;
++
++    switch(MediaStatus){
++    case MEDIA_INSERT:
++        /* set status */
++        MediaChange = MEDIA_CHANGE_ON;
++
++        switch(UsbStatus){
++        case USB_DISCONNECT:
++            storageproto_device_close();
++            break;
++
++        case USB_CONNECT:
++            break;
++
++        default:
++            break;
++        }
++        hotplug("usbdstorage", storage_device, "insert");
++        break;
++
++    case MEDIA_EJECT:
++        switch(UsbStatus){
++        case USB_DISCONNECT:
++            storageproto_device_close();
++            break;
++
++        case USB_CONNECT:
++            break;
++
++        default:
++            break;
++        }
++        hotplug("usbdstorage", storage_device, "eject");
++        break;
++
++    default:
++        break;
++    }
++
++RETURN_LABEL:
++    DBG_STORAGE_FD(KERN_INFO "storage_fd: media check. '%s' '%s' 'file:%p' '%s'.\n",
++        (UsbStatus) ? "USB_CONNECT" : "USB_DISCONNECT",
++        (MediaStatus) ? "MEDIA_INSERT" : "MEDIA_EJECT", DeviceFile,
++        (call_context == CONTEXT_SCHEDULE) ? "CONTEXT_SCHEDULE" : 
++        (call_context == CONTEXT_STORAGE)  ? "CONTEXT_STORAGE" : "CONTEXT_TIMER");
++
++    return;
++}
++
++void storageproto_usb_reset_ind(void)
++{
++    /* status reset */
++    BulkOutLength = 0;
++    StorageStatus = STORAGE_IDLE;
++
++    DBG_STORAGE_FD(KERN_INFO "storage_fd: storage protocol reset.\n");
++
++    return;
++}
++
++void storageproto_init(void)
++{
++    /* timer init */
++    init_timer(&BulkOutTim);
++
++    /* timer init */
++    init_timer(&MediaCheckTim);
++
++    return;
++}
++
++void storageproto_exit(void)
++{
++    /* device close */
++    storageproto_device_close();
++
++    /* delete timer */
++    del_timer(&BulkOutTim);
++
++    /* delete timer */
++    del_timer(&MediaCheckTim);
++
++    return;
++}
++
++ssize_t storageproto_proc_read(struct file* file, char* buf, size_t count,
++                               loff_t* pos)
++{
++    char    string[1024];
++    int     len = 0;
++
++    len += sprintf(string + len, "Protocol status:%s\n",
++            (StorageStatus == STORAGE_IDLE)   ? "STORAGE_IDLE" :
++            (StorageStatus == STORAGE_BULKIN) ? "STORAGE_BULKIN" :
++                                                "STORAGE_BULKOUT");
++
++    len += sprintf(string + len, "USB status:%s\n",
++            (UsbStatus == USB_DISCONNECT) ? "USB_DISCONNECT" :
++                                            "USB_CONNECT");
++
++    len += sprintf(string + len, "Media status:%s\n",
++            (MediaStatus == MEDIA_EJECT) ? "MEDIA_EJECT" :
++                                           "MEDIA_INSERT");
++
++    len += sprintf(string + len, "Media chage:%s\n",
++            (MediaChange == MEDIA_CHANGE_OFF) ? "MEDIA_CHANGE_OFF" :
++                                                "MEDIA_CHANGE_ON");
++
++    len += sprintf(string + len, "Device name:%s\n",
++            storage_device);
++
++    len += sprintf(string + len, "Device file descriptor:0x%p\n",
++            DeviceFile);
++
++    len += sprintf(string + len, "Device size:0x%d\n",
++            DeviceSize);
++
++    len += sprintf(string + len, "Device block size:0x%d\n",
++            DeviceBlockSize);
++
++    len += sprintf(string + len, "Device write protect:%s\n",
++            (DeviceWrProtect == WR_PROTECT_OFF) ? "WR_PROTECT_OFF":
++                                                  "WR_PROTECT_ON");
++
++    len += sprintf(string + len, "Bulk in max size:%ld\n",
++            StatMaxBulkInSize);
++
++    len += sprintf(string + len, "Bulk out max size:%ld\n",
++            StatMaxBulkOutSize);
++
++    len += sprintf(string + len, "device write error:%ld\n",
++            StatDevWriteError);
++
++    len += sprintf(string + len, "device read error:%ld\n",
++            StatDevReadError);
++
++    len += sprintf(string + len, "device flush error:%ld\n",
++            StatDevFlushError);
++
++    len += sprintf(string + len, "write data bulk out timout:%ld\n",
++            StatWriteTimout);
++
++    len += sprintf(string + len, "device write max time:%ld msec\n",
++            (StatMaxWriteTime * 1000) / HZ);
++
++    *pos += len;
++    if(len > count){
++        len = -EINVAL;
++    }
++    else
++    if(len > 0 && copy_to_user(buf, string, len)) {
++        len = -EFAULT;
++    }
++
++    return len;
++}
++
+diff -Nur linux-2.4.18/drivers/usb/device/storage_fd/storageproto.h linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.h
+--- linux-2.4.18/drivers/usb/device/storage_fd/storageproto.h	1970-01-01 03:00:00.000000000 +0300
++++ linux-2.4.18-usb-storage/drivers/usb/device/storage_fd/storageproto.h	2003-11-07 05:34:43.000000000 +0300
+@@ -0,0 +1,585 @@
++/*
++ * linux/drivers/usb/device/storage_fd/storageproto.h - mass storage protocol library header
++ *
++ * Copyright (c) 2003 Lineo Solutions, Inc.
++ *
++ * Written by Shunnosuke kabata
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++#ifndef _STORAGEPROTO_H_
++#define _STORAGEPROTO_H_
++
++/******************************************************************************
++** Macro Define
++******************************************************************************/
++
++/**************************************
++** Class Code
++**************************************/
++
++/*
++ * Class
++ */
++
++#define MASS_STORAGE_CLASS                  0x08
++
++/*
++ * SubClass
++ */
++
++#define MASS_STORAGE_SUBCLASS_RBC           0x01
++#define MASS_STORAGE_SUBCLASS_SFF8020I      0x02
++#define MASS_STORAGE_SUBCLASS_QIC157        0x03
++#define MASS_STORAGE_SUBCLASS_UFI           0x04
++#define MASS_STORAGE_SUBCLASS_SFF8070I      0x05
++#define MASS_STORAGE_SUBCLASS_SCSI          0x06
++
++/*
++ * Protocol
++ */
++
++#define MASS_STORAGE_PROTO_CBI_WITH_COMP    0x00
++#define MASS_STORAGE_PROTO_CBI_NO_COMP      0x01
++#define MASS_STORAGE_PROTO_BULK_ONLY        0x50
++
++/**************************************
++** SCSI Command
++**************************************/
++
++#define SCSI_FORMAT_UNT                      0x04
++#define SCSI_INQUIRY                         0x12
++#define SCSI_START_STOP                      0x1b
++#define SCSI_MODE_SELECT                     0x55
++#define SCSI_MODE_SENSE                      0x1a
++#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL    0x1e
++#define SCSI_READ_10                         0x28
++#define SCSI_READ_12                         0xa8
++#define SCSI_READ_CAPACITY                   0x25
++#define SCSI_READ_FORMAT_CAPACITY            0x23
++#define SCSI_REQUEST_SENSE                   0x03
++#define SCSI_REZERO_UNIT                     0x01
++#define SCSI_SEEK_10                         0x2b
++#define SCSI_SEND_DIAGNOSTIC                 0x1d
++#define SCSI_TEST_UNIT_READY                 0x00
++#define SCSI_VERIFY                          0x2f
++#define SCSI_WRITE_10                        0x2a
++#define SCSI_WRITE_12                        0xaa
++#define SCSI_WRITE_AND_VERIFY                0x2e
++
++/**************************************
++** SCSI Command Parameter
++**************************************/
++
++#define CBW_SIGNATURE           0x43425355  /* USBC */
++#define CSW_SIGNATURE           0x53425355  /* USBS */
++
++#define PRODUCT_REVISION_LEVEL  "1.00"
++
++/**************************************
++** Status
++**************************************/
++
++#define WR_PROTECT_OFF      0
++#define WR_PROTECT_ON       1
++
++#define STORAGE_IDLE        0
++#define STORAGE_BULKIN      1
++#define STORAGE_BULKOUT     2
++
++#define USB_DISCONNECT      0
++#define USB_CONNECT         1
++
++#define MEDIA_EJECT         0
++#define MEDIA_INSERT        1
++
++#define MEDIA_CHANGE_OFF    0
++#define MEDIA_CHANGE_ON     1
++
++/**************************************
++** Mass Storage Thread Name
++**************************************/
++
++#define STORAGE_THREAD_NAME "usbdstorage"
++
++/**************************************
++** Media Signal Delay Time(ms)
++**************************************/
++
++#define USB_EVENT_DELAY_TIM 1000
++
++/**************************************
++** Write Bulk Out Check Time(ms)
++**************************************/
++
++#define WR_BULKOUT_CHK_TIM  1000
++
++/**************************************
++** Media Check Time(ms)
++**************************************/
++
++#define MEDIA_CHECK_TIM     3000
++#define MEDIA_CHECK_RETRY   3
++
++/**************************************
++** Context
++**************************************/
++
++#define CONTEXT_SCHEDULE    0
++#define CONTEXT_STORAGE     1
++#define CONTEXT_TIMER       2
++
++/**************************************
++** Debug Message
++**************************************/
++#if 0
++#define DBG_STORAGE_FD(fmt, args...)    printk(fmt, ##args)
++#else
++#define DBG_STORAGE_FD(fmt, args...)
++#endif
++
++/******************************************************************************
++** Structure Define
++******************************************************************************/
++
++/**************************************
++** Command Block Wrapper / Command Status Wrapper
++**************************************/
++
++/*
++ * Command Block Wrapper
++ */
++typedef struct{
++    unsigned long   dCBWSignature;
++    unsigned long   dCBWTag;
++    unsigned long   dCBWDataTransferLength;
++    unsigned char   bmCBWFlags;
++    unsigned char   bCBWLUN:4,
++                    Reserved:4;
++    unsigned char   bCBWCBLength:5,
++                    Reserved2:3;
++    unsigned char   CBWCB[16];
++} __attribute__((packed)) COMMAND_BLOCK_WRAPPER;
++
++/*
++ * Command Status Wrapper
++ */
++typedef struct{
++    unsigned long   dCSWSignature;
++    unsigned long   dCSWTag;
++    unsigned long   dCSWDataResidue;
++    unsigned char   bCSWStatus;
++} __attribute__((packed)) COMMAND_STATUS_WRAPPER;
++
++/**************************************
++** SCSI Command
++**************************************/
++
++/*
++ * INQUIRY
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   EVPD:1,
++                    Reserved1:4,
++                    LogicalUnitNumber:3;
++    unsigned char   PageCode;
++    unsigned char   Reserved2;
++    unsigned char   AllocationLength;
++    unsigned char   Reserved3;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   Reserved7;
++    unsigned char   Reserved8;
++    unsigned char   Reserved9;
++} __attribute__((packed)) SCSI_INQUIRY_COMMAND;
++
++typedef struct{
++    unsigned char   PeripheralDeviceType:5,
++                    Reserved1:3;
++    unsigned char   Reserved2:7,
++                    RMB:1;
++    unsigned char   ANSIVersion:3,
++                    ECMAVersion:3,
++                    ISOVersion:2;
++    unsigned char   ResponseDataFormat:4,
++                    Reserved3:4;
++    unsigned char   AdditionalLength;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   VendorInformation[8];
++    unsigned char   ProductIdentification[16];
++    unsigned char   ProductRevisionLevel[4];
++} __attribute__((packed)) SCSI_INQUIRY_DATA;
++
++/*
++ * READ FORMAT CAPACITY
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   Reserved1:5,
++                    LogicalUnitNumber:3;
++    unsigned char   Reserved2;
++    unsigned char   Reserved3;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   AllocationLength[2];
++    unsigned char   Reserved7;
++    unsigned char   Reserved8;
++    unsigned char   Reserved9;
++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_COMMAND;
++
++typedef struct{
++    struct{
++        unsigned char   Reserved1;
++        unsigned char   Reserved2;
++        unsigned char   Reserved3;
++        unsigned char   CapacityListLength;
++    } __attribute__((packed)) CapacityListHeader;
++    struct{
++        unsigned char   NumberofBlocks[4];
++        unsigned char   DescriptorCode:2,
++                        Reserved1:6;
++        unsigned char   BlockLength[3];
++    } __attribute__((packed)) CurrentMaximumCapacityDescriptor;
++} __attribute__((packed)) SCSI_READ_FORMAT_CAPACITY_DATA;
++
++/*
++ * READ FORMAT CAPACITY
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   RelAdr:1,
++                    Reserved1:4,
++                    LogicalUnitNumber:3;
++    unsigned char   LogicalBlockAddress[4];
++    unsigned char   Reserved2;
++    unsigned char   Reserved3;
++    unsigned char   PMI:1,
++                    Reserved4:7;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   Reserved7;
++} __attribute__((packed)) SCSI_READ_CAPACITY_COMMAND;
++
++typedef struct{
++    unsigned char   LastLogicalBlockAddress[4];
++    unsigned char   BlockLengthInBytes[4];
++} __attribute__((packed)) SCSI_READ_CAPACITY_DATA;
++
++/*
++ * REQUEST SENSE
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   Reserved1:5,
++                    LogicalUnitNumber:3;
++    unsigned char   Reserved2;
++    unsigned char   Reserved3;
++    unsigned char   AllocationLength;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   Reserved7;
++    unsigned char   Reserved8;
++    unsigned char   Reserved9;
++    unsigned char   Reserved10;
++} __attribute__((packed)) SCSI_REQUEST_SENSE_COMMAND;
++
++typedef struct{
++    unsigned char   ErrorCode:7,
++                    Valid:1;
++    unsigned char   Reserved1;
++    unsigned char   SenseKey:4,
++                    Reserved2:4;
++    unsigned char   Information[4];
++    unsigned char   AdditionalSenseLength;
++    unsigned char   Reserved3[4];
++    unsigned char   AdditionalSenseCode;
++    unsigned char   AdditionalSenseCodeQualifier;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5[3];
++} __attribute__((packed)) SCSI_REQUEST_SENSE_DATA;
++
++/*
++ * READ(10)
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   RelAdr:1,
++                    Reserved1:2,
++                    FUA:1,
++                    DPO:1,
++                    LogicalUnitNumber:3;
++    unsigned char   LogicalBlockAddress[4];
++    unsigned char   Reserved2;
++    unsigned char   TransferLength[2];
++    unsigned char   Reserved3;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++} __attribute__((packed)) SCSI_READ_10_COMMAND;
++
++/*
++ * MODE SENSE
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   Reserved1:3,
++                    DBD:1,
++                    Reserved2:1,
++                    LogicalUnitNumber:3;
++    unsigned char   PageCode:6,
++                    PC:2;
++    unsigned char   Reserved3;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   ParameterListLength[2];
++    unsigned char   Reserved7;
++    unsigned char   Reserved8;
++    unsigned char   Reserved9;
++} __attribute__((packed)) SCSI_MODE_SENSE_COMMAND;
++
++typedef struct{
++    unsigned char   ModeDataLength;
++    unsigned char   MediumTypeCode;
++    unsigned char   Reserved1:4,
++                    DPOFUA:1,
++                    Reserved2:2,
++                    WP:1;
++    unsigned char   Reserved3;
++} __attribute__((packed)) MODE_PARAMETER_HEADER;
++
++typedef struct{
++    unsigned char   PageCode:6,
++                    Reserved1:1,
++                    PS:1;
++    unsigned char   PageLength;
++    unsigned char   DCR:1,
++                    Reserved2:1,
++                    PER:1,
++                    Reserved3:1,
++                    RC:1,
++                    Reserved4:1,
++                    Reserved5:1,
++                    AWRE:1;
++    unsigned char   ReadRetryCount;
++    unsigned char   Reserved6[4];
++    unsigned char   WriteRetryCount;
++    unsigned char   Reserved7[3];
++} __attribute__((packed)) READ_WRITE_ERROR_RECOVERY_PAGE;
++
++typedef struct{
++    unsigned char   PageCode:6,
++                    Reserved1:1,
++                    PS:1;
++    unsigned char   PageLength;
++    unsigned char   TransferRate[2];
++    unsigned char   NumberofHeads;
++    unsigned char   SectorsperTrack;
++    unsigned char   DataBytesperSector[2];
++    unsigned char   NumberofCylinders[2];
++    unsigned char   Reserved2[9];
++    unsigned char   MotorOnDelay;
++    unsigned char   MotorOffDelay;
++    unsigned char   Reserved3[7];
++    unsigned char   MediumRotationRate[2];
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++} __attribute__((packed)) FLEXIBLE_DISK_PAGE;
++
++typedef struct{
++    unsigned char   PageCode:6,
++                    Reserved1:1,
++                    PS:1;
++    unsigned char   PageLength;
++    unsigned char   Reserved2:6,
++                    SRFP:1,
++                    SFLP:1;
++    unsigned char   TLUN:3,
++                    Reserved3:3,
++                    SML:1,
++                    NCD:1;
++    unsigned char   Reserved4[8];
++} __attribute__((packed)) REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE;
++
++typedef struct{
++    unsigned char   PageCode:6,
++                    Reserved1:1,
++                    PS:1;
++    unsigned char   PageLength;
++    unsigned char   Reserved2;
++    unsigned char   InactivityTimeMultiplier:4,
++                    Reserved3:4;
++    unsigned char   SWPP:1,
++                    DISP:1,
++                    Reserved4:6;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   Reserved7;
++} __attribute__((packed)) TIMER_AND_PROTECT_PAGE;
++
++typedef struct{
++    READ_WRITE_ERROR_RECOVERY_PAGE              ReadWriteErrorRecoveryPage;
++    FLEXIBLE_DISK_PAGE                          FlexibleDiskPage;
++    REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE    RemovableBlockAccessCapabilitiesPage;
++    TIMER_AND_PROTECT_PAGE                      TimerAndProtectPage;
++} __attribute__((packed)) MODE_ALL_PAGES;
++
++typedef struct{
++    MODE_PARAMETER_HEADER   ModeParameterHeader;
++    union{
++        READ_WRITE_ERROR_RECOVERY_PAGE              ReadWriteErrorRecoveryPage;
++        FLEXIBLE_DISK_PAGE                          FlexibleDiskPage;
++        REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGE    RemovableBlockAccessCapabilitiesPage;
++        TIMER_AND_PROTECT_PAGE                      TimerAndProtectPage;
++        MODE_ALL_PAGES                              ModeAllPages;
++    } __attribute__((packed)) ModePages;
++} __attribute__((packed)) SCSI_MODE_SENSE_DATA;
++
++/*
++ * TEST UNIT READY
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   Reserved1:5,
++                    LogicalUnitNumber:3;
++    unsigned char   Reserved2;
++    unsigned char   Reserved3;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   Reserved7;
++    unsigned char   Reserved8;
++    unsigned char   Reserved9;
++    unsigned char   Reserved10;
++    unsigned char   Reserved11;
++} __attribute__((packed)) SCSI_TEST_UNIT_READY_COMMAND;
++
++/*
++ * PREVENT-ALLOW MEDIUM REMOVAL
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   Reserved1:5,
++                    LogicalUnitNumber:3;
++    unsigned char   Reserved2;
++    unsigned char   Reserved3;
++    unsigned char   Prevent:1,
++                    Reserved4:7;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   Reserved7;
++    unsigned char   Reserved8;
++    unsigned char   Reserved9;
++    unsigned char   Reserved10;
++    unsigned char   Reserved11;
++} __attribute__((packed)) SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL_COMMAND;
++
++/*
++ * START-STOP UNIT
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   IMMED:1,
++                    Reserved1:4,
++                    LogicalUnitNumber:3;
++    unsigned char   Reserved2;
++    unsigned char   Reserved3;
++    unsigned char   Start:1,
++                    LoEj:1,
++                    Reserved4:6;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++    unsigned char   Reserved7;
++    unsigned char   Reserved8;
++    unsigned char   Reserved9;
++    unsigned char   Reserved10;
++    unsigned char   Reserved11;
++} __attribute__((packed)) SCSI_START_STOP_COMMAND;
++
++/*
++ * WRITE(10)
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   RelAdr:1,
++                    Reserved1:2,
++                    FUA:1,
++                    DPO:1,
++                    LogicalUnitNumber:3;
++    unsigned char   LogicalBlockAddress[4];
++    unsigned char   Reserved2;
++    unsigned char   TransferLength[2];
++    unsigned char   Reserved3;
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++} __attribute__((packed)) SCSI_WRITE_10_COMMAND;
++
++/*
++ * VERIFY
++ */
++
++typedef struct{
++    unsigned char   OperationCode;
++    unsigned char   RelAdr:1,
++                    ByteChk:1,
++                    Reserved1:1,
++                    Reserved2:1,
++                    DPO:1,
++                    LogicalUnitNumber:3;
++    unsigned char   LogicalBlockAddress[4];
++    unsigned char   Reserved3;
++    unsigned char   VerificationLength[2];
++    unsigned char   Reserved4;
++    unsigned char   Reserved5;
++    unsigned char   Reserved6;
++} __attribute__((packed)) SCSI_VERIFY_COMMAND;
++
++/******************************************************************************
++** Global Function Prototype
++******************************************************************************/
++
++/* storage-fd.c */
++void    storage_urb_send(struct usb_device_instance*, void*, int);
++
++/* storageproto.c */
++void    storageproto_urb_analysis(struct urb*);
++int     storageproto_device_open_check(void);
++void    storageproto_device_close(void);
++void    storageproto_usb_status_check(int);
++void    storageproto_media_status_check(int);
++void    storageproto_usb_reset_ind(void);
++ssize_t storageproto_proc_read(struct file*, char*, size_t, loff_t* pos);
++void    storageproto_init(void);
++void    storageproto_exit(void);
++
++#endif  /* _STORAGEPROTO_H_ */
++
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch
index e69de29bb2..1912b33328 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/battery.patch
@@ -0,0 +1,326 @@
+
+--- linux/arch/arm/mach-sa1100/collie_battery.c	Tue Jul 22 02:24:32 2003
++++ linux/arch/arm/mach-sa1100/collie_battery.c	Tue Jul 22 03:07:56 2003
+@@ -14,10 +14,11 @@
+  * 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.
+  *
+  * ChangeLog:
++ *	Nov 2002 Dietz Proepper: improved battery status.
+  *	12-Nov-2001 Lineo Japan, Inc.
+  *	30-Jul-2002 Lineo Japan, Inc.  for 2.4.18
+  *      29-Jan-2003 Sharp Corporation  modify for new QT I/F
+  *
+  */
+@@ -79,10 +80,11 @@ int collie_read_BackBattery(void);
+ int collie_read_Temp(void);
+ int collie_check_temp(void);
+ int collie_check_voltage(void);
+ static void collie_charge_on(void);
+ static void collie_charge_off(void);
++static void do_main_battery(void);
+ int set_led_status(int which,int status);
+ int GetMainLevel( int Volt );
+ int GetBackLevel( int Volt );
+ int collie_get_main_battery(void);
+ unsigned short GetBackupBatteryAD(void);
+@@ -91,40 +93,35 @@ int suspend_collie_read_Temp(void);
+ /*** extern ***********************************************************************/
+ extern u32 apm_wakeup_src_mask;
+ extern int counter_step_contrast;
+ 
+ 
+-/*** gloabal variables ************************************************************/
+-int charge_status = 0;			/* charge status  1 : charge  0: not charge */
+-
+-typedef struct BatteryThresh {
+-	int high;
+-	int low;
+-	int verylow;
+-} BATTERY_THRESH;
++/* defines */
++#define COLLIE_BATTERY_STATUS_HIGH      APM_BATTERY_STATUS_HIGH
++#define COLLIE_BATTERY_STATUS_LOW       APM_BATTERY_STATUS_LOW
++#define COLLIE_BATTERY_STATUS_VERYLOW   APM_BATTERY_STATUS_VERY_LOW
++#define COLLIE_BATTERY_STATUS_CRITICAL  APM_BATTERY_STATUS_CRITICAL
+ 
++/*** gloabal variables ************************************************************/
++int charge_status = 0;	/* charge status  1 : charge  0: not charge */
+ 
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \
+-    defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV)
+-BATTERY_THRESH  collie_main_battery_thresh_fl = {
+-  368, 358, 356
+-};
+-
+-BATTERY_THRESH  collie_main_battery_thresh_nofl = {
+-  378, 364, 362
+-};
+-#else
+-BATTERY_THRESH  collie_main_battery_thresh_fl = {
+-  368, 358, 356
+-};
+-
+-BATTERY_THRESH  collie_main_battery_thresh_nofl = {
+-  378, 365, 363
++typedef struct {
++    int voltage_thres[2];		/* 0: nofl 1: fl */
++    int percent;
++    int state;
++} main_battery_thres;
++    
++#define MAIN_BATTERY_THRES 4
++
++main_battery_thres main_batt_thres[MAIN_BATTERY_THRES+2] = {
++	{{5000, 5000}, 100, COLLIE_BATTERY_STATUS_HIGH }, /* do not remove! */
++	{{412,408}, 100, COLLIE_BATTERY_STATUS_HIGH},
++	{{378,368}, 40, COLLIE_BATTERY_STATUS_HIGH},
++	{{364,358}, 5, COLLIE_BATTERY_STATUS_LOW},
++	{{362,356}, 1, COLLIE_BATTERY_STATUS_CRITICAL},
++	{{0, 0}, 1, COLLIE_BATTERY_STATUS_CRITICAL }	/* do not remove, too! */
+ };
+-#endif
+-
+-
+ 
+ typedef struct ChargeThresh {
+   int bar1;
+   int bar2;
+   int bar3;
+@@ -180,24 +177,18 @@ static struct miscdevice battery_device 
+ #define GetBackADCtoPower(x)   (( 330 * x * 2 ) / 1024 )     // MAX 3.3V
+ #define ConvRevise(x)          ( ( ad_revise * x ) / 652 )
+ #define MAIN_DIFF          50	// 0.5V 
+ #define DIFF_CNT           ( 3 - 1 )
+ 
+-#define COLLIE_BATTERY_STATUS_HIGH	APM_BATTERY_STATUS_HIGH
+-#define COLLIE_BATTERY_STATUS_LOW	APM_BATTERY_STATUS_LOW
+-#define COLLIE_BATTERY_STATUS_VERYLOW	APM_BATTERY_STATUS_VERY_LOW
+-#define COLLIE_BATTERY_STATUS_CRITICAL	APM_BATTERY_STATUS_CRITICAL
+-
+ #define COLLIE_AC_LINE_STATUS	(!( GPLR & GPIO_AC_IN )	? APM_AC_OFFLINE : APM_AC_ONLINE)
+ 
+-
+ #define COLLIE_PM_TICK         		( 1000 / 10 )                   // 1sec
+ #define COLLIE_APO_TICKTIME		(  5  * COLLIE_PM_TICK )	// 5sec
+ #define COLLIE_LPO_TICKTIME		COLLIE_APO_TICKTIME
+ #define COLLIE_APO_DEFAULT		( ( 3 * 60 ) * COLLIE_PM_TICK )	// 3 min
+ #define COLLIE_LPO_DEFAULT		(  20 * COLLIE_PM_TICK )	// 20 sec
+-#define COLLIE_MAIN_GOOD_COUNT		( 10*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
++#define COLLIE_MAIN_GOOD_COUNT		( 1*60 / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
+ #define COLLIE_MAIN_NOGOOD_COUNT	( 1*60  / ( COLLIE_APO_TICKTIME / COLLIE_PM_TICK ) )
+ 
+ #define COLLIE_BACKUP_BATTERY_CK_TIME	( 10*60*1*100 )		// 10min
+ #define COLLIE_BACKUP_BATTERY_LOW	( 190 )	
+ 
+@@ -212,10 +203,11 @@ unsigned int LPOCntWk = 0;
+ static DECLARE_WAIT_QUEUE_HEAD(queue);
+ static int	msglevel;
+ 
+ int collie_backup_battery = COLLIE_BATTERY_STATUS_HIGH;
+ int collie_main_battery   = COLLIE_BATTERY_STATUS_HIGH;
++int collie_main_battery_percent = 100;
+ int collie_main_charge_battery = 100;
+ int collie_ac_status = APM_AC_OFFLINE;
+ int ad_revise = 0;
+ 
+ static int MainCntWk = COLLIE_MAIN_GOOD_COUNT;
+@@ -229,10 +221,11 @@ static struct pm_dev *battery_pm_dev;	 /
+ 
+ static int battery_off_flag = 0;	/* charge : suspend while get adc */
+ static int collie_charge_temp = 973;
+ static int collie_charge_volt = 465;	/* charge : check charge 3.0V     */
+ static int charge_off_mode = 0;		/* charge : check volt or non     */
++static int collie_main_battery_voltage = 400;
+ 
+ static DECLARE_WAIT_QUEUE_HEAD(wq_on);
+ static DECLARE_WAIT_QUEUE_HEAD(wq_off);
+ #if 1 // 2003.1.29
+ static DECLARE_WAIT_QUEUE_HEAD(battery_waitqueue);
+@@ -276,28 +269,11 @@ int collie_apm_get_power_status(u_char *
+ 	}
+ 	collie_battery_status = *battery_status;
+ #endif
+ 
+ 	// main battery status to percentage
+-	switch (*battery_status)
+-	  {
+-	  case COLLIE_BATTERY_STATUS_HIGH:
+-	    *battery_percentage = 100;
+-	    break;
+-	  case COLLIE_BATTERY_STATUS_LOW:
+-	    *battery_percentage = 40;
+-	    break;
+-	  case COLLIE_BATTERY_STATUS_VERYLOW:
+-	    *battery_percentage = 5;
+-	    break;
+-	  case COLLIE_BATTERY_STATUS_CRITICAL:
+-	    *battery_percentage = 1;
+-	    break;
+-	  default:
+-	    *battery_percentage = 100;
+-	    break;
+-	  }
++	*battery_percentage = collie_main_battery_percent;
+ 
+ 	if ( *ac_line_status == APM_AC_ONLINE )
+ 	  *battery_percentage = 100;
+ 
+ 	// good or ac in   --> GOOD_COUNT
+@@ -529,12 +505,13 @@ int collie_get_main_battery(void)
+ 	    voltage = collie_read_MainBattery();
+ 	    if ( voltage > 0 ) break;
+ 	    if ( i++ > 5 ) { voltage = 380; break; }
+ 	  }
+ 
+-	  collie_main_battery = GetMainLevel(GetMainADCtoPower(voltage));
+-	  collie_main_charge_battery = GetMainChargePercent(GetMainADCtoPower(voltage));
++	  collie_main_battery_voltage = GetMainADCtoPower(voltage);
++	  do_main_battery();
++	  collie_main_charge_battery = GetMainChargePercent(collie_main_battery_voltage);
+ 
+ 	  DPRINTK2("charge percent = %d ( at %d ) \n",collie_main_charge_battery,jiffies);
+ 
+ 	  DPRINTK(" get Main battery status %d\n",collie_main_battery);
+ 
+@@ -562,36 +539,36 @@ int GetMainChargePercent( int Volt )
+   } else {
+     return 5;
+   }
+ }
+ 
+-int GetMainLevel( int Volt )
++static void do_main_battery()
+ {
+-
+-  DPRINTK("  volt = %d  \n",Volt);
+-
+-
+-  if ( counter_step_contrast ) {
+-	if ( Volt > collie_main_battery_thresh_fl.high )
+-		return COLLIE_BATTERY_STATUS_HIGH;
+-	else if ( Volt > collie_main_battery_thresh_fl.low )
+-		return COLLIE_BATTERY_STATUS_LOW;
+-	else if ( Volt > collie_main_battery_thresh_fl.verylow )
+-		return COLLIE_BATTERY_STATUS_VERYLOW;
+-	else
+-		return COLLIE_BATTERY_STATUS_CRITICAL;
+-  } else {
+-	if ( Volt > collie_main_battery_thresh_nofl.high )
+-		return COLLIE_BATTERY_STATUS_HIGH;
+-	else if ( Volt > collie_main_battery_thresh_nofl.low )
+-		return COLLIE_BATTERY_STATUS_LOW;
+-	else if ( Volt > collie_main_battery_thresh_nofl.verylow )
+-		return COLLIE_BATTERY_STATUS_VERYLOW;
+-	else
+-		return COLLIE_BATTERY_STATUS_CRITICAL;
+-  }
+-
++	int i = MAIN_BATTERY_THRES;
++	int fl = (counter_step_contrast)? 1 : 0;
++  
++	while ( i > 0 &&
++		( collie_main_battery_voltage > main_batt_thres[i].voltage_thres[fl] ) )
++		i--;
++	/* i is now between 0 and MAIN_BATTERY_THRES. That means
++	 * we can safely access main_batt_thres[i] and
++	 * main_batt_thres[i+1] */
++	
++	collie_main_battery = main_batt_thres[i].state;
++	{ /* perhaps we should put that deltas to our table, too? */
++		long deltav = main_batt_thres[i].voltage_thres[fl] -
++			      main_batt_thres[i+1].voltage_thres[fl];
++		long deltap = main_batt_thres[i].percent -
++			      main_batt_thres[i+1].percent;
++		
++		collie_main_battery_percent = 			/* (1) */
++	   	   main_batt_thres[i+1].percent + 
++	   	   deltap * (collie_main_battery_voltage - 
++ 		   main_batt_thres[i+1].voltage_thres[fl]) /
++	   	   deltav; 
++		DPRINTK("Battery stuff: v=%i i=%i , dv=%li , dp=%li , p=%i",collie_main_battery_voltage , i, deltav, deltap, collie_main_battery_percent );
++	}
+ }
+ 
+ 
+ int GetBackLevel( int Volt )
+ {
+@@ -834,20 +811,18 @@ unsigned short chkFatalBatt(void)
+     GEDR = GPIO_CO;
+     //    printk("CO = %x\n",GEDR&GPIO_CO);
+   }
+ 
+ 
+-  if ( volt < collie_main_battery_thresh_nofl.verylow )
++  if ( volt < main_batt_thres[MAIN_BATTERY_THRES].voltage_thres[0] )
+     return 0;
+   else
+     return 1;
+ #endif
+ }
+ 
+ 
+-
+-
+ int suspend_collie_check_temp(void)
+ {
+   unsigned short temp , i = 0;
+ 
+   while(1) {
+@@ -1032,10 +1007,11 @@ struct proc_dir_entry *proc_batt;
+ typedef struct collie_battery_entry {
+ 	int*		addr;
+ 	int		def_value;
+ 	char*		name;
+ 	char*		description;
++	char		readonly;
+ 	unsigned short	low_ino;
+ } collie_battery_entry_t;
+ 
+ #if 1 // 2003.1.29
+ static collie_battery_entry_t collie_battery_params[] = {
+@@ -1044,11 +1020,13 @@ static collie_battery_entry_t collie_bat
+   { &collie_change_battery_status , 0 , "chg_status", "Change status" }
+ };
+ #else
+ static collie_battery_entry_t collie_battery_params[] = {
+ /*  { addr,	def_value,	name,	    description }*/
+-  { &msglevel,	0,		"msglevel",    "debug message output level" }
++/*  { &msglevel,	0,		"msglevel",    "debug message output level" } */
++  { &msglevel,	0,		"msglevel",    "debug message output level", 0 },
++  { &collie_main_battery_voltage, -1, "main_voltage", "main battery voltage", 1 }
+ };
+ #endif
+ #define NUM_OF_BATTERY_ENTRY	(sizeof(collie_battery_params)/sizeof(collie_battery_entry_t))
+ 
+ static ssize_t collie_battery_read_params(struct file *file, char *buf,
+@@ -1069,11 +1047,12 @@ static ssize_t collie_battery_read_param
+ 		}
+ 	}
+ 	if (current_param==NULL) {
+ 		return -EINVAL;
+ 	}
+-	count = sprintf(outputbuf, "0x%08X\n",
++//	count = sprintf(outputbuf, "0x%08X\n",
++	count = sprintf(outputbuf, "%04i\n",
+ 			*((volatile Word *) current_param->addr));
+ 	*ppos += count;
+ 	if (count>nbytes)	/* Assume output can be read at one time */
+ 		return -EINVAL;
+ 	if (copy_to_user(buf, outputbuf, count))
+@@ -1094,11 +1073,12 @@ static ssize_t collie_battery_write_para
+ 		if(collie_battery_params[i].low_ino==i_ino) {
+ 			current_param = &collie_battery_params[i];
+ 			break;
+ 		}
+ 	}
+-	if (current_param==NULL) {
++//	if (current_param==NULL) {
++	if (current_param==NULL || current_param->readonly) {
+ 		return -EINVAL;
+ 	}
+ 
+ 	param = simple_strtoul(buf,&endp,0);
+ 	if (param == -1) {
+
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff
index e69de29bb2..b31c57992f 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/bluetooth-patch-2.4.18-mh9.diff
@@ -0,0 +1,30831 @@
+diff -urN linux-2.4.18/CREDITS linux-2.4.18-mh9/CREDITS
+--- linux-2.4.18/CREDITS	Mon Feb 25 20:37:50 2002
++++ linux-2.4.18-mh9/CREDITS	Mon Aug 25 18:38:09 2003
+@@ -1317,6 +1317,14 @@
+ S: Provo, Utah 84606-5607
+ S: USA
+ 
++N: Marcel Holtmann
++E: marcel@holtmann.org
++W: http://www.holtmann.org
++D: Author and maintainer of the various Bluetooth HCI drivers
++D: Author and maintainer of the CAPI message transport protocol driver
++D: Various other Bluetooth related patches, cleanups and fixes
++S: Germany
++
+ N: Rob W. W. Hooft
+ E: hooft@EMBL-Heidelberg.DE
+ D: Shared libs for graphics-tools and for the f2c compiler
+diff -urN linux-2.4.18/Documentation/Configure.help linux-2.4.18-mh9/Documentation/Configure.help
+--- linux-2.4.18/Documentation/Configure.help	Mon Feb 25 20:37:51 2002
++++ linux-2.4.18-mh9/Documentation/Configure.help	Mon Aug 25 18:38:10 2003
+@@ -2824,14 +2824,6 @@
+ 
+   If unsure, say N.
+ 
+-HCI EMU (virtual device) driver
+-CONFIG_BLUEZ_HCIEMU
+-  Bluetooth Virtual HCI device driver.
+-  This driver is required if you want to use HCI Emulation software.
+-
+-  Say Y here to compile support for Virtual HCI devices into the
+-  kernel or say M to compile it as module (hci_usb.o).
+-
+ # Choice: alphatype
+ Alpha system type
+ CONFIG_ALPHA_GENERIC
+@@ -11037,6 +11029,12 @@
+ 
+   If unsure, say N.
+ 
++Hotplug firmware loading support (EXPERIMENTAL)
++CONFIG_FW_LOADER
++  This option is provided for the case where no in-kernel-tree modules require
++  hotplug firmware loading support, but a module built outside the kernel tree
++  does.
++
+ Use PCI shared memory for NIC registers
+ CONFIG_TULIP_MMIO
+   Use PCI shared memory for the NIC registers, rather than going through 
+@@ -19870,11 +19868,15 @@
+   Bluetooth can be found at <http://www.bluetooth.com/>.
+ 
+   Linux Bluetooth subsystem consist of several layers:
+-               HCI Core (device and connection manager, scheduler)
++               BlueZ Core (HCI device and connection manager, scheduler)
+                HCI Device drivers (interface to the hardware)
+                L2CAP Module (L2CAP protocol)
++               SCO Module (SCO links)
++               RFCOMM Module (RFCOMM protocol)
++               BNEP Module (BNEP protocol)
++               CMTP Module (CMTP protocol)
+ 
+-  Say Y here to enable Linux Bluetooth support and to build HCI Core
++  Say Y here to enable Linux Bluetooth support and to build BlueZ Core
+   layer.
+ 
+   To use Linux Bluetooth subsystem, you will need several user-space
+@@ -19882,7 +19884,7 @@
+   Bluetooth kernel modules are provided in the BlueZ package.
+   For more information, see <http://bluez.sourceforge.net/>.
+ 
+-  If you want to compile HCI Core as module (hci.o) say M here.
++  If you want to compile BlueZ Core as module (bluez.o) say M here.
+ 
+ L2CAP protocol support
+ CONFIG_BLUEZ_L2CAP
+@@ -19893,15 +19895,91 @@
+   Say Y here to compile L2CAP support into the kernel or say M to
+   compile it as module (l2cap.o).
+ 
++SCO links support
++CONFIG_BLUEZ_SCO
++  SCO link provides voice transport over Bluetooth. SCO support is
++  required for voice applications like Headset and Audio.
++
++  Say Y here to compile SCO support into the kernel or say M to
++  compile it as module (sco.o).
++
++RFCOMM protocol support
++CONFIG_BLUEZ_RFCOMM
++  RFCOMM provides connection oriented stream transport. RFCOMM
++  support is required for Dialup Networking, OBEX and other Bluetooth
++  applications.
++
++  Say Y here to compile RFCOMM support into the kernel or say M to
++  compile it as module (rfcomm.o).
++
++RFCOMM TTY emulation support
++CONFIG_BLUEZ_RFCOMM_TTY
++  This option enables TTY emulation support for RFCOMM channels.
++
++BNEP protocol support
++CONFIG_BLUEZ_BNEP
++  BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet
++  emulation layer on top of Bluetooth. BNEP is required for Bluetooth
++  PAN (Personal Area Network).
++
++  To use BNEP, you will need user-space utilities provided in the 
++  BlueZ-PAN package.
++  For more information, see <http://bluez.sourceforge.net>.
++
++  Say Y here to compile BNEP support into the kernel or say M to
++  compile it as module (bnep.o).
++
++CMTP protocol support
++CONFIG_BLUEZ_CMTP
++  CMTP (CAPI Message Transport Protocol) is a transport layer
++  for CAPI messages. CMTP is required for the Bluetooth Common
++  ISDN Access Profile.
++
++  Say Y here to compile CMTP support into the kernel or say M to
++  compile it as module (cmtp.o).
++
++BNEP multicast filter support
++CONFIG_BLUEZ_BNEP_MC_FILTER
++  This option enables the multicast filter support for BNEP.
++
++BNEP protocol filter support
++CONFIG_BLUEZ_BNEP_PROTO_FILTER
++  This option enables the protocol filter support for BNEP.
++
+ HCI UART driver
+ CONFIG_BLUEZ_HCIUART
+   Bluetooth HCI UART driver.
+   This driver is required if you want to use Bluetooth devices with
+-  serial port interface.
++  serial port interface. You will also need this driver if you have 
++  UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card 
++  adapter and BrainBoxes Bluetooth PC Card.
+ 
+   Say Y here to compile support for Bluetooth UART devices into the
+   kernel or say M to compile it as module (hci_uart.o).
+ 
++HCI UART (H4) protocol support 
++CONFIG_BLUEZ_HCIUART_H4
++  UART (H4) is serial protocol for communication between Bluetooth 
++  device and host. This protocol is required for most Bluetooth devices 
++  with UART interface, including PCMCIA and CF cards. 
++
++  Say Y here to compile support for HCI UART (H4) protocol.
++
++HCI BCSP protocol support 
++CONFIG_BLUEZ_HCIUART_BCSP
++  BCSP (BlueCore Serial Protocol) is serial protocol for communication 
++  between Bluetooth device and host. This protocol is required for non
++  USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and 
++  CF cards.
++
++  Say Y here to compile support for HCI BCSP protocol.
++
++HCI BCSP transmit CRC with every BCSP packet
++CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++  If you say Y here, a 16-bit CRC checksum will be transmitted along with
++  every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip.
++  This increases reliability, but slightly reduces efficiency.
++
+ HCI USB driver
+ CONFIG_BLUEZ_HCIUSB
+   Bluetooth HCI USB driver.
+@@ -19911,13 +19989,90 @@
+   Say Y here to compile support for Bluetooth USB devices into the
+   kernel or say M to compile it as module (hci_usb.o).
+ 
+-HCI VHCI virtual HCI device driver
++HCI USB SCO (voice) support
++CONFIG_BLUEZ_USB_SCO
++  This option enables the SCO support in the HCI USB driver. You need this
++  to transmit voice data with your Bluetooth USB device. And your device
++  must also support sending SCO data over the HCI layer, because some of
++  them sends the SCO data to an internal PCM adapter.
++ 
++  Say Y here to compile support for HCI SCO data.
++ 
++HCI USB zero packet support
++CONFIG_BLUEZ_USB_ZERO_PACKET
++  This option is provided only as a work around for buggy Bluetooth USB 
++  devices. Do NOT enable it unless you know for sure that your device 
++  requires zero packets.
++ 
++  Most people should say N here.
++
++HCI VHCI Virtual HCI device driver
+ CONFIG_BLUEZ_HCIVHCI
+   Bluetooth Virtual HCI device driver.
+   This driver is required if you want to use HCI Emulation software.
+ 
+   Say Y here to compile support for virtual HCI devices into the
+   kernel or say M to compile it as module (hci_vhci.o).
++
++HCI BFUSB device driver
++CONFIG_BLUEZ_HCIBFUSB
++  Bluetooth HCI BlueFRITZ! USB driver.
++  This driver provides support for Bluetooth USB devices with AVM
++  interface:
++     AVM BlueFRITZ! USB
++
++  Say Y here to compile support for HCI BFUSB devices into the
++  kernel or say M to compile it as module (bfusb.o).
++
++HCI DTL1 (PC Card) device driver
++CONFIG_BLUEZ_HCIDTL1
++  Bluetooth HCI DTL1 (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  Nokia DTL1 interface:
++     Nokia Bluetooth Card
++     Socket Bluetooth CF Card
++
++  Say Y here to compile support for HCI DTL1 devices into the
++  kernel or say M to compile it as module (dtl1_cs.o).
++
++HCI BT3C (PC Card) device driver
++CONFIG_BLUEZ_HCIBT3C
++  Bluetooth HCI BT3C (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  3Com BT3C interface:
++     3Com Bluetooth Card (3CRWB6096)
++     HP Bluetooth Card
++
++  The HCI BT3C driver uses external firmware loader program provided in
++  the BlueFW package. For more information, see <http://bluez.sf.net>.
++
++  Say Y here to compile support for HCI BT3C devices into the
++  kernel or say M to compile it as module (bt3c_cs.o).
++
++HCI BlueCard (PC Card) device driver
++CONFIG_BLUEZ_HCIBLUECARD
++  Bluetooth HCI BlueCard (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  Anycom BlueCard interface:
++     Anycom Bluetooth PC Card
++     Anycom Bluetooth CF Card
++
++  Say Y here to compile support for HCI BlueCard devices into the
++  kernel or say M to compile it as module (bluecard_cs.o).
++
++HCI UART (PC Card) device driver
++CONFIG_BLUEZ_HCIBTUART
++  Bluetooth HCI UART (PC Card) driver.
++  This driver provides support for Bluetooth PCMCIA devices with
++  an UART interface:
++     Xircom CreditCard Bluetooth Adapter
++     Xircom RealPort2 Bluetooth Adapter
++     Sphinx PICO Card
++     H-Soft blue+Card
++     Cyber-blue Compact Flash Card
++
++  Say Y here to compile support for HCI UART devices into the
++  kernel or say M to compile it as module (btuart_cs.o).
+ 
+ # The following options are for Linux when running on the Hitachi
+ # SuperH family of RISC microprocessors.
+diff -urN linux-2.4.18/Documentation/firmware_class/README linux-2.4.18-mh9/Documentation/firmware_class/README
+--- linux-2.4.18/Documentation/firmware_class/README	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/Documentation/firmware_class/README	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,58 @@
++
++ request_firmware() hotplug interface:
++ ------------------------------------
++	Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
++
++ Why:
++ ---
++
++ Today, the most extended way to use firmware in the Linux kernel is linking
++ it statically in a header file. Which has political and technical issues:
++
++  1) Some firmware is not legal to redistribute.
++  2) The firmware occupies memory permanently, even though it often is just
++     used once.
++  3) Some people, like the Debian crowd, don't consider some firmware free
++     enough and remove entire drivers (e.g.: keyspan).
++
++ about in-kernel persistence:
++ ---------------------------
++ Under some circumstances, as explained below, it would be interesting to keep
++ firmware images in non-swappable kernel memory or even in the kernel image
++ (probably within initramfs).
++
++ Note that this functionality has not been implemented.
++
++ - Why OPTIONAL in-kernel persistence may be a good idea sometimes:
++ 
++	- If the device that needs the firmware is needed to access the
++	  filesystem. When upon some error the device has to be reset and the
++	  firmware reloaded, it won't be possible to get it from userspace.
++	  e.g.:
++		- A diskless client with a network card that needs firmware.
++		- The filesystem is stored in a disk behind an scsi device
++		  that needs firmware.
++	- Replacing buggy DSDT/SSDT ACPI tables on boot.
++	  Note: this would require the persistent objects to be included
++	  within the kernel image, probably within initramfs.
++	  
++   And the same device can be needed to access the filesystem or not depending
++   on the setup, so I think that the choice on what firmware to make
++   persistent should be left to userspace.
++
++ - Why register_firmware()+__init can be useful:
++ 	- For boot devices needing firmware.
++	- To make the transition easier:
++		The firmware can be declared __init and register_firmware()
++		called on module_init. Then the firmware is warranted to be
++		there even if "firmware hotplug userspace" is not there yet or
++		it doesn't yet provide the needed firmware.
++		Once the firmware is widely available in userspace, it can be
++		removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE).
++
++	In either case, if firmware hotplug support is there, it can move the
++	firmware out of kernel memory into the real filesystem for later
++	usage.
++
++	Note: If persistence is implemented on top of initramfs,
++	register_firmware() may not be appropriate.
+diff -urN linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c linux-2.4.18-mh9/Documentation/firmware_class/firmware_sample_driver.c
+--- linux-2.4.18/Documentation/firmware_class/firmware_sample_driver.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/Documentation/firmware_class/firmware_sample_driver.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,121 @@
++/*
++ * firmware_sample_driver.c -
++ *
++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
++ *
++ * Sample code on how to use request_firmware() from drivers.
++ *
++ * Note that register_firmware() is currently useless.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/string.h>
++
++#include "linux/firmware.h"
++
++#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
++char __init inkernel_firmware[] = "let's say that this is firmware\n";
++#endif
++
++static char ghost_device[] = "ghost0";
++
++static void sample_firmware_load(char *firmware, int size)
++{
++	u8 buf[size+1];
++	memcpy(buf, firmware, size);
++	buf[size] = '\0';
++	printk("firmware_sample_driver: firmware: %s\n", buf);
++}
++
++static void sample_probe_default(void)
++{
++	/* uses the default method to get the firmware */
++        const struct firmware *fw_entry;
++	printk("firmware_sample_driver: a ghost device got inserted :)\n");
++
++        if(request_firmware(&fw_entry, "sample_driver_fw", ghost_device)!=0)
++	{
++		printk(KERN_ERR
++		       "firmware_sample_driver: Firmware not available\n");
++		return;
++	}
++	
++	sample_firmware_load(fw_entry->data, fw_entry->size);
++
++	release_firmware(fw_entry);
++
++	/* finish setting up the device */
++}
++static void sample_probe_specific(void)
++{
++	/* Uses some specific hotplug support to get the firmware from
++	 * userspace  directly into the hardware, or via some sysfs file */
++
++	/* NOTE: This currently doesn't work */
++
++	printk("firmware_sample_driver: a ghost device got inserted :)\n");
++
++        if(request_firmware(NULL, "sample_driver_fw", ghost_device)!=0)
++	{
++		printk(KERN_ERR
++		       "firmware_sample_driver: Firmware load failed\n");
++		return;
++	}
++	
++	/* request_firmware blocks until userspace finished, so at
++	 * this point the firmware should be already in the device */
++
++	/* finish setting up the device */
++}
++static void sample_probe_async_cont(const struct firmware *fw, void *context)
++{
++	if(!fw){
++		printk(KERN_ERR
++		       "firmware_sample_driver: firmware load failed\n");
++		return;
++	}
++
++	printk("firmware_sample_driver: device pointer \"%s\"\n",
++	       (char *)context);
++	sample_firmware_load(fw->data, fw->size);
++}
++static void sample_probe_async(void)
++{
++	/* Let's say that I can't sleep */
++	int error;
++	error = request_firmware_nowait (THIS_MODULE,
++					 "sample_driver_fw", ghost_device,
++					 "my device pointer",
++					 sample_probe_async_cont);
++	if(error){
++		printk(KERN_ERR 
++		       "firmware_sample_driver:"
++		       " request_firmware_nowait failed\n");
++	}
++}
++
++static int sample_init(void)
++{
++#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
++	register_firmware("sample_driver_fw", inkernel_firmware,
++			  sizeof(inkernel_firmware));
++#endif
++	/* since there is no real hardware insertion I just call the
++	 * sample probe functions here */
++	sample_probe_specific();
++	sample_probe_default();
++	sample_probe_async();
++	return 0;
++}
++static void __exit sample_exit(void)
++{
++}
++
++module_init (sample_init);
++module_exit (sample_exit);
++
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/Documentation/firmware_class/hotplug-script linux-2.4.18-mh9/Documentation/firmware_class/hotplug-script
+--- linux-2.4.18/Documentation/firmware_class/hotplug-script	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/Documentation/firmware_class/hotplug-script	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,16 @@
++#!/bin/sh
++
++# Simple hotplug script sample:
++# 
++# Both $DEVPATH and $FIRMWARE are already provided in the environment.
++
++HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
++
++echo 1 > /sysfs/$DEVPATH/loading
++cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
++echo 0 > /sysfs/$DEVPATH/loading
++
++# To cancel the load in case of error:
++#
++#	echo -1 > /sysfs/$DEVPATH/loading
++#
+diff -urN linux-2.4.18/MAINTAINERS linux-2.4.18-mh9/MAINTAINERS
+--- linux-2.4.18/MAINTAINERS	Mon Feb 25 20:37:52 2002
++++ linux-2.4.18-mh9/MAINTAINERS	Mon Aug 25 18:38:10 2003
+@@ -252,7 +252,73 @@
+ L:	linux-kernel@vger.kernel.org
+ S:	Maintained
+ 
+-BLUETOOTH SUBSYSTEM (BlueZ)
++BLUETOOTH SUBSYSTEM
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH RFCOMM LAYER
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH BNEP LAYER
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH CMTP LAYER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI USB DRIVER
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH HCI UART DRIVER
++P:	Maxim Krasnyansky
++M:	maxk@qualcomm.com
++W:	http://bluez.sf.net
++S:	Maintained
++
++BLUETOOTH HCI BFUSB DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI DTL1 DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI BLUECARD DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI BT3C DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI BTUART DRIVER
++P:	Marcel Holtmann
++M:	marcel@holtmann.org
++W:	http://www.holtmann.org/linux/bluetooth/
++S:	Maintained
++
++BLUETOOTH HCI VHCI DRIVER
+ P:	Maxim Krasnyansky
+ M:	maxk@qualcomm.com
+ W:	http://bluez.sf.net
+diff -urN linux-2.4.18/arch/alpha/config.in linux-2.4.18-mh9/arch/alpha/config.in
+--- linux-2.4.18/arch/alpha/config.in	Wed Nov 21 00:49:31 2001
++++ linux-2.4.18-mh9/arch/alpha/config.in	Mon Aug 25 18:38:10 2003
+@@ -371,9 +371,7 @@
+ source drivers/usb/Config.in
+ source drivers/input/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+diff -urN linux-2.4.18/arch/arm/config.in linux-2.4.18-mh9/arch/arm/config.in
+--- linux-2.4.18/arch/arm/config.in	Fri Nov  9 22:58:02 2001
++++ linux-2.4.18-mh9/arch/arm/config.in	Mon Aug 25 18:38:10 2003
+@@ -584,9 +584,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+diff -urN linux-2.4.18/arch/i386/config.in linux-2.4.18-mh9/arch/i386/config.in
+--- linux-2.4.18/arch/i386/config.in	Mon Feb 25 20:37:52 2002
++++ linux-2.4.18-mh9/arch/i386/config.in	Mon Aug 25 18:38:10 2003
+@@ -407,9 +407,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+diff -urN linux-2.4.18/arch/ppc/config.in linux-2.4.18-mh9/arch/ppc/config.in
+--- linux-2.4.18/arch/ppc/config.in	Mon Feb 25 20:37:55 2002
++++ linux-2.4.18-mh9/arch/ppc/config.in	Mon Aug 25 18:38:10 2003
+@@ -389,9 +389,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Kernel hacking'
+diff -urN linux-2.4.18/arch/sparc/config.in linux-2.4.18-mh9/arch/sparc/config.in
+--- linux-2.4.18/arch/sparc/config.in	Tue Jun 12 04:15:27 2001
++++ linux-2.4.18-mh9/arch/sparc/config.in	Mon Aug 25 18:38:10 2003
+@@ -251,9 +251,7 @@
+ 
+ source fs/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Watchdog'
+diff -urN linux-2.4.18/arch/sparc64/config.in linux-2.4.18-mh9/arch/sparc64/config.in
+--- linux-2.4.18/arch/sparc64/config.in	Fri Dec 21 18:41:53 2001
++++ linux-2.4.18-mh9/arch/sparc64/config.in	Mon Aug 25 18:38:10 2003
+@@ -283,9 +283,7 @@
+ 
+ source drivers/usb/Config.in
+ 
+-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+-   source net/bluetooth/Config.in
+-fi
++source net/bluetooth/Config.in
+ 
+ mainmenu_option next_comment
+ comment 'Watchdog'
+diff -urN linux-2.4.18/arch/sparc64/kernel/ioctl32.c linux-2.4.18-mh9/arch/sparc64/kernel/ioctl32.c
+--- linux-2.4.18/arch/sparc64/kernel/ioctl32.c	Mon Feb 25 20:37:56 2002
++++ linux-2.4.18-mh9/arch/sparc64/kernel/ioctl32.c	Mon Aug 25 18:38:10 2003
+@@ -92,6 +92,7 @@
+ 
+ #include <net/bluetooth/bluetooth.h>
+ #include <net/bluetooth/hci.h>
++#include <net/bluetooth/rfcomm.h>
+ 
+ #include <linux/usb.h>
+ #include <linux/usbdevice_fs.h>
+@@ -3822,6 +3823,15 @@
+ 	return err;
+ }
+ 
++/* Bluetooth ioctls */
++#define HCIUARTSETPROTO	_IOW('U', 200, int)
++#define HCIUARTGETPROTO	_IOR('U', 201, int)
++
++#define BNEPCONNADD	_IOW('B', 200, int)
++#define BNEPCONNDEL	_IOW('B', 201, int)
++#define BNEPGETCONNLIST	_IOR('B', 210, int)
++#define BNEPGETCONNINFO	_IOR('B', 211, int)
++
+ struct mtd_oob_buf32 {
+ 	u32 start;
+ 	u32 length;
+@@ -3878,6 +3888,11 @@
+ 	return ((0 == ret) ? 0 : -EFAULT);
+ }	
+ 
++#define CMTPCONNADD	_IOW('C', 200, int)
++#define CMTPCONNDEL	_IOW('C', 201, int)
++#define CMTPGETCONNLIST	_IOR('C', 210, int)
++#define CMTPGETCONNINFO	_IOR('C', 211, int)
++
+ struct ioctl_trans {
+ 	unsigned int cmd;
+ 	unsigned int handler;
+@@ -4540,6 +4555,21 @@
+ COMPATIBLE_IOCTL(HCISETSCAN)
+ COMPATIBLE_IOCTL(HCISETAUTH)
+ COMPATIBLE_IOCTL(HCIINQUIRY)
++COMPATIBLE_IOCTL(HCIUARTSETPROTO)
++COMPATIBLE_IOCTL(HCIUARTGETPROTO)
++COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
++COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
++COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
++COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
++COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
++COMPATIBLE_IOCTL(BNEPCONNADD)
++COMPATIBLE_IOCTL(BNEPCONNDEL)
++COMPATIBLE_IOCTL(BNEPGETCONNLIST)
++COMPATIBLE_IOCTL(BNEPGETCONNINFO)
++COMPATIBLE_IOCTL(CMTPCONNADD)
++COMPATIBLE_IOCTL(CMTPCONNDEL)
++COMPATIBLE_IOCTL(CMTPGETCONNLIST)
++COMPATIBLE_IOCTL(CMTPGETCONNINFO)
+ /* Misc. */
+ COMPATIBLE_IOCTL(0x41545900)		/* ATYIO_CLKR */
+ COMPATIBLE_IOCTL(0x41545901)		/* ATYIO_CLKW */
+diff -urN linux-2.4.18/drivers/bluetooth/Config.in linux-2.4.18-mh9/drivers/bluetooth/Config.in
+--- linux-2.4.18/drivers/bluetooth/Config.in	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/drivers/bluetooth/Config.in	Mon Aug 25 18:38:10 2003
+@@ -1,8 +1,34 @@
++#
++# Bluetooth HCI device drivers configuration
++#
++
+ mainmenu_option next_comment
+ comment 'Bluetooth device drivers'
+ 
+ dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
++if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
++   bool '  SCO (voice) support'  CONFIG_BLUEZ_USB_SCO
++   bool '  USB zero packet support'  CONFIG_BLUEZ_USB_ZERO_PACKET
++fi
++
+ dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
+-dep_tristate 'HCI VHCI virtual HCI device driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
++if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
++   bool '  UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
++   bool '  BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
++   dep_bool '  Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP
++fi
++
++dep_tristate 'HCI BlueFRITZ! USB driver' CONFIG_BLUEZ_HCIBFUSB $CONFIG_BLUEZ $CONFIG_USB
++
++dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ
++
++dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
+ 
+ endmenu
++
+diff -urN linux-2.4.18/drivers/bluetooth/Makefile linux-2.4.18-mh9/drivers/bluetooth/Makefile
+--- linux-2.4.18/drivers/bluetooth/Makefile	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/drivers/bluetooth/Makefile	Mon Aug 25 18:38:10 2003
+@@ -1,11 +1,27 @@
+ #
+-# Makefile for Bluetooth HCI device drivers.
++# Makefile for the Linux Bluetooth HCI device drivers
+ #
+ 
+ O_TARGET	:= bluetooth.o
+ 
++list-multi	:= hci_uart.o
++
+ obj-$(CONFIG_BLUEZ_HCIUSB)	+= hci_usb.o
+-obj-$(CONFIG_BLUEZ_HCIUART)	+= hci_uart.o
+ obj-$(CONFIG_BLUEZ_HCIVHCI)	+= hci_vhci.o
+ 
++obj-$(CONFIG_BLUEZ_HCIUART)		+= hci_uart.o
++uart-y					:= hci_ldisc.o
++uart-$(CONFIG_BLUEZ_HCIUART_H4)		+= hci_h4.o
++uart-$(CONFIG_BLUEZ_HCIUART_BCSP)	+= hci_bcsp.o
++
++obj-$(CONFIG_BLUEZ_HCIBFUSB)	+= bfusb.o
++
++obj-$(CONFIG_BLUEZ_HCIDTL1)	+= dtl1_cs.o
++obj-$(CONFIG_BLUEZ_HCIBT3C)	+= bt3c_cs.o
++obj-$(CONFIG_BLUEZ_HCIBLUECARD)	+= bluecard_cs.o
++obj-$(CONFIG_BLUEZ_HCIBTUART)	+= btuart_cs.o
++
+ include $(TOPDIR)/Rules.make
++
++hci_uart.o: $(uart-y)
++	$(LD) -r -o $@ $(uart-y)
+diff -urN linux-2.4.18/drivers/bluetooth/Makefile.lib linux-2.4.18-mh9/drivers/bluetooth/Makefile.lib
+--- linux-2.4.18/drivers/bluetooth/Makefile.lib	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/Makefile.lib	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1 @@
++obj-$(CONFIG_BLUEZ_HCIBFUSB) += firmware_class.o
+diff -urN linux-2.4.18/drivers/bluetooth/bfusb.c linux-2.4.18-mh9/drivers/bluetooth/bfusb.c
+--- linux-2.4.18/drivers/bluetooth/bfusb.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/bfusb.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,781 @@
++/*
++ *
++ *  AVM BlueFRITZ! USB driver
++ *
++ *  Copyright (C) 2003  Marcel Holtmann <marcel@holtmann.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
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/skbuff.h>
++
++#include <linux/firmware.h>
++#include <linux/usb.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++#ifndef CONFIG_BLUEZ_HCIBFUSB_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define VERSION "1.1"
++
++static struct usb_device_id bfusb_table[] = {
++	/* AVM BlueFRITZ! USB */
++	{ USB_DEVICE(0x057c, 0x2200) },
++
++	{ }	/* Terminating entry */
++};
++
++MODULE_DEVICE_TABLE(usb, bfusb_table);
++
++
++#define BFUSB_MAX_BLOCK_SIZE	256
++
++#define BFUSB_BLOCK_TIMEOUT	(HZ * 3)
++
++#define BFUSB_TX_PROCESS	1
++#define BFUSB_TX_WAKEUP		2
++
++#define BFUSB_MAX_BULK_TX	1
++#define BFUSB_MAX_BULK_RX	1
++
++struct bfusb {
++	struct hci_dev		hdev;
++
++	unsigned long		state;
++
++	struct usb_device	*udev;
++
++	unsigned int		bulk_in_ep;
++	unsigned int		bulk_out_ep;
++	unsigned int		bulk_pkt_size;
++
++	rwlock_t		lock;
++
++	struct sk_buff_head	transmit_q;
++
++	struct sk_buff		*reassembly;
++
++	atomic_t		pending_tx;
++	struct sk_buff_head	pending_q;
++	struct sk_buff_head	completed_q;
++};
++
++struct bfusb_scb {
++	struct urb *urb;
++};
++
++static void bfusb_tx_complete(struct urb *urb);
++static void bfusb_rx_complete(struct urb *urb);
++
++static struct urb *bfusb_get_completed(struct bfusb *bfusb)
++{
++	struct sk_buff *skb;
++	struct urb *urb = NULL;
++
++	BT_DBG("bfusb %p", bfusb);
++
++	skb = skb_dequeue(&bfusb->completed_q);
++	if (skb) {
++		urb = ((struct bfusb_scb *) skb->cb)->urb;
++		kfree_skb(skb);
++	}
++
++	return urb;
++}
++
++static inline void bfusb_unlink_urbs(struct bfusb *bfusb)
++{
++	struct sk_buff *skb;
++	struct urb *urb;
++
++	BT_DBG("bfusb %p", bfusb);
++
++	while ((skb = skb_dequeue(&bfusb->pending_q))) {
++		urb = ((struct bfusb_scb *) skb->cb)->urb;
++		usb_unlink_urb(urb);
++		skb_queue_tail(&bfusb->completed_q, skb);
++	}
++
++	while ((urb = bfusb_get_completed(bfusb)))
++		usb_free_urb(urb);
++}
++
++
++static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
++{
++	struct bfusb_scb *scb = (void *) skb->cb;
++	struct urb *urb = bfusb_get_completed(bfusb);
++	int err, pipe;
++
++	BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
++
++	if (!urb && !(urb = usb_alloc_urb(0)))
++		return -ENOMEM;
++
++	pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
++
++	FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, skb->len,
++			bfusb_tx_complete, skb);
++
++	urb->transfer_flags = USB_QUEUE_BULK;
++
++	scb->urb = urb;
++
++	skb_queue_tail(&bfusb->pending_q, skb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk tx submit failed urb %p err %d", 
++					bfusb->hdev.name, urb, err);
++		skb_unlink(skb);
++		usb_free_urb(urb);
++	} else
++		atomic_inc(&bfusb->pending_tx);
++
++	return err;
++}
++
++static void bfusb_tx_wakeup(struct bfusb *bfusb)
++{
++	struct sk_buff *skb;
++
++	BT_DBG("bfusb %p", bfusb);
++
++	if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
++		set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
++		return;
++	}
++
++	do {
++		clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
++
++		while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
++				(skb = skb_dequeue(&bfusb->transmit_q))) {
++			if (bfusb_send_bulk(bfusb, skb) < 0) {
++				skb_queue_head(&bfusb->transmit_q, skb);
++				break;
++			}
++		}
++
++	} while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
++
++	clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
++}
++
++static void bfusb_tx_complete(struct urb *urb)
++{
++	struct sk_buff *skb = (struct sk_buff *) urb->context;
++	struct bfusb *bfusb = (struct bfusb *) skb->dev;
++
++	BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
++
++	atomic_dec(&bfusb->pending_tx);
++
++	if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
++		return;
++
++	if (!urb->status)
++		bfusb->hdev.stat.byte_tx += skb->len;
++	else
++		bfusb->hdev.stat.err_tx++;
++
++	read_lock(&bfusb->lock);
++
++	skb_unlink(skb);
++	skb_queue_tail(&bfusb->completed_q, skb);
++
++	bfusb_tx_wakeup(bfusb);
++
++	read_unlock(&bfusb->lock);
++}
++
++
++static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
++{
++	struct bfusb_scb *scb;
++	struct sk_buff *skb;
++	int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
++
++	BT_DBG("bfusb %p urb %p", bfusb, urb);
++
++	if (!urb && !(urb = usb_alloc_urb(0)))
++		return -ENOMEM;
++
++	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
++		usb_free_urb(urb);
++		return -ENOMEM;
++	}
++
++	skb->dev = (void *) bfusb;
++
++	scb = (struct bfusb_scb *) skb->cb;
++	scb->urb = urb;
++
++	pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
++
++	FILL_BULK_URB(urb, bfusb->udev, pipe, skb->data, size,
++			bfusb_rx_complete, skb);
++
++	urb->transfer_flags = USB_QUEUE_BULK;
++
++	skb_queue_tail(&bfusb->pending_q, skb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk rx submit failed urb %p err %d",
++					bfusb->hdev.name, urb, err);
++		skb_unlink(skb);
++		kfree_skb(skb);
++		usb_free_urb(urb);
++	}
++
++	return err;
++}
++
++static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
++{
++	BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
++
++	if (hdr & 0x10) {
++		BT_ERR("%s error in block", bfusb->hdev.name);
++		if (bfusb->reassembly)
++			kfree_skb(bfusb->reassembly);
++		bfusb->reassembly = NULL;
++		return -EIO;
++	}
++
++	if (hdr & 0x04) {
++		struct sk_buff *skb;
++		unsigned char pkt_type;
++		int pkt_len = 0;
++
++		if (bfusb->reassembly) {
++			BT_ERR("%s unexpected start block", bfusb->hdev.name);
++			kfree_skb(bfusb->reassembly);
++			bfusb->reassembly = NULL;
++		}
++
++		if (len < 1) {
++			BT_ERR("%s no packet type found", bfusb->hdev.name);
++			return -EPROTO;
++		}
++
++		pkt_type = *data++; len--;
++
++		switch (pkt_type) {
++		case HCI_EVENT_PKT:
++			if (len >= HCI_EVENT_HDR_SIZE) {
++				hci_event_hdr *hdr = (hci_event_hdr *) data;
++				pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
++			} else {
++				BT_ERR("%s event block is too short", bfusb->hdev.name);
++				return -EILSEQ;
++			}
++			break;
++
++		case HCI_ACLDATA_PKT:
++			if (len >= HCI_ACL_HDR_SIZE) {
++				hci_acl_hdr *hdr = (hci_acl_hdr *) data;
++				pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
++			} else {
++				BT_ERR("%s data block is too short", bfusb->hdev.name);
++				return -EILSEQ;
++			}
++			break;
++
++		case HCI_SCODATA_PKT:
++			if (len >= HCI_SCO_HDR_SIZE) {
++				hci_sco_hdr *hdr = (hci_sco_hdr *) data;
++				pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
++			} else {
++				BT_ERR("%s audio block is too short", bfusb->hdev.name);
++				return -EILSEQ;
++			}
++			break;
++		}
++
++		skb = bluez_skb_alloc(pkt_len, GFP_ATOMIC);
++		if (!skb) {
++			BT_ERR("%s no memory for the packet", bfusb->hdev.name);
++			return -ENOMEM;
++		}
++
++		skb->dev = (void *) &bfusb->hdev;
++		skb->pkt_type = pkt_type;
++
++		bfusb->reassembly = skb;
++	} else {
++		if (!bfusb->reassembly) {
++			BT_ERR("%s unexpected continuation block", bfusb->hdev.name);
++			return -EIO;
++		}
++	}
++
++	if (len > 0)
++		memcpy(skb_put(bfusb->reassembly, len), data, len);
++
++	if (hdr & 0x08) {
++		hci_recv_frame(bfusb->reassembly);
++		bfusb->reassembly = NULL;
++	}
++
++	return 0;
++}
++
++static void bfusb_rx_complete(struct urb *urb)
++{
++	struct sk_buff *skb = (struct sk_buff *) urb->context;
++	struct bfusb *bfusb = (struct bfusb *) skb->dev;
++	unsigned char *buf = urb->transfer_buffer;
++	int count = urb->actual_length;
++	int err, hdr, len;
++
++	BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
++
++	if (!test_bit(HCI_RUNNING, &bfusb->hdev.flags))
++		return;
++
++	read_lock(&bfusb->lock);
++
++	if (urb->status || !count)
++		goto resubmit;
++
++	bfusb->hdev.stat.byte_rx += count;
++
++	skb_put(skb, count);
++
++	while (count) {
++		hdr = buf[0] | (buf[1] << 8);
++
++		if (hdr & 0x4000) {
++			len = 0;
++			count -= 2;
++			buf   += 2;
++		} else {
++			len = (buf[2] == 0) ? 256 : buf[2];
++			count -= 3;
++			buf   += 3;
++		}
++
++		if (count < len) {
++			BT_ERR("%s block extends over URB buffer ranges",
++					bfusb->hdev.name);
++		}
++
++		if ((hdr & 0xe1) == 0xc1)
++			bfusb_recv_block(bfusb, hdr, buf, len);
++
++		count -= len;
++		buf   += len;
++	}
++
++	skb_unlink(skb);
++	kfree_skb(skb);
++
++	bfusb_rx_submit(bfusb, urb);
++
++	read_unlock(&bfusb->lock);
++
++	return;
++
++resubmit:
++	urb->dev = bfusb->udev;
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk resubmit failed urb %p err %d",
++					bfusb->hdev.name, urb, err);
++	}
++
++	read_unlock(&bfusb->lock);
++}
++
++
++static int bfusb_open(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++	unsigned long flags;
++	int i, err;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
++	MOD_INC_USE_COUNT;
++
++	write_lock_irqsave(&bfusb->lock, flags);
++
++	err = bfusb_rx_submit(bfusb, NULL);
++	if (!err) {
++		for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
++			bfusb_rx_submit(bfusb, NULL);
++	} else {
++		clear_bit(HCI_RUNNING, &hdev->flags);
++		MOD_DEC_USE_COUNT;
++	}
++
++	write_unlock_irqrestore(&bfusb->lock, flags);
++
++	return err;
++}
++
++static int bfusb_flush(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	skb_queue_purge(&bfusb->transmit_q);
++
++	return 0;
++}
++
++static int bfusb_close(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++	unsigned long flags;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
++	write_lock_irqsave(&bfusb->lock, flags);
++
++	bfusb_unlink_urbs(bfusb);
++	bfusb_flush(hdev);
++
++	write_unlock_irqrestore(&bfusb->lock, flags);
++
++	MOD_DEC_USE_COUNT;
++
++	return 0;
++}
++
++static int bfusb_send_frame(struct sk_buff *skb)
++{
++	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
++	struct bfusb *bfusb;
++	struct sk_buff *nskb;
++	unsigned char buf[3];
++	int sent = 0, size, count;
++
++	BT_DBG("hdev %p skb %p type %d len %d", hdev, skb, skb->pkt_type, skb->len);
++
++	if (!hdev) {
++		BT_ERR("Frame for unknown HCI device (hdev=NULL)");
++		return -ENODEV;
++	}
++
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return -EBUSY;
++
++	bfusb = (struct bfusb *) hdev->driver_data;
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++
++	count = skb->len;
++
++	/* Max HCI frame size seems to be 1511 + 1 */
++	if (!(nskb = bluez_skb_alloc(count + 32, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for new packet");
++		return -ENOMEM;
++	}
++
++	nskb->dev = (void *) bfusb;
++
++	while (count) {
++		size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
++
++		buf[0] = 0xc1 | ((sent == 0) ? 0x04 : 0) | ((count == size) ? 0x08 : 0);
++		buf[1] = 0x00;
++		buf[2] = (size == BFUSB_MAX_BLOCK_SIZE) ? 0 : size;
++
++		memcpy(skb_put(nskb, 3), buf, 3);
++		memcpy(skb_put(nskb, size), skb->data + sent, size);
++
++		sent  += size;
++		count -= size;
++	}
++
++	/* Don't send frame with multiple size of bulk max packet */
++	if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
++		buf[0] = 0xdd;
++		buf[1] = 0x00;
++		memcpy(skb_put(nskb, 2), buf, 2);
++	}
++
++	read_lock(&bfusb->lock);
++
++	skb_queue_tail(&bfusb->transmit_q, nskb);
++	bfusb_tx_wakeup(bfusb);
++
++	read_unlock(&bfusb->lock);
++
++	kfree_skb(skb);
++
++	return 0;
++}
++
++static void bfusb_destruct(struct hci_dev *hdev)
++{
++	struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
++
++	BT_DBG("hdev %p bfusb %p", hdev, bfusb);
++
++	kfree(bfusb);
++}
++
++static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
++{
++	unsigned char *buf;
++	int err, pipe, len, size, sent = 0;
++
++	BT_DBG("bfusb %p udev %p firmware %p count %d", bfusb, bfusb->udev, firmware, count);
++
++	BT_INFO("BlueFRITZ! USB loading firmware");
++
++	if (usb_set_configuration(bfusb->udev, 1) < 0) {
++		BT_ERR("Can't change to loading configuration");
++		return -EBUSY;
++	}
++
++	buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
++	if (!buf) {
++		BT_ERR("Can't allocate memory chunk for firmware");
++		return -ENOMEM;
++	}
++
++	pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
++
++	while (count) {
++		size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
++
++		memcpy(buf, firmware + sent, size);
++
++		err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
++					&len, BFUSB_BLOCK_TIMEOUT);
++
++		if (err || (len != size)) {
++			BT_ERR("Error in firmware loading");
++			goto error;
++		}
++
++		sent  += size;
++		count -= size;
++	}
++
++	if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
++				&len, BFUSB_BLOCK_TIMEOUT)) < 0) {
++		BT_ERR("Error in null packet request");
++		goto error;
++	}
++
++	if ((err = usb_set_configuration(bfusb->udev, 2)) < 0) {
++		BT_ERR("Can't change to running configuration");
++		goto error;
++	}
++
++	BT_INFO("BlueFRITZ! USB device ready");
++
++	kfree(buf);
++	return 0;
++
++error:
++	kfree(buf);
++
++	pipe = usb_sndctrlpipe(bfusb->udev, 0);
++
++	usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
++				0, 0, 0, NULL, 0, BFUSB_BLOCK_TIMEOUT);
++
++	return err;
++}
++
++static void *bfusb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
++{
++	const struct firmware *firmware;
++	char device[16];
++	struct usb_interface *iface;
++	struct usb_interface_descriptor *iface_desc;
++	struct usb_endpoint_descriptor *bulk_out_ep;
++	struct usb_endpoint_descriptor *bulk_in_ep;
++	struct hci_dev *hdev;
++	struct bfusb *bfusb;
++
++	BT_DBG("udev %p ifnum %d id %p", udev, ifnum, id);
++
++	/* Check number of endpoints */
++	iface = &udev->actconfig->interface[0];
++	iface_desc = &iface->altsetting[0];
++
++	if (iface_desc->bNumEndpoints < 2)
++		return NULL;
++
++	bulk_out_ep = &iface_desc->endpoint[0];
++	bulk_in_ep  = &iface_desc->endpoint[1];
++
++	if (!bulk_out_ep || !bulk_in_ep) {
++		BT_ERR("Bulk endpoints not found");
++		goto done;
++	}
++
++	/* Initialize control structure and load firmware */
++	if (!(bfusb = kmalloc(sizeof(struct bfusb), GFP_KERNEL))) {
++		BT_ERR("Can't allocate memory for control structure");
++		goto done;
++	}
++
++	memset(bfusb, 0, sizeof(struct bfusb));
++
++	bfusb->udev = udev;
++	bfusb->bulk_in_ep    = bulk_in_ep->bEndpointAddress;
++	bfusb->bulk_out_ep   = bulk_out_ep->bEndpointAddress;
++	bfusb->bulk_pkt_size = bulk_out_ep->wMaxPacketSize;
++
++	bfusb->lock = RW_LOCK_UNLOCKED;
++
++	bfusb->reassembly = NULL;
++
++	skb_queue_head_init(&bfusb->transmit_q);
++	skb_queue_head_init(&bfusb->pending_q);
++	skb_queue_head_init(&bfusb->completed_q);
++
++	snprintf(device, sizeof(device), "bfusb%3.3d%3.3d", udev->bus->busnum, udev->devnum);
++
++	if (request_firmware(&firmware, "bfubase.frm", device) < 0) {
++		BT_ERR("Firmware request failed");
++		goto error;
++	}
++
++	if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
++		BT_ERR("Firmware loading failed");
++		goto release;
++	}
++
++	release_firmware(firmware);
++
++	/* Initialize and register HCI device */
++	hdev = &bfusb->hdev;
++
++	hdev->type = HCI_USB;
++	hdev->driver_data = bfusb;
++
++	hdev->open     = bfusb_open;
++	hdev->close    = bfusb_close;
++	hdev->flush    = bfusb_flush;
++	hdev->send     = bfusb_send_frame;
++	hdev->destruct = bfusb_destruct;
++	hdev->ioctl    = bfusb_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		BT_ERR("Can't register HCI device");
++		goto error;
++	}
++
++	return bfusb;
++
++release:
++	release_firmware(firmware);
++
++error:
++	kfree(bfusb);
++
++done:
++	return NULL;
++}
++
++static void bfusb_disconnect(struct usb_device *udev, void *ptr)
++{
++	struct bfusb *bfusb = (struct bfusb *) ptr;
++	struct hci_dev *hdev = &bfusb->hdev;
++
++	BT_DBG("udev %p ptr %p", udev, ptr);
++
++	if (!hdev)
++		return;
++
++	bfusb_close(hdev);
++
++	if (hci_unregister_dev(hdev) < 0)
++		BT_ERR("Can't unregister HCI device %s", hdev->name);
++}
++
++static struct usb_driver bfusb_driver = {
++	name:		"bfusb",
++	probe:		bfusb_probe,
++	disconnect:	bfusb_disconnect,
++	id_table:	bfusb_table,
++};
++
++static int __init bfusb_init(void)
++{
++	int err;
++
++	BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
++	BT_INFO("Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>");
++
++	if ((err = usb_register(&bfusb_driver)) < 0)
++		BT_ERR("Failed to register BlueFRITZ! USB driver");
++
++	return err;
++}
++
++static void __exit bfusb_cleanup(void)
++{
++	usb_deregister(&bfusb_driver);
++}
++
++module_init(bfusb_init);
++module_exit(bfusb_cleanup);
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueFRITZ! USB driver ver " VERSION);
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/drivers/bluetooth/bluecard_cs.c linux-2.4.18-mh9/drivers/bluetooth/bluecard_cs.c
+--- linux-2.4.18/drivers/bluetooth/bluecard_cs.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/bluecard_cs.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,1113 @@
++/*
++ *
++ *  Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++#include <linux/skbuff.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0x86bc;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct bluecard_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;		/* For serializing operations */
++	struct timer_list timer;	/* For LED control */
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++
++	unsigned char ctrl_reg;
++	unsigned long hw_state;		/* Status of the hardware and LED control */
++} bluecard_info_t;
++
++
++void bluecard_config(dev_link_t *link);
++void bluecard_release(u_long arg);
++int bluecard_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "bluecard_cs";
++
++dev_link_t *bluecard_attach(void);
++void bluecard_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Default baud rate: 57600, 115200, 230400 or 460800 */
++#define DEFAULT_BAUD_RATE  230400
++
++
++/* Hardware states */
++#define CARD_READY             1
++#define CARD_HAS_PCCARD_ID     4
++#define CARD_HAS_POWER_LED     5
++#define CARD_HAS_ACTIVITY_LED  6
++
++/* Transmit states  */
++#define XMIT_SENDING         1
++#define XMIT_WAKEUP          2
++#define XMIT_BUFFER_NUMBER   5	/* unset = buffer one, set = buffer two */
++#define XMIT_BUF_ONE_READY   6
++#define XMIT_BUF_TWO_READY   7
++#define XMIT_SENDING_READY   8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE   0
++#define RECV_WAIT_EVENT_HEADER  1
++#define RECV_WAIT_ACL_HEADER    2
++#define RECV_WAIT_SCO_HEADER    3
++#define RECV_WAIT_DATA          4
++
++/* Special packet types */
++#define PKT_BAUD_RATE_57600   0x80
++#define PKT_BAUD_RATE_115200  0x81
++#define PKT_BAUD_RATE_230400  0x82
++#define PKT_BAUD_RATE_460800  0x83
++
++
++/* These are the register offsets */
++#define REG_COMMAND     0x20
++#define REG_INTERRUPT   0x21
++#define REG_CONTROL     0x22
++#define REG_RX_CONTROL  0x24
++#define REG_CARD_RESET  0x30
++#define REG_LED_CTRL    0x30
++
++/* REG_COMMAND */
++#define REG_COMMAND_TX_BUF_ONE  0x01
++#define REG_COMMAND_TX_BUF_TWO  0x02
++#define REG_COMMAND_RX_BUF_ONE  0x04
++#define REG_COMMAND_RX_BUF_TWO  0x08
++#define REG_COMMAND_RX_WIN_ONE  0x00
++#define REG_COMMAND_RX_WIN_TWO  0x10
++
++/* REG_CONTROL */
++#define REG_CONTROL_BAUD_RATE_57600   0x00
++#define REG_CONTROL_BAUD_RATE_115200  0x01
++#define REG_CONTROL_BAUD_RATE_230400  0x02
++#define REG_CONTROL_BAUD_RATE_460800  0x03
++#define REG_CONTROL_RTS               0x04
++#define REG_CONTROL_BT_ON             0x08
++#define REG_CONTROL_BT_RESET          0x10
++#define REG_CONTROL_BT_RES_PU         0x20
++#define REG_CONTROL_INTERRUPT         0x40
++#define REG_CONTROL_CARD_RESET        0x80
++
++/* REG_RX_CONTROL */
++#define RTS_LEVEL_SHIFT_BITS  0x02
++
++
++
++/* ======================== LED handling routines ======================== */
++
++
++void bluecard_activity_led_timeout(u_long arg)
++{
++	bluecard_info_t *info = (bluecard_info_t *)arg;
++	unsigned int iobase = info->link.io.BasePort1;
++
++	if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
++		/* Disable activity LED */
++		outb(0x08 | 0x20, iobase + 0x30);
++	} else {
++		/* Disable power LED */
++		outb(0x00, iobase + 0x30);
++	}
++}
++
++
++static void bluecard_enable_activity_led(bluecard_info_t *info)
++{
++	unsigned int iobase = info->link.io.BasePort1;
++
++	if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
++		/* Enable activity LED */
++		outb(0x10 | 0x40, iobase + 0x30);
++
++		/* Stop the LED after HZ/4 */
++		mod_timer(&(info->timer), jiffies + HZ / 4);
++	} else {
++		/* Enable power LED */
++		outb(0x08 | 0x20, iobase + 0x30);
++
++		/* Stop the LED after HZ/2 */
++		mod_timer(&(info->timer), jiffies + HZ / 2);
++	}
++}
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
++{
++	int i, actual;
++
++	actual = (len > 15) ? 15 : len;
++
++	outb_p(actual, iobase + offset);
++
++	for (i = 0; i < actual; i++)
++		outb_p(buf[i], iobase + offset + i + 1);
++
++	return actual;
++}
++
++
++static void bluecard_write_wakeup(bluecard_info_t *info)
++{
++	if (!info) {
++		printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
++		return;
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register unsigned int offset;
++		register unsigned char command;
++		register unsigned long ready_bit;
++		register struct sk_buff *skb;
++		register int len;
++
++		clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (!(info->link.state & DEV_PRESENT))
++			return;
++
++		if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
++			if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
++				break;
++			offset = 0x10;
++			command = REG_COMMAND_TX_BUF_TWO;
++			ready_bit = XMIT_BUF_TWO_READY;
++		} else {
++			if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
++				break;
++			offset = 0x00;
++			command = REG_COMMAND_TX_BUF_ONE;
++			ready_bit = XMIT_BUF_ONE_READY;
++		}
++
++		if (!(skb = skb_dequeue(&(info->txq))))
++			break;
++
++		if (skb->pkt_type & 0x80) {
++			/* Disable RTS */
++			info->ctrl_reg |= REG_CONTROL_RTS;
++			outb(info->ctrl_reg, iobase + REG_CONTROL);
++		}
++
++		/* Activate LED */
++		bluecard_enable_activity_led(info);
++
++		/* Send frame */
++		len = bluecard_write(iobase, offset, skb->data, skb->len);
++
++		/* Tell the FPGA to send the data */
++		outb_p(command, iobase + REG_COMMAND);
++
++		/* Mark the buffer as dirty */
++		clear_bit(ready_bit, &(info->tx_state));
++
++		if (skb->pkt_type & 0x80) {
++
++			wait_queue_head_t wait;
++			unsigned char baud_reg;
++
++			switch (skb->pkt_type) {
++			case PKT_BAUD_RATE_460800:
++				baud_reg = REG_CONTROL_BAUD_RATE_460800;
++				break;
++			case PKT_BAUD_RATE_230400:
++				baud_reg = REG_CONTROL_BAUD_RATE_230400;
++				break;
++			case PKT_BAUD_RATE_115200:
++				baud_reg = REG_CONTROL_BAUD_RATE_115200;
++				break;
++			case PKT_BAUD_RATE_57600:
++				/* Fall through... */
++			default:
++				baud_reg = REG_CONTROL_BAUD_RATE_57600;
++				break;
++			}
++
++			/* Wait until the command reaches the baseband */
++			init_waitqueue_head(&wait);
++			interruptible_sleep_on_timeout(&wait, HZ / 10);
++
++			/* Set baud on baseband */
++			info->ctrl_reg &= ~0x03;
++			info->ctrl_reg |= baud_reg;
++			outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++			/* Enable RTS */
++			info->ctrl_reg &= ~REG_CONTROL_RTS;
++			outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++			/* Wait before the next HCI packet can be send */
++			interruptible_sleep_on_timeout(&wait, HZ);
++
++		}
++
++		if (len == skb->len) {
++			kfree_skb(skb);
++		} else {
++			skb_pull(skb, len);
++			skb_queue_head(&(info->txq), skb);
++		}
++
++		info->hdev.stat.byte_tx += len;
++
++		/* Change buffer */
++		change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
++
++	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++	clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
++{
++	int i, n, len;
++
++	outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
++
++	len = inb(iobase + offset);
++	n = 0;
++	i = 1;
++
++	while (n < len) {
++
++		if (i == 16) {
++			outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
++			i = 0;
++		}
++
++		buf[n] = inb(iobase + offset + i);
++
++		n++;
++		i++;
++
++	}
++
++	return len;
++}
++
++
++static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
++{
++	unsigned int iobase;
++	unsigned char buf[31];
++	int i, len;
++
++	if (!info) {
++		printk(KERN_WARNING "bluecard_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
++		bluecard_enable_activity_led(info);
++
++	len = bluecard_read(iobase, offset, buf, sizeof(buf));
++
++	for (i = 0; i < len; i++) {
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL) {
++			info->rx_state = RECV_WAIT_PACKET_TYPE;
++			info->rx_count = 0;
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
++				return;
++			}
++		}
++
++		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++			info->rx_skb->dev = (void *)&(info->hdev);
++			info->rx_skb->pkt_type = buf[i];
++
++			switch (info->rx_skb->pkt_type) {
++
++			case 0x00:
++				/* init packet */
++				if (offset != 0x00) {
++					set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
++					set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
++					set_bit(XMIT_SENDING_READY, &(info->tx_state));
++					bluecard_write_wakeup(info);
++				}
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			case HCI_EVENT_PKT:
++				info->rx_state = RECV_WAIT_EVENT_HEADER;
++				info->rx_count = HCI_EVENT_HDR_SIZE;
++				break;
++
++			case HCI_ACLDATA_PKT:
++				info->rx_state = RECV_WAIT_ACL_HEADER;
++				info->rx_count = HCI_ACL_HDR_SIZE;
++				break;
++
++			case HCI_SCODATA_PKT:
++				info->rx_state = RECV_WAIT_SCO_HEADER;
++				info->rx_count = HCI_SCO_HDR_SIZE;
++				break;
++
++			default:
++				/* unknown packet */
++				printk(KERN_WARNING "bluecard_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++				info->hdev.stat.err_rx++;
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			}
++
++		} else {
++
++			*skb_put(info->rx_skb, 1) = buf[i];
++			info->rx_count--;
++
++			if (info->rx_count == 0) {
++
++				int dlen;
++				hci_event_hdr *eh;
++				hci_acl_hdr *ah;
++				hci_sco_hdr *sh;
++
++				switch (info->rx_state) {
++
++				case RECV_WAIT_EVENT_HEADER:
++					eh = (hci_event_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = eh->plen;
++					break;
++
++				case RECV_WAIT_ACL_HEADER:
++					ah = (hci_acl_hdr *)(info->rx_skb->data);
++					dlen = __le16_to_cpu(ah->dlen);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = dlen;
++					break;
++
++				case RECV_WAIT_SCO_HEADER:
++					sh = (hci_sco_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = sh->dlen;
++					break;
++
++				case RECV_WAIT_DATA:
++					hci_recv_frame(info->rx_skb);
++					info->rx_skb = NULL;
++					break;
++
++				}
++
++			}
++
++		}
++
++
++	}
++
++	info->hdev.stat.byte_rx += len;
++}
++
++
++void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	bluecard_info_t *info = dev_inst;
++	unsigned int iobase;
++	unsigned char reg;
++
++	if (!info) {
++		printk(KERN_WARNING "bluecard_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	if (!test_bit(CARD_READY, &(info->hw_state)))
++		return;
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	/* Disable interrupt */
++	info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	reg = inb(iobase + REG_INTERRUPT);
++
++	if ((reg != 0x00) && (reg != 0xff)) {
++
++		if (reg & 0x04) {
++			bluecard_receive(info, 0x00);
++			outb(0x04, iobase + REG_INTERRUPT);
++			outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
++		}
++
++		if (reg & 0x08) {
++			bluecard_receive(info, 0x10);
++			outb(0x08, iobase + REG_INTERRUPT);
++			outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
++		}
++
++		if (reg & 0x01) {
++			set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
++			outb(0x01, iobase + REG_INTERRUPT);
++			bluecard_write_wakeup(info);
++		}
++
++		if (reg & 0x02) {
++			set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
++			outb(0x02, iobase + REG_INTERRUPT);
++			bluecard_write_wakeup(info);
++		}
++
++	}
++
++	/* Enable interrupt */
++	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	spin_unlock(&(info->lock));
++}
++
++
++
++/* ======================== Device specific HCI commands ======================== */
++
++
++static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++	struct sk_buff *skb;
++
++	/* Ericsson baud rate command */
++	unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
++
++	if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++		printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
++		return -1;
++	}
++
++	switch (baud) {
++	case 460800:
++		cmd[4] = 0x00;
++		skb->pkt_type = PKT_BAUD_RATE_460800;
++		break;
++	case 230400:
++		cmd[4] = 0x01;
++		skb->pkt_type = PKT_BAUD_RATE_230400;
++		break;
++	case 115200:
++		cmd[4] = 0x02;
++		skb->pkt_type = PKT_BAUD_RATE_115200;
++		break;
++	case 57600:
++		/* Fall through... */
++	default:
++		cmd[4] = 0x03;
++		skb->pkt_type = PKT_BAUD_RATE_57600;
++		break;
++	}
++
++	memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
++
++	skb_queue_tail(&(info->txq), skb);
++
++	bluecard_write_wakeup(info);
++
++	return 0;
++}
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int bluecard_hci_flush(struct hci_dev *hdev)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int bluecard_hci_open(struct hci_dev *hdev)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++	unsigned int iobase = info->link.io.BasePort1;
++
++	bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
++
++	if (test_and_set_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	/* Enable LED */
++	outb(0x08 | 0x20, iobase + 0x30);
++
++	return 0;
++}
++
++
++static int bluecard_hci_close(struct hci_dev *hdev)
++{
++	bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data);
++	unsigned int iobase = info->link.io.BasePort1;
++
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	bluecard_hci_flush(hdev);
++
++	/* Disable LED */
++	outb(0x00, iobase + 0x30);
++
++	return 0;
++}
++
++
++static int bluecard_hci_send_frame(struct sk_buff *skb)
++{
++	bluecard_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++	if (!hdev) {
++		printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (bluecard_info_t *)(hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++	skb_queue_tail(&(info->txq), skb);
++
++	bluecard_write_wakeup(info);
++
++	return 0;
++}
++
++
++static void bluecard_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int bluecard_open(bluecard_info_t *info)
++{
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev;
++	unsigned char id;
++
++	spin_lock_init(&(info->lock));
++
++	init_timer(&(info->timer));
++	info->timer.function = &bluecard_activity_led_timeout;
++	info->timer.data = (u_long)info;
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_PACKET_TYPE;
++	info->rx_count = 0;
++	info->rx_skb = NULL;
++
++	id = inb(iobase + 0x30);
++
++	if ((id & 0x0f) == 0x02)
++		set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
++
++	if (id & 0x10)
++		set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
++
++	if (id & 0x20)
++		set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
++
++	/* Reset card */
++	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Turn FPGA off */
++	outb(0x80, iobase + 0x30);
++
++	/* Wait some time */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ / 100);
++
++	/* Turn FPGA on */
++	outb(0x00, iobase + 0x30);
++
++	/* Activate card */
++	info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Enable interrupt */
++	outb(0xff, iobase + REG_INTERRUPT);
++	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Start the RX buffers */
++	outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
++	outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
++
++	/* Signal that the hardware is ready */
++	set_bit(CARD_READY, &(info->hw_state));
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	/* Control the point at which RTS is enabled */
++	outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
++
++	/* Timeout before it is safe to send the first HCI packet */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout((HZ * 5) / 4);		// or set it to 3/2
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = bluecard_hci_open;
++	hdev->close = bluecard_hci_close;
++	hdev->flush = bluecard_hci_flush;
++	hdev->send = bluecard_hci_send_frame;
++	hdev->destruct = bluecard_hci_destruct;
++	hdev->ioctl = bluecard_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "bluecard_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int bluecard_close(bluecard_info_t *info)
++{
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev = &(info->hdev);
++
++	bluecard_hci_close(hdev);
++
++	clear_bit(CARD_READY, &(info->hw_state));
++
++	/* Reset card */
++	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
++	outb(info->ctrl_reg, iobase + REG_CONTROL);
++
++	/* Turn FPGA off */
++	outb(0x80, iobase + 0x30);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "bluecard_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *bluecard_attach(void)
++{
++	bluecard_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &bluecard_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = bluecard_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &bluecard_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		bluecard_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void bluecard_detach(dev_link_t *link)
++{
++	bluecard_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG)
++		bluecard_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void bluecard_config(dev_link_t *link)
++{
++	client_handle_t handle = link->handle;
++	bluecard_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	config_info_t config;
++	int i, n, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	link->conf.ConfigIndex = 0x20;
++	link->io.NumPorts1 = 64;
++	link->io.IOAddrLines = 6;
++
++	for (n = 0; n < 0x400; n += 0x40) {
++		link->io.BasePort1 = n ^ 0x300;
++		i = CardServices(RequestIO, link->handle, &link->io);
++		if (i == CS_SUCCESS)
++			break;
++	}
++
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (bluecard_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	bluecard_release((u_long)link);
++}
++
++
++void bluecard_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	bluecard_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		bluecard_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int bluecard_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	bluecard_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			bluecard_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		bluecard_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_bluecard_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "bluecard_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &bluecard_attach, &bluecard_detach);
++
++	return err;
++}
++
++
++void __exit exit_bluecard_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		bluecard_detach(dev_list);
++}
++
++
++module_init(init_bluecard_cs);
++module_exit(exit_bluecard_cs);
++
++EXPORT_NO_SYMBOLS;
+diff -urN linux-2.4.18/drivers/bluetooth/bt3c_cs.c linux-2.4.18-mh9/drivers/bluetooth/bt3c_cs.c
+--- linux-2.4.18/drivers/bluetooth/bt3c_cs.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/bt3c_cs.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,946 @@
++/*
++ *
++ *  Driver for the 3Com Bluetooth PCMCIA card
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *                           Jose Orlando Pereira <jop@di.uminho.pt>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#define __KERNEL_SYSCALLS__
++
++#include <linux/kernel.h>
++#include <linux/kmod.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/delay.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/unistd.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0xffff;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
++MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct bt3c_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;		/* For serializing operations */
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++} bt3c_info_t;
++
++
++void bt3c_config(dev_link_t *link);
++void bt3c_release(u_long arg);
++int bt3c_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "bt3c_cs";
++
++dev_link_t *bt3c_attach(void);
++void bt3c_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Transmit states  */
++#define XMIT_SENDING  1
++#define XMIT_WAKEUP   2
++#define XMIT_WAITING  8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE   0
++#define RECV_WAIT_EVENT_HEADER  1
++#define RECV_WAIT_ACL_HEADER    2
++#define RECV_WAIT_SCO_HEADER    3
++#define RECV_WAIT_DATA          4
++
++
++
++/* ======================== Special I/O functions ======================== */
++
++
++#define DATA_L   0
++#define DATA_H   1
++#define ADDR_L   2
++#define ADDR_H   3
++#define CONTROL  4
++
++
++inline void bt3c_address(unsigned int iobase, unsigned short addr)
++{
++	outb(addr & 0xff, iobase + ADDR_L);
++	outb((addr >> 8) & 0xff, iobase + ADDR_H);
++}
++
++
++inline void bt3c_put(unsigned int iobase, unsigned short value)
++{
++	outb(value & 0xff, iobase + DATA_L);
++	outb((value >> 8) & 0xff, iobase + DATA_H);
++}
++
++
++inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
++{
++	bt3c_address(iobase, addr);
++	bt3c_put(iobase, value);
++}
++
++
++inline unsigned short bt3c_get(unsigned int iobase)
++{
++	unsigned short value = inb(iobase + DATA_L);
++
++	value |= inb(iobase + DATA_H) << 8;
++
++	return value;
++}
++
++
++inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
++{
++	bt3c_address(iobase, addr);
++
++	return bt3c_get(iobase);
++}
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
++{
++	int actual = 0;
++
++	bt3c_address(iobase, 0x7080);
++
++	/* Fill FIFO with current frame */
++	while (actual < len) {
++		/* Transmit next byte */
++		bt3c_put(iobase, buf[actual]);
++		actual++;
++	}
++
++	bt3c_io_write(iobase, 0x7005, actual);
++
++	return actual;
++}
++
++
++static void bt3c_write_wakeup(bt3c_info_t *info, int from)
++{
++	unsigned long flags;
++
++	if (!info) {
++		printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
++		return;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register struct sk_buff *skb;
++		register int len;
++
++		if (!(info->link.state & DEV_PRESENT))
++			break;
++
++
++		if (!(skb = skb_dequeue(&(info->txq)))) {
++			clear_bit(XMIT_SENDING, &(info->tx_state));
++			break;
++		}
++
++		/* Send frame */
++		len = bt3c_write(iobase, 256, skb->data, skb->len);
++
++		if (len != skb->len) {
++			printk(KERN_WARNING "bt3c_cs: very strange\n");
++		}
++
++		kfree_skb(skb);
++
++		info->hdev.stat.byte_tx += len;
++
++	} while (0);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++}
++
++
++static void bt3c_receive(bt3c_info_t *info)
++{
++	unsigned int iobase;
++	int size = 0, avail;
++
++	if (!info) {
++		printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	avail = bt3c_read(iobase, 0x7006);
++	//printk("bt3c_cs: receiving %d bytes\n", avail);
++
++	bt3c_address(iobase, 0x7480);
++	while (size < avail) {
++		size++;
++		info->hdev.stat.byte_rx++;
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL) {
++			info->rx_state = RECV_WAIT_PACKET_TYPE;
++			info->rx_count = 0;
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
++				return;
++			}
++		}
++
++
++		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++			info->rx_skb->dev = (void *)&(info->hdev);
++			info->rx_skb->pkt_type = inb(iobase + DATA_L);
++			inb(iobase + DATA_H);
++			//printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);
++
++			switch (info->rx_skb->pkt_type) {
++
++			case HCI_EVENT_PKT:
++				info->rx_state = RECV_WAIT_EVENT_HEADER;
++				info->rx_count = HCI_EVENT_HDR_SIZE;
++				break;
++
++			case HCI_ACLDATA_PKT:
++				info->rx_state = RECV_WAIT_ACL_HEADER;
++				info->rx_count = HCI_ACL_HDR_SIZE;
++				break;
++
++			case HCI_SCODATA_PKT:
++				info->rx_state = RECV_WAIT_SCO_HEADER;
++				info->rx_count = HCI_SCO_HDR_SIZE;
++				break;
++
++			default:
++				/* Unknown packet */
++				printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++				info->hdev.stat.err_rx++;
++				clear_bit(HCI_RUNNING, &(info->hdev.flags));
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			}
++
++		} else {
++
++			__u8 x = inb(iobase + DATA_L);
++
++			*skb_put(info->rx_skb, 1) = x;
++			inb(iobase + DATA_H);
++			info->rx_count--;
++
++			if (info->rx_count == 0) {
++
++				int dlen;
++				hci_event_hdr *eh;
++				hci_acl_hdr *ah;
++				hci_sco_hdr *sh;
++
++				switch (info->rx_state) {
++
++				case RECV_WAIT_EVENT_HEADER:
++					eh = (hci_event_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = eh->plen;
++					break;
++
++				case RECV_WAIT_ACL_HEADER:
++					ah = (hci_acl_hdr *)(info->rx_skb->data);
++					dlen = __le16_to_cpu(ah->dlen);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = dlen;
++					break;
++
++				case RECV_WAIT_SCO_HEADER:
++					sh = (hci_sco_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = sh->dlen;
++					break;
++
++				case RECV_WAIT_DATA:
++					hci_recv_frame(info->rx_skb);
++					info->rx_skb = NULL;
++					break;
++
++				}
++
++			}
++
++		}
++
++	}
++
++	bt3c_io_write(iobase, 0x7006, 0x0000);
++}
++
++
++void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	bt3c_info_t *info = dev_inst;
++	unsigned int iobase;
++	int iir;
++
++	if (!info) {
++		printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	iir = inb(iobase + CONTROL);
++	if (iir & 0x80) {
++		int stat = bt3c_read(iobase, 0x7001);
++
++		if ((stat & 0xff) == 0x7f) {
++			printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat);
++		} else if ((stat & 0xff) != 0xff) {
++			if (stat & 0x0020) {
++				int stat = bt3c_read(iobase, 0x7002) & 0x10;
++				printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN");
++			}
++			if (stat & 0x0001)
++				bt3c_receive(info);
++			if (stat & 0x0002) {
++				//printk("bt3c_cs: ACK %04x\n", stat);
++				clear_bit(XMIT_SENDING, &(info->tx_state));
++				bt3c_write_wakeup(info, 1);
++			}
++
++			bt3c_io_write(iobase, 0x7001, 0x0000);
++
++			outb(iir, iobase + CONTROL);
++		}
++	}
++
++	spin_unlock(&(info->lock));
++}
++
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int bt3c_hci_flush(struct hci_dev *hdev)
++{
++	bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int bt3c_hci_open(struct hci_dev *hdev)
++{
++	set_bit(HCI_RUNNING, &(hdev->flags));
++
++	return 0;
++}
++
++
++static int bt3c_hci_close(struct hci_dev *hdev)
++{
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	bt3c_hci_flush(hdev);
++
++	return 0;
++}
++
++
++static int bt3c_hci_send_frame(struct sk_buff *skb)
++{
++	bt3c_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++	if (!hdev) {
++		printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (bt3c_info_t *) (hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++	skb_queue_tail(&(info->txq), skb);
++
++	bt3c_write_wakeup(info, 0);
++
++	return 0;
++}
++
++
++static void bt3c_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== User mode firmware loader ======================== */
++
++
++#define FW_LOADER  "/sbin/bluefw"
++static int errno;
++
++
++static int bt3c_fw_loader_exec(void *dev)
++{
++	char *argv[] = { FW_LOADER, "pccard", dev, NULL };
++	char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
++	int err;
++
++	err = exec_usermodehelper(FW_LOADER, argv, envp);
++	if (err)
++		printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev);
++
++	return err;
++}
++
++
++static int bt3c_firmware_load(bt3c_info_t *info)
++{
++	sigset_t tmpsig;
++	char dev[16];
++	pid_t pid;
++	int result;
++
++	/* Check if root fs is mounted */
++	if (!current->fs->root) {
++		printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n");
++		return -EPERM;
++	}
++
++	sprintf(dev, "%04x", info->link.io.BasePort1);
++
++	pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0);
++	if (pid < 0) {
++		printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid);
++		return pid;
++	}
++
++	/* Block signals, everything but SIGKILL/SIGSTOP */
++	spin_lock_irq(&current->sigmask_lock);
++	tmpsig = current->blocked;
++	siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
++	recalc_sigpending(current);
++	spin_unlock_irq(&current->sigmask_lock);
++
++	result = waitpid(pid, NULL, __WCLONE);
++
++	/* Allow signals again */
++	spin_lock_irq(&current->sigmask_lock);
++	current->blocked = tmpsig;
++	recalc_sigpending(current);
++	spin_unlock_irq(&current->sigmask_lock);
++
++	if (result != pid) {
++		printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result);
++		return -result;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int bt3c_open(bt3c_info_t *info)
++{
++	struct hci_dev *hdev;
++	int err;
++
++	spin_lock_init(&(info->lock));
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_PACKET_TYPE;
++	info->rx_count = 0;
++	info->rx_skb = NULL;
++
++	/* Load firmware */
++
++	if ((err = bt3c_firmware_load(info)) < 0)
++		return err;
++
++	/* Timeout before it is safe to send the first HCI packet */
++
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ);
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = bt3c_hci_open;
++	hdev->close = bt3c_hci_close;
++	hdev->flush = bt3c_hci_flush;
++	hdev->send = bt3c_hci_send_frame;
++	hdev->destruct = bt3c_hci_destruct;
++	hdev->ioctl = bt3c_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int bt3c_close(bt3c_info_t *info)
++{
++	struct hci_dev *hdev = &(info->hdev);
++
++	bt3c_hci_close(hdev);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *bt3c_attach(void)
++{
++	bt3c_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &bt3c_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = bt3c_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++	    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &bt3c_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		bt3c_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void bt3c_detach(dev_link_t *link)
++{
++	bt3c_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++
++	if (link->state & DEV_CONFIG)
++		bt3c_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void bt3c_config(dev_link_t *link)
++{
++	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
++	client_handle_t handle = link->handle;
++	bt3c_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++	config_info_t config;
++	int i, j, try, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	/* First pass: look for a config entry that looks normal. */
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++	/* Two tries: without IO aliases, then with aliases */
++	for (try = 0; try < 2; try++) {
++		i = first_tuple(handle, &tuple, &parse);
++		while (i != CS_NO_MORE_ITEMS) {
++			if (i != CS_SUCCESS)
++				goto next_entry;
++			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
++				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
++			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
++				link->conf.ConfigIndex = cf->index;
++				link->io.BasePort1 = cf->io.win[0].base;
++				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++next_entry:
++			i = next_tuple(handle, &tuple, &parse);
++		}
++	}
++
++	/* Second pass: try to find an entry that isn't picky about
++	   its base address, then try to grab any standard serial port
++	   address, and finally try to get any free port. */
++	i = first_tuple(handle, &tuple, &parse);
++	while (i != CS_NO_MORE_ITEMS) {
++		if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
++			link->conf.ConfigIndex = cf->index;
++			for (j = 0; j < 5; j++) {
++				link->io.BasePort1 = base[j];
++				link->io.IOAddrLines = base[j] ? 16 : 3;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++		}
++		i = next_tuple(handle, &tuple, &parse);
++	}
++
++found_port:
++	if (i != CS_SUCCESS) {
++		printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n");
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (bt3c_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	bt3c_release((u_long)link);
++}
++
++
++void bt3c_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	bt3c_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		bt3c_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int bt3c_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	bt3c_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			bt3c_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		bt3c_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_bt3c_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach);
++
++	return err;
++}
++
++
++void __exit exit_bt3c_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		bt3c_detach(dev_list);
++}
++
++
++module_init(init_bt3c_cs);
++module_exit(exit_bt3c_cs);
++
++EXPORT_NO_SYMBOLS;
+diff -urN linux-2.4.18/drivers/bluetooth/btuart_cs.c linux-2.4.18-mh9/drivers/bluetooth/btuart_cs.c
+--- linux-2.4.18/drivers/bluetooth/btuart_cs.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/btuart_cs.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,906 @@
++/*
++ *
++ *  Driver for Bluetooth PCMCIA cards with HCI UART interface
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0xffff;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct btuart_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;	/* For serializing operations */
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++} btuart_info_t;
++
++
++void btuart_config(dev_link_t *link);
++void btuart_release(u_long arg);
++int btuart_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "btuart_cs";
++
++dev_link_t *btuart_attach(void);
++void btuart_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Maximum baud rate */
++#define SPEED_MAX  115200
++
++/* Default baud rate: 57600, 115200, 230400 or 460800 */
++#define DEFAULT_BAUD_RATE  115200
++
++
++/* Transmit states  */
++#define XMIT_SENDING	1
++#define XMIT_WAKEUP	2
++#define XMIT_WAITING	8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE	0
++#define RECV_WAIT_EVENT_HEADER	1
++#define RECV_WAIT_ACL_HEADER	2
++#define RECV_WAIT_SCO_HEADER	3
++#define RECV_WAIT_DATA		4
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
++{
++	int actual = 0;
++
++	/* Tx FIFO should be empty */
++	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
++		return 0;
++
++	/* Fill FIFO with current frame */
++	while ((fifo_size-- > 0) && (actual < len)) {
++		/* Transmit next byte */
++		outb(buf[actual], iobase + UART_TX);
++		actual++;
++	}
++
++	return actual;
++}
++
++
++static void btuart_write_wakeup(btuart_info_t *info)
++{
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register struct sk_buff *skb;
++		register int len;
++
++		clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (!(info->link.state & DEV_PRESENT))
++			return;
++
++		if (!(skb = skb_dequeue(&(info->txq))))
++			break;
++
++		/* Send frame */
++		len = btuart_write(iobase, 16, skb->data, skb->len);
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (len == skb->len) {
++			kfree_skb(skb);
++		} else {
++			skb_pull(skb, len);
++			skb_queue_head(&(info->txq), skb);
++		}
++
++		info->hdev.stat.byte_tx += len;
++
++	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++	clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static void btuart_receive(btuart_info_t *info)
++{
++	unsigned int iobase;
++	int boguscount = 0;
++
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	do {
++		info->hdev.stat.byte_rx++;
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL) {
++			info->rx_state = RECV_WAIT_PACKET_TYPE;
++			info->rx_count = 0;
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n");
++				return;
++			}
++		}
++
++		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++			info->rx_skb->dev = (void *)&(info->hdev);
++			info->rx_skb->pkt_type = inb(iobase + UART_RX);
++
++			switch (info->rx_skb->pkt_type) {
++
++			case HCI_EVENT_PKT:
++				info->rx_state = RECV_WAIT_EVENT_HEADER;
++				info->rx_count = HCI_EVENT_HDR_SIZE;
++				break;
++
++			case HCI_ACLDATA_PKT:
++				info->rx_state = RECV_WAIT_ACL_HEADER;
++				info->rx_count = HCI_ACL_HDR_SIZE;
++				break;
++
++			case HCI_SCODATA_PKT:
++				info->rx_state = RECV_WAIT_SCO_HEADER;
++				info->rx_count = HCI_SCO_HDR_SIZE;
++				break;
++
++			default:
++				/* Unknown packet */
++				printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++				info->hdev.stat.err_rx++;
++				clear_bit(HCI_RUNNING, &(info->hdev.flags));
++
++				kfree_skb(info->rx_skb);
++				info->rx_skb = NULL;
++				break;
++
++			}
++
++		} else {
++
++			*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
++			info->rx_count--;
++
++			if (info->rx_count == 0) {
++
++				int dlen;
++				hci_event_hdr *eh;
++				hci_acl_hdr *ah;
++				hci_sco_hdr *sh;
++
++
++				switch (info->rx_state) {
++
++				case RECV_WAIT_EVENT_HEADER:
++					eh = (hci_event_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = eh->plen;
++					break;
++
++				case RECV_WAIT_ACL_HEADER:
++					ah = (hci_acl_hdr *)(info->rx_skb->data);
++					dlen = __le16_to_cpu(ah->dlen);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = dlen;
++					break;
++
++				case RECV_WAIT_SCO_HEADER:
++					sh = (hci_sco_hdr *)(info->rx_skb->data);
++					info->rx_state = RECV_WAIT_DATA;
++					info->rx_count = sh->dlen;
++					break;
++
++				case RECV_WAIT_DATA:
++					hci_recv_frame(info->rx_skb);
++					info->rx_skb = NULL;
++					break;
++
++				}
++
++			}
++
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 16)
++			break;
++
++	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
++}
++
++
++void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	btuart_info_t *info = dev_inst;
++	unsigned int iobase;
++	int boguscount = 0;
++	int iir, lsr;
++
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++	while (iir) {
++
++		/* Clear interrupt */
++		lsr = inb(iobase + UART_LSR);
++
++		switch (iir) {
++		case UART_IIR_RLSI:
++			printk(KERN_NOTICE "btuart_cs: RLSI\n");
++			break;
++		case UART_IIR_RDI:
++			/* Receive interrupt */
++			btuart_receive(info);
++			break;
++		case UART_IIR_THRI:
++			if (lsr & UART_LSR_THRE) {
++				/* Transmitter ready for data */
++				btuart_write_wakeup(info);
++			}
++			break;
++		default:
++			printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir);
++			break;
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 100)
++			break;
++
++		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++
++	}
++
++	spin_unlock(&(info->lock));
++}
++
++
++static void btuart_change_speed(btuart_info_t *info, unsigned int speed)
++{
++	unsigned long flags;
++	unsigned int iobase;
++	int fcr;		/* FIFO control reg */
++	int lcr;		/* Line control reg */
++	int divisor;
++
++	if (!info) {
++		printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	divisor = SPEED_MAX / speed;
++
++	fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;
++
++	/* 
++	 * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and
++	 * almost 1,7 ms at 19200 bps. At speeds above that we can just forget
++	 * about this timeout since it will always be fast enough. 
++	 */
++
++	if (speed < 38400)
++		fcr |= UART_FCR_TRIGGER_1;
++	else
++		fcr |= UART_FCR_TRIGGER_14;
++
++	/* Bluetooth cards use 8N1 */
++	lcr = UART_LCR_WLEN8;
++
++	outb(UART_LCR_DLAB | lcr, iobase + UART_LCR);	/* Set DLAB */
++	outb(divisor & 0xff, iobase + UART_DLL);	/* Set speed */
++	outb(divisor >> 8, iobase + UART_DLM);
++	outb(lcr, iobase + UART_LCR);	/* Set 8N1  */
++	outb(fcr, iobase + UART_FCR);	/* Enable FIFO's */
++
++	/* Turn on interrups */
++	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++}
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int btuart_hci_flush(struct hci_dev *hdev)
++{
++	btuart_info_t *info = (btuart_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int btuart_hci_open(struct hci_dev *hdev)
++{
++	set_bit(HCI_RUNNING, &(hdev->flags));
++
++	return 0;
++}
++
++
++static int btuart_hci_close(struct hci_dev *hdev)
++{
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	btuart_hci_flush(hdev);
++
++	return 0;
++}
++
++
++static int btuart_hci_send_frame(struct sk_buff *skb)
++{
++	btuart_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++	if (!hdev) {
++		printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (btuart_info_t *)(hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++	};
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++	skb_queue_tail(&(info->txq), skb);
++
++	btuart_write_wakeup(info);
++
++	return 0;
++}
++
++
++static void btuart_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int btuart_open(btuart_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev;
++
++	spin_lock_init(&(info->lock));
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_PACKET_TYPE;
++	info->rx_count = 0;
++	info->rx_skb = NULL;
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	/* Initialize UART */
++	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
++	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
++
++	/* Turn on interrupts */
++	// outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	btuart_change_speed(info, DEFAULT_BAUD_RATE);
++
++	/* Timeout before it is safe to send the first HCI packet */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ);
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = btuart_hci_open;
++	hdev->close = btuart_hci_close;
++	hdev->flush = btuart_hci_flush;
++	hdev->send = btuart_hci_send_frame;
++	hdev->destruct = btuart_hci_destruct;
++	hdev->ioctl = btuart_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int btuart_close(btuart_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev = &(info->hdev);
++
++	btuart_hci_close(hdev);
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *btuart_attach(void)
++{
++	btuart_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &btuart_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = btuart_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &btuart_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		btuart_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void btuart_detach(dev_link_t *link)
++{
++	btuart_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG)
++		btuart_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void btuart_config(dev_link_t *link)
++{
++	static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
++	client_handle_t handle = link->handle;
++	btuart_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++	config_info_t config;
++	int i, j, try, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	/* First pass: look for a config entry that looks normal. */
++	tuple.TupleData = (cisdata_t *) buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++	/* Two tries: without IO aliases, then with aliases */
++	for (try = 0; try < 2; try++) {
++		i = first_tuple(handle, &tuple, &parse);
++		while (i != CS_NO_MORE_ITEMS) {
++			if (i != CS_SUCCESS)
++				goto next_entry;
++			if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM))
++				link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000;
++			if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) {
++				link->conf.ConfigIndex = cf->index;
++				link->io.BasePort1 = cf->io.win[0].base;
++				link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++next_entry:
++			i = next_tuple(handle, &tuple, &parse);
++		}
++	}
++
++	/* Second pass: try to find an entry that isn't picky about
++	   its base address, then try to grab any standard serial port
++	   address, and finally try to get any free port. */
++	i = first_tuple(handle, &tuple, &parse);
++	while (i != CS_NO_MORE_ITEMS) {
++		if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
++		    && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
++			link->conf.ConfigIndex = cf->index;
++			for (j = 0; j < 5; j++) {
++				link->io.BasePort1 = base[j];
++				link->io.IOAddrLines = base[j] ? 16 : 3;
++				i = CardServices(RequestIO, link->handle, &link->io);
++				if (i == CS_SUCCESS)
++					goto found_port;
++			}
++		}
++		i = next_tuple(handle, &tuple, &parse);
++	}
++
++found_port:
++	if (i != CS_SUCCESS) {
++		printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n");
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (btuart_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	btuart_release((u_long) link);
++}
++
++
++void btuart_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	btuart_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		btuart_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int btuart_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	btuart_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			btuart_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		btuart_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_btuart_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach);
++
++	return err;
++}
++
++
++void __exit exit_btuart_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		btuart_detach(dev_list);
++}
++
++
++module_init(init_btuart_cs);
++module_exit(exit_btuart_cs);
++
++EXPORT_NO_SYMBOLS;
+diff -urN linux-2.4.18/drivers/bluetooth/dtl1_cs.c linux-2.4.18-mh9/drivers/bluetooth/dtl1_cs.c
+--- linux-2.4.18/drivers/bluetooth/dtl1_cs.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/dtl1_cs.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,858 @@
++/*
++ *
++ *  A driver for Nokia Connectivity Card DTL-1 devices
++ *
++ *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
++ *
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation;
++ *
++ *  Software distributed under the License is distributed on an "AS
++ *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ *  implied. See the License for the specific language governing
++ *  rights and limitations under the License.
++ *
++ *  The initial developer of the original code is David A. Hinds
++ *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
++ *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0xffff;
++static int irq_list[4] = { -1 };
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct dtl1_info_t {
++	dev_link_t link;
++	dev_node_t node;
++
++	struct hci_dev hdev;
++
++	spinlock_t lock;		/* For serializing operations */
++
++	unsigned long flowmask;		/* HCI flow mask */
++	int ri_latch;
++
++	struct sk_buff_head txq;
++	unsigned long tx_state;
++
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++} dtl1_info_t;
++
++
++void dtl1_config(dev_link_t *link);
++void dtl1_release(u_long arg);
++int dtl1_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "dtl1_cs";
++
++dev_link_t *dtl1_attach(void);
++void dtl1_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++
++/* Transmit states  */
++#define XMIT_SENDING  1
++#define XMIT_WAKEUP   2
++#define XMIT_WAITING  8
++
++/* Receiver States */
++#define RECV_WAIT_NSH   0
++#define RECV_WAIT_DATA  1
++
++
++typedef struct {
++	u8 type;
++	u8 zero;
++	u16 len;
++} __attribute__ ((packed)) nsh_t;	/* Nokia Specific Header */
++
++#define NSHL  4				/* Nokia Specific Header Length */
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
++{
++	int actual = 0;
++
++	/* Tx FIFO should be empty */
++	if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
++		return 0;
++
++	/* Fill FIFO with current frame */
++	while ((fifo_size-- > 0) && (actual < len)) {
++		/* Transmit next byte */
++		outb(buf[actual], iobase + UART_TX);
++		actual++;
++	}
++
++	return actual;
++}
++
++
++static void dtl1_write_wakeup(dtl1_info_t *info)
++{
++	if (!info) {
++		printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
++		return;
++	}
++
++	if (test_bit(XMIT_WAITING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++		set_bit(XMIT_WAKEUP, &(info->tx_state));
++		return;
++	}
++
++	do {
++		register unsigned int iobase = info->link.io.BasePort1;
++		register struct sk_buff *skb;
++		register int len;
++
++		clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++		if (!(info->link.state & DEV_PRESENT))
++			return;
++
++		if (!(skb = skb_dequeue(&(info->txq))))
++			break;
++
++		/* Send frame */
++		len = dtl1_write(iobase, 32, skb->data, skb->len);
++
++		if (len == skb->len) {
++			set_bit(XMIT_WAITING, &(info->tx_state));
++			kfree_skb(skb);
++		} else {
++			skb_pull(skb, len);
++			skb_queue_head(&(info->txq), skb);
++		}
++
++		info->hdev.stat.byte_tx += len;
++
++	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++	clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
++{
++	u8 flowmask = *(u8 *)skb->data;
++	int i;
++
++	printk(KERN_INFO "dtl1_cs: Nokia control data = ");
++	for (i = 0; i < skb->len; i++) {
++		printk("%02x ", skb->data[i]);
++	}
++	printk("\n");
++
++	/* transition to active state */
++	if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) {
++		clear_bit(XMIT_WAITING, &(info->tx_state));
++		dtl1_write_wakeup(info);
++	}
++
++	info->flowmask = flowmask;
++
++	kfree_skb(skb);
++}
++
++
++static void dtl1_receive(dtl1_info_t *info)
++{
++	unsigned int iobase;
++	nsh_t *nsh;
++	int boguscount = 0;
++
++	if (!info) {
++		printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	do {
++		info->hdev.stat.byte_rx++;
++
++		/* Allocate packet */
++		if (info->rx_skb == NULL)
++			if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++				printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
++				info->rx_state = RECV_WAIT_NSH;
++				info->rx_count = NSHL;
++				return;
++			}
++
++		*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
++		nsh = (nsh_t *)info->rx_skb->data;
++
++		info->rx_count--;
++
++		if (info->rx_count == 0) {
++
++			switch (info->rx_state) {
++			case RECV_WAIT_NSH:
++				info->rx_state = RECV_WAIT_DATA;
++				info->rx_count = nsh->len + (nsh->len & 0x0001);
++				break;
++			case RECV_WAIT_DATA:
++				info->rx_skb->pkt_type = nsh->type;
++
++				/* remove PAD byte if it exists */
++				if (nsh->len & 0x0001) {
++					info->rx_skb->tail--;
++					info->rx_skb->len--;
++				}
++
++				/* remove NSH */
++				skb_pull(info->rx_skb, NSHL);
++
++				switch (info->rx_skb->pkt_type) {
++				case 0x80:
++					/* control data for the Nokia Card */
++					dtl1_control(info, info->rx_skb);
++					break;
++				case 0x82:
++				case 0x83:
++				case 0x84:
++					/* send frame to the HCI layer */
++					info->rx_skb->dev = (void *)&(info->hdev);
++					info->rx_skb->pkt_type &= 0x0f;
++					hci_recv_frame(info->rx_skb);
++					break;
++				default:
++					/* unknown packet */
++					printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
++					kfree_skb(info->rx_skb);
++					break;
++				}
++
++				info->rx_state = RECV_WAIT_NSH;
++				info->rx_count = NSHL;
++				info->rx_skb = NULL;
++				break;
++			}
++
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 32)
++			break;
++
++	} while (inb(iobase + UART_LSR) & UART_LSR_DR);
++}
++
++
++void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++	dtl1_info_t *info = dev_inst;
++	unsigned int iobase;
++	unsigned char msr;
++	int boguscount = 0;
++	int iir, lsr;
++
++	if (!info) {
++		printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
++		return;
++	}
++
++	iobase = info->link.io.BasePort1;
++
++	spin_lock(&(info->lock));
++
++	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++	while (iir) {
++
++		/* Clear interrupt */
++		lsr = inb(iobase + UART_LSR);
++
++		switch (iir) {
++		case UART_IIR_RLSI:
++			printk(KERN_NOTICE "dtl1_cs: RLSI\n");
++			break;
++		case UART_IIR_RDI:
++			/* Receive interrupt */
++			dtl1_receive(info);
++			break;
++		case UART_IIR_THRI:
++			if (lsr & UART_LSR_THRE) {
++				/* Transmitter ready for data */
++				dtl1_write_wakeup(info);
++			}
++			break;
++		default:
++			printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
++			break;
++		}
++
++		/* Make sure we don't stay here to long */
++		if (boguscount++ > 100)
++			break;
++
++		iir = inb(iobase + UART_IIR) & UART_IIR_ID;
++
++	}
++
++	msr = inb(iobase + UART_MSR);
++
++	if (info->ri_latch ^ (msr & UART_MSR_RI)) {
++		info->ri_latch = msr & UART_MSR_RI;
++		clear_bit(XMIT_WAITING, &(info->tx_state));
++		dtl1_write_wakeup(info);
++	}
++
++	spin_unlock(&(info->lock));
++}
++
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int dtl1_hci_open(struct hci_dev *hdev)
++{
++	set_bit(HCI_RUNNING, &(hdev->flags));
++
++	return 0;
++}
++
++
++static int dtl1_hci_flush(struct hci_dev *hdev)
++{
++	dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
++
++	/* Drop TX queue */
++	skb_queue_purge(&(info->txq));
++
++	return 0;
++}
++
++
++static int dtl1_hci_close(struct hci_dev *hdev)
++{
++	if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++		return 0;
++
++	dtl1_hci_flush(hdev);
++
++	return 0;
++}
++
++
++static int dtl1_hci_send_frame(struct sk_buff *skb)
++{
++	dtl1_info_t *info;
++	struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++	struct sk_buff *s;
++	nsh_t nsh;
++
++	if (!hdev) {
++		printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
++		return -ENODEV;
++	}
++
++	info = (dtl1_info_t *)(hdev->driver_data);
++
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		nsh.type = 0x81;
++		break;
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		nsh.type = 0x82;
++		break;
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		nsh.type = 0x83;
++		break;
++	};
++
++	nsh.zero = 0;
++	nsh.len = skb->len;
++
++	s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
++	skb_reserve(s, NSHL);
++	memcpy(skb_put(s, skb->len), skb->data, skb->len);
++	if (skb->len & 0x0001)
++		*skb_put(s, 1) = 0;	/* PAD */
++
++	/* Prepend skb with Nokia frame header and queue */
++	memcpy(skb_push(s, NSHL), &nsh, NSHL);
++	skb_queue_tail(&(info->txq), s);
++
++	dtl1_write_wakeup(info);
++
++	kfree_skb(skb);
++
++	return 0;
++}
++
++
++static void dtl1_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,  unsigned long arg)
++{
++	return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++int dtl1_open(dtl1_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev;
++
++	spin_lock_init(&(info->lock));
++
++	skb_queue_head_init(&(info->txq));
++
++	info->rx_state = RECV_WAIT_NSH;
++	info->rx_count = NSHL;
++	info->rx_skb = NULL;
++
++	set_bit(XMIT_WAITING, &(info->tx_state));
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	/* Initialize UART */
++	outb(UART_LCR_WLEN8, iobase + UART_LCR);	/* Reset DLAB */
++	outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
++
++	info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
++
++	/* Turn on interrupts */
++	outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	/* Timeout before it is safe to send the first HCI packet */
++	set_current_state(TASK_INTERRUPTIBLE);
++	schedule_timeout(HZ * 2);
++
++
++	/* Initialize and register HCI device */
++
++	hdev = &(info->hdev);
++
++	hdev->type = HCI_PCCARD;
++	hdev->driver_data = info;
++
++	hdev->open = dtl1_hci_open;
++	hdev->close = dtl1_hci_close;
++	hdev->flush = dtl1_hci_flush;
++	hdev->send = dtl1_hci_send_frame;
++	hdev->destruct = dtl1_hci_destruct;
++	hdev->ioctl = dtl1_hci_ioctl;
++
++	if (hci_register_dev(hdev) < 0) {
++		printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
++		return -ENODEV;
++	}
++
++	return 0;
++}
++
++
++int dtl1_close(dtl1_info_t *info)
++{
++	unsigned long flags;
++	unsigned int iobase = info->link.io.BasePort1;
++	struct hci_dev *hdev = &(info->hdev);
++
++	dtl1_hci_close(hdev);
++
++	spin_lock_irqsave(&(info->lock), flags);
++
++	/* Reset UART */
++	outb(0, iobase + UART_MCR);
++
++	/* Turn off interrupts */
++	outb(0, iobase + UART_IER);
++
++	spin_unlock_irqrestore(&(info->lock), flags);
++
++	if (hci_unregister_dev(hdev) < 0)
++		printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++	return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++	error_info_t err = { func, ret };
++
++	CardServices(ReportError, handle, &err);
++}
++
++
++dev_link_t *dtl1_attach(void)
++{
++	dtl1_info_t *info;
++	client_reg_t client_reg;
++	dev_link_t *link;
++	int i, ret;
++
++	/* Create new info device */
++	info = kmalloc(sizeof(*info), GFP_KERNEL);
++	if (!info)
++		return NULL;
++	memset(info, 0, sizeof(*info));
++
++	link = &info->link;
++	link->priv = info;
++
++	link->release.function = &dtl1_release;
++	link->release.data = (u_long)link;
++	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++	link->io.NumPorts1 = 8;
++	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++	if (irq_list[0] == -1)
++		link->irq.IRQInfo2 = irq_mask;
++	else
++		for (i = 0; i < 4; i++)
++			link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++	link->irq.Handler = dtl1_interrupt;
++	link->irq.Instance = info;
++
++	link->conf.Attributes = CONF_ENABLE_IRQ;
++	link->conf.Vcc = 50;
++	link->conf.IntType = INT_MEMORY_AND_IO;
++
++	/* Register with Card Services */
++	link->next = dev_list;
++	dev_list = link;
++	client_reg.dev_info = &dev_info;
++	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++	client_reg.EventMask =
++		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++	client_reg.event_handler = &dtl1_event;
++	client_reg.Version = 0x0210;
++	client_reg.event_callback_args.client_data = link;
++
++	ret = CardServices(RegisterClient, &link->handle, &client_reg);
++	if (ret != CS_SUCCESS) {
++		cs_error(link->handle, RegisterClient, ret);
++		dtl1_detach(link);
++		return NULL;
++	}
++
++	return link;
++}
++
++
++void dtl1_detach(dev_link_t *link)
++{
++	dtl1_info_t *info = link->priv;
++	dev_link_t **linkp;
++	int ret;
++
++	/* Locate device structure */
++	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++		if (*linkp == link)
++			break;
++
++	if (*linkp == NULL)
++		return;
++
++	del_timer(&link->release);
++	if (link->state & DEV_CONFIG)
++		dtl1_release((u_long)link);
++
++	if (link->handle) {
++		ret = CardServices(DeregisterClient, link->handle);
++		if (ret != CS_SUCCESS)
++			cs_error(link->handle, DeregisterClient, ret);
++	}
++
++	/* Unlink device structure, free bits */
++	*linkp = link->next;
++
++	kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++	int i;
++
++	i = CardServices(fn, handle, tuple);
++	if (i != CS_SUCCESS)
++		return CS_NO_MORE_ITEMS;
++
++	i = CardServices(GetTupleData, handle, tuple);
++	if (i != CS_SUCCESS)
++		return i;
++
++	return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++void dtl1_config(dev_link_t *link)
++{
++	client_handle_t handle = link->handle;
++	dtl1_info_t *info = link->priv;
++	tuple_t tuple;
++	u_short buf[256];
++	cisparse_t parse;
++	cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++	config_info_t config;
++	int i, last_ret, last_fn;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++
++	/* Get configuration register information */
++	tuple.DesiredTuple = CISTPL_CONFIG;
++	last_ret = first_tuple(handle, &tuple, &parse);
++	if (last_ret != CS_SUCCESS) {
++		last_fn = ParseTuple;
++		goto cs_failed;
++	}
++	link->conf.ConfigBase = parse.config.base;
++	link->conf.Present = parse.config.rmask[0];
++
++	/* Configure card */
++	link->state |= DEV_CONFIG;
++	i = CardServices(GetConfigurationInfo, handle, &config);
++	link->conf.Vcc = config.Vcc;
++
++	tuple.TupleData = (cisdata_t *)buf;
++	tuple.TupleOffset = 0;
++	tuple.TupleDataMax = 255;
++	tuple.Attributes = 0;
++	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
++
++	/* Look for a generic full-sized window */
++	link->io.NumPorts1 = 8;
++	i = first_tuple(handle, &tuple, &parse);
++	while (i != CS_NO_MORE_ITEMS) {
++		if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
++			link->conf.ConfigIndex = cf->index;
++			link->io.BasePort1 = cf->io.win[0].base;
++			link->io.NumPorts1 = cf->io.win[0].len;	/*yo */
++			link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
++			i = CardServices(RequestIO, link->handle, &link->io);
++			if (i == CS_SUCCESS)
++				break;
++		}
++		i = next_tuple(handle, &tuple, &parse);
++	}
++
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIO, i);
++		goto failed;
++	}
++
++	i = CardServices(RequestIRQ, link->handle, &link->irq);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestIRQ, i);
++		link->irq.AssignedIRQ = 0;
++	}
++
++	i = CardServices(RequestConfiguration, link->handle, &link->conf);
++	if (i != CS_SUCCESS) {
++		cs_error(link->handle, RequestConfiguration, i);
++		goto failed;
++	}
++
++	MOD_INC_USE_COUNT;
++
++	if (dtl1_open(info) != 0)
++		goto failed;
++
++	strcpy(info->node.dev_name, info->hdev.name);
++	link->dev = &info->node;
++	link->state &= ~DEV_CONFIG_PENDING;
++
++	return;
++
++cs_failed:
++	cs_error(link->handle, last_fn, last_ret);
++
++failed:
++	dtl1_release((u_long)link);
++}
++
++
++void dtl1_release(u_long arg)
++{
++	dev_link_t *link = (dev_link_t *)arg;
++	dtl1_info_t *info = link->priv;
++
++	if (link->state & DEV_PRESENT)
++		dtl1_close(info);
++
++	MOD_DEC_USE_COUNT;
++
++	link->dev = NULL;
++
++	CardServices(ReleaseConfiguration, link->handle);
++	CardServices(ReleaseIO, link->handle, &link->io);
++	CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++	link->state &= ~DEV_CONFIG;
++}
++
++
++int dtl1_event(event_t event, int priority, event_callback_args_t *args)
++{
++	dev_link_t *link = args->client_data;
++	dtl1_info_t *info = link->priv;
++
++	switch (event) {
++	case CS_EVENT_CARD_REMOVAL:
++		link->state &= ~DEV_PRESENT;
++		if (link->state & DEV_CONFIG) {
++			dtl1_close(info);
++			mod_timer(&link->release, jiffies + HZ / 20);
++		}
++		break;
++	case CS_EVENT_CARD_INSERTION:
++		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++		dtl1_config(link);
++		break;
++	case CS_EVENT_PM_SUSPEND:
++		link->state |= DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_RESET_PHYSICAL:
++		if (link->state & DEV_CONFIG)
++			CardServices(ReleaseConfiguration, link->handle);
++		break;
++	case CS_EVENT_PM_RESUME:
++		link->state &= ~DEV_SUSPEND;
++		/* Fall through... */
++	case CS_EVENT_CARD_RESET:
++		if (DEV_OK(link))
++			CardServices(RequestConfiguration, link->handle, &link->conf);
++		break;
++	}
++
++	return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_dtl1_cs(void)
++{
++	servinfo_t serv;
++	int err;
++
++	CardServices(GetCardServicesInfo, &serv);
++	if (serv.Revision != CS_RELEASE_CODE) {
++		printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n");
++		return -1;
++	}
++
++	err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
++
++	return err;
++}
++
++
++void __exit exit_dtl1_cs(void)
++{
++	unregister_pccard_driver(&dev_info);
++
++	while (dev_list != NULL)
++		dtl1_detach(dev_list);
++}
++
++
++module_init(init_dtl1_cs);
++module_exit(exit_dtl1_cs);
++
++EXPORT_NO_SYMBOLS;
+diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.c linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.c
+--- linux-2.4.18/drivers/bluetooth/hci_bcsp.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,710 @@
++/* 
++   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
++   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
++
++   Based on
++       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
++       ABCSP     by Carl Orsborn <cjo@csr.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#define VERSION "0.1"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/poll.h>
++
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/signal.h>
++#include <linux/ioctl.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include "hci_uart.h"
++#include "hci_bcsp.h"
++
++#ifndef HCI_UART_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
++#endif
++
++/* ---- BCSP CRC calculation ---- */
++
++/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
++initial value 0xffff, bits shifted in reverse order. */
++
++static const u16 crc_table[] = {
++	0x0000, 0x1081, 0x2102, 0x3183,
++	0x4204, 0x5285, 0x6306, 0x7387,
++	0x8408, 0x9489, 0xa50a, 0xb58b,
++	0xc60c, 0xd68d, 0xe70e, 0xf78f
++};
++
++/* Initialise the crc calculator */
++#define BCSP_CRC_INIT(x) x = 0xffff
++
++/*
++   Update crc with next data byte
++
++   Implementation note
++        The data byte is treated as two nibbles.  The crc is generated
++        in reverse, i.e., bits are fed into the register from the top.
++*/
++static void bcsp_crc_update(u16 *crc, u8 d)
++{
++	u16 reg = *crc;
++
++	reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
++	reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
++
++	*crc = reg;
++}
++
++/*
++   Get reverse of generated crc
++
++   Implementation note
++        The crc generator (bcsp_crc_init() and bcsp_crc_update())
++        creates a reversed crc, so it needs to be swapped back before
++        being passed on.
++*/
++static u16 bcsp_crc_reverse(u16 crc)
++{
++	u16 b, rev;
++
++	for (b = 0, rev = 0; b < 16; b++) {
++		rev = rev << 1;
++		rev |= (crc & 1);
++		crc = crc >> 1;
++	}
++	return (rev);
++}
++
++/* ---- BCSP core ---- */
++
++static void bcsp_slip_msgdelim(struct sk_buff *skb)
++{
++	const char pkt_delim = 0xc0;
++	memcpy(skb_put(skb, 1), &pkt_delim, 1);
++}
++
++static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c)
++{
++	const char esc_c0[2] = { 0xdb, 0xdc };
++	const char esc_db[2] = { 0xdb, 0xdd };
++
++	switch (c) {
++	case 0xc0:
++		memcpy(skb_put(skb, 2), &esc_c0, 2);
++		break;
++	case 0xdb:
++		memcpy(skb_put(skb, 2), &esc_db, 2);
++		break;
++	default:
++		memcpy(skb_put(skb, 1), &c, 1);
++	}
++}
++
++static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++
++	if (skb->len > 0xFFF) {
++		BT_ERR("Packet too long");
++		kfree_skb(skb);
++		return 0;
++	}
++
++	switch (skb->pkt_type) {
++	case HCI_ACLDATA_PKT:
++	case HCI_COMMAND_PKT:
++		skb_queue_tail(&bcsp->rel, skb);
++		break;
++
++	case HCI_SCODATA_PKT:
++		skb_queue_tail(&bcsp->unrel, skb);
++		break;
++		
++	default:
++		BT_ERR("Unknown packet type");
++		kfree_skb(skb);
++		break;
++	}
++	return 0;
++}
++
++static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
++		int len, int pkt_type)
++{
++	struct sk_buff *nskb;
++	u8  hdr[4], chan;
++	int rel, i;
++
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++	u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
++#endif
++
++	switch (pkt_type) {
++	case HCI_ACLDATA_PKT:
++		chan = 6;	/* BCSP ACL channel */
++		rel = 1;	/* reliable channel */
++		break;
++	case HCI_COMMAND_PKT:
++		chan = 5;	/* BCSP cmd/evt channel */
++		rel = 1;	/* reliable channel */
++		break;
++	case HCI_SCODATA_PKT:
++		chan = 7;	/* BCSP SCO channel */
++		rel = 0;	/* unreliable channel */
++		break;
++	case BCSP_LE_PKT:
++		chan = 1;	/* BCSP LE channel */
++		rel = 0;	/* unreliable channel */
++		break;
++	case BCSP_ACK_PKT:
++		chan = 0;	/* BCSP internal channel */
++		rel = 0;	/* unreliable channel */
++		break;
++	default:
++		BT_ERR("Unknown packet type");
++		return NULL;
++	}
++
++	/* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2
++	   (because bytes 0xc0 and 0xdb are escaped, worst case is
++	   when the packet is all made of 0xc0 and 0xdb :) )
++	   + 2 (0xc0 delimiters at start and end). */
++
++	nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
++	if (!nskb)
++		return NULL;
++
++	nskb->pkt_type = pkt_type;
++
++	bcsp_slip_msgdelim(nskb);
++
++	hdr[0] = bcsp->rxseq_txack << 3;
++	bcsp->txack_req = 0;
++	BT_DBG("We request packet no %u to card", bcsp->rxseq_txack);
++
++	if (rel) {
++		hdr[0] |= 0x80 + bcsp->msgq_txseq;
++		BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
++		bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
++	}
++#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++	hdr[0] |= 0x40;
++#endif
++
++	hdr[1]  = (len << 4) & 0xFF;
++	hdr[1] |= chan;
++	hdr[2]  = len >> 4;
++	hdr[3]  = ~(hdr[0] + hdr[1] + hdr[2]);
++
++	/* Put BCSP header */
++	for (i = 0; i < 4; i++) {
++		bcsp_slip_one_byte(nskb, hdr[i]);
++#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++		bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
++#endif
++	}
++
++	/* Put payload */
++	for (i = 0; i < len; i++) {
++		bcsp_slip_one_byte(nskb, data[i]);
++#ifdef  CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++		bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
++#endif
++	}
++
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
++	/* Put CRC */
++	bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
++	bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
++	bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff));
++#endif
++
++	bcsp_slip_msgdelim(nskb);
++	return nskb;
++}
++
++/* This is a rewrite of pkt_avail in ABCSP */
++static struct sk_buff *bcsp_dequeue(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
++	unsigned long flags;
++	struct sk_buff *skb;
++	
++	/* First of all, check for unreliable messages in the queue,
++	   since they have priority */
++
++	if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) {
++		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
++		if (nskb) {
++			kfree_skb(skb);
++			return nskb;
++		} else {
++			skb_queue_head(&bcsp->unrel, skb);
++			BT_ERR("Could not dequeue pkt because alloc_skb failed");
++		}
++	}
++
++	/* Now, try to send a reliable pkt. We can only send a
++	   reliable packet if the number of packets sent but not yet ack'ed
++	   is < than the winsize */
++
++	spin_lock_irqsave(&bcsp->unack.lock, flags);
++
++	if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) {
++		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type);
++		if (nskb) {
++			__skb_queue_tail(&bcsp->unack, skb);
++			mod_timer(&bcsp->tbcsp, jiffies + HZ / 4);
++			spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++			return nskb;
++		} else {
++			skb_queue_head(&bcsp->rel, skb);
++			BT_ERR("Could not dequeue pkt because alloc_skb failed");
++		}
++	}
++
++	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++
++
++	/* We could not send a reliable packet, either because there are
++	   none or because there are too many unack'ed pkts. Did we receive
++	   any packets we have not acknowledged yet ? */
++
++	if (bcsp->txack_req) {
++		/* if so, craft an empty ACK pkt and send it on BCSP unreliable
++		   channel 0 */
++		struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT);
++		return nskb;
++	}
++
++	/* We have nothing to send */
++	return NULL;
++}
++
++static int bcsp_flush(struct hci_uart *hu)
++{
++	BT_DBG("hu %p", hu);
++	return 0;
++}
++
++/* Remove ack'ed packets */
++static void bcsp_pkt_cull(struct bcsp_struct *bcsp)
++{
++	unsigned long flags;
++	struct sk_buff *skb;
++	int i, pkts_to_be_removed;
++	u8 seqno;
++
++	spin_lock_irqsave(&bcsp->unack.lock, flags);
++
++	pkts_to_be_removed = bcsp->unack.qlen;
++	seqno = bcsp->msgq_txseq;
++
++	while (pkts_to_be_removed) {
++		if (bcsp->rxack == seqno)
++			break;
++		pkts_to_be_removed--;
++		seqno = (seqno - 1) & 0x07;
++	}
++
++	if (bcsp->rxack != seqno)
++		BT_ERR("Peer acked invalid packet");
++
++	BT_DBG("Removing %u pkts out of %u, up to seqno %u",
++	       pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07);
++
++	for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed
++			&& skb != (struct sk_buff *) &bcsp->unack; i++) {
++		struct sk_buff *nskb;
++
++		nskb = skb->next;
++		__skb_unlink(skb, &bcsp->unack);
++		kfree_skb(skb);
++		skb = nskb;
++	}
++	if (bcsp->unack.qlen == 0)
++		del_timer(&bcsp->tbcsp);
++	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++
++	if (i != pkts_to_be_removed)
++		BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
++}
++
++/* Handle BCSP link-establishment packets. When we
++   detect a "sync" packet, symptom that the BT module has reset,
++   we do nothing :) (yet) */
++static void bcsp_handle_le_pkt(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	u8 conf_pkt[4]     = { 0xad, 0xef, 0xac, 0xed };
++	u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 };
++	u8 sync_pkt[4]     = { 0xda, 0xdc, 0xed, 0xed };
++
++	/* spot "conf" pkts and reply with a "conf rsp" pkt */
++	if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
++			!memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) {
++		struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC);
++
++		BT_DBG("Found a LE conf pkt");
++		if (!nskb)
++			return;
++		memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4);
++		nskb->pkt_type = BCSP_LE_PKT;
++
++		skb_queue_head(&bcsp->unrel, nskb);
++		hci_uart_tx_wakeup(hu);
++	}
++	/* Spot "sync" pkts. If we find one...disaster! */
++	else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 &&
++			!memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) {
++		BT_ERR("Found a LE sync pkt, card has reset");
++	}
++}
++
++static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte)
++{
++	const u8 c0 = 0xc0, db = 0xdb;
++
++	switch (bcsp->rx_esc_state) {
++	case BCSP_ESCSTATE_NOESC:
++		switch (byte) {
++		case 0xdb:
++			bcsp->rx_esc_state = BCSP_ESCSTATE_ESC;
++			break;
++		default:
++			memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1);
++			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
++					bcsp->rx_state != BCSP_W4_CRC)
++				bcsp_crc_update(&bcsp->message_crc, byte);
++			bcsp->rx_count--;
++		}
++		break;
++
++	case BCSP_ESCSTATE_ESC:
++		switch (byte) {
++		case 0xdc:
++			memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1);
++			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
++					bcsp->rx_state != BCSP_W4_CRC)
++				bcsp_crc_update(&bcsp-> message_crc, 0xc0);
++			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
++			bcsp->rx_count--;
++			break;
++
++		case 0xdd:
++			memcpy(skb_put(bcsp->rx_skb, 1), &db, 1);
++			if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && 
++					bcsp->rx_state != BCSP_W4_CRC) 
++				bcsp_crc_update(&bcsp-> message_crc, 0xdb);
++			bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
++			bcsp->rx_count--;
++			break;
++
++		default:
++			BT_ERR ("Invalid byte %02x after esc byte", byte);
++			kfree_skb(bcsp->rx_skb);
++			bcsp->rx_skb = NULL;
++			bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++			bcsp->rx_count = 0;
++		}
++	}
++}
++
++static inline void bcsp_complete_rx_pkt(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	int pass_up;
++
++	if (bcsp->rx_skb->data[0] & 0x80) {	/* reliable pkt */
++		BT_DBG("Received seqno %u from card", bcsp->rxseq_txack);
++		bcsp->rxseq_txack++;
++		bcsp->rxseq_txack %= 0x8;
++		bcsp->txack_req    = 1;
++
++		/* If needed, transmit an ack pkt */
++		hci_uart_tx_wakeup(hu);
++	}
++
++	bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07;
++	BT_DBG("Request for pkt %u from card", bcsp->rxack);
++
++	bcsp_pkt_cull(bcsp);
++	if ((bcsp->rx_skb->data[1] & 0x0f) == 6 &&
++			bcsp->rx_skb->data[0] & 0x80) {
++		bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT;
++		pass_up = 1;
++	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 &&
++			bcsp->rx_skb->data[0] & 0x80) {
++		bcsp->rx_skb->pkt_type = HCI_EVENT_PKT;
++		pass_up = 1;
++	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) {
++		bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT;
++		pass_up = 1;
++	} else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 &&
++			!(bcsp->rx_skb->data[0] & 0x80)) {
++		bcsp_handle_le_pkt(hu);
++		pass_up = 0;
++	} else
++		pass_up = 0;
++
++	if (!pass_up) {
++		if ((bcsp->rx_skb->data[1] & 0x0f) != 0 &&
++	    		(bcsp->rx_skb->data[1] & 0x0f) != 1) {
++			BT_ERR ("Packet for unknown channel (%u %s)",
++				bcsp->rx_skb->data[1] & 0x0f,
++				bcsp->rx_skb->data[0] & 0x80 ? 
++				"reliable" : "unreliable");
++		}
++		kfree_skb(bcsp->rx_skb);
++	} else {
++		/* Pull out BCSP hdr */
++		skb_pull(bcsp->rx_skb, 4);
++
++		hci_recv_frame(bcsp->rx_skb);
++	}
++	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++	bcsp->rx_skb = NULL;
++}
++
++/* Recv data */
++static int bcsp_recv(struct hci_uart *hu, void *data, int count)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	register unsigned char *ptr;
++
++	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
++		hu, count, bcsp->rx_state, bcsp->rx_count);
++
++	ptr = data;
++	while (count) {
++		if (bcsp->rx_count) {
++			if (*ptr == 0xc0) {
++				BT_ERR("Short BCSP packet");
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_START;
++				bcsp->rx_count = 0;
++			} else
++				bcsp_unslip_one_byte(bcsp, *ptr);
++
++			ptr++; count--;
++			continue;
++		}
++
++		switch (bcsp->rx_state) {
++		case BCSP_W4_BCSP_HDR:
++			if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] +
++					bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) {
++				BT_ERR("Error in BCSP hdr checksum");
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++				bcsp->rx_count = 0;
++				continue;
++			}
++			if (bcsp->rx_skb->data[0] & 0x80	/* reliable pkt */
++			    		&& (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) {
++				BT_ERR ("Out-of-order packet arrived, got %u expected %u",
++					bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack);
++
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++				bcsp->rx_count = 0;
++				continue;
++			}
++			bcsp->rx_state = BCSP_W4_DATA;
++			bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + 
++					(bcsp->rx_skb->data[2] << 4);	/* May be 0 */
++			continue;
++
++		case BCSP_W4_DATA:
++			if (bcsp->rx_skb->data[0] & 0x40) {	/* pkt with crc */
++				bcsp->rx_state = BCSP_W4_CRC;
++				bcsp->rx_count = 2;
++			} else
++				bcsp_complete_rx_pkt(hu);
++			continue;
++
++		case BCSP_W4_CRC:
++			if (bcsp_crc_reverse(bcsp->message_crc) !=
++					(bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) +
++					bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) {
++
++				BT_ERR ("Checksum failed: computed %04x received %04x",
++					bcsp_crc_reverse(bcsp->message_crc),
++				     	(bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) +
++				     	bcsp->rx_skb->data[bcsp->rx_skb->len - 1]);
++
++				kfree_skb(bcsp->rx_skb);
++				bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++				bcsp->rx_count = 0;
++				continue;
++			}
++			skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2);
++			bcsp_complete_rx_pkt(hu);
++			continue;
++
++		case BCSP_W4_PKT_DELIMITER:
++			switch (*ptr) {
++			case 0xc0:
++				bcsp->rx_state = BCSP_W4_PKT_START;
++				break;
++			default:
++				/*BT_ERR("Ignoring byte %02x", *ptr);*/
++				break;
++			}
++			ptr++; count--;
++			break;
++
++		case BCSP_W4_PKT_START:
++			switch (*ptr) {
++			case 0xc0:
++				ptr++; count--;
++				break;
++
++			default:
++				bcsp->rx_state = BCSP_W4_BCSP_HDR;
++				bcsp->rx_count = 4;
++				bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC;
++				BCSP_CRC_INIT(bcsp->message_crc);
++				
++				/* Do not increment ptr or decrement count
++				 * Allocate packet. Max len of a BCSP pkt= 
++				 * 0xFFF (payload) +4 (header) +2 (crc) */
++
++				bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
++				if (!bcsp->rx_skb) {
++					BT_ERR("Can't allocate mem for new packet");
++					bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++					bcsp->rx_count = 0;
++					return 0;
++				}
++				bcsp->rx_skb->dev = (void *) &hu->hdev;
++				break;
++			}
++			break;
++		}
++	}
++	return count;
++}
++
++	/* Arrange to retransmit all messages in the relq. */
++static void bcsp_timed_event(unsigned long arg)
++{
++	struct hci_uart *hu = (struct hci_uart *) arg;
++	struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv;
++	struct sk_buff *skb;
++	unsigned long flags;
++
++	BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen);
++	spin_lock_irqsave(&bcsp->unack.lock, flags);
++
++	while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) {
++		bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07;
++		skb_queue_head(&bcsp->rel, skb);
++	}
++
++	spin_unlock_irqrestore(&bcsp->unack.lock, flags);
++
++	hci_uart_tx_wakeup(hu);
++}
++
++static int bcsp_open(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp;
++
++	BT_DBG("hu %p", hu);
++
++	bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC);
++	if (!bcsp)
++		return -ENOMEM;
++	memset(bcsp, 0, sizeof(*bcsp));
++
++	hu->priv = bcsp;
++	skb_queue_head_init(&bcsp->unack);
++	skb_queue_head_init(&bcsp->rel);
++	skb_queue_head_init(&bcsp->unrel);
++
++	init_timer(&bcsp->tbcsp);
++	bcsp->tbcsp.function = bcsp_timed_event;
++	bcsp->tbcsp.data     = (u_long) hu;
++
++	bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
++
++	return 0;
++}
++
++static int bcsp_close(struct hci_uart *hu)
++{
++	struct bcsp_struct *bcsp = hu->priv;
++	hu->priv = NULL;
++
++	BT_DBG("hu %p", hu);
++
++	skb_queue_purge(&bcsp->unack);
++	skb_queue_purge(&bcsp->rel);
++	skb_queue_purge(&bcsp->unrel);
++	del_timer(&bcsp->tbcsp);
++
++	kfree(bcsp);
++	return 0;
++}
++
++static struct hci_uart_proto bcsp = {
++	id:      HCI_UART_BCSP,
++	open:    bcsp_open,
++	close:   bcsp_close,
++	enqueue: bcsp_enqueue,
++	dequeue: bcsp_dequeue,
++	recv:    bcsp_recv,
++	flush:   bcsp_flush
++};
++
++int bcsp_init(void)
++{
++	return hci_uart_register_proto(&bcsp);
++}
++
++int bcsp_deinit(void)
++{
++	return hci_uart_unregister_proto(&bcsp);
++}
+diff -urN linux-2.4.18/drivers/bluetooth/hci_bcsp.h linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.h
+--- linux-2.4.18/drivers/bluetooth/hci_bcsp.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_bcsp.h	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,70 @@
++/* 
++   BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ).
++   Copyright 2002 by Fabrizio Gennari <fabrizio.gennari@philips.com>
++
++   Based on
++       hci_h4.c  by Maxim Krasnyansky <maxk@qualcomm.com>
++       ABCSP     by Carl Orsborn <cjo@csr.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/* 
++ * $Id$
++ */
++
++#ifndef __HCI_BCSP_H__
++#define __HCI_BCSP_H__
++
++#define BCSP_TXWINSIZE  4
++
++#define BCSP_ACK_PKT    0x05
++#define BCSP_LE_PKT     0x06
++
++struct bcsp_struct {
++	struct sk_buff_head unack;	/* Unack'ed packets queue */
++	struct sk_buff_head rel;	/* Reliable packets queue */
++	struct sk_buff_head unrel;	/* Unreliable packets queue */
++
++	unsigned long rx_count;
++	struct  sk_buff *rx_skb;
++	u8      rxseq_txack;		/* rxseq == txack. */
++	u8      rxack;			/* Last packet sent by us that the peer ack'ed */
++	struct  timer_list tbcsp;
++	
++	enum {
++		BCSP_W4_PKT_DELIMITER,
++		BCSP_W4_PKT_START,
++		BCSP_W4_BCSP_HDR,
++		BCSP_W4_DATA,
++		BCSP_W4_CRC
++	} rx_state;
++
++	enum {
++		BCSP_ESCSTATE_NOESC,
++		BCSP_ESCSTATE_ESC
++	} rx_esc_state;
++
++	u16     message_crc;
++	u8      txack_req;		/* Do we need to send ack's to the peer? */
++
++	/* Reliable packet sequence number - used to assign seq to each rel pkt. */
++	u8      msgq_txseq;
++};
++
++#endif	/* __HCI_BCSP_H__ */
+diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.c linux-2.4.18-mh9/drivers/bluetooth/hci_h4.c
+--- linux-2.4.18/drivers/bluetooth/hci_h4.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_h4.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,277 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ HCI UART(H4) protocol.
++ *
++ * $Id$    
++ */
++#define VERSION "1.2"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/poll.h>
++
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/signal.h>
++#include <linux/ioctl.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include "hci_uart.h"
++#include "hci_h4.h"
++
++#ifndef HCI_UART_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
++#endif
++
++/* Initialize protocol */
++static int h4_open(struct hci_uart *hu)
++{
++	struct h4_struct *h4;
++	
++	BT_DBG("hu %p", hu);
++	
++	h4 = kmalloc(sizeof(*h4), GFP_ATOMIC);
++	if (!h4)
++		return -ENOMEM;
++	memset(h4, 0, sizeof(*h4));
++
++	skb_queue_head_init(&h4->txq);
++
++	hu->priv = h4;
++	return 0;
++}
++
++/* Flush protocol data */
++static int h4_flush(struct hci_uart *hu)
++{
++	struct h4_struct *h4 = hu->priv;
++
++	BT_DBG("hu %p", hu);
++	skb_queue_purge(&h4->txq);
++	return 0;
++}
++
++/* Close protocol */
++static int h4_close(struct hci_uart *hu)
++{
++	struct h4_struct *h4 = hu->priv;
++	hu->priv = NULL;
++
++	BT_DBG("hu %p", hu);
++
++	skb_queue_purge(&h4->txq);
++	if (h4->rx_skb)
++		kfree_skb(h4->rx_skb);
++
++	hu->priv = NULL;
++	kfree(h4);
++	return 0;
++}
++
++/* Enqueue frame for transmittion (padding, crc, etc) */
++static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
++{
++	struct h4_struct *h4 = hu->priv;
++
++	BT_DBG("hu %p skb %p", hu, skb);
++
++	/* Prepend skb with frame type */
++	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
++	skb_queue_tail(&h4->txq, skb);
++	return 0;
++}
++
++static inline int h4_check_data_len(struct h4_struct *h4, int len)
++{
++	register int room = skb_tailroom(h4->rx_skb);
++
++	BT_DBG("len %d room %d", len, room);
++	if (!len) {
++		BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
++		hci_recv_frame(h4->rx_skb);
++	} else if (len > room) {
++		BT_ERR("Data length is too large");
++		kfree_skb(h4->rx_skb);
++	} else {
++		h4->rx_state = H4_W4_DATA;
++		h4->rx_count = len;
++		return len;
++	}
++
++	h4->rx_state = H4_W4_PACKET_TYPE;
++	h4->rx_skb   = NULL;
++	h4->rx_count = 0;
++	return 0;
++}
++
++/* Recv data */
++static int h4_recv(struct hci_uart *hu, void *data, int count)
++{
++	struct h4_struct *h4 = hu->priv;
++	register char *ptr;
++	hci_event_hdr *eh;
++	hci_acl_hdr   *ah;
++	hci_sco_hdr   *sh;
++	register int len, type, dlen;
++
++	BT_DBG("hu %p count %d rx_state %ld rx_count %ld", 
++			hu, count, h4->rx_state, h4->rx_count);
++
++	ptr = data;
++	while (count) {
++		if (h4->rx_count) {
++			len = MIN(h4->rx_count, count);
++			memcpy(skb_put(h4->rx_skb, len), ptr, len);
++			h4->rx_count -= len; count -= len; ptr += len;
++
++			if (h4->rx_count)
++				continue;
++
++			switch (h4->rx_state) {
++			case H4_W4_DATA:
++				BT_DBG("Complete data");
++
++				BT_DMP(h4->rx_skb->data, h4->rx_skb->len);
++
++				hci_recv_frame(h4->rx_skb);
++
++				h4->rx_state = H4_W4_PACKET_TYPE;
++				h4->rx_skb = NULL;
++				continue;
++
++			case H4_W4_EVENT_HDR:
++				eh = (hci_event_hdr *) h4->rx_skb->data;
++
++				BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
++
++				h4_check_data_len(h4, eh->plen);
++				continue;
++
++			case H4_W4_ACL_HDR:
++				ah = (hci_acl_hdr *) h4->rx_skb->data;
++				dlen = __le16_to_cpu(ah->dlen);
++
++				BT_DBG("ACL header: dlen %d", dlen);
++
++				h4_check_data_len(h4, dlen);
++				continue;
++
++			case H4_W4_SCO_HDR:
++				sh = (hci_sco_hdr *) h4->rx_skb->data;
++
++				BT_DBG("SCO header: dlen %d", sh->dlen);
++
++				h4_check_data_len(h4, sh->dlen);
++				continue;
++			}
++		}
++
++		/* H4_W4_PACKET_TYPE */
++		switch (*ptr) {
++		case HCI_EVENT_PKT:
++			BT_DBG("Event packet");
++			h4->rx_state = H4_W4_EVENT_HDR;
++			h4->rx_count = HCI_EVENT_HDR_SIZE;
++			type = HCI_EVENT_PKT;
++			break;
++
++		case HCI_ACLDATA_PKT:
++			BT_DBG("ACL packet");
++			h4->rx_state = H4_W4_ACL_HDR;
++			h4->rx_count = HCI_ACL_HDR_SIZE;
++			type = HCI_ACLDATA_PKT;
++			break;
++
++		case HCI_SCODATA_PKT:
++			BT_DBG("SCO packet");
++			h4->rx_state = H4_W4_SCO_HDR;
++			h4->rx_count = HCI_SCO_HDR_SIZE;
++			type = HCI_SCODATA_PKT;
++			break;
++
++		default:
++			BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
++			hu->hdev.stat.err_rx++;
++			ptr++; count--;
++			continue;
++		};
++		ptr++; count--;
++
++		/* Allocate packet */
++		h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
++		if (!h4->rx_skb) {
++			BT_ERR("Can't allocate mem for new packet");
++			h4->rx_state = H4_W4_PACKET_TYPE;
++			h4->rx_count = 0;
++			return 0;
++		}
++		h4->rx_skb->dev = (void *) &hu->hdev;
++		h4->rx_skb->pkt_type = type;
++	}
++	return count;
++}
++
++static struct sk_buff *h4_dequeue(struct hci_uart *hu)
++{
++	struct h4_struct *h4 = hu->priv;
++	return skb_dequeue(&h4->txq);
++}
++
++static struct hci_uart_proto h4p = {
++	id:      HCI_UART_H4,
++	open:    h4_open,
++	close:   h4_close,
++	recv:    h4_recv,
++	enqueue: h4_enqueue,
++	dequeue: h4_dequeue,
++	flush:   h4_flush,
++};
++	      
++int h4_init(void)
++{
++	return hci_uart_register_proto(&h4p);
++}
++
++int h4_deinit(void)
++{
++	return hci_uart_unregister_proto(&h4p);
++}
+diff -urN linux-2.4.18/drivers/bluetooth/hci_h4.h linux-2.4.18-mh9/drivers/bluetooth/hci_h4.h
+--- linux-2.4.18/drivers/bluetooth/hci_h4.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_h4.h	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,44 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifdef __KERNEL__
++struct h4_struct {
++	unsigned long rx_state;
++	unsigned long rx_count;
++	struct sk_buff *rx_skb;
++	struct sk_buff_head txq;
++};
++
++/* H4 receiver States */
++#define H4_W4_PACKET_TYPE 0
++#define H4_W4_EVENT_HDR	  1
++#define H4_W4_ACL_HDR     2
++#define H4_W4_SCO_HDR     3
++#define H4_W4_DATA        4
++
++#endif /* __KERNEL__ */
+diff -urN linux-2.4.18/drivers/bluetooth/hci_ldisc.c linux-2.4.18-mh9/drivers/bluetooth/hci_ldisc.c
+--- linux-2.4.18/drivers/bluetooth/hci_ldisc.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_ldisc.c	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,580 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ HCI UART driver.
++ *
++ * $Id$    
++ */
++#define VERSION "2.1"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/version.h>
++#include <linux/config.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/sched.h>
++#include <linux/types.h>
++#include <linux/fcntl.h>
++#include <linux/interrupt.h>
++#include <linux/ptrace.h>
++#include <linux/poll.h>
++
++#include <linux/slab.h>
++#include <linux/tty.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/signal.h>
++#include <linux/ioctl.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include "hci_uart.h"
++
++#ifndef HCI_UART_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
++#endif
++
++static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
++
++int hci_uart_register_proto(struct hci_uart_proto *p)
++{
++	if (p->id >= HCI_UART_MAX_PROTO)
++		return -EINVAL;
++
++	if (hup[p->id])
++		return -EEXIST;
++
++	hup[p->id] = p;
++	return 0;
++}
++
++int hci_uart_unregister_proto(struct hci_uart_proto *p)
++{
++	if (p->id >= HCI_UART_MAX_PROTO)
++		return -EINVAL;
++
++	if (!hup[p->id])
++		return -EINVAL;
++
++	hup[p->id] = NULL;
++	return 0;
++}
++
++static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
++{
++	if (id >= HCI_UART_MAX_PROTO)
++		return NULL;
++	return hup[id];
++}
++
++static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
++{
++	struct hci_dev *hdev = &hu->hdev;
++	
++	/* Update HCI stat counters */
++	switch (pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++
++	case HCI_SCODATA_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++	}
++}
++
++static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
++{
++	struct sk_buff *skb = hu->tx_skb;
++	if (!skb)
++		skb = hu->proto->dequeue(hu);
++	else
++		hu->tx_skb = NULL;
++	return skb;
++}
++
++int hci_uart_tx_wakeup(struct hci_uart *hu)
++{
++	struct tty_struct *tty = hu->tty;
++	struct hci_dev *hdev = &hu->hdev;
++	struct sk_buff *skb;
++	
++	if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) {
++		set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
++		return 0;
++	}
++
++	BT_DBG("");
++
++restart:
++	clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
++
++	while ((skb = hci_uart_dequeue(hu))) {
++		int len;
++	
++		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
++		len = tty->driver.write(tty, 0, skb->data, skb->len);
++		hdev->stat.byte_tx += len;
++
++		skb_pull(skb, len);
++		if (skb->len) {
++			hu->tx_skb = skb;
++			break;
++		}
++	
++		hci_uart_tx_complete(hu, skb->pkt_type);
++		kfree_skb(skb);
++	} 
++	
++	if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state))
++		goto restart;
++
++	clear_bit(HCI_UART_SENDING, &hu->tx_state);
++	return 0;
++}
++
++/* ------- Interface to HCI layer ------ */
++/* Initialize device */
++static int hci_uart_open(struct hci_dev *hdev)
++{
++	BT_DBG("%s %p", hdev->name, hdev);
++
++	/* Nothing to do for UART driver */
++
++	set_bit(HCI_RUNNING, &hdev->flags);
++	return 0;
++}
++
++/* Reset device */
++static int hci_uart_flush(struct hci_dev *hdev)
++{
++	struct hci_uart *hu  = (struct hci_uart *) hdev->driver_data;
++	struct tty_struct *tty = hu->tty;
++
++	BT_DBG("hdev %p tty %p", hdev, tty);
++
++	if (hu->tx_skb) {
++		kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
++	}
++
++	/* Flush any pending characters in the driver and discipline. */
++	if (tty->ldisc.flush_buffer)
++		tty->ldisc.flush_buffer(tty);
++
++	if (tty->driver.flush_buffer)
++		tty->driver.flush_buffer(tty);
++
++	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
++		hu->proto->flush(hu);
++
++	return 0;
++}
++
++/* Close device */
++static int hci_uart_close(struct hci_dev *hdev)
++{
++	BT_DBG("hdev %p", hdev);
++
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
++	hci_uart_flush(hdev);
++	return 0;
++}
++
++/* Send frames from HCI layer */
++static int hci_uart_send_frame(struct sk_buff *skb)
++{
++	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
++	struct tty_struct *tty;
++	struct hci_uart *hu;
++
++	if (!hdev) {
++		BT_ERR("Frame for uknown device (hdev=NULL)");
++		return -ENODEV;
++	}
++
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return -EBUSY;
++
++	hu = (struct hci_uart *) hdev->driver_data;
++	tty = hu->tty;
++
++	BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
++
++	hu->proto->enqueue(hu, skb);
++
++	hci_uart_tx_wakeup(hu);
++	return 0;
++}
++
++static void hci_uart_destruct(struct hci_dev *hdev)
++{
++	struct hci_uart *hu;
++
++	if (!hdev) return;
++
++	BT_DBG("%s", hdev->name);
++
++	hu = (struct hci_uart *) hdev->driver_data;
++	kfree(hu);
++
++	MOD_DEC_USE_COUNT;
++}
++
++/* ------ LDISC part ------ */
++/* hci_uart_tty_open
++ * 
++ *     Called when line discipline changed to HCI_UART.
++ *
++ * Arguments:
++ *     tty    pointer to tty info structure
++ * Return Value:    
++ *     0 if success, otherwise error code
++ */
++static int hci_uart_tty_open(struct tty_struct *tty)
++{
++	struct hci_uart *hu = (void *) tty->disc_data;
++
++	BT_DBG("tty %p", tty);
++
++	if (hu)
++		return -EEXIST;
++
++	if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
++		BT_ERR("Can't allocate controll structure");
++		return -ENFILE;
++	}
++	memset(hu, 0, sizeof(struct hci_uart));
++
++	tty->disc_data = hu;
++	hu->tty = tty;
++
++	spin_lock_init(&hu->rx_lock);
++
++	/* Flush any pending characters in the driver and line discipline */
++	if (tty->ldisc.flush_buffer)
++		tty->ldisc.flush_buffer(tty);
++
++	if (tty->driver.flush_buffer)
++		tty->driver.flush_buffer(tty);
++	
++	MOD_INC_USE_COUNT;
++	return 0;
++}
++
++/* hci_uart_tty_close()
++ *
++ *    Called when the line discipline is changed to something
++ *    else, the tty is closed, or the tty detects a hangup.
++ */
++static void hci_uart_tty_close(struct tty_struct *tty)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++
++	BT_DBG("tty %p", tty);
++
++	/* Detach from the tty */
++	tty->disc_data = NULL;
++
++	if (hu) {
++		struct hci_dev *hdev = &hu->hdev;
++		hci_uart_close(hdev);
++
++		if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) {
++			hu->proto->close(hu);
++			hci_unregister_dev(hdev);
++		}
++
++		MOD_DEC_USE_COUNT;
++	}
++}
++
++/* hci_uart_tty_wakeup()
++ *
++ *    Callback for transmit wakeup. Called when low level
++ *    device driver can accept more send data.
++ *
++ * Arguments:        tty    pointer to associated tty instance data
++ * Return Value:    None
++ */
++static void hci_uart_tty_wakeup(struct tty_struct *tty)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++
++	BT_DBG("");
++
++	if (!hu)
++		return;
++
++	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
++
++	if (tty != hu->tty)
++		return;
++
++	if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
++		hci_uart_tx_wakeup(hu);
++}
++
++/* hci_uart_tty_room()
++ * 
++ *    Callback function from tty driver. Return the amount of 
++ *    space left in the receiver's buffer to decide if remote
++ *    transmitter is to be throttled.
++ *
++ * Arguments:        tty    pointer to associated tty instance data
++ * Return Value:    number of bytes left in receive buffer
++ */
++static int hci_uart_tty_room (struct tty_struct *tty)
++{
++	return 65536;
++}
++
++/* hci_uart_tty_receive()
++ * 
++ *     Called by tty low level driver when receive data is
++ *     available.
++ *     
++ * Arguments:  tty          pointer to tty isntance data
++ *             data         pointer to received data
++ *             flags        pointer to flags for data
++ *             count        count of received data in bytes
++ *     
++ * Return Value:    None
++ */
++static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++	
++	if (!hu || tty != hu->tty)
++		return;
++
++	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
++		return;
++	
++	spin_lock(&hu->rx_lock);
++	hu->proto->recv(hu, (void *) data, count);
++	hu->hdev.stat.byte_rx += count;
++	spin_unlock(&hu->rx_lock);
++
++	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
++		tty->driver.unthrottle(tty);
++}
++
++static int hci_uart_register_dev(struct hci_uart *hu)
++{
++	struct hci_dev *hdev;
++
++	BT_DBG("");
++
++	/* Initialize and register HCI device */
++	hdev = &hu->hdev;
++
++	hdev->type = HCI_UART;
++	hdev->driver_data = hu;
++
++	hdev->open  = hci_uart_open;
++	hdev->close = hci_uart_close;
++	hdev->flush = hci_uart_flush;
++	hdev->send  = hci_uart_send_frame;
++	hdev->destruct = hci_uart_destruct;
++
++	if (hci_register_dev(hdev) < 0) {
++		BT_ERR("Can't register HCI device %s", hdev->name);
++		return -ENODEV;
++	}
++	MOD_INC_USE_COUNT;
++	return 0;
++}
++
++static int hci_uart_set_proto(struct hci_uart *hu, int id)
++{
++	struct hci_uart_proto *p;
++	int err;	
++	
++	p = hci_uart_get_proto(id);
++	if (!p)
++		return -EPROTONOSUPPORT;
++
++	err = p->open(hu);
++	if (err)
++		return err;
++
++	hu->proto = p;
++
++	err = hci_uart_register_dev(hu);
++	if (err) {
++		p->close(hu);
++		return err;
++	}
++	return 0;
++}
++
++/* hci_uart_tty_ioctl()
++ *
++ *    Process IOCTL system call for the tty device.
++ *
++ * Arguments:
++ *
++ *    tty        pointer to tty instance data
++ *    file       pointer to open file object for device
++ *    cmd        IOCTL command code
++ *    arg        argument for IOCTL call (cmd dependent)
++ *
++ * Return Value:    Command dependent
++ */
++static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
++                            unsigned int cmd, unsigned long arg)
++{
++	struct hci_uart *hu = (void *)tty->disc_data;
++	int err = 0;
++
++	BT_DBG("");
++
++	/* Verify the status of the device */
++	if (!hu)
++		return -EBADF;
++
++	switch (cmd) {
++	case HCIUARTSETPROTO:
++		if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) {
++			err = hci_uart_set_proto(hu, arg);
++			if (err) {
++				clear_bit(HCI_UART_PROTO_SET, &hu->flags);
++				return err;
++			}
++			tty->low_latency = 1;
++		} else	
++			return -EBUSY;
++
++	case HCIUARTGETPROTO:
++		if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
++			return hu->proto->id;
++		return -EUNATCH;
++		
++	default:
++		err = n_tty_ioctl(tty, file, cmd, arg);
++		break;
++	};
++
++	return err;
++}
++
++/*
++ * We don't provide read/write/poll interface for user space.
++ */
++static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
++{
++	return 0;
++}
++static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
++{
++	return 0;
++}
++static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
++{
++	return 0;
++}
++
++#ifdef CONFIG_BLUEZ_HCIUART_H4
++int h4_init(void);
++int h4_deinit(void);
++#endif
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP
++int bcsp_init(void);
++int bcsp_deinit(void);
++#endif
++
++int __init hci_uart_init(void)
++{
++	static struct tty_ldisc hci_uart_ldisc;
++	int err;
++
++	BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
++		VERSION);
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++
++	/* Register the tty discipline */
++
++	memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc));
++	hci_uart_ldisc.magic       = TTY_LDISC_MAGIC;
++	hci_uart_ldisc.name        = "n_hci";
++	hci_uart_ldisc.open        = hci_uart_tty_open;
++	hci_uart_ldisc.close       = hci_uart_tty_close;
++	hci_uart_ldisc.read        = hci_uart_tty_read;
++	hci_uart_ldisc.write       = hci_uart_tty_write;
++	hci_uart_ldisc.ioctl       = hci_uart_tty_ioctl;
++	hci_uart_ldisc.poll        = hci_uart_tty_poll;
++	hci_uart_ldisc.receive_room= hci_uart_tty_room;
++	hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
++	hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
++
++	if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
++		BT_ERR("Can't register HCI line discipline (%d)", err);
++		return err;
++	}
++
++#ifdef CONFIG_BLUEZ_HCIUART_H4
++	h4_init();
++#endif
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP
++	bcsp_init();
++#endif
++	
++	return 0;
++}
++
++void hci_uart_cleanup(void)
++{
++	int err;
++
++#ifdef CONFIG_BLUEZ_HCIUART_H4
++	h4_deinit();
++#endif
++#ifdef CONFIG_BLUEZ_HCIUART_BCSP
++	bcsp_deinit();
++#endif
++
++	/* Release tty registration of line discipline */
++	if ((err = tty_register_ldisc(N_HCI, NULL)))
++		BT_ERR("Can't unregister HCI line discipline (%d)", err);
++}
++
++module_init(hci_uart_init);
++module_exit(hci_uart_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
++MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.c linux-2.4.18-mh9/drivers/bluetooth/hci_uart.c
+--- linux-2.4.18/drivers/bluetooth/hci_uart.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_uart.c	Thu Jan  1 01:00:00 1970
+@@ -1,580 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * BlueZ HCI UART driver.
+- *
+- * $Id$    
+- */
+-#define VERSION "1.0"
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-
+-#include <linux/version.h>
+-#include <linux/config.h>
+-#include <linux/kernel.h>
+-#include <linux/init.h>
+-#include <linux/sched.h>
+-#include <linux/types.h>
+-#include <linux/fcntl.h>
+-#include <linux/interrupt.h>
+-#include <linux/ptrace.h>
+-#include <linux/poll.h>
+-
+-#include <linux/slab.h>
+-#include <linux/tty.h>
+-#include <linux/errno.h>
+-#include <linux/string.h>
+-#include <linux/signal.h>
+-#include <linux/ioctl.h>
+-#include <linux/skbuff.h>
+-
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci_uart.h>
+-
+-#ifndef HCI_UART_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#undef  DMP
+-#define DMP( A... )
+-#endif
+-
+-/* ------- Interface to HCI layer ------ */
+-/* Initialize device */
+-int n_hci_open(struct hci_dev *hdev)
+-{
+-	DBG("%s %p", hdev->name, hdev);
+-
+-	/* Nothing to do for UART driver */
+-
+-	hdev->flags |= HCI_RUNNING;
+-
+-	return 0;
+-}
+-
+-/* Reset device */
+-int n_hci_flush(struct hci_dev *hdev)
+-{
+-	struct n_hci *n_hci  = (struct n_hci *) hdev->driver_data;
+-	struct tty_struct *tty = n_hci->tty;
+-
+-	DBG("hdev %p tty %p", hdev, tty);
+-
+-	/* Drop TX queue */
+-	skb_queue_purge(&n_hci->txq);
+-
+-	/* Flush any pending characters in the driver and discipline. */
+-	if (tty->ldisc.flush_buffer)
+-		tty->ldisc.flush_buffer(tty);
+-
+-	if (tty->driver.flush_buffer)
+-		tty->driver.flush_buffer(tty);
+-
+-	return 0;
+-}
+-
+-/* Close device */
+-int n_hci_close(struct hci_dev *hdev)
+-{
+-	DBG("hdev %p", hdev);
+-
+-	hdev->flags &= ~HCI_RUNNING;
+-
+-	n_hci_flush(hdev);
+-
+-	return 0;
+-}
+-
+-int n_hci_tx_wakeup(struct n_hci *n_hci)
+-{
+-	register struct tty_struct *tty = n_hci->tty;
+-
+-	if (test_and_set_bit(TRANS_SENDING, &n_hci->tx_state)) {
+-		set_bit(TRANS_WAKEUP, &n_hci->tx_state);
+-		return 0;
+-	}
+-
+-	DBG("");
+-	do {
+-		register struct sk_buff *skb;
+-		register int len;
+-
+-		clear_bit(TRANS_WAKEUP, &n_hci->tx_state);
+-
+-		if (!(skb = skb_dequeue(&n_hci->txq)))
+-			break;
+-
+-		DMP(skb->data, skb->len);
+-
+-		/* Send frame to TTY driver */
+-		tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+-		len = tty->driver.write(tty, 0, skb->data, skb->len);
+-
+-		n_hci->hdev.stat.byte_tx += len;
+-
+-		DBG("sent %d", len);
+-
+-		if (len == skb->len) {
+-			/* Full frame was sent */
+-			kfree_skb(skb);
+-		} else {
+-			/* Subtract sent part and requeue  */
+-			skb_pull(skb, len);
+-			skb_queue_head(&n_hci->txq, skb);
+-		}
+-	} while (test_bit(TRANS_WAKEUP, &n_hci->tx_state));
+-	clear_bit(TRANS_SENDING, &n_hci->tx_state);
+-
+-	return 0;
+-}
+-
+-/* Send frames from HCI layer */
+-int n_hci_send_frame(struct sk_buff *skb)
+-{
+-	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+-	struct tty_struct *tty;
+-	struct n_hci *n_hci;
+-
+-	if (!hdev) {
+-		ERR("Frame for uknown device (hdev=NULL)");
+-		return -ENODEV;
+-	}
+-
+-	if (!(hdev->flags & HCI_RUNNING))
+-		return -EBUSY;
+-
+-	n_hci = (struct n_hci *) hdev->driver_data;
+-	tty = n_hci2tty(n_hci);
+-
+-	DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len);
+-
+-	switch (skb->pkt_type) {
+-		case HCI_COMMAND_PKT:
+-			hdev->stat.cmd_tx++;
+-			break;
+-
+-                case HCI_ACLDATA_PKT:
+-			hdev->stat.acl_tx++;
+-                        break;
+-
+-		case HCI_SCODATA_PKT:
+-			hdev->stat.cmd_tx++;
+-                        break;
+-	};
+-
+-	/* Prepend skb with frame type and queue */
+-	memcpy(skb_push(skb, 1), &skb->pkt_type, 1);
+-	skb_queue_tail(&n_hci->txq, skb);
+-
+-	n_hci_tx_wakeup(n_hci);
+-
+-	return 0;
+-}
+-
+-/* ------ LDISC part ------ */
+-
+-/* n_hci_tty_open
+- * 
+- *     Called when line discipline changed to N_HCI.
+- *     
+- * Arguments:    
+- *     tty    pointer to tty info structure
+- * Return Value:    
+- *     0 if success, otherwise error code
+- */
+-static int n_hci_tty_open(struct tty_struct *tty)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-	struct hci_dev *hdev;
+-
+-	DBG("tty %p", tty);
+-
+-	if (n_hci)
+-		return -EEXIST;
+-
+-	if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) {
+-		ERR("Can't allocate controll structure");
+-		return -ENFILE;
+-	}
+-	memset(n_hci, 0, sizeof(struct n_hci));
+-
+-	/* Initialize and register HCI device */
+-	hdev = &n_hci->hdev;
+-
+-	hdev->type = HCI_UART;
+-	hdev->driver_data = n_hci;
+-
+-	hdev->open  = n_hci_open;
+-	hdev->close = n_hci_close;
+-	hdev->flush = n_hci_flush;
+-	hdev->send  = n_hci_send_frame;
+-
+-	if (hci_register_dev(hdev) < 0) {
+-		ERR("Can't register HCI device %s", hdev->name);
+-		kfree(n_hci);
+-		return -ENODEV;
+-	}
+-
+-	tty->disc_data = n_hci;
+-	n_hci->tty = tty;
+-
+-	spin_lock_init(&n_hci->rx_lock);
+-	n_hci->rx_state = WAIT_PACKET_TYPE;
+-
+-	skb_queue_head_init(&n_hci->txq);
+-
+-	MOD_INC_USE_COUNT;
+-
+-	/* Flush any pending characters in the driver and discipline. */
+-	if (tty->ldisc.flush_buffer)
+-		tty->ldisc.flush_buffer(tty);
+-
+-	if (tty->driver.flush_buffer)
+-		tty->driver.flush_buffer(tty);
+-
+-	return 0;
+-}
+-
+-/* n_hci_tty_close()
+- *
+- *    Called when the line discipline is changed to something
+- *    else, the tty is closed, or the tty detects a hangup.
+- */
+-static void n_hci_tty_close(struct tty_struct *tty)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-	struct hci_dev *hdev = &n_hci->hdev;
+-
+-	DBG("tty %p hdev %p", tty, hdev);
+-
+-	if (n_hci != NULL) {
+-		n_hci_close(hdev);
+-
+-		if (hci_unregister_dev(hdev) < 0) {
+-			ERR("Can't unregister HCI device %s",hdev->name);
+-		}
+-
+-		hdev->driver_data = NULL;
+-		tty->disc_data = NULL;
+-		kfree(n_hci);
+-
+-		MOD_DEC_USE_COUNT;
+-	}
+-}
+-
+-/* n_hci_tty_wakeup()
+- *
+- *    Callback for transmit wakeup. Called when low level
+- *    device driver can accept more send data.
+- *
+- * Arguments:        tty    pointer to associated tty instance data
+- * Return Value:    None
+- */
+-static void n_hci_tty_wakeup( struct tty_struct *tty )
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-
+-	DBG("");
+-
+-	if (!n_hci)
+-		return;
+-
+-	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+-
+-	if (tty != n_hci->tty)
+-		return;
+-
+-	n_hci_tx_wakeup(n_hci);
+-}
+-
+-/* n_hci_tty_room()
+- * 
+- *    Callback function from tty driver. Return the amount of 
+- *    space left in the receiver's buffer to decide if remote
+- *    transmitter is to be throttled.
+- *
+- * Arguments:        tty    pointer to associated tty instance data
+- * Return Value:    number of bytes left in receive buffer
+- */
+-static int n_hci_tty_room (struct tty_struct *tty)
+-{
+-	return 65536;
+-}
+-
+-static inline int n_hci_check_data_len(struct n_hci *n_hci, int len)
+-{
+-	register int room = skb_tailroom(n_hci->rx_skb);
+-
+-	DBG("len %d room %d", len, room);
+-	if (!len) {
+-		DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
+-		hci_recv_frame(n_hci->rx_skb);
+-	} else if (len > room) {
+-		ERR("Data length is to large");
+-		kfree_skb(n_hci->rx_skb);
+-		n_hci->hdev.stat.err_rx++;
+-	} else {
+-		n_hci->rx_state = WAIT_DATA;
+-		n_hci->rx_count = len;
+-		return len;
+-	}
+-
+-	n_hci->rx_state = WAIT_PACKET_TYPE;
+-	n_hci->rx_skb   = NULL;
+-	n_hci->rx_count = 0;
+-	return 0;
+-}
+-
+-static inline void n_hci_rx(struct n_hci *n_hci, const __u8 * data, char *flags, int count)
+-{
+-	register const char *ptr;
+-	hci_event_hdr *eh;
+-	hci_acl_hdr   *ah;
+-	hci_sco_hdr   *sh;
+-	register int len, type, dlen;
+-
+-	DBG("count %d state %ld rx_count %ld", count, n_hci->rx_state, n_hci->rx_count);
+-
+-	n_hci->hdev.stat.byte_rx += count;
+-
+-	ptr = data;
+-	while (count) {
+-		if (n_hci->rx_count) {
+-			len = MIN(n_hci->rx_count, count);
+-			memcpy(skb_put(n_hci->rx_skb, len), ptr, len);
+-			n_hci->rx_count -= len; count -= len; ptr += len;
+-
+-			if (n_hci->rx_count)
+-				continue;
+-
+-			switch (n_hci->rx_state) {
+-				case WAIT_DATA:
+-					DBG("Complete data");
+-
+-					DMP(n_hci->rx_skb->data, n_hci->rx_skb->len);
+-
+-					hci_recv_frame(n_hci->rx_skb);
+-
+-					n_hci->rx_state = WAIT_PACKET_TYPE;
+-					n_hci->rx_skb = NULL;
+-					continue;
+-
+-				case WAIT_EVENT_HDR:
+-					eh = (hci_event_hdr *) n_hci->rx_skb->data;
+-
+-					DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
+-
+-					n_hci_check_data_len(n_hci, eh->plen);
+-					continue;
+-
+-				case WAIT_ACL_HDR:
+-					ah = (hci_acl_hdr *) n_hci->rx_skb->data;
+-					dlen = __le16_to_cpu(ah->dlen);
+-
+-					DBG("ACL header: dlen %d", dlen);
+-
+-					n_hci_check_data_len(n_hci, dlen);
+-					continue;
+-
+-				case WAIT_SCO_HDR:
+-					sh = (hci_sco_hdr *) n_hci->rx_skb->data;
+-
+-					DBG("SCO header: dlen %d", sh->dlen);
+-
+-					n_hci_check_data_len(n_hci, sh->dlen);
+-					continue;
+-			};
+-		}
+-
+-		/* WAIT_PACKET_TYPE */
+-		switch (*ptr) {
+-			case HCI_EVENT_PKT:
+-				DBG("Event packet");
+-				n_hci->rx_state = WAIT_EVENT_HDR;
+-				n_hci->rx_count = HCI_EVENT_HDR_SIZE;
+-				type = HCI_EVENT_PKT;
+-				break;
+-
+-			case HCI_ACLDATA_PKT:
+-				DBG("ACL packet");
+-				n_hci->rx_state = WAIT_ACL_HDR;
+-				n_hci->rx_count = HCI_ACL_HDR_SIZE;
+-				type = HCI_ACLDATA_PKT;
+-				break;
+-
+-			case HCI_SCODATA_PKT:
+-				DBG("SCO packet");
+-				n_hci->rx_state = WAIT_SCO_HDR;
+-				n_hci->rx_count = HCI_SCO_HDR_SIZE;
+-				type = HCI_SCODATA_PKT;
+-				break;
+-
+-			default:
+-				ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
+-				n_hci->hdev.stat.err_rx++;
+-				ptr++; count--;
+-				continue;
+-		};
+-		ptr++; count--;
+-
+-		/* Allocate packet */
+-		if (!(n_hci->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+-			ERR("Can't allocate mem for new packet");
+-
+-			n_hci->rx_state = WAIT_PACKET_TYPE;
+-			n_hci->rx_count = 0;
+-			return;
+-		}
+-		n_hci->rx_skb->dev = (void *) &n_hci->hdev;
+-		n_hci->rx_skb->pkt_type = type;
+-	}
+-}
+-
+-/* n_hci_tty_receive()
+- * 
+- *     Called by tty low level driver when receive data is
+- *     available.
+- *     
+- * Arguments:  tty          pointer to tty isntance data
+- *             data         pointer to received data
+- *             flags        pointer to flags for data
+- *             count        count of received data in bytes
+- *     
+- * Return Value:    None
+- */
+-static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-
+-	if (!n_hci || tty != n_hci->tty)
+-		return;
+-
+-	spin_lock(&n_hci->rx_lock);
+-	n_hci_rx(n_hci, data, flags, count);
+-	spin_unlock(&n_hci->rx_lock);
+-
+-	if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle)
+-		tty->driver.unthrottle(tty);
+-}
+-
+-/* n_hci_tty_ioctl()
+- *
+- *    Process IOCTL system call for the tty device.
+- *
+- * Arguments:
+- *
+- *    tty        pointer to tty instance data
+- *    file       pointer to open file object for device
+- *    cmd        IOCTL command code
+- *    arg        argument for IOCTL call (cmd dependent)
+- *
+- * Return Value:    Command dependent
+- */
+-static int n_hci_tty_ioctl (struct tty_struct *tty, struct file * file,
+-                            unsigned int cmd, unsigned long arg)
+-{
+-	struct n_hci *n_hci = tty2n_hci(tty);
+-	int error = 0;
+-
+-	DBG("");
+-
+-	/* Verify the status of the device */
+-	if (!n_hci)
+-		return -EBADF;
+-
+-	switch (cmd) {
+-		default:
+-			error = n_tty_ioctl(tty, file, cmd, arg);
+-			break;
+-	};
+-
+-	return error;
+-}
+-
+-/*
+- * We don't provide read/write/poll interface for user space.
+- */
+-static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr)
+-{
+-	return 0;
+-}
+-static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count)
+-{
+-	return 0;
+-}
+-static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait)
+-{
+-	return 0;
+-}
+-
+-int __init n_hci_init(void)
+-{
+-	static struct tty_ldisc n_hci_ldisc;
+-	int err;
+-
+-	INF("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", 
+-		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+-
+-	/* Register the tty discipline */
+-
+-	memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc));
+-	n_hci_ldisc.magic       = TTY_LDISC_MAGIC;
+-	n_hci_ldisc.name        = "n_hci";
+-	n_hci_ldisc.open        = n_hci_tty_open;
+-	n_hci_ldisc.close       = n_hci_tty_close;
+-	n_hci_ldisc.read        = n_hci_tty_read;
+-	n_hci_ldisc.write       = n_hci_tty_write;
+-	n_hci_ldisc.ioctl       = n_hci_tty_ioctl;
+-	n_hci_ldisc.poll        = n_hci_tty_poll;
+-	n_hci_ldisc.receive_room= n_hci_tty_room;
+-	n_hci_ldisc.receive_buf = n_hci_tty_receive;
+-	n_hci_ldisc.write_wakeup= n_hci_tty_wakeup;
+-
+-	if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) {
+-		ERR("Can't register HCI line discipline (%d)", err);
+-		return err;
+-	}
+-
+-	return 0;
+-}
+-
+-void n_hci_cleanup(void)
+-{
+-	int err;
+-
+-	/* Release tty registration of line discipline */
+-	if ((err = tty_register_ldisc(N_HCI, NULL)))
+-		ERR("Can't unregister HCI line discipline (%d)", err);
+-}
+-
+-module_init(n_hci_init);
+-module_exit(n_hci_cleanup);
+-
+-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+-MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
+-MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/drivers/bluetooth/hci_uart.h linux-2.4.18-mh9/drivers/bluetooth/hci_uart.h
+--- linux-2.4.18/drivers/bluetooth/hci_uart.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_uart.h	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,81 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef N_HCI 
++#define N_HCI	15
++#endif
++
++/* Ioctls */
++#define HCIUARTSETPROTO	_IOW('U', 200, int)
++#define HCIUARTGETPROTO	_IOR('U', 201, int)
++
++/* UART protocols */
++#define HCI_UART_MAX_PROTO	3
++
++#define HCI_UART_H4	0
++#define HCI_UART_BCSP	1
++#define HCI_UART_NCSP	2
++
++#ifdef __KERNEL__
++struct hci_uart;
++
++struct hci_uart_proto {
++	unsigned int id;
++	int (*open)(struct hci_uart *hu);
++	int (*close)(struct hci_uart *hu);
++	int (*flush)(struct hci_uart *hu);
++	int (*recv)(struct hci_uart *hu, void *data, int len);
++	int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
++	struct sk_buff *(*dequeue)(struct hci_uart *hu);
++};
++
++struct hci_uart {
++	struct tty_struct  *tty;
++	struct hci_dev     hdev;
++	unsigned long      flags;
++
++	struct hci_uart_proto *proto;
++	void               *priv;
++	
++	struct sk_buff     *tx_skb;
++	unsigned long      tx_state;
++	spinlock_t         rx_lock;
++};
++
++/* HCI_UART flag bits */
++#define HCI_UART_PROTO_SET		0
++
++/* TX states  */
++#define HCI_UART_SENDING		1
++#define HCI_UART_TX_WAKEUP		2
++
++int hci_uart_register_proto(struct hci_uart_proto *p);
++int hci_uart_unregister_proto(struct hci_uart_proto *p);
++int hci_uart_tx_wakeup(struct hci_uart *hu);
++
++#endif /* __KERNEL__ */
+diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.c linux-2.4.18-mh9/drivers/bluetooth/hci_usb.c
+--- linux-2.4.18/drivers/bluetooth/hci_usb.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_usb.c	Mon Aug 25 18:38:12 2003
+@@ -1,9 +1,10 @@
+ /* 
+-   BlueZ - Bluetooth protocol stack for Linux
++   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
+    Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+    Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+ 
++   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
++
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License version 2 as
+    published by the Free Software Foundation;
+@@ -23,598 +24,901 @@
+ */
+ 
+ /*
+- * BlueZ HCI USB driver.
+  * Based on original USB Bluetooth driver for Linux kernel
+  *    Copyright (c) 2000 Greg Kroah-Hartman        <greg@kroah.com>
+  *    Copyright (c) 2000 Mark Douglas Corner       <mcorner@umich.edu>
+  *
+- * $Id$    
++ * $Id$    
+  */
+-#define VERSION "1.0"
++#define VERSION "2.4"
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
+ 
+ #include <linux/version.h>
+-#include <linux/config.h>
+ #include <linux/kernel.h>
+ #include <linux/init.h>
+ #include <linux/sched.h>
++#include <linux/unistd.h>
+ #include <linux/types.h>
+-#include <linux/fcntl.h>
+ #include <linux/interrupt.h>
+-#include <linux/ptrace.h>
+-#include <linux/poll.h>
+ 
+ #include <linux/slab.h>
+-#include <linux/tty.h>
+ #include <linux/errno.h>
+ #include <linux/string.h>
+-#include <linux/signal.h>
+-#include <linux/ioctl.h>
+ #include <linux/skbuff.h>
+ 
+ #include <linux/usb.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci_usb.h>
++
++#include "hci_usb.h"
+ 
+ #ifndef HCI_USB_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#undef  DMP
+-#define DMP( A... )
++#undef  BT_DBG
++#define BT_DBG( A... )
++#undef  BT_DMP
++#define BT_DMP( A... )
+ #endif
+ 
+-static struct usb_device_id usb_bluetooth_ids [] = {
++#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET
++#undef  USB_ZERO_PACKET
++#define USB_ZERO_PACKET 0
++#endif
++
++static struct usb_driver hci_usb_driver; 
++
++static struct usb_device_id bluetooth_ids[] = {
++	/* Generic Bluetooth USB device */
+ 	{ USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) },
++
++	/* Ericsson with non-standard id */
++	{ USB_DEVICE(0x0bdb, 0x1002) },
++
++	/* Bluetooth Ultraport Module from IBM */
++	{ USB_DEVICE(0x04bf, 0x030a) },
++
+ 	{ }	/* Terminating entry */
+ };
+ 
+-MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
++MODULE_DEVICE_TABLE (usb, bluetooth_ids);
+ 
+-static int hci_usb_ctrl_msg(struct hci_usb *husb,  struct sk_buff *skb);
+-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb);
++static struct usb_device_id ignore_ids[] = {
++	/* Broadcom BCM2033 without firmware */
++	{ USB_DEVICE(0x0a5c, 0x2033) },
+ 
+-static void hci_usb_unlink_urbs(struct hci_usb *husb)
+-{
+-	usb_unlink_urb(husb->read_urb);
+-	usb_unlink_urb(husb->intr_urb);
+-	usb_unlink_urb(husb->ctrl_urb);
+-	usb_unlink_urb(husb->write_urb);
+-}
++	{ }	/* Terminating entry */
++};
+ 
+-static void hci_usb_free_bufs(struct hci_usb *husb)
++struct _urb *_urb_alloc(int isoc, int gfp)
+ {
+-	if (husb->read_urb) {
+-		if (husb->read_urb->transfer_buffer)
+-			kfree(husb->read_urb->transfer_buffer);
+-		usb_free_urb(husb->read_urb);
+-	}
+-
+-	if (husb->intr_urb) {
+-		if (husb->intr_urb->transfer_buffer)
+-			kfree(husb->intr_urb->transfer_buffer);
+-		usb_free_urb(husb->intr_urb);
++	struct _urb *_urb = kmalloc(sizeof(struct _urb) +
++				sizeof(iso_packet_descriptor_t) * isoc, gfp);
++	if (_urb) {
++		memset(_urb, 0, sizeof(*_urb));
++		spin_lock_init(&_urb->urb.lock);
++	}
++	return _urb;
++}
++
++struct _urb *_urb_dequeue(struct _urb_queue *q)
++{
++	struct _urb *_urb = NULL;
++        unsigned long flags;
++        spin_lock_irqsave(&q->lock, flags);
++	{
++		struct list_head *head = &q->head;
++		struct list_head *next = head->next;
++		if (next != head) {
++			_urb = list_entry(next, struct _urb, list);
++			list_del(next); _urb->queue = NULL;
++		}
+ 	}
++	spin_unlock_irqrestore(&q->lock, flags);
++	return _urb;
++}
+ 
+-	if (husb->ctrl_urb)
+-		usb_free_urb(husb->ctrl_urb);
++static void hci_usb_rx_complete(struct urb *urb);
++static void hci_usb_tx_complete(struct urb *urb);
+ 
+-	if (husb->write_urb)
+-		usb_free_urb(husb->write_urb);
++#define __pending_tx(husb, type)  (&husb->pending_tx[type-1])
++#define __pending_q(husb, type)   (&husb->pending_q[type-1])
++#define __completed_q(husb, type) (&husb->completed_q[type-1])
++#define __transmit_q(husb, type)  (&husb->transmit_q[type-1])
++#define __reassembly(husb, type)  (husb->reassembly[type-1])
+ 
+-	if (husb->intr_skb)
+-		kfree_skb(husb->intr_skb);
++static inline struct _urb *__get_completed(struct hci_usb *husb, int type)
++{
++	return _urb_dequeue(__completed_q(husb, type)); 
+ }
+ 
+-/* ------- Interface to HCI layer ------ */
+-/* Initialize device */
+-int hci_usb_open(struct hci_dev *hdev)
++static void __fill_isoc_desc(struct urb *urb, int len, int mtu)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+-	int status;
+-
+-	DBG("%s", hdev->name);
+-
+-	husb->read_urb->dev = husb->udev;
+-	if ((status = usb_submit_urb(husb->read_urb)))
+-		DBG("read submit failed. %d", status);
++	int offset = 0, i;
+ 
+-	husb->intr_urb->dev = husb->udev;
+-	if ((status = usb_submit_urb(husb->intr_urb)))
+-		DBG("interrupt submit failed. %d", status);
++	BT_DBG("len %d mtu %d", len, mtu);
+ 
+-	hdev->flags |= HCI_RUNNING;
+-
+-	return 0;
++	for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) {
++		urb->iso_frame_desc[i].offset = offset;
++		urb->iso_frame_desc[i].length = mtu;
++		BT_DBG("desc %d offset %d len %d", i, offset, mtu);
++	}
++	if (len && i < HCI_MAX_ISOC_FRAMES) {
++		urb->iso_frame_desc[i].offset = offset;
++		urb->iso_frame_desc[i].length = len;
++		BT_DBG("desc %d offset %d len %d", i, offset, len);
++		i++;
++	}
++	urb->number_of_packets = i;
+ }
+ 
+-/* Reset device */
+-int hci_usb_flush(struct hci_dev *hdev)
++static int hci_usb_intr_rx_submit(struct hci_usb *husb)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	struct _urb *_urb;
++	struct urb *urb;
++	int err, pipe, interval, size;
++	void *buf;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", husb->hdev.name);
+ 
+-	/* Drop TX queues */
+-	skb_queue_purge(&husb->tx_ctrl_q);
+-	skb_queue_purge(&husb->tx_write_q);
++        size = husb->intr_in_ep->wMaxPacketSize;
+ 
+-	return 0;
++	buf = kmalloc(size, GFP_ATOMIC);
++	if (!buf)
++		return -ENOMEM;
++
++	_urb = _urb_alloc(0, GFP_ATOMIC);
++	if (!_urb) {
++		kfree(buf);
++		return -ENOMEM;
++	}
++	_urb->type = HCI_EVENT_PKT;
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
++
++	urb = &_urb->urb;
++	pipe     = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress);
++	interval = husb->intr_in_ep->bInterval;
++	FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval);
++	
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s intr rx submit failed urb %p err %d",
++				husb->hdev.name, urb, err);
++		_urb_unlink(_urb);
++		_urb_free(_urb);
++		kfree(buf);
++	}
++	return err;
+ }
+ 
+-/* Close device */
+-int hci_usb_close(struct hci_dev *hdev)
++static int hci_usb_bulk_rx_submit(struct hci_usb *husb)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	struct _urb *_urb;
++	struct urb *urb;
++	int err, pipe, size = HCI_MAX_FRAME_SIZE;
++	void *buf;
+ 
+-	DBG("%s", hdev->name);
++	buf = kmalloc(size, GFP_ATOMIC);
++	if (!buf)
++		return -ENOMEM;
+ 
+-	hdev->flags &= ~HCI_RUNNING;
+-	hci_usb_unlink_urbs(husb);
++	_urb = _urb_alloc(0, GFP_ATOMIC);
++	if (!_urb) {
++		kfree(buf);
++		return -ENOMEM;
++	}
++	_urb->type = HCI_ACLDATA_PKT;
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
+ 
+-	hci_usb_flush(hdev);
++	urb  = &_urb->urb;
++	pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress);
++        FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb);
++        urb->transfer_flags = USB_QUEUE_BULK;
+ 
+-	return 0;
++	BT_DBG("%s urb %p", husb->hdev.name, urb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s bulk rx submit failed urb %p err %d",
++				husb->hdev.name, urb, err);
++		_urb_unlink(_urb);
++		_urb_free(_urb);
++		kfree(buf);
++	}
++	return err;
+ }
+ 
+-void hci_usb_ctrl_wakeup(struct hci_usb *husb)
++#ifdef CONFIG_BLUEZ_USB_SCO
++static int hci_usb_isoc_rx_submit(struct hci_usb *husb)
+ {
+-	struct sk_buff *skb;
+-
+-	if (test_and_set_bit(HCI_TX_CTRL, &husb->tx_state))
+-		return;
++	struct _urb *_urb;
++	struct urb *urb;
++	int err, mtu, size;
++	void *buf;
+ 
+-	DBG("%s", husb->hdev.name);
++	mtu  = husb->isoc_in_ep->wMaxPacketSize;
++        size = mtu * HCI_MAX_ISOC_FRAMES;
+ 
+-	if (!(skb = skb_dequeue(&husb->tx_ctrl_q)))
+-		goto done;
++	buf = kmalloc(size, GFP_ATOMIC);
++	if (!buf)
++		return -ENOMEM;
+ 
+-	if (hci_usb_ctrl_msg(husb, skb)){
+-		kfree_skb(skb);
+-		goto done;
++	_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
++	if (!_urb) {
++		kfree(buf);
++		return -ENOMEM;
+ 	}
++	_urb->type = HCI_SCODATA_PKT;
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
+ 
+-	DMP(skb->data, skb->len);
++	urb = &_urb->urb;
+ 
+-	husb->hdev.stat.byte_tx += skb->len;
+-	return;
++	urb->context  = husb;
++	urb->dev      = husb->udev;
++	urb->pipe     = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress);
++	urb->complete = hci_usb_rx_complete;
+ 
+-done:
+-	clear_bit(HCI_TX_CTRL, &husb->tx_state);
+-	return;
++	urb->transfer_buffer_length = size;
++	urb->transfer_buffer = buf;
++	urb->transfer_flags  = USB_ISO_ASAP;
++
++	__fill_isoc_desc(urb, size, mtu);
++
++	BT_DBG("%s urb %p", husb->hdev.name, urb);
++
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s isoc rx submit failed urb %p err %d",
++				husb->hdev.name, urb, err);
++		_urb_unlink(_urb);
++		_urb_free(_urb);
++		kfree(buf);
++	}
++	return err;
+ }
++#endif
+ 
+-void hci_usb_write_wakeup(struct hci_usb *husb)
++/* Initialize device */
++static int hci_usb_open(struct hci_dev *hdev)
+ {
+-	struct sk_buff *skb;
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	int i, err;
++	unsigned long flags;
+ 
+-	if (test_and_set_bit(HCI_TX_WRITE, &husb->tx_state))
+-		return;
++	BT_DBG("%s", hdev->name);
+ 
+-	DBG("%s", husb->hdev.name);
++	if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
+ 
+-	if (!(skb = skb_dequeue(&husb->tx_write_q)))
+-		goto done;
++	MOD_INC_USE_COUNT;
+ 
+-	if (hci_usb_write_msg(husb, skb)) {
+-		skb_queue_head(&husb->tx_write_q, skb);
+-		goto done;
++	write_lock_irqsave(&husb->completion_lock, flags);
++
++	err = hci_usb_intr_rx_submit(husb);
++	if (!err) {
++		for (i = 0; i < HCI_MAX_BULK_RX; i++)
++			hci_usb_bulk_rx_submit(husb);
++
++#ifdef CONFIG_BLUEZ_USB_SCO
++		if (husb->isoc_iface)
++			for (i = 0; i < HCI_MAX_ISOC_RX; i++)
++				hci_usb_isoc_rx_submit(husb);
++#endif
++	} else {
++		clear_bit(HCI_RUNNING, &hdev->flags);
++		MOD_DEC_USE_COUNT;
+ 	}
+ 
+-	DMP(skb->data, skb->len);
++	write_unlock_irqrestore(&husb->completion_lock, flags);
++	return err;
++}
++
++/* Reset device */
++static int hci_usb_flush(struct hci_dev *hdev)
++{
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	int i;
+ 
+-	husb->hdev.stat.byte_tx += skb->len;
+-	return;
++	BT_DBG("%s", hdev->name);
+ 
+-done:
+-	clear_bit(HCI_TX_WRITE, &husb->tx_state);
+-	return;
++	for (i=0; i < 4; i++)
++		skb_queue_purge(&husb->transmit_q[i]);
++	return 0;
+ }
+ 
+-/* Send frames from HCI layer */
+-int hci_usb_send_frame(struct sk_buff *skb)
++static void hci_usb_unlink_urbs(struct hci_usb *husb)
+ {
+-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+-	struct hci_usb *husb;
++	int i;
+ 
+-	if (!hdev) {
+-		ERR("frame for uknown device (hdev=NULL)");
+-		return -ENODEV;
++	BT_DBG("%s", husb->hdev.name);
++
++	for (i=0; i < 4; i++) {
++		struct _urb *_urb;
++		struct urb *urb;
++
++		/* Kill pending requests */
++		while ((_urb = _urb_dequeue(&husb->pending_q[i]))) {
++			urb = &_urb->urb;
++			BT_DBG("%s unlinking _urb %p type %d urb %p", 
++					husb->hdev.name, _urb, _urb->type, urb);
++			usb_unlink_urb(urb);
++			_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
++		}
++
++		/* Release completed requests */
++		while ((_urb = _urb_dequeue(&husb->completed_q[i]))) {
++			urb = &_urb->urb;
++			BT_DBG("%s freeing _urb %p type %d urb %p",
++					husb->hdev.name, _urb, _urb->type, urb);
++			if (urb->setup_packet)
++				kfree(urb->setup_packet);
++			if (urb->transfer_buffer)
++				kfree(urb->transfer_buffer);
++			_urb_free(_urb);
++		}
++
++		/* Release reassembly buffers */
++		if (husb->reassembly[i]) {
++			kfree_skb(husb->reassembly[i]);
++			husb->reassembly[i] = NULL;
++		}
+ 	}
++}
+ 
+-	if (!(hdev->flags & HCI_RUNNING))
++/* Close device */
++static int hci_usb_close(struct hci_dev *hdev)
++{
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
++	unsigned long flags;
++	
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ 		return 0;
+ 
+-	husb = (struct hci_usb *) hdev->driver_data;
++	BT_DBG("%s", hdev->name);
+ 
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
++	write_lock_irqsave(&husb->completion_lock, flags);
++	
++	hci_usb_unlink_urbs(husb);
++	hci_usb_flush(hdev);
+ 
+-	switch (skb->pkt_type) {
+-		case HCI_COMMAND_PKT:
+-			skb_queue_tail(&husb->tx_ctrl_q, skb);
+-			hci_usb_ctrl_wakeup(husb);
+-			hdev->stat.cmd_tx++;
+-			return 0;
+-
+-		case HCI_ACLDATA_PKT:
+-			skb_queue_tail(&husb->tx_write_q, skb);
+-			hci_usb_write_wakeup(husb);
+-			hdev->stat.acl_tx++;
+-			return 0;
+-
+-		case HCI_SCODATA_PKT:
+-			return -EOPNOTSUPP;
+-	};
++	write_unlock_irqrestore(&husb->completion_lock, flags);
+ 
++	MOD_DEC_USE_COUNT;
+ 	return 0;
+ }
+ 
+-/* ---------- USB ------------- */
+-
+-static void hci_usb_ctrl(struct urb *urb)
++static int __tx_submit(struct hci_usb *husb, struct _urb *_urb)
+ {
+-	struct sk_buff *skb = (struct sk_buff *) urb->context;
+-	struct hci_dev *hdev;
+-	struct hci_usb *husb;
+-
+-	if (!skb)
+-		return;
+-	hdev = (struct hci_dev *) skb->dev;
+-	husb = (struct hci_usb *) hdev->driver_data;
++	struct urb *urb = &_urb->urb;
++	int err;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type);
++	
++	_urb_queue_tail(__pending_q(husb, _urb->type), _urb);
++	err = usb_submit_urb(urb);
++	if (err) {
++		BT_ERR("%s tx submit failed urb %p type %d err %d",
++				husb->hdev.name, urb, _urb->type, err);
++		_urb_unlink(_urb);
++		_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
++	} else
++		atomic_inc(__pending_tx(husb, _urb->type));
++
++	return err;
++}
++
++static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb)
++{
++	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
++	devrequest *dr;
++	struct urb *urb;
++
++	if (!_urb) {
++	       	_urb = _urb_alloc(0, GFP_ATOMIC);
++	       	if (!_urb)
++			return -ENOMEM;
++		_urb->type = skb->pkt_type;
++
++		dr = kmalloc(sizeof(*dr), GFP_ATOMIC);
++		if (!dr) {
++			_urb_free(_urb);
++			return -ENOMEM;
++		}
++	} else
++		dr = (void *) _urb->urb.setup_packet;
+ 
+-	if (urb->status)
+-		DBG("%s ctrl status: %d", hdev->name, urb->status);
++	dr->requesttype = HCI_CTRL_REQ;
++	dr->request = 0;
++	dr->index   = 0;
++	dr->value   = 0;
++	dr->length  = __cpu_to_le16(skb->len);
+ 
+-	clear_bit(HCI_TX_CTRL, &husb->tx_state);
+-	kfree_skb(skb);
++	urb = &_urb->urb;
++	FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0),
++		(void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb);
+ 
+-	/* Wake up device */
+-	hci_usb_ctrl_wakeup(husb);
++	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
++	
++	_urb->priv = skb;
++	return __tx_submit(husb, _urb);
+ }
+ 
+-static void hci_usb_bulk_write(struct urb *urb)
++static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb)
+ {
+-	struct sk_buff *skb = (struct sk_buff *) urb->context;
+-	struct hci_dev *hdev;
+-	struct hci_usb *husb;
+-
+-	if (!skb)
+-		return;
+-	hdev = (struct hci_dev *) skb->dev;
+-	husb = (struct hci_usb *) hdev->driver_data;
++	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
++	struct urb *urb;
++	int pipe;
+ 
+-	DBG("%s", hdev->name);
+-
+-	if (urb->status)
+-		DBG("%s bulk write status: %d", hdev->name, urb->status);
++	if (!_urb) {
++	       	_urb = _urb_alloc(0, GFP_ATOMIC);
++	       	if (!_urb)
++			return -ENOMEM;
++		_urb->type = skb->pkt_type;
++	}
+ 
+-	clear_bit(HCI_TX_WRITE, &husb->tx_state);
+-	kfree_skb(skb);
++	urb  = &_urb->urb;
++	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress);
++	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, 
++			hci_usb_tx_complete, husb);
++	urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET;
+ 
+-	/* Wake up device */
+-	hci_usb_write_wakeup(husb);
++	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
+ 
+-	return;
++	_urb->priv = skb;
++	return __tx_submit(husb, _urb);
+ }
+ 
+-static void hci_usb_intr(struct urb *urb)
++#ifdef CONFIG_BLUEZ_USB_SCO
++static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) urb->context;
+-	unsigned char *data = urb->transfer_buffer;
+-	register int count  = urb->actual_length;
+-	register struct sk_buff *skb = husb->intr_skb;
+-	hci_event_hdr *eh;
+-	register int len;
++	struct _urb *_urb = __get_completed(husb, skb->pkt_type);
++	struct urb *urb;
++	
++	if (!_urb) {
++	       	_urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC);
++	       	if (!_urb)
++			return -ENOMEM;
++		_urb->type = skb->pkt_type;
++	}
+ 
+-	if (!husb)
+-		return;
++	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
+ 
+-	DBG("%s count %d", husb->hdev.name, count);
++	urb = &_urb->urb;
++	
++	urb->context  = husb;
++	urb->dev      = husb->udev;
++	urb->pipe     = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress);
++	urb->complete = hci_usb_tx_complete;
++	urb->transfer_flags = USB_ISO_ASAP;
+ 
+-	if (urb->status || !count) {
+-		DBG("%s intr status %d, count %d", husb->hdev.name, urb->status, count);
+-		return;
+-	}
++	urb->transfer_buffer = skb->data;
++	urb->transfer_buffer_length = skb->len;
++	
++	__fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize);
+ 
+-	/* Do we really have to handle continuations here ? */
+-	if (!skb) {
+-		/* New frame */
+-		if (count < HCI_EVENT_HDR_SIZE) {
+-			DBG("%s bad frame len %d", husb->hdev.name, count);
+-			return;
+-		}
++	_urb->priv = skb;
++	return __tx_submit(husb, _urb);
++}
++#endif
++
++static void hci_usb_tx_process(struct hci_usb *husb)
++{
++	struct sk_buff_head *q;
++	struct sk_buff *skb;
+ 
+-		eh = (hci_event_hdr *) data;
+-		len = eh->plen + HCI_EVENT_HDR_SIZE;
++	BT_DBG("%s", husb->hdev.name);
+ 
+-		if (count > len) {
+-			DBG("%s corrupted frame, len %d", husb->hdev.name, count);
+-			return;
++	do {
++		clear_bit(HCI_USB_TX_WAKEUP, &husb->state);
++
++		/* Process command queue */
++		q = __transmit_q(husb, HCI_COMMAND_PKT);
++		if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) &&
++				(skb = skb_dequeue(q))) {
++			if (hci_usb_send_ctrl(husb, skb) < 0)
++				skb_queue_head(q, skb);
+ 		}
+ 
+-		/* Allocate skb */
+-		if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
+-			ERR("Can't allocate mem for new packet");
+-			return;
++#ifdef CONFIG_BLUEZ_USB_SCO
++		/* Process SCO queue */
++		q = __transmit_q(husb, HCI_SCODATA_PKT);
++		if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX &&
++				(skb = skb_dequeue(q))) {
++			if (hci_usb_send_isoc(husb, skb) < 0)
++				skb_queue_head(q, skb);
++		}
++#endif
++		
++		/* Process ACL queue */
++		q = __transmit_q(husb, HCI_ACLDATA_PKT);
++		while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX &&
++				(skb = skb_dequeue(q))) {
++			if (hci_usb_send_bulk(husb, skb) < 0) {
++				skb_queue_head(q, skb);
++				break;
++			}
+ 		}
+-		skb->dev = (void *) &husb->hdev;
+-		skb->pkt_type = HCI_EVENT_PKT;
++	} while(test_bit(HCI_USB_TX_WAKEUP, &husb->state));
++}
+ 
+-		husb->intr_skb = skb;
+-		husb->intr_count = len;
+-	} else {
+-		/* Continuation */
+-		if (count > husb->intr_count) {
+-			ERR("%s bad frame len %d (expected %d)", husb->hdev.name, count, husb->intr_count);
++static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
++{
++	/* Serialize TX queue processing to avoid data reordering */
++	if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) {
++		hci_usb_tx_process(husb);
++		clear_bit(HCI_USB_TX_PROCESS, &husb->state);
++	} else
++		set_bit(HCI_USB_TX_WAKEUP, &husb->state);
++}
+ 
+-			kfree_skb(skb);
+-			husb->intr_skb = NULL;
+-			husb->intr_count = 0;
+-			return;
+-		}
++/* Send frames from HCI layer */
++static int hci_usb_send_frame(struct sk_buff *skb)
++{
++	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
++	struct hci_usb *husb;
++
++	if (!hdev) {
++		BT_ERR("frame for uknown device (hdev=NULL)");
++		return -ENODEV;
+ 	}
+ 
+-	memcpy(skb_put(skb, count), data, count);
+-	husb->intr_count -= count;
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return -EBUSY;
+ 
+-	DMP(data, count);
++	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+ 
+-	if (!husb->intr_count) {
+-		/* Got complete frame */
++	husb = (struct hci_usb *) hdev->driver_data;
+ 
+-		husb->hdev.stat.byte_rx += skb->len;
+-		hci_recv_frame(skb);
++	switch (skb->pkt_type) {
++	case HCI_COMMAND_PKT:
++		hdev->stat.cmd_tx++;
++		break;
++
++	case HCI_ACLDATA_PKT:
++		hdev->stat.acl_tx++;
++		break;
++
++#ifdef CONFIG_BLUEZ_USB_SCO
++	case HCI_SCODATA_PKT:
++		hdev->stat.sco_tx++;
++		break;
++#endif
+ 
+-		husb->intr_skb = NULL;
++	default:
++		kfree_skb(skb);
++		return 0;
+ 	}
++
++	read_lock(&husb->completion_lock);
++
++	skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb);
++	hci_usb_tx_wakeup(husb);
++
++	read_unlock(&husb->completion_lock);
++	return 0;
+ }
+ 
+-static void hci_usb_bulk_read(struct urb *urb)
++static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count)
+ {
+-	struct hci_usb *husb = (struct hci_usb *) urb->context;
+-	unsigned char *data = urb->transfer_buffer;
+-	int count = urb->actual_length, status;
+-	struct sk_buff *skb;
+-	hci_acl_hdr *ah;
+-	register __u16 dlen;
+-
+-	if (!husb)
+-		return;
++	BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count);
+ 
+-	DBG("%s status %d, count %d, flags %x", husb->hdev.name, urb->status, count, urb->transfer_flags);
++	husb->hdev.stat.byte_rx += count;
+ 
+-	if (urb->status) {
+-		/* Do not re-submit URB on critical errors */
+-		switch (urb->status) {
+-			case -ENOENT:
+-				return;
+-			default:
+-				goto resubmit;
+-		};
+-	}
+-	if (!count)
+-		goto resubmit;
++	while (count) {
++		struct sk_buff *skb = __reassembly(husb, type);
++		struct { int expect; } *scb;
++		int len = 0;
++	
++		if (!skb) {
++			/* Start of the frame */
++
++			switch (type) {
++			case HCI_EVENT_PKT:
++				if (count >= HCI_EVENT_HDR_SIZE) {
++					hci_event_hdr *h = data;
++					len = HCI_EVENT_HDR_SIZE + h->plen;
++				} else
++					return -EILSEQ;
++				break;
+ 
+-	DMP(data, count);
++			case HCI_ACLDATA_PKT:
++				if (count >= HCI_ACL_HDR_SIZE) {
++					hci_acl_hdr *h = data;
++					len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen);
++				} else
++					return -EILSEQ;
++				break;
++#ifdef CONFIG_BLUEZ_USB_SCO
++			case HCI_SCODATA_PKT:
++				if (count >= HCI_SCO_HDR_SIZE) {
++					hci_sco_hdr *h = data;
++					len = HCI_SCO_HDR_SIZE + h->dlen;
++				} else 
++					return -EILSEQ;
++				break;
++#endif
++			}
++			BT_DBG("new packet len %d", len);
++				
++			skb = bluez_skb_alloc(len, GFP_ATOMIC);
++			if (!skb) {
++				BT_ERR("%s no memory for the packet", husb->hdev.name);
++				return -ENOMEM;
++			}
++			skb->dev = (void *) &husb->hdev;
++			skb->pkt_type = type;
++	
++			__reassembly(husb, type) = skb;
++
++			scb = (void *) skb->cb;
++			scb->expect = len;
++		} else {
++			/* Continuation */
++			scb = (void *) skb->cb;
++			len = scb->expect;
++		}
+ 
+-	ah = (hci_acl_hdr *) data;
+-	dlen = le16_to_cpu(ah->dlen);
++		len = min(len, count);
++		
++		memcpy(skb_put(skb, len), data, len);
++
++		scb->expect -= len;
++		if (!scb->expect) {
++			/* Complete frame */
++			__reassembly(husb, type) = NULL;
++			hci_recv_frame(skb);
++		}
+ 
+-	/* Verify frame len and completeness */
+-	if ((count - HCI_ACL_HDR_SIZE) != dlen) {
+-		ERR("%s corrupted ACL packet: count %d, plen %d", husb->hdev.name, count, dlen);
+-		goto resubmit;
++		count -= len; data += len;
+ 	}
++	return 0;
++}
+ 
+-	/* Allocate packet */
+-	if (!(skb = bluez_skb_alloc(count, GFP_ATOMIC))) {
+-		ERR("Can't allocate mem for new packet");
+-		goto resubmit;
+-	}
++static void hci_usb_rx_complete(struct urb *urb)
++{
++	struct _urb *_urb = container_of(urb, struct _urb, urb);
++	struct hci_usb *husb = (void *) urb->context;
++	struct hci_dev *hdev = &husb->hdev;
++	int    err, count = urb->actual_length;
+ 
+-	memcpy(skb_put(skb, count), data, count);
+-	skb->dev = (void *) &husb->hdev;
+-	skb->pkt_type = HCI_ACLDATA_PKT;
++	BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
++			_urb->type, urb->status, count, urb->transfer_flags);
+ 
+-	husb->hdev.stat.byte_rx += skb->len;
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return;
+ 
+-	hci_recv_frame(skb);
++	read_lock(&husb->completion_lock);
+ 
+-resubmit:
+-	husb->read_urb->dev = husb->udev;
+-	if ((status = usb_submit_urb(husb->read_urb)))
+-		DBG("%s read URB submit failed %d", husb->hdev.name, status);
++	if (urb->status || !count)
++		goto resubmit;
++
++	if (_urb->type == HCI_SCODATA_PKT) {
++#ifdef CONFIG_BLUEZ_USB_SCO
++		int i;
++		for (i=0; i < urb->number_of_packets; i++) {
++			BT_DBG("desc %d status %d offset %d len %d", i,
++					urb->iso_frame_desc[i].status,
++					urb->iso_frame_desc[i].offset,
++					urb->iso_frame_desc[i].actual_length);
++	
++			if (!urb->iso_frame_desc[i].status)
++				__recv_frame(husb, _urb->type, 
++					urb->transfer_buffer + urb->iso_frame_desc[i].offset,
++					urb->iso_frame_desc[i].actual_length);
++		}
++#else
++		;
++#endif
++	} else {
++		err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count);
++		if (err < 0) { 
++			BT_ERR("%s corrupted packet: type %d count %d",
++					husb->hdev.name, _urb->type, count);
++			hdev->stat.err_rx++;
++		}
++	}
+ 
+-	DBG("%s read URB re-submited", husb->hdev.name);
++resubmit:
++	if (_urb->type != HCI_EVENT_PKT) {
++		urb->dev = husb->udev;
++		err      = usb_submit_urb(urb);
++		BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
++				_urb->type, err);
++	}
++	read_unlock(&husb->completion_lock);
+ }
+ 
+-static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb)
++static void hci_usb_tx_complete(struct urb *urb)
+ {
+-	struct urb *urb = husb->ctrl_urb;
+-	devrequest *dr  = &husb->dev_req;
+-	int pipe, status;
++	struct _urb *_urb = container_of(urb, struct _urb, urb);
++	struct hci_usb *husb = (void *) urb->context;
++	struct hci_dev *hdev = &husb->hdev;
+ 
+-	DBG("%s len %d", husb->hdev.name, skb->len);
++	BT_DBG("%s urb %p status %d flags %x", hdev->name, urb,
++			urb->status, urb->transfer_flags);
+ 
+-	pipe = usb_sndctrlpipe(husb->udev, 0);
++	atomic_dec(__pending_tx(husb, _urb->type));
+ 
+-	dr->requesttype = HCI_CTRL_REQ;
+-	dr->request = 0;
+-	dr->index   = 0;
+-	dr->value   = 0;
+-	dr->length  = cpu_to_le16(skb->len);
++	urb->transfer_buffer = NULL;
++	kfree_skb((struct sk_buff *) _urb->priv);
+ 
+-	FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len,
+-	                 hci_usb_ctrl, skb);
+-
+-	if ((status = usb_submit_urb(urb))) {
+-		DBG("%s control URB submit failed %d", husb->hdev.name, status);
+-		return status;
+-	}
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
++		return;
+ 
+-	return 0;
+-}
++	if (!urb->status)
++		hdev->stat.byte_tx += urb->transfer_buffer_length;
++	else
++		hdev->stat.err_tx++;
+ 
+-static int hci_usb_write_msg(struct hci_usb *husb, struct sk_buff *skb)
+-{
+-	struct urb *urb = husb->write_urb;
+-	int pipe, status;
++	read_lock(&husb->completion_lock);
+ 
+-	DBG("%s len %d", husb->hdev.name, skb->len);
++	_urb_unlink(_urb);
++	_urb_queue_tail(__completed_q(husb, _urb->type), _urb);
+ 
+-	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep_addr);
++	hci_usb_tx_wakeup(husb);
++	
++	read_unlock(&husb->completion_lock);
++}
+ 
+-	FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len,
+-	              hci_usb_bulk_write, skb);
+-	urb->transfer_flags |= USB_QUEUE_BULK;
++static void hci_usb_destruct(struct hci_dev *hdev)
++{
++	struct hci_usb *husb = (struct hci_usb *) hdev->driver_data;
+ 
+-	if ((status = usb_submit_urb(urb))) {
+-		DBG("%s write URB submit failed %d", husb->hdev.name, status);
+-		return status;
+-	}
++	BT_DBG("%s", hdev->name);
+ 
+-	return 0;
++	kfree(husb);
+ }
+ 
+-static void * hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
++static void *hci_usb_probe(struct usb_device *udev, unsigned int ifnum, const struct usb_device_id *id)
+ {
+-	struct usb_endpoint_descriptor *bulk_out_ep, *intr_in_ep, *bulk_in_ep;
++	struct usb_endpoint_descriptor *bulk_out_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *isoc_out_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *bulk_in_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *isoc_in_ep[HCI_MAX_IFACE_NUM];
++	struct usb_endpoint_descriptor *intr_in_ep[HCI_MAX_IFACE_NUM];
+ 	struct usb_interface_descriptor *uif;
+ 	struct usb_endpoint_descriptor *ep;
++	struct usb_interface *iface, *isoc_iface;
+ 	struct hci_usb *husb;
+ 	struct hci_dev *hdev;
+-	int i, size, pipe;
+-	__u8 * buf;
++	int i, a, e, size, ifn, isoc_ifnum, isoc_alts;
+ 
+-	DBG("udev %p ifnum %d", udev, ifnum);
+-
+-	/* Check device signature */
+-	if ((udev->descriptor.bDeviceClass    != HCI_DEV_CLASS)   ||
+-	    (udev->descriptor.bDeviceSubClass != HCI_DEV_SUBCLASS)||
+-	    (udev->descriptor.bDeviceProtocol != HCI_DEV_PROTOCOL) )
+-		return NULL;
+-
+-	MOD_INC_USE_COUNT;
++	BT_DBG("udev %p ifnum %d", udev, ifnum);
+ 
+-	uif = &udev->actconfig->interface[ifnum].altsetting[0];
++	iface = &udev->actconfig->interface[0];
+ 
+-	if (uif->bNumEndpoints != 3) {
+-		DBG("Wrong number of endpoints %d", uif->bNumEndpoints);
+-		MOD_DEC_USE_COUNT;
++	/* Check our black list */
++	if (usb_match_id(udev, iface, ignore_ids))
+ 		return NULL;
+-	}
+ 
+-	bulk_out_ep = intr_in_ep = bulk_in_ep = NULL;
++	/* Check number of endpoints */
++	if (udev->actconfig->interface[ifnum].altsetting[0].bNumEndpoints < 3)
++		return NULL;
+ 
++	memset(bulk_out_ep, 0, sizeof(bulk_out_ep));
++	memset(isoc_out_ep, 0, sizeof(isoc_out_ep));
++	memset(bulk_in_ep,  0, sizeof(bulk_in_ep));
++	memset(isoc_in_ep,  0, sizeof(isoc_in_ep));
++	memset(intr_in_ep,  0, sizeof(intr_in_ep));
++
++	size = 0; 
++	isoc_iface = NULL;
++	isoc_alts  = isoc_ifnum = 0;
++	
+ 	/* Find endpoints that we need */
+-	for ( i = 0; i < uif->bNumEndpoints; ++i) {
+-		ep = &uif->endpoint[i];
+ 
+-		switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+-			case USB_ENDPOINT_XFER_BULK:
+-				if (ep->bEndpointAddress & USB_DIR_IN)
+-					bulk_in_ep  = ep;
+-				else
+-					bulk_out_ep = ep;
+-				break;
++	ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
++	for (i = 0; i < ifn; i++) {
++		iface = &udev->actconfig->interface[i];
++		for (a = 0; a < iface->num_altsetting; a++) {
++			uif = &iface->altsetting[a];
++			for (e = 0; e < uif->bNumEndpoints; e++) {
++				ep = &uif->endpoint[e];
++
++				switch (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
++				case USB_ENDPOINT_XFER_INT:
++					if (ep->bEndpointAddress & USB_DIR_IN)
++						intr_in_ep[i] = ep;
++					break;
++
++				case USB_ENDPOINT_XFER_BULK:
++					if (ep->bEndpointAddress & USB_DIR_IN)
++						bulk_in_ep[i]  = ep;
++					else
++						bulk_out_ep[i] = ep;
++					break;
++
++#ifdef CONFIG_BLUEZ_USB_SCO
++				case USB_ENDPOINT_XFER_ISOC:
++					if (ep->wMaxPacketSize < size || a > 2)
++						break;
++					size = ep->wMaxPacketSize;
++
++					isoc_iface = iface;
++					isoc_alts  = a;
++					isoc_ifnum = i;
++
++					if (ep->bEndpointAddress & USB_DIR_IN)
++						isoc_in_ep[i]  = ep;
++					else
++						isoc_out_ep[i] = ep;
++					break;
++#endif
++				}
++			}
++		}
++	}
+ 
+-			case USB_ENDPOINT_XFER_INT:
+-				intr_in_ep = ep;
+-				break;
+-		};
++	if (!bulk_in_ep[0] || !bulk_out_ep[0] || !intr_in_ep[0]) {
++		BT_DBG("Bulk endpoints not found");
++		goto done;
+ 	}
+ 
+-	if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) {
+-		DBG("Endpoints not found: %p %p %p", bulk_in_ep, bulk_out_ep, intr_in_ep);
+-		MOD_DEC_USE_COUNT;
+-		return NULL;
++#ifdef CONFIG_BLUEZ_USB_SCO
++	if (!isoc_in_ep[1] || !isoc_out_ep[1]) {
++		BT_DBG("Isoc endpoints not found");
++		isoc_iface = NULL;
+ 	}
++#endif
+ 
+ 	if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) {
+-		ERR("Can't allocate: control structure");
+-		MOD_DEC_USE_COUNT;
+-		return NULL;
++		BT_ERR("Can't allocate: control structure");
++		goto done;
+ 	}
+ 
+ 	memset(husb, 0, sizeof(struct hci_usb));
+ 
+ 	husb->udev = udev;
+-	husb->bulk_out_ep_addr = bulk_out_ep->bEndpointAddress;
+-
+-	if (!(husb->ctrl_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: control URB");
+-		goto probe_error;
+-	}
+-
+-	if (!(husb->write_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: write URB");
+-		goto probe_error;
+-	}
+-
+-	if (!(husb->read_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: read URB");
+-		goto probe_error;
+-	}
+-
+-	ep = bulk_in_ep;
+-	pipe = usb_rcvbulkpipe(udev, ep->bEndpointAddress);
+-	size = HCI_MAX_FRAME_SIZE;
+-
+-	if (!(buf = kmalloc(size, GFP_KERNEL))) {
+-		ERR("Can't allocate: read buffer");
+-		goto probe_error;
+-	}
+-
+-	FILL_BULK_URB(husb->read_urb, udev, pipe, buf, size, hci_usb_bulk_read, husb);
+-	husb->read_urb->transfer_flags |= USB_QUEUE_BULK;
+-
+-	ep = intr_in_ep;
+-	pipe = usb_rcvintpipe(udev, ep->bEndpointAddress);
+-	size = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+-
+-	if (!(husb->intr_urb = usb_alloc_urb(0))) {
+-		ERR("Can't allocate: interrupt URB");
+-		goto probe_error;
++	husb->bulk_out_ep = bulk_out_ep[0];
++	husb->bulk_in_ep  = bulk_in_ep[0];
++	husb->intr_in_ep  = intr_in_ep[0];
++
++#ifdef CONFIG_BLUEZ_USB_SCO
++	if (isoc_iface) {
++		BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts);
++		if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) {
++			BT_ERR("Can't set isoc interface settings");
++			isoc_iface = NULL;
++		}
++		usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb);
++		husb->isoc_iface  = isoc_iface;
++		husb->isoc_in_ep  = isoc_in_ep[isoc_ifnum];
++		husb->isoc_out_ep = isoc_out_ep[isoc_ifnum];
+ 	}
++#endif
++	
++	husb->completion_lock = RW_LOCK_UNLOCKED;
+ 
+-	if (!(buf = kmalloc(size, GFP_KERNEL))) {
+-		ERR("Can't allocate: interrupt buffer");
+-		goto probe_error;
++	for (i = 0; i < 4; i++) {	
++		skb_queue_head_init(&husb->transmit_q[i]);
++		_urb_queue_init(&husb->pending_q[i]);
++		_urb_queue_init(&husb->completed_q[i]);
+ 	}
+ 
+-	FILL_INT_URB(husb->intr_urb, udev, pipe, buf, size, hci_usb_intr, husb, ep->bInterval);
+-
+-	skb_queue_head_init(&husb->tx_ctrl_q);
+-	skb_queue_head_init(&husb->tx_write_q);
+-
+ 	/* Initialize and register HCI device */
+ 	hdev = &husb->hdev;
+ 
+-	hdev->type = HCI_USB;
++	hdev->type  = HCI_USB;
+ 	hdev->driver_data = husb;
+ 
+ 	hdev->open  = hci_usb_open;
+ 	hdev->close = hci_usb_close;
+ 	hdev->flush = hci_usb_flush;
+-	hdev->send	= hci_usb_send_frame;
++	hdev->send  = hci_usb_send_frame;
++	hdev->destruct = hci_usb_destruct;
+ 
+ 	if (hci_register_dev(hdev) < 0) {
+-		ERR("Can't register HCI device %s", hdev->name);
++		BT_ERR("Can't register HCI device");
+ 		goto probe_error;
+ 	}
+ 
+ 	return husb;
+ 
+ probe_error:
+-	hci_usb_free_bufs(husb);
+ 	kfree(husb);
+-	MOD_DEC_USE_COUNT;
++
++done:
+ 	return NULL;
+ }
+ 
+@@ -626,38 +930,34 @@
+ 	if (!husb)
+ 		return;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", hdev->name);
+ 
+ 	hci_usb_close(hdev);
+ 
+-	if (hci_unregister_dev(hdev) < 0) {
+-		ERR("Can't unregister HCI device %s", hdev->name);
+-	}
++	if (husb->isoc_iface)
++		usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface);
+ 
+-	hci_usb_free_bufs(husb);
+-	kfree(husb);
+-
+-	MOD_DEC_USE_COUNT;
++	if (hci_unregister_dev(hdev) < 0)
++		BT_ERR("Can't unregister HCI device %s", hdev->name);
+ }
+ 
+-static struct usb_driver hci_usb_driver =
+-{
++static struct usb_driver hci_usb_driver = {
+ 	name:           "hci_usb",
+ 	probe:          hci_usb_probe,
+ 	disconnect:     hci_usb_disconnect,
+-	id_table:       usb_bluetooth_ids,
++	id_table:       bluetooth_ids,
+ };
+ 
+ int hci_usb_init(void)
+ {
+ 	int err;
+ 
+-	INF("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
++	BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+ 		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+ 
+ 	if ((err = usb_register(&hci_usb_driver)) < 0)
+-		ERR("Failed to register HCI USB driver");
++		BT_ERR("Failed to register HCI USB driver");
+ 
+ 	return err;
+ }
+diff -urN linux-2.4.18/drivers/bluetooth/hci_usb.h linux-2.4.18-mh9/drivers/bluetooth/hci_usb.h
+--- linux-2.4.18/drivers/bluetooth/hci_usb.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_usb.h	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,139 @@
++/* 
++   HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifdef __KERNEL__
++
++/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
++#define HCI_DEV_CLASS        0xe0	/* Wireless class */
++#define HCI_DEV_SUBCLASS     0x01	/* RF subclass */
++#define HCI_DEV_PROTOCOL     0x01	/* Bluetooth programming protocol */
++
++#define HCI_CTRL_REQ	     0x20
++
++#define HCI_MAX_IFACE_NUM	3 
++
++#define HCI_MAX_BULK_TX     	4
++#define HCI_MAX_BULK_RX     	1
++
++#define HCI_MAX_ISOC_RX		2
++#define HCI_MAX_ISOC_TX		2
++
++#define HCI_MAX_ISOC_FRAMES     10
++
++struct _urb_queue {
++	struct list_head head;
++	spinlock_t       lock;
++};
++
++struct _urb {
++	struct list_head  list;
++	struct _urb_queue *queue;
++	int               type;
++	void              *priv;
++	struct urb        urb;
++};
++
++struct _urb *_urb_alloc(int isoc, int gfp);
++
++static inline void _urb_free(struct _urb *_urb)
++{
++	kfree(_urb);
++}
++
++static inline void _urb_queue_init(struct _urb_queue *q)
++{
++	INIT_LIST_HEAD(&q->head);
++	spin_lock_init(&q->lock);
++}
++
++static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb)
++{
++        unsigned long flags;
++        spin_lock_irqsave(&q->lock, flags);
++	list_add(&_urb->list, &q->head); _urb->queue = q;
++	spin_unlock_irqrestore(&q->lock, flags);
++}
++
++static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb)
++{
++        unsigned long flags;
++        spin_lock_irqsave(&q->lock, flags);
++	list_add_tail(&_urb->list, &q->head); _urb->queue = q;
++	spin_unlock_irqrestore(&q->lock, flags);
++}
++
++static inline void _urb_unlink(struct _urb *_urb)
++{
++	struct _urb_queue *q = _urb->queue;
++        unsigned long flags;
++	if (q) {
++        	spin_lock_irqsave(&q->lock, flags);
++		list_del(&_urb->list); _urb->queue = NULL;
++		spin_unlock_irqrestore(&q->lock, flags);
++	}
++}
++
++struct _urb *_urb_dequeue(struct _urb_queue *q);
++
++#ifndef container_of
++#define container_of(ptr, type, member) ({                      \
++		        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
++			        (type *)( (char *)__mptr - offsetof(type,member) );})
++#endif
++
++struct hci_usb {
++	struct hci_dev		hdev;
++
++	unsigned long		state;
++	
++	struct usb_device 	*udev;
++	
++	struct usb_endpoint_descriptor	*bulk_in_ep;
++	struct usb_endpoint_descriptor	*bulk_out_ep;
++	struct usb_endpoint_descriptor	*intr_in_ep;
++
++	struct usb_interface            *isoc_iface;
++	struct usb_endpoint_descriptor	*isoc_out_ep;
++	struct usb_endpoint_descriptor	*isoc_in_ep;
++
++	struct sk_buff_head	transmit_q[4];
++	struct sk_buff		*reassembly[4]; // Reassembly buffers
++
++	rwlock_t		completion_lock;
++
++	atomic_t		pending_tx[4];  // Number of pending requests 
++	struct _urb_queue	pending_q[4];   // Pending requests
++	struct _urb_queue	completed_q[4]; // Completed requests
++};
++
++/* States  */
++#define HCI_USB_TX_PROCESS	1
++#define HCI_USB_TX_WAKEUP	2
++
++#endif /* __KERNEL__ */
+diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.c linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.c
+--- linux-2.4.18/drivers/bluetooth/hci_vhci.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.c	Mon Aug 25 18:38:10 2003
+@@ -25,9 +25,9 @@
+ /*
+  * BlueZ HCI virtual device driver.
+  *
+- * $Id$ 
++ * $Id$ 
+  */
+-#define VERSION "1.0"
++#define VERSION "1.1"
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
+@@ -49,43 +49,56 @@
+ #include <asm/uaccess.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci_vhci.h>
++#include "hci_vhci.h"
+ 
+ /* HCI device part */
+ 
+-int hci_vhci_open(struct hci_dev *hdev)
++static int hci_vhci_open(struct hci_dev *hdev)
+ {
+-	hdev->flags |= HCI_RUNNING;
++	set_bit(HCI_RUNNING, &hdev->flags);
+ 	return 0;
+ }
+ 
+-int hci_vhci_flush(struct hci_dev *hdev)
++static int hci_vhci_flush(struct hci_dev *hdev)
+ {
+ 	struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
+ 	skb_queue_purge(&hci_vhci->readq);
+ 	return 0;
+ }
+ 
+-int hci_vhci_close(struct hci_dev *hdev)
++static int hci_vhci_close(struct hci_dev *hdev)
+ {
+-	hdev->flags &= ~HCI_RUNNING;
++	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
++		return 0;
++
+ 	hci_vhci_flush(hdev);
+ 	return 0;
+ }
+ 
+-int hci_vhci_send_frame(struct sk_buff *skb)
++static void hci_vhci_destruct(struct hci_dev *hdev)
++{
++	struct hci_vhci_struct *vhci;
++
++	if (!hdev) return;
++
++	vhci = (struct hci_vhci_struct *) hdev->driver_data;
++	kfree(vhci);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static int hci_vhci_send_frame(struct sk_buff *skb)
+ {
+ 	struct hci_dev* hdev = (struct hci_dev *) skb->dev;
+ 	struct hci_vhci_struct *hci_vhci;
+ 
+ 	if (!hdev) {
+-		ERR("Frame for uknown device (hdev=NULL)");
++		BT_ERR("Frame for uknown device (hdev=NULL)");
+ 		return -ENODEV;
+ 	}
+ 
+-	if (!(hdev->flags & HCI_RUNNING))
++	if (!test_bit(HCI_RUNNING, &hdev->flags))
+ 		return -EBUSY;
+ 
+ 	hci_vhci = (struct hci_vhci_struct *) hdev->driver_data;
+@@ -188,7 +201,7 @@
+ 
+ 	add_wait_queue(&hci_vhci->read_wait, &wait);
+ 	while (count) {
+-		current->state = TASK_INTERRUPTIBLE;
++		set_current_state(TASK_INTERRUPTIBLE);
+ 
+ 		/* Read frames from device queue */
+ 		if (!(skb = skb_dequeue(&hci_vhci->readq))) {
+@@ -214,8 +227,7 @@
+ 		kfree_skb(skb);
+ 		break;
+ 	}
+-
+-	current->state = TASK_RUNNING;
++	set_current_state(TASK_RUNNING);
+ 	remove_wait_queue(&hci_vhci->read_wait, &wait);
+ 
+ 	return ret;
+@@ -270,11 +282,13 @@
+ 	hdev->close = hci_vhci_close;
+ 	hdev->flush = hci_vhci_flush;
+ 	hdev->send  = hci_vhci_send_frame;
++	hdev->destruct = hci_vhci_destruct;
+ 
+ 	if (hci_register_dev(hdev) < 0) {
+ 		kfree(hci_vhci);
+ 		return -EBUSY;
+ 	}
++	MOD_INC_USE_COUNT;
+ 
+ 	file->private_data = hci_vhci;
+ 	return 0;   
+@@ -285,12 +299,10 @@
+ 	struct hci_vhci_struct *hci_vhci = (struct hci_vhci_struct *) file->private_data;
+ 
+ 	if (hci_unregister_dev(&hci_vhci->hdev) < 0) {
+-		ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
++		BT_ERR("Can't unregister HCI device %s", hci_vhci->hdev.name);
+ 	}
+ 
+-	kfree(hci_vhci);
+ 	file->private_data = NULL;
+-
+ 	return 0;
+ }
+ 
+@@ -315,12 +327,12 @@
+ 
+ int __init hci_vhci_init(void)
+ {
+-	INF("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
++	BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",  
+ 		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+ 
+ 	if (misc_register(&hci_vhci_miscdev)) {
+-		ERR("Can't register misc device %d\n", VHCI_MINOR);
++		BT_ERR("Can't register misc device %d\n", VHCI_MINOR);
+ 		return -EIO;
+ 	}
+ 
+@@ -337,4 +349,4 @@
+ 
+ MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+ MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
+-MODULE_LICENSE("GPL");
++MODULE_LICENSE("GPL"); 
+diff -urN linux-2.4.18/drivers/bluetooth/hci_vhci.h linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.h
+--- linux-2.4.18/drivers/bluetooth/hci_vhci.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/drivers/bluetooth/hci_vhci.h	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,50 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef __HCI_VHCI_H
++#define __HCI_VHCI_H
++
++#ifdef __KERNEL__
++
++struct hci_vhci_struct {
++	struct hci_dev       hdev;
++	__u32                flags;
++	wait_queue_head_t    read_wait;
++	struct sk_buff_head  readq;
++	struct fasync_struct *fasync;
++};
++
++/* VHCI device flags */
++#define VHCI_FASYNC		0x0010
++
++#endif /* __KERNEL__ */
++
++#define VHCI_DEV	"/dev/vhci"
++#define VHCI_MINOR	250
++
++#endif /* __HCI_VHCI_H */
+diff -urN linux-2.4.18/drivers/char/pcmcia/serial_cs.c linux-2.4.18-mh9/drivers/char/pcmcia/serial_cs.c
+--- linux-2.4.18/drivers/char/pcmcia/serial_cs.c	Fri Dec 21 18:41:54 2001
++++ linux-2.4.18-mh9/drivers/char/pcmcia/serial_cs.c	Mon Aug 25 18:38:10 2003
+@@ -2,7 +2,7 @@
+ 
+     A driver for PCMCIA serial devices
+ 
+-    serial_cs.c 1.128 2001/10/18 12:18:35
++    serial_cs.c 1.138 2002/10/25 06:24:52
+ 
+     The contents of this file are subject to the Mozilla Public
+     License Version 1.1 (the "License"); you may not use this file
+@@ -28,7 +28,7 @@
+     and other provisions required by the GPL.  If you do not delete
+     the provisions above, a recipient may use your version of this
+     file under either the MPL or the GPL.
+-    
++
+ ======================================================================*/
+ 
+ #include <linux/module.h>
+@@ -69,14 +69,14 @@
+ static int irq_list[4] = { -1 };
+ MODULE_PARM(irq_list, "1-4i");
+ 
+-/* Enable the speaker? */
+-INT_MODULE_PARM(do_sound, 1);
++INT_MODULE_PARM(do_sound, 1);		/* Enable the speaker? */
++INT_MODULE_PARM(buggy_uart, 0);		/* Skip strict UART tests? */
+ 
+ #ifdef PCMCIA_DEBUG
+ INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+ #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+ static char *version =
+-"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)";
++"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)";
+ #else
+ #define DEBUG(n, args...)
+ #endif
+@@ -95,6 +95,7 @@
+     { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
+     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
+     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
++    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 },
+     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
+     { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 },
+     { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 },
+@@ -148,7 +149,7 @@
+     client_reg_t client_reg;
+     dev_link_t *link;
+     int i, ret;
+-    
++
+     DEBUG(0, "serial_attach()\n");
+ 
+     /* Create new serial device */
+@@ -160,7 +161,7 @@
+     link->release.function = &serial_release;
+     link->release.data = (u_long)link;
+     link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+-    link->io.NumPorts1 = 8;
++    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+     link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+     if (irq_list[0] == -1)
+@@ -169,13 +170,12 @@
+ 	for (i = 0; i < 4; i++)
+ 	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+     link->conf.Attributes = CONF_ENABLE_IRQ;
+-    link->conf.Vcc = 50;
+     if (do_sound) {
+ 	link->conf.Attributes |= CONF_ENABLE_SPKR;
+ 	link->conf.Status = CCSR_AUDIO_ENA;
+     }
+     link->conf.IntType = INT_MEMORY_AND_IO;
+-    
++
+     /* Register with Card Services */
+     link->next = dev_list;
+     dev_list = link;
+@@ -194,7 +194,7 @@
+ 	serial_detach(link);
+ 	return NULL;
+     }
+-    
++
+     return link;
+ } /* serial_attach */
+ 
+@@ -214,7 +214,7 @@
+     int ret;
+ 
+     DEBUG(0, "serial_detach(0x%p)\n", link);
+-    
++
+     /* Locate device structure */
+     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+ 	if (*linkp == link) break;
+@@ -224,17 +224,17 @@
+     del_timer(&link->release);
+     if (link->state & DEV_CONFIG)
+ 	serial_release((u_long)link);
+-    
++
+     if (link->handle) {
+ 	ret = CardServices(DeregisterClient, link->handle);
+ 	if (ret != CS_SUCCESS)
+ 	    cs_error(link->handle, DeregisterClient, ret);
+     }
+-    
++
+     /* Unlink device structure, free bits */
+     *linkp = link->next;
+     kfree(info);
+-    
++
+ } /* serial_detach */
+ 
+ /*====================================================================*/
+@@ -243,18 +243,20 @@
+ {
+     struct serial_struct serial;
+     int line;
+-    
++
+     memset(&serial, 0, sizeof(serial));
+     serial.port = port;
+     serial.irq = irq;
+     serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
++    if (buggy_uart)
++	serial.flags |= ASYNC_BUGGY_UART;
+     line = register_serial(&serial);
+     if (line < 0) {
+ 	printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
+ 	       " irq %d failed\n", (u_long)serial.port, serial.irq);
+ 	return -1;
+     }
+-    
++
+     info->line[info->ndev] = line;
+     sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
+     info->node[info->ndev].major = TTY_MAJOR;
+@@ -262,7 +264,7 @@
+     if (info->ndev > 0)
+ 	info->node[info->ndev-1].next = &info->node[info->ndev];
+     info->ndev++;
+-    
++
+     return 0;
+ }
+ 
+@@ -313,7 +315,10 @@
+ 	    return setup_serial(info, port, config.AssignedIRQ);
+     }
+     link->conf.Vcc = config.Vcc;
+-    
++
++    link->io.NumPorts1 = 8;
++    link->io.NumPorts2 = 0;
++
+     /* First pass: look for a config entry that looks normal. */
+     tuple.TupleData = (cisdata_t *)buf;
+     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+@@ -340,7 +345,7 @@
+ 	    i = next_tuple(handle, &tuple, &parse);
+ 	}
+     }
+-    
++
+     /* Second pass: try to find an entry that isn't picky about
+        its base address, then try to grab any standard serial port
+        address, and finally try to get any free port. */
+@@ -352,8 +357,7 @@
+ 	    for (j = 0; j < 5; j++) {
+ 		link->io.BasePort1 = base[j];
+ 		link->io.IOAddrLines = base[j] ? 16 : 3;
+-		i = CardServices(RequestIO, link->handle,
+-				 &link->io);
++		i = CardServices(RequestIO, link->handle, &link->io);
+ 		if (i == CS_SUCCESS) goto found_port;
+ 	    }
+ 	}
+@@ -365,7 +369,7 @@
+ 	cs_error(link->handle, RequestIO, i);
+ 	return -1;
+     }
+-    
++
+     i = CardServices(RequestIRQ, link->handle, &link->irq);
+     if (i != CS_SUCCESS) {
+ 	cs_error(link->handle, RequestIRQ, i);
+@@ -390,8 +394,12 @@
+     u_char buf[256];
+     cisparse_t parse;
+     cistpl_cftable_entry_t *cf = &parse.cftable_entry;
++    config_info_t config;
+     int i, base2 = 0;
+ 
++    CardServices(GetConfigurationInfo, handle, &config);
++    link->conf.Vcc = config.Vcc;
++
+     tuple.TupleData = (cisdata_t *)buf;
+     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+     tuple.Attributes = 0;
+@@ -433,12 +441,12 @@
+ 	    i = next_tuple(handle, &tuple, &parse);
+ 	}
+     }
+-    
++
+     if (i != CS_SUCCESS) {
+-	cs_error(link->handle, RequestIO, i);
+-	return -1;
++	/* At worst, try to configure as a single port */
++	return simple_config(link);
+     }
+-    
++
+     i = CardServices(RequestIRQ, link->handle, &link->irq);
+     if (i != CS_SUCCESS) {
+ 	cs_error(link->handle, RequestIRQ, i);
+@@ -454,14 +462,27 @@
+ 	cs_error(link->handle, RequestConfiguration, i);
+ 	return -1;
+     }
+-    
++
++    /* The Oxford Semiconductor OXCF950 cards are in fact single-port:
++       8 registers are for the UART, the others are extra registers */
++    if (info->manfid == MANFID_OXSEMI) {
++	if (cf->index == 1 || cf->index == 3) {
++	    setup_serial(info, base2, link->irq.AssignedIRQ);
++	    outb(12,link->io.BasePort1+1);
++	} else {
++	    setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
++	    outb(12,base2+1);
++	}
++	return 0;
++    }
++
+     setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+     /* The Nokia cards are not really multiport cards */
+     if (info->manfid == MANFID_NOKIA)
+ 	return 0;
+     for (i = 0; i < info->multi-1; i++)
+ 	setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
+-    
++
+     return 0;
+ }
+ 
+@@ -487,7 +508,7 @@
+     int i, last_ret, last_fn;
+ 
+     DEBUG(0, "serial_config(0x%p)\n", link);
+-    
++
+     tuple.TupleData = (cisdata_t *)buf;
+     tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+     tuple.Attributes = 0;
+@@ -500,7 +521,7 @@
+     }
+     link->conf.ConfigBase = parse.config.base;
+     link->conf.Present = parse.config.rmask[0];
+-    
++
+     /* Configure card */
+     link->state |= DEV_CONFIG;
+ 
+@@ -508,8 +529,8 @@
+     tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+     tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
+     info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
+-    
+-    /* Is this a multiport card? */
++
++    /* Scan list of known multiport card ID's */
+     tuple.DesiredTuple = CISTPL_MANFID;
+     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+ 	info->manfid = le16_to_cpu(buf[0]);
+@@ -537,15 +558,15 @@
+ 		info->multi = 2;
+ 	}
+     }
+-    
++
+     if (info->multi > 1)
+ 	multi_config(link);
+     else
+ 	simple_config(link);
+-    
++
+     if (info->ndev == 0)
+ 	goto failed;
+-    
++
+     if (info->manfid == MANFID_IBM) {
+ 	conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
+ 	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
+@@ -562,6 +583,7 @@
+     cs_error(link->handle, last_fn, last_ret);
+ failed:
+     serial_release((u_long)link);
++    link->state &= ~DEV_CONFIG_PENDING;
+ 
+ } /* serial_config */
+ 
+@@ -569,7 +591,7 @@
+ 
+     After a card is removed, serial_release() will unregister the net
+     device, and release the PCMCIA configuration.
+-    
++
+ ======================================================================*/
+ 
+ void serial_release(u_long arg)
+@@ -577,7 +599,7 @@
+     dev_link_t *link = (dev_link_t *)arg;
+     serial_info_t *info = link->priv;
+     int i;
+-    
++
+     DEBUG(0, "serial_release(0x%p)\n", link);
+ 
+     for (i = 0; i < info->ndev; i++) {
+@@ -590,7 +612,7 @@
+ 	CardServices(ReleaseIO, link->handle, &link->io);
+ 	CardServices(ReleaseIRQ, link->handle, &link->irq);
+     }
+-    
++
+     link->state &= ~DEV_CONFIG;
+ 
+ } /* serial_release */
+@@ -601,7 +623,7 @@
+     stuff to run after an event is received.  A CARD_REMOVAL event
+     also sets some flags to discourage the serial drivers from
+     talking to the ports.
+-    
++
+ ======================================================================*/
+ 
+ static int serial_event(event_t event, int priority,
+@@ -609,9 +631,9 @@
+ {
+     dev_link_t *link = args->client_data;
+     serial_info_t *info = link->priv;
+-    
++
+     DEBUG(1, "serial_event(0x%06x)\n", event);
+-    
++
+     switch (event) {
+     case CS_EVENT_CARD_REMOVAL:
+ 	link->state &= ~DEV_PRESENT;
+@@ -650,7 +672,7 @@
+     if (serv.Revision != CS_RELEASE_CODE) {
+ 	printk(KERN_NOTICE "serial_cs: Card Services release "
+ 	       "does not match!\n");
+-	return -1;
++	return -EINVAL;
+     }
+     register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
+     return 0;
+diff -urN linux-2.4.18/drivers/usb/Config.in linux-2.4.18-mh9/drivers/usb/Config.in
+--- linux-2.4.18/drivers/usb/Config.in	Mon Feb 25 20:38:07 2002
++++ linux-2.4.18-mh9/drivers/usb/Config.in	Mon Aug 25 18:38:10 2003
+@@ -31,7 +31,13 @@
+ 
+ comment 'USB Device Class drivers'
+ dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
+-dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL
++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
++   if [ "$CONFIG_BLUEZ" = "n" ]; then
++      dep_tristate '  USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
++   else
++      comment '  USB Bluetooth can only be used with disabled Bluetooth subsystem'
++   fi
++fi
+ if [ "$CONFIG_SCSI" = "n" ]; then
+    comment '  SCSI support is needed for USB Storage'
+ fi
+diff -urN linux-2.4.18/include/linux/firmware.h linux-2.4.18-mh9/include/linux/firmware.h
+--- linux-2.4.18/include/linux/firmware.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/include/linux/firmware.h	Mon Aug 25 18:38:10 2003
+@@ -0,0 +1,20 @@
++#ifndef _LINUX_FIRMWARE_H
++#define _LINUX_FIRMWARE_H
++#include <linux/module.h>
++#include <linux/types.h>
++#define FIRMWARE_NAME_MAX 30 
++struct firmware {
++	size_t size;
++	u8 *data;
++};
++int request_firmware (const struct firmware **fw, const char *name,
++		      const char *device);
++int request_firmware_nowait (
++	struct module *module,
++	const char *name, const char *device, void *context,
++	void (*cont)(const struct firmware *fw, void *context));
++/* On 2.5 'device' is 'struct device *' */
++
++void release_firmware (const struct firmware *fw);
++void register_firmware (const char *name, const u8 *data, size_t size);
++#endif
+diff -urN linux-2.4.18/include/linux/kernel.h linux-2.4.18-mh9/include/linux/kernel.h
+--- linux-2.4.18/include/linux/kernel.h	Mon Feb 25 20:38:13 2002
++++ linux-2.4.18-mh9/include/linux/kernel.h	Mon Aug 25 18:38:11 2003
+@@ -11,6 +11,7 @@
+ #include <linux/linkage.h>
+ #include <linux/stddef.h>
+ #include <linux/types.h>
++#include <linux/compiler.h>
+ 
+ /* Optimization barrier */
+ /* The "volatile" is due to gcc bugs */
+@@ -181,4 +182,6 @@
+ 	char _f[20-2*sizeof(long)-sizeof(int)];	/* Padding: libc5 uses this.. */
+ };
+ 
+-#endif
++#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
++
++#endif /* _LINUX_KERNEL_H */
+diff -urN linux-2.4.18/include/net/bluetooth/bluetooth.h linux-2.4.18-mh9/include/net/bluetooth/bluetooth.h
+--- linux-2.4.18/include/net/bluetooth/bluetooth.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/bluetooth.h	Mon Aug 25 18:38:11 2003
+@@ -23,7 +23,7 @@
+ */
+ 
+ /*
+- *  $Id$
++ *  $Id$
+  */
+ 
+ #ifndef __BLUETOOTH_H
+@@ -31,17 +31,63 @@
+ 
+ #include <asm/types.h>
+ #include <asm/byteorder.h>
++#include <linux/poll.h>
++#include <net/sock.h>
+ 
+ #ifndef AF_BLUETOOTH
+ #define AF_BLUETOOTH	31
+ #define PF_BLUETOOTH	AF_BLUETOOTH
+ #endif
+ 
++/* Reserv for core and drivers use */
++#define BLUEZ_SKB_RESERVE       8
++
++#ifndef MIN
++#define MIN(a,b) ((a) < (b) ? (a) : (b))
++#endif
++
+ #define BTPROTO_L2CAP   0
+ #define BTPROTO_HCI     1
++#define BTPROTO_SCO   	2
++#define BTPROTO_RFCOMM	3
++#define BTPROTO_BNEP	4
++#define BTPROTO_CMTP	5
+ 
+ #define SOL_HCI     0
+ #define SOL_L2CAP   6
++#define SOL_SCO     17
++#define SOL_RFCOMM  18
++
++/* Debugging */
++#ifdef CONFIG_BLUEZ_DEBUG
++
++#define HCI_CORE_DEBUG		1
++#define HCI_SOCK_DEBUG		1
++#define HCI_UART_DEBUG		1
++#define HCI_USB_DEBUG		1
++//#define HCI_DATA_DUMP		1
++
++#define L2CAP_DEBUG		1
++#define SCO_DEBUG		1
++#define AF_BLUETOOTH_DEBUG	1
++
++#endif /* CONFIG_BLUEZ_DEBUG */
++
++extern void bluez_dump(char *pref, __u8 *buf, int count);
++
++#if __GNUC__ <= 2 && __GNUC_MINOR__ < 95
++#define __func__ __FUNCTION__
++#endif
++
++#define BT_INFO(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
++#define BT_DBG(fmt, arg...)  printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
++#define BT_ERR(fmt, arg...)  printk(KERN_ERR  "%s: " fmt "\n" , __func__ , ## arg)
++
++#ifdef HCI_DATA_DUMP
++#define BT_DMP(buf, len)    bluez_dump(__func__, buf, len)
++#else
++#define BT_DMP(D...)
++#endif
+ 
+ /* Connection and socket states */
+ enum {
+@@ -50,6 +96,7 @@
+ 	BT_BOUND,
+ 	BT_LISTEN,
+ 	BT_CONNECT,
++	BT_CONNECT2,
+ 	BT_CONFIG,
+ 	BT_DISCONN,
+ 	BT_CLOSED
+@@ -66,7 +113,8 @@
+ 	__u8 b[6];
+ } __attribute__((packed)) bdaddr_t;
+ 
+-#define BDADDR_ANY ((bdaddr_t *)"\000\000\000\000\000")
++#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
++#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
+ 
+ /* Copy, swap, convert BD Address */
+ static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2)
+@@ -82,6 +130,91 @@
+ char *batostr(bdaddr_t *ba);
+ bdaddr_t *strtoba(char *str);
+ 
++/* Common socket structures and functions */
++
++#define bluez_pi(sk) ((struct bluez_pinfo *) &sk->protinfo)
++#define bluez_sk(pi) ((struct sock *) \
++	((void *)pi - (unsigned long)(&((struct sock *)0)->protinfo)))
++
++struct bluez_pinfo {
++	bdaddr_t	src;
++	bdaddr_t	dst;
++
++	struct list_head accept_q;
++	struct sock *parent;
++};
++
++struct bluez_sock_list {
++	struct sock *head;
++	rwlock_t     lock;
++};
++
++int  bluez_sock_register(int proto, struct net_proto_family *ops);
++int  bluez_sock_unregister(int proto);
++void bluez_sock_init(struct socket *sock, struct sock *sk);
++void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
++void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
++int  bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm);
++uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait);
++int  bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
++
++void bluez_accept_enqueue(struct sock *parent, struct sock *sk);
++struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock);
++
++/* Skb helpers */
++struct bluez_skb_cb {
++	int    incomming;
++};
++#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
++
++static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
++{
++	struct sk_buff *skb;
++
++	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
++		skb_reserve(skb, BLUEZ_SKB_RESERVE);
++		bluez_cb(skb)->incomming  = 0;
++	}
++	return skb;
++}
++
++static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
++						       int nb, int *err)
++{
++	struct sk_buff *skb;
++
++	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
++		skb_reserve(skb, BLUEZ_SKB_RESERVE);
++		bluez_cb(skb)->incomming  = 0;
++	}
++
++	return skb;
++}
++
++static inline int skb_frags_no(struct sk_buff *skb)
++{
++	register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
++	register int n = 1;
++
++	for (; frag; frag=frag->next, n++);
++	return n;
++}
++
++int hci_core_init(void);
++int hci_core_cleanup(void);
++int hci_sock_init(void);
++int hci_sock_cleanup(void);
++
+ int bterr(__u16 code);
++
++#ifndef MODULE_LICENSE
++#define MODULE_LICENSE(x)
++#endif
++
++#ifndef list_for_each_safe
++#define list_for_each_safe(pos, n, head) \
++	for (pos = (head)->next, n = pos->next; pos != (head); \
++		pos = n, n = pos->next)
++#endif
+ 
+ #endif /* __BLUETOOTH_H */
+diff -urN linux-2.4.18/include/net/bluetooth/bluez.h linux-2.4.18-mh9/include/net/bluetooth/bluez.h
+--- linux-2.4.18/include/net/bluetooth/bluez.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/bluez.h	Thu Jan  1 01:00:00 1970
+@@ -1,124 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- *  $Id$
+- */
+-
+-#ifndef __IF_BLUEZ_H
+-#define __IF_BLUEZ_H
+-
+-#include <net/sock.h>
+-
+-#define BLUEZ_MAX_PROTO 	2
+-
+-/* Reserv for core and drivers use */
+-#define BLUEZ_SKB_RESERVE	8
+-
+-#ifndef MIN
+-#define MIN(a,b) ((a) < (b) ? (a) : (b))
+-#endif
+-
+-/* Debugging */
+-#ifdef BLUEZ_DEBUG
+-
+-#define HCI_CORE_DEBUG		1
+-#define HCI_SOCK_DEBUG		1
+-#define HCI_UART_DEBUG		1
+-#define HCI_USB_DEBUG		1
+-//#define HCI_DATA_DUMP		1
+-
+-#define L2CAP_DEBUG			1
+-
+-#endif /* BLUEZ_DEBUG */
+-
+-extern void bluez_dump(char *pref, __u8 *buf, int count);
+-
+-#define INF(fmt, arg...) printk(KERN_INFO fmt "\n" , ## arg)
+-#define DBG(fmt, arg...) printk(KERN_INFO __FUNCTION__ ": " fmt "\n" , ## arg)
+-#define ERR(fmt, arg...) printk(KERN_ERR  __FUNCTION__ ": " fmt "\n" , ## arg)
+-
+-#ifdef HCI_DATA_DUMP
+-#define DMP(buf, len)    bluez_dump(__FUNCTION__, buf, len)
+-#else
+-#define DMP(D...)
+-#endif
+-
+-/* ----- Sockets ------ */
+-struct bluez_sock_list {
+-	struct sock *head;
+-	rwlock_t     lock;
+-};
+-
+-extern int  bluez_sock_register(int proto, struct net_proto_family *ops);
+-extern int  bluez_sock_unregister(int proto);
+-
+-extern void bluez_sock_link(struct bluez_sock_list *l, struct sock *s);
+-extern void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s);
+-
+-/* ----- SKB helpers ----- */
+-struct bluez_skb_cb {
+-	int    incomming;
+-};
+-#define bluez_cb(skb)	((struct bluez_skb_cb *)(skb->cb)) 
+-
+-static inline struct sk_buff *bluez_skb_alloc(unsigned int len, int how)
+-{
+-	struct sk_buff *skb;
+-
+-	if ((skb = alloc_skb(len + BLUEZ_SKB_RESERVE, how))) {
+-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+-		bluez_cb(skb)->incomming  = 0;
+-	}
+-	return skb;
+-}
+-
+-static inline struct sk_buff *bluez_skb_send_alloc(struct sock *sk, unsigned long len, 
+-						       int nb, int *err)
+-{
+-	struct sk_buff *skb;
+-
+-	if ((skb = sock_alloc_send_skb(sk, len + BLUEZ_SKB_RESERVE, nb, err))) {
+-		skb_reserve(skb, BLUEZ_SKB_RESERVE);
+-		bluez_cb(skb)->incomming  = 0;
+-	}
+-
+-	return skb;
+-}
+-
+-static inline int skb_frags_no(struct sk_buff *skb)
+-{
+-	register struct sk_buff *frag = skb_shinfo(skb)->frag_list;
+-	register int n = 1;
+-
+-	for (; frag; frag=frag->next, n++);
+-	return n;
+-}
+-
+-extern int hci_core_init(void);
+-extern int hci_core_cleanup(void);
+-extern int hci_sock_init(void);
+-extern int hci_sock_cleanup(void);
+-
+-#endif /* __IF_BLUEZ_H */
+diff -urN linux-2.4.18/include/net/bluetooth/hci.h linux-2.4.18-mh9/include/net/bluetooth/hci.h
+--- linux-2.4.18/include/net/bluetooth/hci.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/hci.h	Mon Aug 25 18:38:12 2003
+@@ -23,59 +23,80 @@
+ */
+ 
+ /*
+- *  $Id$
++ *  $Id$
+  */
+ 
+ #ifndef __HCI_H
+ #define __HCI_H
+ 
+-#include <asm/byteorder.h>
+-
+-#define HCI_MAX_DEV 	8
+-#define HCI_MAX_FRAME_SIZE	2048
++#define HCI_MAX_ACL_SIZE	1024
++#define HCI_MAX_SCO_SIZE	255
++#define HCI_MAX_EVENT_SIZE	260
++#define HCI_MAX_FRAME_SIZE	(HCI_MAX_ACL_SIZE + 4)
+ 
+ /* HCI dev events */
+ #define HCI_DEV_REG	1
+ #define HCI_DEV_UNREG   2
+ #define HCI_DEV_UP	3
+ #define HCI_DEV_DOWN	4
++#define HCI_DEV_SUSPEND	5
++#define HCI_DEV_RESUME	6
++
++/* HCI notify events */
++#define HCI_NOTIFY_CONN_ADD		1
++#define HCI_NOTIFY_CONN_DEL		2
++#define HCI_NOTIFY_VOICE_SETTING	3
+ 
+ /* HCI device types */
+-#define HCI_UART 	0
++#define HCI_VHCI	0
+ #define HCI_USB		1
+-#define HCI_VHCI	2
+-
+-/* HCI device modes */
+-#define HCI_NORMAL 	0x0001
+-#define HCI_RAW		0x0002
+-#define HCI_MODE_MASK   (HCI_NORMAL | HCI_RAW)
+-#define HCI_SOCK	0x1000
+-
+-/* HCI device states */
+-#define HCI_INIT	0x0010
+-#define HCI_UP 		0x0020
+-#define HCI_RUNNING	0x0040
++#define HCI_PCCARD	2
++#define HCI_UART 	3
++#define HCI_RS232 	4
++#define HCI_PCI		5
+ 
+ /* HCI device flags */
+-#define HCI_PSCAN	0x0100
+-#define HCI_ISCAN	0x0200
+-#define HCI_AUTH	0x0400
++enum {
++	HCI_UP,
++	HCI_INIT,
++	HCI_RUNNING,
++
++	HCI_PSCAN,
++	HCI_ISCAN,
++	HCI_AUTH,
++	HCI_ENCRYPT,
++	HCI_INQUIRY,
++
++	HCI_RAW
++};
+ 
+-/* HCI Ioctl defines */
++/* HCI ioctl defines */
+ #define HCIDEVUP        _IOW('H', 201, int)
+ #define HCIDEVDOWN      _IOW('H', 202, int)
+ #define HCIDEVRESET     _IOW('H', 203, int)
+-#define HCIRESETSTAT    _IOW('H', 204, int)
+-#define HCIGETINFO      _IOR('H', 205, int)
+-#define HCIGETDEVLIST   _IOR('H', 206, int)
+-#define HCISETRAW       _IOW('H', 207, int)
+-#define HCISETSCAN      _IOW('H', 208, int)
+-#define HCISETAUTH      _IOW('H', 209, int)
+-#define HCIINQUIRY      _IOR('H', 210, int)
+-#define HCISETPTYPE     _IOW('H', 211, int)
++#define HCIDEVRESTAT    _IOW('H', 204, int)
++
++#define HCIGETDEVLIST   _IOR('H', 210, int)
++#define HCIGETDEVINFO   _IOR('H', 211, int)
+ #define HCIGETCONNLIST  _IOR('H', 212, int)
++#define HCIGETCONNINFO  _IOR('H', 213, int)
+ 
+-#ifndef __NO_HCI_DEFS
++#define HCISETRAW       _IOW('H', 220, int)
++#define HCISETSCAN      _IOW('H', 221, int)
++#define HCISETAUTH      _IOW('H', 222, int)
++#define HCISETENCRYPT   _IOW('H', 223, int)
++#define HCISETPTYPE     _IOW('H', 224, int)
++#define HCISETLINKPOL   _IOW('H', 225, int)
++#define HCISETLINKMODE  _IOW('H', 226, int)
++#define HCISETACLMTU    _IOW('H', 227, int)
++#define HCISETSCOMTU    _IOW('H', 228, int)
++
++#define HCIINQUIRY      _IOR('H', 240, int)
++
++/* HCI timeouts */
++#define HCI_CONN_TIMEOUT 	(HZ * 40)
++#define HCI_DISCONN_TIMEOUT 	(HZ * 2)
++#define HCI_CONN_IDLE_TIMEOUT	(HZ * 60)
+ 
+ /* HCI Packet types */
+ #define HCI_COMMAND_PKT		0x01
+@@ -92,11 +113,18 @@
+ #define HCI_DH3 	0x0800
+ #define HCI_DH5 	0x8000
+ 
++#define HCI_HV1		0x0020
++#define HCI_HV2		0x0040
++#define HCI_HV3		0x0080
++
++#define SCO_PTYPE_MASK	(HCI_HV1 | HCI_HV2 | HCI_HV3)
++#define ACL_PTYPE_MASK	(~SCO_PTYPE_MASK)
++
+ /* ACL flags */
+-#define ACL_CONT		0x0001
+-#define ACL_START		0x0002
+-#define ACL_ACTIVE_BCAST	0x0010
+-#define ACL_PICO_BCAST		0x0020
++#define ACL_CONT		0x01
++#define ACL_START		0x02
++#define ACL_ACTIVE_BCAST	0x04
++#define ACL_PICO_BCAST		0x08
+ 
+ /* Baseband links */
+ #define SCO_LINK	0x00
+@@ -125,6 +153,20 @@
+ #define LMP_PSCHEME	0x02
+ #define LMP_PCONTROL	0x04
+ 
++/* Link policies */
++#define HCI_LP_RSWITCH	0x0001
++#define HCI_LP_HOLD	0x0002
++#define HCI_LP_SNIFF	0x0004
++#define HCI_LP_PARK	0x0008
++
++/* Link mode */
++#define HCI_LM_ACCEPT	0x8000
++#define HCI_LM_MASTER	0x0001
++#define HCI_LM_AUTH	0x0002
++#define HCI_LM_ENCRYPT	0x0004
++#define HCI_LM_TRUSTED	0x0008
++#define HCI_LM_RELIABLE	0x0010
++
+ /* -----  HCI Commands ----- */
+ /* OGF & OCF values */
+ 
+@@ -137,9 +179,10 @@
+ 	__u8  hci_ver;
+ 	__u16 hci_rev;
+ 	__u8  lmp_ver;
+-	__u16 man_name;
+-	__u16 lmp_sub;
++	__u16 manufacturer;
++	__u16 lmp_subver;
+ } __attribute__ ((packed)) read_local_version_rp;
++#define READ_LOCAL_VERSION_RP_SIZE 9
+ 
+ #define OCF_READ_LOCAL_FEATURES	0x0003
+ typedef struct {
+@@ -165,18 +208,24 @@
+ /* Host Controller and Baseband */
+ #define OGF_HOST_CTL	0x03
+ #define OCF_RESET		0x0003
++#define OCF_READ_AUTH_ENABLE	0x001F
+ #define OCF_WRITE_AUTH_ENABLE	0x0020
+-	#define AUTH_DISABLED			0x00
+-	#define AUTH_ENABLED			0x01
++	#define AUTH_DISABLED		0x00
++	#define AUTH_ENABLED		0x01
++
++#define OCF_READ_ENCRYPT_MODE	0x0021
++#define OCF_WRITE_ENCRYPT_MODE	0x0022
++	#define ENCRYPT_DISABLED	0x00
++	#define ENCRYPT_P2P		0x01
++	#define ENCRYPT_BOTH		0x02
+ 
+ #define OCF_WRITE_CA_TIMEOUT  	0x0016	
+ #define OCF_WRITE_PG_TIMEOUT  	0x0018
+ 
+ #define OCF_WRITE_SCAN_ENABLE 	0x001A
+-	#define SCANS_DISABLED		0x00
+-	#define IS_ENA_PS_DIS		0x01
+-	#define IS_DIS_PS_ENA		0x02
+-	#define IS_ENA_PS_ENA		0x03
++	#define SCAN_DISABLED		0x00
++	#define SCAN_INQUIRY		0x01
++	#define SCAN_PAGE		0x02
+ 
+ #define OCF_SET_EVENT_FLT	0x0005
+ typedef struct {
+@@ -226,9 +275,31 @@
+ } __attribute__ ((packed)) write_class_of_dev_cp;
+ #define WRITE_CLASS_OF_DEV_CP_SIZE 3
+ 
++#define OCF_READ_VOICE_SETTING	0x0025
++typedef struct {
++	__u8	status;
++	__u16	voice_setting;
++} __attribute__ ((packed)) read_voice_setting_rp;
++#define READ_VOICE_SETTING_RP_SIZE 3
++
++#define OCF_WRITE_VOICE_SETTING	0x0026
++typedef struct {
++	__u16	voice_setting;
++} __attribute__ ((packed)) write_voice_setting_cp;
++#define WRITE_VOICE_SETTING_CP_SIZE 2
++
++#define OCF_HOST_BUFFER_SIZE	0x0033
++typedef struct {
++	__u16 	acl_mtu;
++	__u8 	sco_mtu;
++	__u16 	acl_max_pkt;
++	__u16	sco_max_pkt;
++} __attribute__ ((packed)) host_buffer_size_cp;
++#define HOST_BUFFER_SIZE_CP_SIZE 7
++
+ /* Link Control */
+ #define OGF_LINK_CTL	0x01 
+-#define OCF_CREATE_CONN	0x0005
++#define OCF_CREATE_CONN		0x0005
+ typedef struct {
+ 	bdaddr_t bdaddr;
+ 	__u16 	pkt_type;
+@@ -246,6 +317,13 @@
+ } __attribute__ ((packed)) accept_conn_req_cp;
+ #define ACCEPT_CONN_REQ_CP_SIZE	7
+ 
++#define OCF_REJECT_CONN_REQ	0x000a
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8 	reason;
++} __attribute__ ((packed)) reject_conn_req_cp;
++#define REJECT_CONN_REQ_CP_SIZE	7
++
+ #define OCF_DISCONNECT	0x0006
+ typedef struct {
+ 	__u16 	handle;
+@@ -253,17 +331,142 @@
+ } __attribute__ ((packed)) disconnect_cp;
+ #define DISCONNECT_CP_SIZE 3
+ 
++#define OCF_ADD_SCO	0x0007
++typedef struct {
++	__u16 	handle;
++	__u16 	pkt_type;
++} __attribute__ ((packed)) add_sco_cp;
++#define ADD_SCO_CP_SIZE 4
++
+ #define OCF_INQUIRY		0x0001
+ typedef struct {
+ 	__u8 	lap[3];
+-	__u8 	lenght;
++	__u8 	length;
+ 	__u8	num_rsp;
+ } __attribute__ ((packed)) inquiry_cp;
+ #define INQUIRY_CP_SIZE 5
+ 
+-#define OGF_LINK_POLICY	 	0x02   /* Link Policy */
++typedef struct {
++	__u8     status;
++	bdaddr_t bdaddr;
++} __attribute__ ((packed)) status_bdaddr_rp;
++#define STATUS_BDADDR_RP_SIZE 7
++
++#define OCF_INQUIRY_CANCEL	0x0002
++
++#define OCF_LINK_KEY_REPLY	0x000B
++#define OCF_LINK_KEY_NEG_REPLY	0x000C
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8     link_key[16];
++} __attribute__ ((packed)) link_key_reply_cp;
++#define LINK_KEY_REPLY_CP_SIZE 22
++
++#define OCF_PIN_CODE_REPLY	0x000D
++#define OCF_PIN_CODE_NEG_REPLY	0x000E
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8	 pin_len;
++	__u8	 pin_code[16];
++} __attribute__ ((packed)) pin_code_reply_cp;
++#define PIN_CODE_REPLY_CP_SIZE 23
++
++#define OCF_CHANGE_CONN_PTYPE	0x000F
++typedef struct {
++	__u16	 handle;
++	__u16	 pkt_type;
++} __attribute__ ((packed)) change_conn_ptype_cp;
++#define CHANGE_CONN_PTYPE_CP_SIZE 4
++
++#define OCF_AUTH_REQUESTED	0x0011
++typedef struct {
++	__u16	 handle;
++} __attribute__ ((packed)) auth_requested_cp;
++#define AUTH_REQUESTED_CP_SIZE 2
++
++#define OCF_SET_CONN_ENCRYPT	0x0013
++typedef struct {
++	__u16	 handle;
++	__u8	 encrypt;
++} __attribute__ ((packed)) set_conn_encrypt_cp;
++#define SET_CONN_ENCRYPT_CP_SIZE 3
++
++#define OCF_REMOTE_NAME_REQ	0x0019
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8     pscan_rep_mode;
++	__u8     pscan_mode;
++	__u16    clock_offset;
++} __attribute__ ((packed)) remote_name_req_cp;
++#define REMOTE_NAME_REQ_CP_SIZE 10
++
++#define OCF_READ_REMOTE_FEATURES 0x001B
++typedef struct {
++	__u16   handle;
++} __attribute__ ((packed)) read_remote_features_cp;
++#define READ_REMOTE_FEATURES_CP_SIZE 2
++
++#define OCF_READ_REMOTE_VERSION 0x001D
++typedef struct {
++	__u16   handle;
++} __attribute__ ((packed)) read_remote_version_cp;
++#define READ_REMOTE_VERSION_CP_SIZE 2
++
++/* Link Policy */
++#define OGF_LINK_POLICY	 0x02   
++#define OCF_ROLE_DISCOVERY	0x0009
++typedef struct {
++	__u16	handle;
++} __attribute__ ((packed)) role_discovery_cp;
++#define ROLE_DISCOVERY_CP_SIZE 2
++typedef struct {
++	__u8    status;
++	__u16	handle;
++	__u8    role;
++} __attribute__ ((packed)) role_discovery_rp;
++#define ROLE_DISCOVERY_RP_SIZE 4
+ 
+-/* --------- HCI Events --------- */
++#define OCF_READ_LINK_POLICY	0x000C
++typedef struct {
++	__u16	handle;
++} __attribute__ ((packed)) read_link_policy_cp;
++#define READ_LINK_POLICY_CP_SIZE 2
++typedef struct {
++	__u8    status;
++	__u16	handle;
++	__u16   policy;
++} __attribute__ ((packed)) read_link_policy_rp;
++#define READ_LINK_POLICY_RP_SIZE 5
++
++#define OCF_SWITCH_ROLE	0x000B
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8     role;
++} __attribute__ ((packed)) switch_role_cp;
++#define SWITCH_ROLE_CP_SIZE 7
++
++#define OCF_WRITE_LINK_POLICY	0x000D
++typedef struct {
++	__u16	handle;
++	__u16   policy;
++} __attribute__ ((packed)) write_link_policy_cp;
++#define WRITE_LINK_POLICY_CP_SIZE 4
++typedef struct {
++	__u8    status;
++	__u16	handle;
++} __attribute__ ((packed)) write_link_policy_rp;
++#define WRITE_LINK_POLICY_RP_SIZE 3
++
++/* Status params */
++#define OGF_STATUS_PARAM 	0x05
++
++/* Testing commands */
++#define OGF_TESTING_CMD 	0x3e
++
++/* Vendor specific commands */
++#define OGF_VENDOR_CMD  	0x3f
++
++/* ---- HCI Events ---- */
+ #define EVT_INQUIRY_COMPLETE 	0x01
+ 
+ #define EVT_INQUIRY_RESULT 	0x02
+@@ -272,7 +475,7 @@
+ 	__u8	pscan_rep_mode;
+ 	__u8	pscan_period_mode;
+ 	__u8	pscan_mode;
+-	__u8	class[3];
++	__u8	dev_class[3];
+ 	__u16	clock_offset;
+ } __attribute__ ((packed)) inquiry_info;
+ #define INQUIRY_INFO_SIZE 14
+@@ -303,6 +506,44 @@
+ } __attribute__ ((packed)) evt_disconn_complete;
+ #define EVT_DISCONN_COMPLETE_SIZE 4
+ 
++#define EVT_AUTH_COMPLETE	0x06
++typedef struct {
++	__u8 	status;
++	__u16 	handle;
++} __attribute__ ((packed)) evt_auth_complete;
++#define EVT_AUTH_COMPLETE_SIZE 3
++
++#define EVT_REMOTE_NAME_REQ_COMPLETE	0x07
++typedef struct {
++	__u8 	 status;
++	bdaddr_t bdaddr;
++	__u8 	 name[248];
++} __attribute__ ((packed)) evt_remote_name_req_complete;
++#define EVT_REMOTE_NAME_REQ_COMPLETE_SIZE 255
++
++#define EVT_ENCRYPT_CHANGE	0x08
++typedef struct {
++	__u8 	status;
++	__u16 	handle;
++	__u8	encrypt;
++} __attribute__ ((packed)) evt_encrypt_change;
++#define EVT_ENCRYPT_CHANGE_SIZE 5
++
++#define EVT_QOS_SETUP_COMPLETE 0x0D
++typedef struct {
++	__u8	service_type;
++	__u32	token_rate;
++	__u32	peak_bandwidth;
++	__u32	latency;
++	__u32	delay_variation;
++} __attribute__ ((packed)) hci_qos;
++typedef struct {
++	__u8	status;
++	__u16	handle;
++	hci_qos qos;
++} __attribute__ ((packed)) evt_qos_setup_complete;
++#define EVT_QOS_SETUP_COMPLETE_SIZE 20
++
+ #define EVT_CMD_COMPLETE 	0x0e
+ typedef struct {
+ 	__u8 	ncmd;
+@@ -321,16 +562,78 @@
+ #define EVT_NUM_COMP_PKTS	0x13
+ typedef struct {
+ 	__u8 	num_hndl;
+-	/* variable lenght part */
++	/* variable length part */
+ } __attribute__ ((packed)) evt_num_comp_pkts;
+ #define EVT_NUM_COMP_PKTS_SIZE 1
+ 
+-#define EVT_HCI_DEV_EVENT	0xfd
++#define EVT_ROLE_CHANGE		0x12
++typedef struct {
++	__u8 	 status;
++	bdaddr_t bdaddr;
++	__u8     role;
++} __attribute__ ((packed)) evt_role_change;
++#define EVT_ROLE_CHANGE_SIZE 8
++
++#define EVT_PIN_CODE_REQ        0x16
++typedef struct {
++	bdaddr_t bdaddr;
++} __attribute__ ((packed)) evt_pin_code_req;
++#define EVT_PIN_CODE_REQ_SIZE 6
++
++#define EVT_LINK_KEY_REQ        0x17
++typedef struct {
++	bdaddr_t bdaddr;
++} __attribute__ ((packed)) evt_link_key_req;
++#define EVT_LINK_KEY_REQ_SIZE 6
++
++#define EVT_LINK_KEY_NOTIFY	0x18
++typedef struct {
++	bdaddr_t bdaddr;
++	__u8	 link_key[16];
++	__u8	 key_type;
++} __attribute__ ((packed)) evt_link_key_notify;
++#define EVT_LINK_KEY_NOTIFY_SIZE 23
++
++#define EVT_READ_REMOTE_FEATURES_COMPLETE 0x0B
++typedef struct {
++	__u8    status;
++	__u16   handle;
++	__u8    features[8];
++} __attribute__ ((packed)) evt_read_remote_features_complete;
++#define EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE 11
++
++#define EVT_READ_REMOTE_VERSION_COMPLETE 0x0C
++typedef struct {
++	__u8    status;
++	__u16   handle;
++	__u8    lmp_ver;
++	__u16   manufacturer;
++	__u16   lmp_subver;
++} __attribute__ ((packed)) evt_read_remote_version_complete;
++#define EVT_READ_REMOTE_VERSION_COMPLETE_SIZE 8
++
++/* Internal events generated by BlueZ stack */
++#define EVT_STACK_INTERNAL	0xfd
++typedef struct {
++	__u16   type;
++	__u8 	data[0];
++} __attribute__ ((packed)) evt_stack_internal;
++#define EVT_STACK_INTERNAL_SIZE 2
++
++#define EVT_SI_DEVICE  	0x01
++typedef struct {
++	__u16   event;
++	__u16 	dev_id;
++} __attribute__ ((packed)) evt_si_device;
++#define EVT_SI_DEVICE_SIZE 4
++
++#define EVT_SI_SECURITY	0x02
+ typedef struct {
+ 	__u16 	event;
+-	__u16 	param;
+-} __attribute__ ((packed)) evt_hci_dev_event;
+-#define EVT_HCI_DEV_EVENT_SIZE 4
++	__u16   proto;
++	__u16   subproto;
++	__u8    incomming;
++} __attribute__ ((packed)) evt_si_security;
+ 
+ /* --------  HCI Packet structures  -------- */
+ #define HCI_TYPE_LEN	1
+@@ -369,14 +672,14 @@
+ #define acl_handle(h)		(h & 0x0fff)
+ #define acl_flags(h)		(h >> 12)
+ 
+-#endif /* _NO_HCI_DEFS */
+-
+ /* HCI Socket options */
+-#define HCI_DATA_DIR	0x0001
+-#define HCI_FILTER	0x0002
++#define HCI_DATA_DIR	1
++#define HCI_FILTER	2
++#define HCI_TIME_STAMP	3
+ 
+ /* HCI CMSG flags */
+ #define HCI_CMSG_DIR	0x0001
++#define HCI_CMSG_TSTAMP	0x0002
+ 
+ struct sockaddr_hci {
+ 	sa_family_t    hci_family;
+@@ -387,27 +690,29 @@
+ struct hci_filter {
+ 	__u32 type_mask;
+ 	__u32 event_mask[2];
++	__u16 opcode;
+ };
+ 
+-struct hci_dev_req {
+-	__u16 dev_id;
+-	__u32 dev_opt;
+-};
+-
+-struct hci_dev_list_req {
+-	__u16  dev_num;
+-	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */
+-};
+-
+-struct hci_inquiry_req {
+-	__u16 dev_id;
+-	__u16 flags;
+-	__u8  lap[3];
+-	__u8  length;
+-	__u8  num_rsp;
+-};
+-#define IREQ_CACHE_FLUSH 0x0001
++#define HCI_FLT_TYPE_BITS	31
++#define HCI_FLT_EVENT_BITS	63
++#define HCI_FLT_OGF_BITS	63
++#define HCI_FLT_OCF_BITS	127
++
++#if BITS_PER_LONG == 64
++static inline void hci_set_bit(int nr, void *addr)
++{
++	*((__u32 *) addr + (nr >> 5)) |= ((__u32) 1 << (nr & 31));
++}
++static inline int hci_test_bit(int nr, void *addr)
++{
++	return *((__u32 *) addr + (nr >> 5)) & ((__u32) 1 << (nr & 31));
++}
++#else
++#define hci_set_bit	set_bit
++#define hci_test_bit	test_bit
++#endif
+ 
++/* Ioctl requests structures */
+ struct hci_dev_stats {
+ 	__u32 err_rx;
+ 	__u32 err_tx;
+@@ -433,11 +738,13 @@
+ 	__u8  features[8];
+ 
+ 	__u32 pkt_type;
++	__u32 link_policy;
++	__u32 link_mode;
+ 
+ 	__u16 acl_mtu;
+-	__u16 acl_max;
++	__u16 acl_pkts;
+ 	__u16 sco_mtu;
+-	__u16 sco_max;
++	__u16 sco_pkts;
+ 
+ 	struct hci_dev_stats stat;
+ };
+@@ -445,12 +752,48 @@
+ struct hci_conn_info {
+ 	__u16    handle;
+ 	bdaddr_t bdaddr;
++	__u8	 type;
++	__u8	 out;
++	__u16	 state;
++	__u32	 link_mode;
++};
++
++struct hci_dev_req {
++	__u16 dev_id;
++	__u32 dev_opt;
++};
++
++struct hci_dev_list_req {
++	__u16  dev_num;
++	struct hci_dev_req dev_req[0];	/* hci_dev_req structures */
+ };
+ 
+ struct hci_conn_list_req {
+ 	__u16  dev_id;
+ 	__u16  conn_num;
+ 	struct hci_conn_info conn_info[0];
++};
++
++struct hci_conn_info_req {
++	bdaddr_t bdaddr;
++	__u8     type;
++	struct   hci_conn_info conn_info[0];
++};
++
++struct hci_inquiry_req {
++	__u16 dev_id;
++	__u16 flags;
++	__u8  lap[3];
++	__u8  length;
++	__u8  num_rsp;
++};
++#define IREQ_CACHE_FLUSH 0x0001
++
++struct hci_remotename_req {
++	__u16 dev_id;
++	__u16 flags;
++	bdaddr_t bdaddr;
++	__u8  name[248];
+ };
+ 
+ #endif /* __HCI_H */
+diff -urN linux-2.4.18/include/net/bluetooth/hci_core.h linux-2.4.18-mh9/include/net/bluetooth/hci_core.h
+--- linux-2.4.18/include/net/bluetooth/hci_core.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/hci_core.h	Mon Aug 25 18:38:12 2003
+@@ -23,7 +23,7 @@
+ */
+ 
+ /* 
+- * $Id$ 
++ * $Id$ 
+  */
+ 
+ #ifndef __HCI_CORE_H
+@@ -32,14 +32,12 @@
+ #include <net/bluetooth/hci.h>
+ 
+ /* HCI upper protocols */
+-#define HCI_MAX_PROTO 	1
+ #define HCI_PROTO_L2CAP	0
++#define HCI_PROTO_SCO	1
+ 
+ #define HCI_INIT_TIMEOUT (HZ * 10)
+ 
+-/* ----- Inquiry cache ----- */
+-#define INQUIRY_CACHE_AGE_MAX   (HZ*5)    // 5 seconds
+-#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
++/* HCI Core structures */
+ 
+ struct inquiry_entry {
+ 	struct inquiry_entry 	*next;
+@@ -53,111 +51,182 @@
+ 	struct inquiry_entry 	*list;
+ };
+ 
+-static inline void inquiry_cache_init(struct inquiry_cache *cache)
+-{
+-	spin_lock_init(&cache->lock);
+-	cache->list = NULL;
+-}
++struct conn_hash {
++	struct list_head list;
++	spinlock_t       lock;
++	unsigned int     num;
++};
+ 
+-static inline void inquiry_cache_lock(struct inquiry_cache *cache)
+-{
+-	spin_lock(&cache->lock);
+-}
++struct hci_dev {
++	struct list_head list;
++	spinlock_t	lock;
++	atomic_t 	refcnt;
+ 
+-static inline void inquiry_cache_unlock(struct inquiry_cache *cache)
+-{
+-	spin_unlock(&cache->lock);
+-}
++	char		name[8];
++	unsigned long	flags;
++	__u16		id;
++	__u8	 	type;
++	bdaddr_t	bdaddr;
++	__u8		features[8];
++	__u16		voice_setting;
+ 
+-static inline void inquiry_cache_lock_bh(struct inquiry_cache *cache)
+-{
+-	spin_lock_bh(&cache->lock);
+-}
++	__u16		pkt_type;
++	__u16		link_policy;
++	__u16		link_mode;
+ 
+-static inline void inquiry_cache_unlock_bh(struct inquiry_cache *cache)
+-{
+-	spin_unlock_bh(&cache->lock);
+-}
++	atomic_t 	cmd_cnt;
++	unsigned int 	acl_cnt;
++	unsigned int 	sco_cnt;
+ 
+-static inline long inquiry_cache_age(struct inquiry_cache *cache)
+-{
+-	return jiffies - cache->timestamp;
+-}
++	unsigned int	acl_mtu;
++	unsigned int 	sco_mtu;
++	unsigned int	acl_pkts;
++	unsigned int	sco_pkts;
+ 
+-static inline long inquiry_entry_age(struct inquiry_entry *e)
+-{
+-	return jiffies - e->timestamp;
+-}
+-extern void inquiry_cache_flush(struct inquiry_cache *cache);
++	unsigned long   cmd_last_tx;
++	unsigned long   acl_last_tx;
++	unsigned long   sco_last_tx;
++	
++	struct tasklet_struct 	cmd_task;
++	struct tasklet_struct	rx_task;
++	struct tasklet_struct 	tx_task;
+ 
+-struct hci_dev;
++	struct sk_buff_head	rx_q;
++	struct sk_buff_head 	raw_q;
++	struct sk_buff_head 	cmd_q;
++
++	struct sk_buff     	*sent_cmd;
++
++	struct semaphore	req_lock;
++	wait_queue_head_t	req_wait_q;
++	__u32			req_status;
++	__u32			req_result;
++
++	struct inquiry_cache 	inq_cache;
++	struct conn_hash 	conn_hash;
++
++	struct hci_dev_stats 	stat;
++
++	void			*driver_data;
++	void			*core_data;
++
++	atomic_t 		promisc;
++
++	int (*open)(struct hci_dev *hdev);
++	int (*close)(struct hci_dev *hdev);
++	int (*flush)(struct hci_dev *hdev);
++	int (*send)(struct sk_buff *skb);
++	void (*destruct)(struct hci_dev *hdev);
++	void (*notify)(struct hci_dev *hdev, unsigned int evt, unsigned long arg);
++	int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
++};
+ 
+-/* ----- HCI Connections ----- */
+ struct hci_conn {
+ 	struct list_head list;
++
++	atomic_t	 refcnt;
++	spinlock_t	 lock;
++
+ 	bdaddr_t         dst;
+ 	__u16            handle;
++	__u16            state;
+ 	__u8		 type;
+-	unsigned int     sent;
++	__u8		 out;
++	__u32		 link_mode;
++	unsigned long	 pend;
++	
++	unsigned int	 sent;
++	
++	struct sk_buff_head data_q;
+ 
++	struct timer_list timer;
++	
+ 	struct hci_dev 	*hdev;
+ 	void		*l2cap_data;
++	void		*sco_data;
+ 	void		*priv;
+ 
+-	struct sk_buff_head data_q;
++	struct hci_conn *link;
+ };
+ 
+-struct conn_hash {
+-	struct list_head list;
+-	spinlock_t       lock;
+-	unsigned int     num;
+-};
++extern struct hci_proto *hci_proto[];
++extern struct list_head hdev_list;
++extern rwlock_t hdev_list_lock;
++
++/* ----- Inquiry cache ----- */
++#define INQUIRY_CACHE_AGE_MAX   (HZ*30)   // 30 seconds
++#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
++
++#define inquiry_cache_lock(c)		spin_lock(&c->lock)
++#define inquiry_cache_unlock(c)		spin_unlock(&c->lock)
++#define inquiry_cache_lock_bh(c)	spin_lock_bh(&c->lock)
++#define inquiry_cache_unlock_bh(c)	spin_unlock_bh(&c->lock)
+ 
+-static inline void conn_hash_init(struct conn_hash *h)
++static inline void inquiry_cache_init(struct hci_dev *hdev)
+ {
+-	INIT_LIST_HEAD(&h->list);
+-	spin_lock_init(&h->lock);
+-	h->num = 0;	
++	struct inquiry_cache *c = &hdev->inq_cache;
++	spin_lock_init(&c->lock);
++	c->list = NULL;
+ }
+ 
+-static inline void conn_hash_lock(struct conn_hash *h)
++static inline long inquiry_cache_age(struct hci_dev *hdev)
+ {
+-	spin_lock(&h->lock);
++	struct inquiry_cache *c = &hdev->inq_cache;
++	return jiffies - c->timestamp;
+ }
+ 
+-static inline void conn_hash_unlock(struct conn_hash *h)
++static inline long inquiry_entry_age(struct inquiry_entry *e)
+ {
+-	spin_unlock(&h->lock);
++	return jiffies - e->timestamp;
+ }
+ 
+-static inline void __conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info);
++void inquiry_cache_flush(struct hci_dev *hdev);
++int  inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf);
++
++/* ----- HCI Connections ----- */
++enum {
++	HCI_CONN_AUTH_PEND,
++	HCI_CONN_ENCRYPT_PEND
++};
++
++#define hci_conn_lock(c)	spin_lock(&c->lock)
++#define hci_conn_unlock(c)	spin_unlock(&c->lock)
++#define hci_conn_lock_bh(c)	spin_lock_bh(&c->lock)
++#define hci_conn_unlock_bh(c)	spin_unlock_bh(&c->lock)
++
++#define conn_hash_lock(d)	spin_lock(&d->conn_hash->lock)
++#define conn_hash_unlock(d)	spin_unlock(&d->conn_hash->lock)
++#define conn_hash_lock_bh(d)	spin_lock_bh(&d->conn_hash->lock)
++#define conn_hash_unlock_bh(d)	spin_unlock_bh(&d->conn_hash->lock)
++
++static inline void conn_hash_init(struct hci_dev *hdev)
+ {
+-	list_add(&c->list, &h->list);
+-	h->num++;
++	struct conn_hash *h = &hdev->conn_hash;
++	INIT_LIST_HEAD(&h->list);
++	spin_lock_init(&h->lock);
++	h->num = 0;	
+ }
+ 
+-static inline void conn_hash_add(struct conn_hash *h, __u16 handle, struct hci_conn *c)
++static inline void conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
+ {
+-	conn_hash_lock(h);
+-	__conn_hash_add(h, handle, c);
+-	conn_hash_unlock(h);
++	struct conn_hash *h = &hdev->conn_hash;
++	list_add(&c->list, &h->list);
++	h->num++;
+ }
+ 
+-static inline void __conn_hash_del(struct conn_hash *h, struct hci_conn *c)
++static inline void conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
+ {
++	struct conn_hash *h = &hdev->conn_hash;
+ 	list_del(&c->list);
+ 	h->num--;
+ }
+ 
+-static inline void conn_hash_del(struct conn_hash *h, struct hci_conn *c)
+-{
+-	conn_hash_lock(h);
+-	__conn_hash_del(h, c);
+-	conn_hash_unlock(h);
+-}
+-
+-static inline  struct hci_conn *__conn_hash_lookup(struct conn_hash *h, __u16 handle)
++static inline struct hci_conn *conn_hash_lookup_handle(struct hci_dev *hdev,
++	       				__u16 handle)
+ {
++	register struct conn_hash *h = &hdev->conn_hash;
+ 	register struct list_head *p;
+ 	register struct hci_conn  *c;
+ 
+@@ -169,101 +238,95 @@
+         return NULL;
+ }
+ 
+-static inline struct hci_conn *conn_hash_lookup(struct conn_hash *h, __u16 handle)
++static inline struct hci_conn *conn_hash_lookup_ba(struct hci_dev *hdev,
++					__u8 type, bdaddr_t *ba)
+ {
+-	struct hci_conn *conn;
++	register struct conn_hash *h = &hdev->conn_hash;
++	register struct list_head *p;
++	register struct hci_conn  *c;
+ 
+-	conn_hash_lock(h);
+-	conn = __conn_hash_lookup(h, handle);
+-	conn_hash_unlock(h);
+-	return conn;
++	list_for_each(p, &h->list) {
++		c = list_entry(p, struct hci_conn, list);
++		if (c->type == type && !bacmp(&c->dst, ba))
++			return c;
++	}
++        return NULL;
+ }
+ 
+-/* ----- HCI Devices ----- */
+-struct hci_dev {
+-	atomic_t 	refcnt;
+-
+-	char		name[8];
+-	__u32	 	flags;
+-	__u16		id;
+-	__u8	 	type;
+-	bdaddr_t	bdaddr;
+-	__u8		features[8];
+-
+-	__u16		pkt_type;
+-
+-	atomic_t 	cmd_cnt;
+-	unsigned int 	acl_cnt;
+-	unsigned int 	sco_cnt;
+-
+-	unsigned int	acl_mtu;
+-	unsigned int 	sco_mtu;
+-	unsigned int	acl_max;
+-	unsigned int	sco_max;
+-
+-	void		*driver_data;
+-	void		*l2cap_data;
+-	void		*priv;
+-
+-	struct tasklet_struct 	cmd_task;
+-	struct tasklet_struct	rx_task;
+-	struct tasklet_struct 	tx_task;
+-
+-	struct sk_buff_head	rx_q;
+-	struct sk_buff_head 	raw_q;
+-	struct sk_buff_head 	cmd_q;
+-
+-	struct sk_buff     	*sent_cmd;
+-
+-	struct semaphore	req_lock;
+-	wait_queue_head_t	req_wait_q;
+-	__u32			req_status;
+-	__u32			req_result;
+-
+-	struct inquiry_cache 	inq_cache;
++void hci_acl_connect(struct hci_conn *conn);
++void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
++void hci_add_sco(struct hci_conn *conn, __u16 handle);
+ 
+-	struct conn_hash 	conn_hash;
++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
++int    hci_conn_del(struct hci_conn *conn);
++void   hci_conn_hash_flush(struct hci_dev *hdev);
+ 
+-	struct hci_dev_stats 	stat;
++struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
++int hci_conn_auth(struct hci_conn *conn);
++int hci_conn_encrypt(struct hci_conn *conn);
+ 
+-	int (*open)(struct hci_dev *hdev);
+-	int (*close)(struct hci_dev *hdev);
+-	int (*flush)(struct hci_dev *hdev);
+-	int (*send)(struct sk_buff *skb);
+-};
++static inline void hci_conn_set_timer(struct hci_conn *conn, long timeout)
++{
++	mod_timer(&conn->timer, jiffies + timeout);
++}
+ 
+-static inline void hci_dev_hold(struct hci_dev *hdev)
++static inline void hci_conn_del_timer(struct hci_conn *conn)
+ {
+-	atomic_inc(&hdev->refcnt);
++	del_timer(&conn->timer);
+ }
+ 
+-static inline void hci_dev_put(struct hci_dev *hdev)
++static inline void hci_conn_hold(struct hci_conn *conn)
+ {
+-	atomic_dec(&hdev->refcnt);
++	atomic_inc(&conn->refcnt);
++	hci_conn_del_timer(conn);
+ }
+ 
+-extern struct hci_dev *hci_dev_get(int index);
+-extern int hci_register_dev(struct hci_dev *hdev);
+-extern int hci_unregister_dev(struct hci_dev *hdev);
+-extern int hci_dev_open(__u16 dev);
+-extern int hci_dev_close(__u16 dev);
+-extern int hci_dev_reset(__u16 dev);
+-extern int hci_dev_reset_stat(__u16 dev);
+-extern int hci_dev_info(unsigned long arg);
+-extern int hci_dev_list(unsigned long arg);
+-extern int hci_dev_setscan(unsigned long arg);
+-extern int hci_dev_setauth(unsigned long arg);
+-extern int hci_dev_setptype(unsigned long arg);
+-extern int hci_conn_list(unsigned long arg);
+-extern int hci_inquiry(unsigned long arg);
++static inline void hci_conn_put(struct hci_conn *conn)
++{
++	if (atomic_dec_and_test(&conn->refcnt)) {
++		if (conn->type == SCO_LINK)
++			hci_conn_set_timer(conn, HZ / 100);
++		else if (conn->out)
++			hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT);
++	}
++}
+ 
+-extern __u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode);
+-extern __u32 hci_dev_getmode(struct hci_dev *hdev);
++/* ----- HCI Devices ----- */
++static inline void hci_dev_put(struct hci_dev *d)
++{ 
++	if (atomic_dec_and_test(&d->refcnt))
++		d->destruct(d);
++}
++#define hci_dev_hold(d)		atomic_inc(&d->refcnt)
++
++#define hci_dev_lock(d)		spin_lock(&d->lock)
++#define hci_dev_unlock(d)	spin_unlock(&d->lock)
++#define hci_dev_lock_bh(d)	spin_lock_bh(&d->lock)
++#define hci_dev_unlock_bh(d)	spin_unlock_bh(&d->lock)
++
++struct hci_dev *hci_dev_get(int index);
++struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
++int hci_register_dev(struct hci_dev *hdev);
++int hci_unregister_dev(struct hci_dev *hdev);
++int hci_suspend_dev(struct hci_dev *hdev);
++int hci_resume_dev(struct hci_dev *hdev);
++int hci_dev_open(__u16 dev);
++int hci_dev_close(__u16 dev);
++int hci_dev_reset(__u16 dev);
++int hci_dev_reset_stat(__u16 dev);
++int hci_dev_cmd(unsigned int cmd, unsigned long arg);
++int hci_get_dev_list(unsigned long arg);
++int hci_get_dev_info(unsigned long arg);
++int hci_get_conn_list(unsigned long arg);
++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg);
++int hci_inquiry(unsigned long arg);
+ 
+-extern int hci_recv_frame(struct sk_buff *skb);
++int  hci_recv_frame(struct sk_buff *skb);
++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
+ 
+ /* ----- LMP capabilities ----- */
+ #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH)
++#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT)
+ 
+ /* ----- HCI tasks ----- */
+ static inline void hci_sched_cmd(struct hci_dev *hdev)
+@@ -284,43 +347,130 @@
+ /* ----- HCI protocols ----- */
+ struct hci_proto {
+ 	char 		*name;
+-	__u32		id;
+-	__u32		flags;
++	unsigned int 	id;
++	unsigned long	flags;
+ 
+ 	void		*priv;
+ 
+-	int (*connect_ind) 	(struct hci_dev *hdev, bdaddr_t *bdaddr);
+-	int (*connect_cfm)	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *conn);
++	int (*connect_ind) 	(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
++	int (*connect_cfm)	(struct hci_conn *conn, __u8 status);
+ 	int (*disconn_ind)	(struct hci_conn *conn, __u8 reason);
+-	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb , __u16 flags);
++	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+ 	int (*recv_scodata)	(struct hci_conn *conn, struct sk_buff *skb);
++	int (*auth_cfm)		(struct hci_conn *conn, __u8 status);
++	int (*encrypt_cfm)	(struct hci_conn *conn, __u8 status);
+ };
+ 
+-extern int hci_register_proto(struct hci_proto *hproto);
+-extern int hci_unregister_proto(struct hci_proto *hproto);
+-extern int hci_register_notifier(struct notifier_block *nb);
+-extern int hci_unregister_notifier(struct notifier_block *nb);
+-extern int hci_connect(struct hci_dev * hdev, bdaddr_t * bdaddr);
+-extern int hci_disconnect(struct hci_conn *conn, __u8 reason);
+-extern int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void * param);
+-extern int hci_send_raw(struct sk_buff *skb);
+-extern int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+-extern int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
++static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
++{
++	register struct hci_proto *hp;
++	int mask = 0;
++	
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->connect_ind)
++		mask |= hp->connect_ind(hdev, bdaddr, type);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->connect_ind)
++		mask |= hp->connect_ind(hdev, bdaddr, type);
++
++	return mask;
++}
++
++static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->connect_cfm)
++		hp->connect_cfm(conn, status);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->connect_cfm)
++		hp->connect_cfm(conn, status);
++}
++
++static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->disconn_ind)
++		hp->disconn_ind(conn, reason);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->disconn_ind)
++		hp->disconn_ind(conn, reason);
++}
++
++static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->auth_cfm)
++		hp->auth_cfm(conn, status);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->auth_cfm)
++		hp->auth_cfm(conn, status);
++}
++
++static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status)
++{
++	register struct hci_proto *hp;
++
++	hp = hci_proto[HCI_PROTO_L2CAP];
++	if (hp && hp->encrypt_cfm)
++		hp->encrypt_cfm(conn, status);
++
++	hp = hci_proto[HCI_PROTO_SCO];
++	if (hp && hp->encrypt_cfm)
++		hp->encrypt_cfm(conn, status);
++}
++
++int hci_register_proto(struct hci_proto *hproto);
++int hci_unregister_proto(struct hci_proto *hproto);
++int hci_register_notifier(struct notifier_block *nb);
++int hci_unregister_notifier(struct notifier_block *nb);
++
++int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param);
++int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
++int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
++
++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf);
++
++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
+ 
+ /* ----- HCI Sockets ----- */
+-extern void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
++void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
+ 
+ /* HCI info for socket */
+-#define hci_pi(sk)	((struct hci_pinfo *) &sk->protinfo)
++#define hci_pi(sk)	((struct hci_pinfo *) &sk->tp_pinfo)
+ struct hci_pinfo {
+ 	struct hci_dev 	  *hdev;
+ 	struct hci_filter filter;
+ 	__u32             cmsg_mask;
+ };
+ 
++/* HCI security filter */
++#define HCI_SFLT_MAX_OGF  5
++
++struct hci_sec_filter {
++	__u32 type_mask;
++	__u32 event_mask[2];
++	__u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4];
++};
++
+ /* ----- HCI requests ----- */
+ #define HCI_REQ_DONE	  0
+ #define HCI_REQ_PEND	  1
+ #define HCI_REQ_CANCELED  2
++
++#define hci_req_lock(d)		down(&d->req_lock)
++#define hci_req_unlock(d)	up(&d->req_lock)
++
++void hci_req_complete(struct hci_dev *hdev, int result);
++void hci_req_cancel(struct hci_dev *hdev, int err);
+ 
+ #endif /* __HCI_CORE_H */
+diff -urN linux-2.4.18/include/net/bluetooth/hci_uart.h linux-2.4.18-mh9/include/net/bluetooth/hci_uart.h
+--- linux-2.4.18/include/net/bluetooth/hci_uart.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/hci_uart.h	Thu Jan  1 01:00:00 1970
+@@ -1,62 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * $Id$
+- */
+-
+-#ifndef N_HCI
+-#define N_HCI	15
+-#endif
+-
+-#ifdef __KERNEL__
+-
+-#define tty2n_hci(tty)  ((struct n_hci *)((tty)->disc_data))
+-#define n_hci2tty(n_hci) ((n_hci)->tty)
+-
+-struct n_hci {
+-	struct tty_struct *tty;
+-	struct hci_dev hdev;
+-
+-	struct sk_buff_head txq;
+-	unsigned long tx_state;
+-
+-	spinlock_t rx_lock;
+-	unsigned long rx_state;
+-	unsigned long rx_count;
+-	struct sk_buff *rx_skb;
+-};
+-
+-/* Transmit states  */
+-#define TRANS_SENDING		1
+-#define TRANS_WAKEUP		2
+-
+-/* Receiver States */
+-#define WAIT_PACKET_TYPE	0
+-#define WAIT_EVENT_HDR	 	1
+-#define WAIT_ACL_HDR		2
+-#define WAIT_SCO_HDR		3
+-#define WAIT_DATA	        4
+-
+-#endif /* __KERNEL__ */
+diff -urN linux-2.4.18/include/net/bluetooth/hci_usb.h linux-2.4.18-mh9/include/net/bluetooth/hci_usb.h
+--- linux-2.4.18/include/net/bluetooth/hci_usb.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/hci_usb.h	Thu Jan  1 01:00:00 1970
+@@ -1,68 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * $Id$
+- */
+-
+-#ifdef __KERNEL__
+-
+-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
+-#define HCI_DEV_CLASS        0xe0	/* Wireless class */
+-#define HCI_DEV_SUBCLASS     0x01	/* RF subclass */
+-#define HCI_DEV_PROTOCOL     0x01	/* Bluetooth programming protocol */
+-
+-#define HCI_CTRL_REQ	     0x20
+-
+-struct hci_usb {
+-	struct usb_device 	*udev;
+-
+-	devrequest		dev_req;
+-	struct urb 		*ctrl_urb;
+-	struct urb		*intr_urb;
+-	struct urb		*read_urb;
+-	struct urb		*write_urb;
+-
+-	__u8			*read_buf;
+-	__u8			*intr_buf;
+-	struct sk_buff		*intr_skb;
+-	int			intr_count;
+-
+-	__u8			bulk_out_ep_addr;
+-	__u8			bulk_in_ep_addr;
+-	__u8			intr_in_ep_addr;
+-	__u8			intr_in_interval;
+-
+-	struct hci_dev		hdev;
+-
+-	unsigned long		tx_state;
+-	struct sk_buff_head	tx_ctrl_q;
+-	struct sk_buff_head	tx_write_q;
+-};
+-
+-/* Transmit states  */
+-#define HCI_TX_CTRL	1
+-#define HCI_TX_WRITE	2
+-
+-#endif /* __KERNEL__ */
+diff -urN linux-2.4.18/include/net/bluetooth/hci_vhci.h linux-2.4.18-mh9/include/net/bluetooth/hci_vhci.h
+--- linux-2.4.18/include/net/bluetooth/hci_vhci.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/hci_vhci.h	Thu Jan  1 01:00:00 1970
+@@ -1,50 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * $Id$
+- */
+-
+-#ifndef __HCI_VHCI_H
+-#define __HCI_VHCI_H
+-
+-#ifdef __KERNEL__
+-
+-struct hci_vhci_struct {
+-	struct hci_dev       hdev;
+-	__u32                flags;
+-	wait_queue_head_t    read_wait;
+-	struct sk_buff_head  readq;
+-	struct fasync_struct *fasync;
+-};
+-
+-/* VHCI device flags */
+-#define VHCI_FASYNC		0x0010
+-
+-#endif /* __KERNEL__ */
+-
+-#define VHCI_DEV	"/dev/vhci"
+-#define VHCI_MINOR	250
+-
+-#endif /* __HCI_VHCI_H */
+diff -urN linux-2.4.18/include/net/bluetooth/l2cap.h linux-2.4.18-mh9/include/net/bluetooth/l2cap.h
+--- linux-2.4.18/include/net/bluetooth/l2cap.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/l2cap.h	Mon Aug 25 18:38:12 2003
+@@ -23,22 +23,17 @@
+ */
+ 
+ /*
+- *  $Id$
++ *  $Id$
+  */
+ 
+ #ifndef __L2CAP_H
+ #define __L2CAP_H
+ 
+-#include <asm/types.h>
+-#include <asm/byteorder.h>
+-
+ /* L2CAP defaults */
+ #define L2CAP_DEFAULT_MTU 	672
+ #define L2CAP_DEFAULT_FLUSH_TO	0xFFFF
+ 
+ #define L2CAP_CONN_TIMEOUT 	(HZ * 40)
+-#define L2CAP_DISCONN_TIMEOUT 	(HZ * 2)
+-#define L2CAP_CONN_IDLE_TIMEOUT	(HZ * 60)
+ 
+ /* L2CAP socket address */
+ struct sockaddr_l2 {
+@@ -47,17 +42,12 @@
+ 	bdaddr_t	l2_bdaddr;
+ };
+ 
+-/* set/get sockopt defines */
+-#define L2CAP_OPTIONS  0x01
++/* Socket options */
++#define L2CAP_OPTIONS	0x01
+ struct l2cap_options {
+ 	__u16 omtu;
+ 	__u16 imtu;
+ 	__u16 flush_to;
+-	__u32 token_rate;
+-	__u32 bucket_size;
+-	__u32 pick_band;
+-	__u32 latency;
+-	__u32 delay_var;
+ };
+ 
+ #define L2CAP_CONNINFO  0x02
+@@ -65,6 +55,27 @@
+ 	__u16 hci_handle;
+ };
+ 
++#define L2CAP_LM	0x03
++#define L2CAP_LM_MASTER		0x0001
++#define L2CAP_LM_AUTH		0x0002
++#define L2CAP_LM_ENCRYPT	0x0004
++#define L2CAP_LM_TRUSTED	0x0008
++#define L2CAP_LM_RELIABLE	0x0010
++
++#define L2CAP_QOS	0x04
++struct l2cap_qos {
++	__u16 service_type;
++	__u32 token_rate;
++	__u32 token_bucket_size;
++	__u32 peak_bandwidth;
++	__u32 latency;
++	__u32 delay_variation;
++};
++
++#define L2CAP_SERV_NO_TRAFFIC	0x00
++#define L2CAP_SERV_BEST_EFFORT	0x01
++#define L2CAP_SERV_GUARANTEED	0x02
++
+ /* L2CAP command codes */
+ #define L2CAP_COMMAND_REJ 0x01
+ #define L2CAP_CONN_REQ    0x02
+@@ -79,7 +90,6 @@
+ #define L2CAP_INFO_RSP    0x0b
+ 
+ /* L2CAP structures */
+-
+ typedef struct {
+ 	__u16      len;
+ 	__u16      cid;
+@@ -112,11 +122,17 @@
+ } __attribute__ ((packed))	l2cap_conn_rsp;
+ #define L2CAP_CONN_RSP_SIZE	8
+ 
+-#define L2CAP_CONN_SUCCESS    0x0000
+-#define L2CAP_CONN_PEND       0x0001
+-#define L2CAP_CONN_BAD_PSM    0x0002
+-#define L2CAP_CONN_SEC_BLOCK  0x0003
+-#define L2CAP_CONN_NO_MEM     0x0004
++/* connect result */
++#define L2CAP_CR_SUCCESS    0x0000
++#define L2CAP_CR_PEND       0x0001
++#define L2CAP_CR_BAD_PSM    0x0002
++#define L2CAP_CR_SEC_BLOCK  0x0003
++#define L2CAP_CR_NO_MEM     0x0004
++
++/* connect status */
++#define L2CAP_CS_NO_INFO      0x0000
++#define L2CAP_CS_AUTHEN_PEND  0x0001
++#define L2CAP_CS_AUTHOR_PEND  0x0002
+ 
+ typedef struct {
+ 	__u16      dcid;
+@@ -147,6 +163,8 @@
+ #define L2CAP_CONF_FLUSH_TO	0x02
+ #define L2CAP_CONF_QOS		0x03
+ 
++#define L2CAP_CONF_MAX_SIZE	22
++
+ typedef struct {
+ 	__u16      dcid;
+ 	__u16      scid;
+@@ -158,5 +176,75 @@
+ 	__u16      scid;
+ } __attribute__ ((packed)) 	l2cap_disconn_rsp;
+ #define L2CAP_DISCONN_RSP_SIZE	4
++
++typedef struct {
++	__u16       type;
++	__u8        data[0];
++} __attribute__ ((packed))	l2cap_info_req;
++#define L2CAP_INFO_REQ_SIZE	2
++
++typedef struct {
++	__u16       type;
++	__u16       result;
++	__u8        data[0];
++} __attribute__ ((packed))	l2cap_info_rsp;
++#define L2CAP_INFO_RSP_SIZE	4
++
++/* ----- L2CAP connections ----- */
++struct l2cap_chan_list {
++	struct sock	*head;
++	rwlock_t	lock;
++	long		num;
++};
++
++struct l2cap_conn {
++	struct hci_conn	*hcon;
++
++	bdaddr_t 	*dst;
++	bdaddr_t 	*src;
++	
++	unsigned int    mtu;
++
++	spinlock_t	lock;
++	
++	struct sk_buff *rx_skb;
++	__u32		rx_len;
++	__u8		rx_ident;
++	__u8		tx_ident;
++
++	struct l2cap_chan_list chan_list;
++};
++
++/* ----- L2CAP channel and socket info ----- */
++#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->tp_pinfo)
++
++struct l2cap_pinfo {
++	__u16		psm;
++	__u16		dcid;
++	__u16		scid;
++
++	__u16		imtu;
++	__u16		omtu;
++	__u16		flush_to;
++	
++	__u32		link_mode;
++
++	__u8		conf_state;
++	__u8		conf_retry;
++	__u16		conf_mtu;
++
++	__u8		ident;
++
++	struct l2cap_conn 	*conn;
++	struct sock 		*next_c;
++	struct sock 		*prev_c;
++};
++
++#define L2CAP_CONF_REQ_SENT    0x01
++#define L2CAP_CONF_INPUT_DONE  0x02
++#define L2CAP_CONF_OUTPUT_DONE 0x04
++#define L2CAP_CONF_MAX_RETRIES 2
++
++void l2cap_load(void);
+ 
+ #endif /* __L2CAP_H */
+diff -urN linux-2.4.18/include/net/bluetooth/l2cap_core.h linux-2.4.18-mh9/include/net/bluetooth/l2cap_core.h
+--- linux-2.4.18/include/net/bluetooth/l2cap_core.h	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/include/net/bluetooth/l2cap_core.h	Thu Jan  1 01:00:00 1970
+@@ -1,144 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- *  $Id$
+- */
+-
+-#ifndef __L2CAP_CORE_H
+-#define __L2CAP_CORE_H
+-
+-#ifdef __KERNEL__
+-
+-/* ----- L2CAP interface ----- */
+-struct l2cap_iff {
+-	struct list_head list;
+-	struct hci_dev   *hdev;
+-	bdaddr_t         *bdaddr;
+-	__u16            mtu;
+-	spinlock_t       lock;
+-	struct list_head conn_list;
+-};
+-
+-static inline void l2cap_iff_lock(struct l2cap_iff *iff)
+-{
+-	spin_lock(&iff->lock);
+-}
+-
+-static inline void l2cap_iff_unlock(struct l2cap_iff *iff)
+-{
+-	spin_unlock(&iff->lock);
+-}
+-
+-/* ----- L2CAP connections ----- */
+-struct l2cap_chan_list {
+-	struct sock	*head;
+-	rwlock_t	lock;
+-	long		num;
+-};
+-
+-struct l2cap_conn {
+-	struct l2cap_iff *iff;
+-	struct list_head list;
+-
+-	struct hci_conn	 *hconn;
+-
+-	__u16		state;
+-	__u8		out;
+-	bdaddr_t	src;
+-	bdaddr_t	dst;
+-
+-	spinlock_t	lock;
+-	atomic_t	refcnt;
+-
+-	struct sk_buff *rx_skb;
+-	__u32		rx_len;
+-	__u8		rx_ident;
+-	__u8		tx_ident;
+-
+-	struct l2cap_chan_list chan_list;
+-
+-	struct timer_list timer;
+-};
+-
+-static inline void __l2cap_conn_link(struct l2cap_iff *iff, struct l2cap_conn *c)
+-{
+-	list_add(&c->list, &iff->conn_list);
+-}
+-
+-static inline void __l2cap_conn_unlink(struct l2cap_iff *iff, struct l2cap_conn *c)
+-{
+-	list_del(&c->list);
+-}
+-
+-/* ----- L2CAP channel and socket info ----- */
+-#define l2cap_pi(sk)   ((struct l2cap_pinfo *) &sk->protinfo)
+-
+-struct l2cap_accept_q {
+-	struct sock 	*head;
+-	struct sock 	*tail;
+-};
+-
+-struct l2cap_pinfo {
+-	bdaddr_t	src;
+-	bdaddr_t	dst;
+-	__u16		psm;
+-	__u16		dcid;
+-	__u16		scid;
+-	__u32		flags;
+-
+-	__u16		imtu;
+-	__u16		omtu;
+-	__u16		flush_to;
+-
+-	__u8		conf_state;
+-	__u16		conf_mtu;
+-
+-	__u8		ident;
+-
+-	struct l2cap_conn 	*conn;
+-	struct sock 		*next_c;
+-	struct sock 		*prev_c;
+-
+-	struct sock *parent;
+-	struct sock *next_q;
+-	struct sock *prev_q;
+-
+-	struct l2cap_accept_q accept_q;
+-};
+-
+-#define CONF_REQ_SENT    0x01
+-#define CONF_INPUT_DONE  0x02
+-#define CONF_OUTPUT_DONE 0x04
+-
+-extern struct bluez_sock_list l2cap_sk_list;
+-extern struct list_head  l2cap_iff_list;
+-extern rwlock_t l2cap_rt_lock;
+-
+-extern void l2cap_register_proc(void);
+-extern void l2cap_unregister_proc(void);
+-
+-#endif /* __KERNEL__ */
+-
+-#endif /* __L2CAP_CORE_H */
+diff -urN linux-2.4.18/include/net/bluetooth/rfcomm.h linux-2.4.18-mh9/include/net/bluetooth/rfcomm.h
+--- linux-2.4.18/include/net/bluetooth/rfcomm.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/include/net/bluetooth/rfcomm.h	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,356 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/* 
++   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef __RFCOMM_H
++#define __RFCOMM_H
++
++#define RFCOMM_PSM 3
++
++#define RFCOMM_CONN_TIMEOUT (HZ * 30)
++#define RFCOMM_DISC_TIMEOUT (HZ * 20)
++
++#define RFCOMM_DEFAULT_MTU	127
++#define RFCOMM_DEFAULT_CREDITS	7
++
++#define RFCOMM_MAX_L2CAP_MTU	1024
++#define RFCOMM_MAX_CREDITS	40
++
++#define RFCOMM_SKB_HEAD_RESERVE	8
++#define RFCOMM_SKB_TAIL_RESERVE	2
++#define RFCOMM_SKB_RESERVE	(RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE)
++
++#define RFCOMM_SABM	0x2f
++#define RFCOMM_DISC	0x43
++#define RFCOMM_UA	0x63
++#define RFCOMM_DM	0x0f
++#define RFCOMM_UIH	0xef
++
++#define RFCOMM_TEST	0x08
++#define RFCOMM_FCON	0x28
++#define RFCOMM_FCOFF	0x18
++#define RFCOMM_MSC	0x38
++#define RFCOMM_RPN	0x24
++#define RFCOMM_RLS	0x14
++#define RFCOMM_PN	0x20
++#define RFCOMM_NSC	0x04
++
++#define RFCOMM_V24_FC	0x02
++#define RFCOMM_V24_RTC	0x04
++#define RFCOMM_V24_RTR	0x08
++#define RFCOMM_V24_IC	0x40
++#define RFCOMM_V24_DV	0x80
++
++#define RFCOMM_RPN_BR_2400	0x0
++#define RFCOMM_RPN_BR_4800	0x1
++#define RFCOMM_RPN_BR_7200	0x2
++#define RFCOMM_RPN_BR_9600	0x3
++#define RFCOMM_RPN_BR_19200	0x4
++#define RFCOMM_RPN_BR_38400	0x5
++#define RFCOMM_RPN_BR_57600	0x6
++#define RFCOMM_RPN_BR_115200	0x7
++#define RFCOMM_RPN_BR_230400	0x8
++
++#define RFCOMM_RPN_DATA_5	0x0
++#define RFCOMM_RPN_DATA_6	0x1
++#define RFCOMM_RPN_DATA_7	0x2
++#define RFCOMM_RPN_DATA_8	0x3
++
++#define RFCOMM_RPN_STOP_1	0
++#define RFCOMM_RPN_STOP_15	1
++
++#define RFCOMM_RPN_PARITY_NONE	0x0
++#define RFCOMM_RPN_PARITY_ODD	0x4
++#define RFCOMM_RPN_PARITY_EVEN	0x5
++#define RFCOMM_RPN_PARITY_MARK	0x6
++#define RFCOMM_RPN_PARITY_SPACE	0x7
++
++#define RFCOMM_RPN_FLOW_NONE	0x00
++
++#define RFCOMM_RPN_XON_CHAR	0x11
++#define RFCOMM_RPN_XOFF_CHAR	0x13
++
++#define RFCOMM_RPN_PM_BITRATE		0x0001
++#define RFCOMM_RPN_PM_DATA		0x0002
++#define RFCOMM_RPN_PM_STOP		0x0004
++#define RFCOMM_RPN_PM_PARITY		0x0008
++#define RFCOMM_RPN_PM_PARITY_TYPE	0x0010
++#define RFCOMM_RPN_PM_XON		0x0020
++#define RFCOMM_RPN_PM_XOFF		0x0040
++#define RFCOMM_RPN_PM_FLOW		0x3F00
++
++#define RFCOMM_RPN_PM_ALL		0x3F7F
++
++struct rfcomm_hdr {
++	u8 addr;
++	u8 ctrl;
++	u8 len;    // Actual size can be 2 bytes
++} __attribute__ ((packed));
++
++struct rfcomm_cmd {
++	u8 addr;
++	u8 ctrl;
++	u8 len;
++	u8 fcs;
++} __attribute__ ((packed));
++
++struct rfcomm_mcc {
++	u8 type;
++	u8 len;
++} __attribute__ ((packed));
++
++struct rfcomm_pn {
++	u8  dlci;
++	u8  flow_ctrl;
++	u8  priority;
++	u8  ack_timer;
++	u16 mtu;
++	u8  max_retrans;
++	u8  credits;
++} __attribute__ ((packed));
++
++struct rfcomm_rpn {
++	u8  dlci;
++	u8  bit_rate;
++	u8  line_settings;
++	u8  flow_ctrl;
++	u8  xon_char;
++	u8  xoff_char;
++	u16 param_mask;
++} __attribute__ ((packed));
++
++struct rfcomm_rls {
++	u8  dlci;
++	u8  status;
++} __attribute__ ((packed));
++
++struct rfcomm_msc {
++	u8  dlci;
++	u8  v24_sig;
++} __attribute__ ((packed));
++
++/* ---- Core structures, flags etc ---- */
++
++struct rfcomm_session {
++	struct list_head list;
++	struct socket   *sock;
++	unsigned long    state;
++	unsigned long    flags;
++	atomic_t         refcnt;
++	int              initiator;
++
++	/* Default DLC parameters */
++	uint   mtu;
++	uint   credits;
++
++	struct list_head dlcs;
++};
++
++struct rfcomm_dlc {
++	struct list_head      list;
++	struct rfcomm_session *session;
++	struct sk_buff_head   tx_queue;
++	struct timer_list     timer;
++
++	spinlock_t    lock;
++	unsigned long state;
++	unsigned long flags;
++	atomic_t      refcnt;
++	u8            dlci;
++	u8            addr;
++	u8            priority;
++	u8            v24_sig;
++	u8            mscex;
++
++	uint          mtu;
++	uint          credits;
++	uint          rx_credits;
++	uint          tx_credits;
++
++	void          *owner;
++
++	void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb);
++	void (*state_change)(struct rfcomm_dlc *d, int err);
++	void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig);
++};
++
++/* DLC and session flags */
++#define RFCOMM_RX_THROTTLED 0
++#define RFCOMM_TX_THROTTLED 1
++#define RFCOMM_MSC_PENDING  2
++#define RFCOMM_TIMED_OUT    3
++
++/* Scheduling flags and events */
++#define RFCOMM_SCHED_STATE  0
++#define RFCOMM_SCHED_RX     1
++#define RFCOMM_SCHED_TX     2
++#define RFCOMM_SCHED_TIMEO  3
++#define RFCOMM_SCHED_WAKEUP 31
++
++/* MSC exchange flags */
++#define RFCOMM_MSCEX_TX     1
++#define RFCOMM_MSCEX_RX     2
++#define RFCOMM_MSCEX_OK     (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
++
++extern struct task_struct *rfcomm_thread;
++extern unsigned long rfcomm_event;
++
++static inline void rfcomm_schedule(uint event)
++{
++	if (!rfcomm_thread)
++		return;
++	set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
++	wake_up_process(rfcomm_thread);
++}
++
++extern struct semaphore rfcomm_sem;
++#define rfcomm_lock()	down(&rfcomm_sem);
++#define rfcomm_unlock()	up(&rfcomm_sem);
++
++/* ---- RFCOMM DLCs (channels) ---- */
++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio);
++void rfcomm_dlc_free(struct rfcomm_dlc *d);
++int  rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel);
++int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
++int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
++int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
++int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
++
++#define rfcomm_dlc_lock(d)	spin_lock(&d->lock)
++#define rfcomm_dlc_unlock(d)	spin_unlock(&d->lock)
++
++static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d)
++{
++	atomic_inc(&d->refcnt);
++}
++
++static inline void rfcomm_dlc_put(struct rfcomm_dlc *d)
++{
++	if (atomic_dec_and_test(&d->refcnt))
++		rfcomm_dlc_free(d);
++}
++
++extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d));
++extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d));
++
++static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d)
++{
++	if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags))
++		__rfcomm_dlc_throttle(d);
++}
++
++static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
++{
++	if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags))
++		__rfcomm_dlc_unthrottle(d);
++}
++
++/* ---- RFCOMM sessions ---- */
++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state);
++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err);
++void   rfcomm_session_del(struct rfcomm_session *s);
++void   rfcomm_session_close(struct rfcomm_session *s, int err);
++void   rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst);
++
++static inline void rfcomm_session_hold(struct rfcomm_session *s)
++{
++	atomic_inc(&s->refcnt);
++}
++
++static inline void rfcomm_session_put(struct rfcomm_session *s)
++{
++	if (atomic_dec_and_test(&s->refcnt))
++		rfcomm_session_del(s);
++}
++
++/* ---- RFCOMM chechsum ---- */
++extern u8 rfcomm_crc_table[];
++
++/* ---- RFCOMM sockets ---- */
++struct sockaddr_rc {
++	sa_family_t rc_family;
++	bdaddr_t    rc_bdaddr;
++	u8          rc_channel;
++};
++
++#define rfcomm_pi(sk)	((struct rfcomm_pinfo *) &sk->tp_pinfo)
++
++struct rfcomm_pinfo {
++	struct rfcomm_dlc *dlc;
++	u8 channel;
++};
++
++int  rfcomm_init_sockets(void);
++void rfcomm_cleanup_sockets(void);
++
++int  rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d);
++
++/* ---- RFCOMM TTY ---- */
++#define RFCOMM_MAX_DEV  256
++
++#define RFCOMMCREATEDEV		_IOW('R', 200, int)
++#define RFCOMMRELEASEDEV	_IOW('R', 201, int)
++#define RFCOMMGETDEVLIST	_IOR('R', 210, int)
++#define RFCOMMGETDEVINFO	_IOR('R', 211, int)
++#define RFCOMMSTEALDLC		_IOW('R', 220, int)
++
++#define RFCOMM_REUSE_DLC	0
++#define RFCOMM_RELEASE_ONHUP	1
++#define RFCOMM_HANGUP_NOW	2
++#define RFCOMM_TTY_ATTACHED	3
++
++struct rfcomm_dev_req {
++	s16      dev_id;
++	u32      flags;
++	bdaddr_t src;
++	bdaddr_t dst;
++	u8       channel;
++};
++
++struct rfcomm_dev_info {
++	s16      id;
++	u32      flags;
++	u16      state;
++	bdaddr_t src;
++	bdaddr_t dst;
++	u8       channel;
++};
++
++struct rfcomm_dev_list_req {
++	u16      dev_num;
++	struct   rfcomm_dev_info dev_info[0];
++};
++
++int  rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg);
++int  rfcomm_init_ttys(void);
++void rfcomm_cleanup_ttys(void);
++
++#endif /* __RFCOMM_H */
+diff -urN linux-2.4.18/include/net/bluetooth/sco.h linux-2.4.18-mh9/include/net/bluetooth/sco.h
+--- linux-2.4.18/include/net/bluetooth/sco.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/include/net/bluetooth/sco.h	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,81 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ *  $Id$
++ */
++
++#ifndef __SCO_H
++#define __SCO_H
++
++/* SCO defaults */
++#define SCO_DEFAULT_MTU 	500
++#define SCO_DEFAULT_FLUSH_TO	0xFFFF
++
++#define SCO_CONN_TIMEOUT 	(HZ * 40)
++#define SCO_DISCONN_TIMEOUT 	(HZ * 2)
++#define SCO_CONN_IDLE_TIMEOUT	(HZ * 60)
++
++/* SCO socket address */
++struct sockaddr_sco {
++	sa_family_t	sco_family;
++	bdaddr_t	sco_bdaddr;
++};
++
++/* set/get sockopt defines */
++#define SCO_OPTIONS  0x01
++struct sco_options {
++	__u16 mtu;
++};
++
++#define SCO_CONNINFO  0x02
++struct sco_conninfo {
++	__u16 hci_handle;
++};
++
++/* ---- SCO connections ---- */
++struct sco_conn {
++	struct hci_conn	*hcon;
++
++	bdaddr_t 	*dst;
++	bdaddr_t 	*src;
++	
++	spinlock_t	lock;
++	struct sock 	*sk;
++
++	unsigned int    mtu;
++};
++
++#define sco_conn_lock(c)	spin_lock(&c->lock);
++#define sco_conn_unlock(c)	spin_unlock(&c->lock);
++
++/* ----- SCO socket info ----- */
++#define sco_pi(sk)   ((struct sco_pinfo *) &sk->tp_pinfo)
++
++struct sco_pinfo {
++	__u32		flags;
++	struct sco_conn	*conn;
++};
++
++#endif /* __SCO_H */
+diff -urN linux-2.4.18/include/pcmcia/ciscode.h linux-2.4.18-mh9/include/pcmcia/ciscode.h
+--- linux-2.4.18/include/pcmcia/ciscode.h	Fri Dec 21 18:42:04 2001
++++ linux-2.4.18-mh9/include/pcmcia/ciscode.h	Mon Aug 25 18:38:12 2003
+@@ -1,5 +1,5 @@
+ /*
+- * ciscode.h 1.48 2001/08/24 12:16:12
++ * ciscode.h 1.57 2002/11/03 20:38:14
+  *
+  * The contents of this file are subject to the Mozilla Public License
+  * Version 1.1 (the "License"); you may not use this file except in
+@@ -60,6 +60,10 @@
+ #define PRODID_INTEL_DUAL_RS232		0x0301
+ #define PRODID_INTEL_2PLUS		0x8422
+ 
++#define MANFID_KME			0x0032
++#define PRODID_KME_KXLC005_A		0x0704
++#define PRODID_KME_KXLC005_B		0x2904
++
+ #define MANFID_LINKSYS			0x0143
+ #define PRODID_LINKSYS_PCMLM28		0xc0ab
+ #define PRODID_LINKSYS_3400		0x3341
+@@ -94,6 +98,8 @@
+ #define PRODID_OSITECH_JACK_336		0x0007
+ #define PRODID_OSITECH_SEVEN		0x0008
+ 
++#define MANFID_OXSEMI			0x0279
++
+ #define MANFID_PIONEER			0x000b
+ 
+ #define MANFID_PSION			0x016c
+@@ -103,6 +109,7 @@
+ #define PRODID_QUATECH_SPP100		0x0003
+ #define PRODID_QUATECH_DUAL_RS232	0x0012
+ #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
++#define PRODID_QUATECH_DUAL_RS232_D2	0x0052
+ #define PRODID_QUATECH_QUAD_RS232	0x001b
+ #define PRODID_QUATECH_DUAL_RS422	0x000e
+ #define PRODID_QUATECH_QUAD_RS422	0x0045
+@@ -120,8 +127,11 @@
+ 
+ #define MANFID_TDK			0x0105
+ #define PRODID_TDK_CF010		0x0900
++#define PRODID_TDK_GN3410		0x4815
+ 
+ #define MANFID_TOSHIBA			0x0098
++
++#define MANFID_UNGERMANN		0x02c0
+ 
+ #define MANFID_XIRCOM			0x0105
+ 
+diff -urN linux-2.4.18/lib/Config.in linux-2.4.18-mh9/lib/Config.in
+--- linux-2.4.18/lib/Config.in	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/lib/Config.in	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,12 @@
++#
++# Library configuration
++#
++mainmenu_option next_comment
++comment 'Library routines'
++
++if [ "$CONFIG_EXPERIMENTAL" = "y" -a \
++     "$CONFIG_HOTPLUG" = "y" ]; then
++   tristate 'Hotplug firmware loading support (EXPERIMENTAL)' CONFIG_FW_LOADER
++fi
++
++endmenu
+diff -urN linux-2.4.18/lib/Makefile linux-2.4.18-mh9/lib/Makefile
+--- linux-2.4.18/lib/Makefile	Tue Sep 18 00:31:15 2001
++++ linux-2.4.18-mh9/lib/Makefile	Mon Aug 25 18:38:12 2003
+@@ -8,12 +8,16 @@
+ 
+ L_TARGET := lib.a
+ 
+-export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o
++export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
++	       firmware_class.o
+ 
+ obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o bust_spinlocks.o rbtree.o
+ 
++obj-$(CONFIG_FW_LOADER) += firmware_class.o
+ obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
+ obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
++
++include $(TOPDIR)/drivers/bluetooth/Makefile.lib
+ 
+ ifneq ($(CONFIG_HAVE_DEC_LOCK),y) 
+   obj-y += dec_and_lock.o
+diff -urN linux-2.4.18/lib/firmware_class.c linux-2.4.18-mh9/lib/firmware_class.c
+--- linux-2.4.18/lib/firmware_class.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/lib/firmware_class.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,571 @@
++/*
++ * firmware_class.c - Multi purpose firmware loading support
++ *
++ * Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
++ *
++ * Please see Documentation/firmware_class/ for more information.
++ *
++ */
++/*
++ * Based on kernel/kmod.c and drivers/usb/usb.c
++ */
++/*
++        kernel/kmod.c
++        Kirk Petersen
++
++        Reorganized not to be a daemon by Adam Richter, with guidance
++        from Greg Zornetzer.
++
++        Modified to avoid chroot and file sharing problems.
++        Mikael Pettersson
++
++        Limit the concurrent number of kmod modprobes to catch loops from
++        "modprobe needs a service that is in a module".
++        Keith Owens <kaos@ocs.com.au> December 1999
++
++        Unblock all signals when we exec a usermode process.
++        Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
++*/
++/*
++ * drivers/usb/usb.c
++ *
++ * (C) Copyright Linus Torvalds 1999
++ * (C) Copyright Johannes Erdfelt 1999-2001
++ * (C) Copyright Andreas Gal 1999
++ * (C) Copyright Gregory P. Smith 1999
++ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
++ * (C) Copyright Randy Dunlap 2000
++ * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id)
++ * (C) Copyright Yggdrasil Computing, Inc. 2000
++ *     (usb_device_id matching changes by Adam J. Richter)
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/kmod.h>
++#include <linux/proc_fs.h>
++#include <linux/vmalloc.h>
++#include <asm/hardirq.h>
++
++#include "linux/firmware.h"
++
++MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
++MODULE_DESCRIPTION("Multi purpose firmware loading support");
++MODULE_LICENSE("GPL");
++
++#define err(format, arg...) \
++     printk(KERN_ERR  "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
++#define warn(format, arg...) \
++     printk(KERN_WARNING "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
++#define dbg(format, arg...) \
++     printk(KERN_DEBUG "%s:%s: " format "\n",__FILE__, __FUNCTION__ , ## arg)
++
++static int loading_timeout = 10;	/* In seconds */
++static struct proc_dir_entry *proc_dir_timeout;
++static struct proc_dir_entry *proc_dir;
++
++#ifdef CONFIG_HOTPLUG
++
++static int
++call_helper(char *verb, const char *name, const char *device)
++{
++	char *argv[3], **envp, *buf, *scratch;
++	int i = 0;
++
++	int retval = 0;
++
++	if (!hotplug_path[0])
++		return -ENOENT;
++	if (in_interrupt()) {
++		err("in_interrupt");
++		return -EFAULT;
++	}
++	if (!current->fs->root) {
++		warn("call_policy %s -- no FS yet", verb);
++		return -EPERM;
++	}
++
++	if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
++		err("unable to allocate envp");
++		return -ENOMEM;
++	}
++	if (!(buf = kmalloc(256, GFP_KERNEL))) {
++		kfree(envp);
++		err("unable to allocate buf");
++		return -ENOMEM;
++	}
++
++	/* only one standardized param to hotplug command: type */
++	argv[0] = hotplug_path;
++	argv[1] = "firmware";
++	argv[2] = 0;
++
++	/* minimal command environment */
++	envp[i++] = "HOME=/";
++	envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++
++#ifdef  DEBUG
++	/* hint that policy agent should enter no-stdout debug mode */
++	envp[i++] = "DEBUG=kernel";
++#endif
++	scratch = buf;
++
++	if (device) {
++		envp[i++] = scratch;
++		scratch += snprintf(scratch, FIRMWARE_NAME_MAX+25,
++				    "DEVPATH=/driver/firmware/%s", device) + 1;
++	}
++
++	envp[i++] = scratch;
++	scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
++
++	envp[i++] = scratch;
++	scratch += snprintf(scratch, FIRMWARE_NAME_MAX,
++			    "FIRMWARE=%s", name) + 1;
++
++	envp[i++] = 0;
++
++#ifdef  DEBUG
++	dbg("firmware: %s %s %s", argv[0], argv[1], verb);
++#endif
++
++	retval = call_usermodehelper(argv[0], argv, envp);
++	if (retval) {
++		printk("call_usermodehelper return %d\n", retval);
++	}
++
++	kfree(buf);
++	kfree(envp);
++	return retval;
++}
++#else
++
++static inline int
++call_helper(char *verb, const char *name, const char *device)
++{
++	return -ENOENT;
++}
++
++#endif /* CONFIG_HOTPLUG */
++
++struct firmware_priv {
++	struct completion completion;
++	struct proc_dir_entry *proc_dir;
++	struct proc_dir_entry *attr_data;
++	struct proc_dir_entry *attr_loading;
++	struct firmware *fw;
++	int loading;
++	int abort;
++	int alloc_size;
++	struct timer_list timeout;
++};
++
++static int
++firmware_timeout_show(char *buf, char **start, off_t off,
++		      int count, int *eof, void *data)
++{
++	return sprintf(buf, "%d\n", loading_timeout);
++}
++
++/**
++ * firmware_timeout_store:
++ * Description:
++ *	Sets the number of seconds to wait for the firmware.  Once
++ *	this expires an error will be return to the driver and no
++ *	firmware will be provided.
++ *
++ *	Note: zero means 'wait for ever'
++ *  
++ **/
++static int
++firmware_timeout_store(struct file *file, const char *buf,
++		       unsigned long count, void *data)
++{
++	loading_timeout = simple_strtol(buf, NULL, 10);
++	return count;
++}
++
++static int
++firmware_loading_show(char *buf, char **start, off_t off,
++		      int count, int *eof, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	return sprintf(buf, "%d\n", fw_priv->loading);
++}
++
++/**
++ * firmware_loading_store: - loading control file
++ * Description:
++ *	The relevant values are: 
++ *
++ *	 1: Start a load, discarding any previous partial load.
++ *	 0: Conclude the load and handle the data to the driver code.
++ *	-1: Conclude the load with an error and discard any written data.
++ **/
++static int
++firmware_loading_store(struct file *file, const char *buf,
++		       unsigned long count, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	int prev_loading = fw_priv->loading;
++
++	fw_priv->loading = simple_strtol(buf, NULL, 10);
++
++	switch (fw_priv->loading) {
++	case -1:
++		fw_priv->abort = 1;
++		wmb();
++		complete(&fw_priv->completion);
++		break;
++	case 1:
++		kfree(fw_priv->fw->data);
++		fw_priv->fw->data = NULL;
++		fw_priv->fw->size = 0;
++		fw_priv->alloc_size = 0;
++		break;
++	case 0:
++		if (prev_loading == 1)
++			complete(&fw_priv->completion);
++		break;
++	}
++
++	return count;
++}
++
++static int
++firmware_data_read(char *buffer, char **start, off_t offset,
++		   int count, int *eof, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	struct firmware *fw = fw_priv->fw;
++
++	if (offset > fw->size)
++		return 0;
++	if (offset + count > fw->size)
++		count = fw->size - offset;
++
++	memcpy(buffer, fw->data + offset, count);
++	*start = (void *) ((long) count);
++	return count;
++}
++static int
++fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
++{
++	u8 *new_data;
++	int new_size;
++
++	if (min_size <= fw_priv->alloc_size)
++		return 0;
++	if((min_size % PAGE_SIZE) == 0)
++		new_size = min_size;
++	else
++		new_size = (min_size + PAGE_SIZE) & PAGE_MASK;
++	new_data = vmalloc(new_size);
++	if (!new_data) {
++		printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
++		/* Make sure that we don't keep incomplete data */
++		fw_priv->abort = 1;
++		return -ENOMEM;
++	}
++	fw_priv->alloc_size = new_size;
++	if (fw_priv->fw->data) {
++		memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
++		vfree(fw_priv->fw->data);
++	}
++	fw_priv->fw->data = new_data;
++	BUG_ON(min_size > fw_priv->alloc_size);
++	return 0;
++}
++
++/**
++ * firmware_data_write:
++ *
++ * Description:
++ *
++ *	Data written to the 'data' attribute will be later handled to
++ *	the driver as a firmware image.
++ **/
++static int
++firmware_data_write(struct file *file, const char *buffer,
++		    unsigned long count, void *data)
++{
++	struct firmware_priv *fw_priv = data;
++	struct firmware *fw = fw_priv->fw;
++	int offset = file->f_pos;
++	int retval;
++
++	retval = fw_realloc_buffer(fw_priv, offset + count);
++	if (retval) {
++		printk("%s: retval:%d\n", __FUNCTION__, retval);
++		return retval;
++	}
++
++	memcpy(fw->data + offset, buffer, count);
++
++	fw->size = max_t(size_t, offset + count, fw->size);
++	file->f_pos += count;
++	return count;
++}
++
++static void
++firmware_class_timeout(u_long data)
++{
++	struct firmware_priv *fw_priv = (struct firmware_priv *) data;
++	fw_priv->abort = 1;
++	wmb();
++	complete(&fw_priv->completion);
++}
++static int
++fw_setup_class_device(struct firmware_priv **fw_priv_p,
++		      const char *fw_name, const char *device)
++{
++	int retval;
++	struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
++						GFP_KERNEL);
++	*fw_priv_p = fw_priv;
++	if (!fw_priv) {
++		retval = -ENOMEM;
++		goto out;
++	}
++	memset(fw_priv, 0, sizeof (*fw_priv));
++
++	init_completion(&fw_priv->completion);
++
++	fw_priv->timeout.function = firmware_class_timeout;
++	fw_priv->timeout.data = (u_long) fw_priv;
++	init_timer(&fw_priv->timeout);
++
++	retval = -EAGAIN;
++	fw_priv->proc_dir = create_proc_entry(device, 0644 | S_IFDIR, proc_dir);
++	if (!fw_priv->proc_dir)
++		goto err_free_fw_priv;
++
++	fw_priv->attr_data = create_proc_entry("data", 0644 | S_IFREG,
++					       fw_priv->proc_dir);
++	if (!fw_priv->attr_data)
++		goto err_remove_dir;
++
++	fw_priv->attr_data->read_proc = firmware_data_read;
++	fw_priv->attr_data->write_proc = firmware_data_write;
++	fw_priv->attr_data->data = fw_priv;
++
++	fw_priv->attr_loading = create_proc_entry("loading", 0644 | S_IFREG,
++						  fw_priv->proc_dir);
++	if (!fw_priv->attr_loading)
++		goto err_remove_data;
++
++	fw_priv->attr_loading->read_proc = firmware_loading_show;
++	fw_priv->attr_loading->write_proc = firmware_loading_store;
++	fw_priv->attr_loading->data = fw_priv;
++
++	retval = 0;
++	fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
++	if (!fw_priv->fw) {
++		printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
++		       __FUNCTION__);
++		retval = -ENOMEM;
++		goto err_remove_loading;
++	}
++	memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
++
++	goto out;
++
++err_remove_loading:
++	remove_proc_entry("loading", fw_priv->proc_dir);
++err_remove_data:
++	remove_proc_entry("data", fw_priv->proc_dir);
++err_remove_dir:
++	remove_proc_entry(device, proc_dir);
++err_free_fw_priv:
++	kfree(fw_priv);
++out:
++	return retval;
++}
++static void
++fw_remove_class_device(struct firmware_priv *fw_priv)
++{
++	remove_proc_entry("loading", fw_priv->proc_dir);
++	remove_proc_entry("data", fw_priv->proc_dir);
++	remove_proc_entry(fw_priv->proc_dir->name, proc_dir);
++}
++
++/** 
++ * request_firmware: - request firmware to hotplug and wait for it
++ * Description:
++ *	@firmware will be used to return a firmware image by the name
++ *	of @name for device @device.
++ *
++ *	Should be called from user context where sleeping is allowed.
++ *
++ *	@name will be use as $FIRMWARE in the hotplug environment and
++ *	should be distinctive enough not to be confused with any other
++ *	firmware image for this or any other device.
++ **/
++int
++request_firmware(const struct firmware **firmware, const char *name,
++		 const char *device)
++{
++	struct firmware_priv *fw_priv;
++	int retval;
++
++	if (!firmware) {
++		retval = -EINVAL;
++		goto out;
++	}
++	*firmware = NULL;
++
++	retval = fw_setup_class_device(&fw_priv, name, device);
++	if (retval)
++		goto out;
++
++	retval = call_helper("add", name, device);
++	if (retval)
++		goto out;
++	if (loading_timeout) {
++		fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
++		add_timer(&fw_priv->timeout);
++	}
++
++	wait_for_completion(&fw_priv->completion);
++
++	del_timer(&fw_priv->timeout);
++	fw_remove_class_device(fw_priv);
++
++	if (fw_priv->fw->size && !fw_priv->abort) {
++		*firmware = fw_priv->fw;
++	} else {
++		retval = -ENOENT;
++		vfree(fw_priv->fw->data);
++		kfree(fw_priv->fw);
++	}
++out:
++	kfree(fw_priv);
++	return retval;
++}
++
++void
++release_firmware(const struct firmware *fw)
++{
++	if (fw) {
++		vfree(fw->data);
++		kfree(fw);
++	}
++}
++
++/**
++ * register_firmware: - provide a firmware image for later usage
++ * 
++ * Description:
++ *	Make sure that @data will be available by requesting firmware @name.
++ *
++ *	Note: This will not be possible until some kind of persistence
++ *	is available.
++ **/
++void
++register_firmware(const char *name, const u8 *data, size_t size)
++{
++	/* This is meaningless without firmware caching, so until we
++	 * decide if firmware caching is reasonable just leave it as a
++	 * noop */
++}
++
++/* Async support */
++struct firmware_work {
++	struct tq_struct work;
++	struct module *module;
++	const char *name;
++	const char *device;
++	void *context;
++	void (*cont)(const struct firmware *fw, void *context);
++};
++
++static void
++request_firmware_work_func(void *arg)
++{
++	struct firmware_work *fw_work = arg;
++	const struct firmware *fw;
++	if (!arg)
++		return;
++	request_firmware(&fw, fw_work->name, fw_work->device);
++	fw_work->cont(fw, fw_work->context);
++	release_firmware(fw);
++	__MOD_DEC_USE_COUNT(fw_work->module);
++	kfree(fw_work);
++}
++
++/**
++ * request_firmware_nowait:
++ *
++ * Description:
++ *	Asynchronous variant of request_firmware() for contexts where
++ *	it is not possible to sleep.
++ *
++ *	@cont will be called asynchronously when the firmware request is over.
++ *
++ *	@context will be passed over to @cont.
++ *
++ *	@fw may be %NULL if firmware request fails.
++ *
++ **/
++int
++request_firmware_nowait(
++	struct module *module,
++	const char *name, const char *device, void *context,
++	void (*cont)(const struct firmware *fw, void *context))
++{
++	struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
++						GFP_ATOMIC);
++	if (!fw_work)
++		return -ENOMEM;
++	if (!try_inc_mod_count(module)) {
++		kfree(fw_work);
++		return -EFAULT;
++	}
++
++	*fw_work = (struct firmware_work) {
++		.module = module,
++		.name = name,
++		.device = device,
++		.context = context,
++		.cont = cont,
++	};
++	INIT_TQUEUE(&fw_work->work, request_firmware_work_func, fw_work);
++
++	schedule_task(&fw_work->work);
++	return 0;
++}
++
++static int __init
++firmware_class_init(void)
++{
++	proc_dir = create_proc_entry("driver/firmware", 0755 | S_IFDIR, NULL);
++	if (!proc_dir)
++		return -EAGAIN;
++	proc_dir_timeout = create_proc_entry("timeout",
++					     0644 | S_IFREG, proc_dir);
++	if (!proc_dir_timeout) {
++		remove_proc_entry("driver/firmware", NULL);
++		return -EAGAIN;
++	}
++	proc_dir_timeout->read_proc = firmware_timeout_show;
++	proc_dir_timeout->write_proc = firmware_timeout_store;
++	return 0;
++}
++static void __exit
++firmware_class_exit(void)
++{
++	remove_proc_entry("timeout", proc_dir);
++	remove_proc_entry("driver/firmware", NULL);
++}
++
++module_init(firmware_class_init);
++module_exit(firmware_class_exit);
++
++EXPORT_SYMBOL(release_firmware);
++EXPORT_SYMBOL(request_firmware);
++EXPORT_SYMBOL(request_firmware_nowait);
++EXPORT_SYMBOL(register_firmware);
+diff -urN linux-2.4.18/net/bluetooth/Config.in linux-2.4.18-mh9/net/bluetooth/Config.in
+--- linux-2.4.18/net/bluetooth/Config.in	Tue Jun 12 04:15:27 2001
++++ linux-2.4.18-mh9/net/bluetooth/Config.in	Mon Aug 25 18:38:12 2003
+@@ -1,16 +1,22 @@
+ #
+-# Bluetooth configuration
++# Bluetooth subsystem configuration
+ #
+ 
+ if [ "$CONFIG_NET" != "n" ]; then
++
+    mainmenu_option next_comment
+    comment 'Bluetooth support'
+    dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET
+ 
+    if [ "$CONFIG_BLUEZ" != "n" ]; then
+       dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ
++      dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ
++      source net/bluetooth/rfcomm/Config.in
++      source net/bluetooth/bnep/Config.in
++      source net/bluetooth/cmtp/Config.in
+       source drivers/bluetooth/Config.in
+    fi
++
+    endmenu
+ fi
+ 
+diff -urN linux-2.4.18/net/bluetooth/Makefile linux-2.4.18-mh9/net/bluetooth/Makefile
+--- linux-2.4.18/net/bluetooth/Makefile	Tue Jun 12 04:15:27 2001
++++ linux-2.4.18-mh9/net/bluetooth/Makefile	Mon Aug 25 18:38:12 2003
+@@ -1,20 +1,31 @@
+ #
+-# Makefile for the Bluetooth subsystem
++# Makefile for the Linux Bluetooth subsystem
+ #
+-O_TARGET	:= bluetooth.o
+ 
+-list-multi	:= hci.o l2cap.o
+-export-objs	:= syms.o
+-hci-objs	:= af_bluetooth.o hci_core.o hci_sock.o lib.o syms.o
+-l2cap-objs	:= l2cap_core.o l2cap_proc.o
++O_TARGET    := bluetooth.o
+ 
+-obj-$(CONFIG_BLUEZ) += hci.o
++list-multi  := bluez.o
++export-objs := syms.o l2cap.o
++
++bluez-objs  := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o lib.o syms.o
++
++obj-$(CONFIG_BLUEZ) += bluez.o
+ obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o
++obj-$(CONFIG_BLUEZ_SCO) += sco.o
+ 
+-include $(TOPDIR)/Rules.make
++subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm
++subdir-$(CONFIG_BLUEZ_BNEP) += bnep
++subdir-$(CONFIG_BLUEZ_CMTP) += cmtp
+ 
+-hci.o: $(hci-objs)
+-	$(LD) -r -o $@ $(hci-objs)
++ifeq ($(CONFIG_BLUEZ_RFCOMM),y)
++obj-y += rfcomm/rfcomm.o
++endif
++
++ifeq ($(CONFIG_BLUEZ_BNEP),y)
++obj-y += bnep/bnep.o
++endif
++
++include $(TOPDIR)/Rules.make
+ 
+-l2cap.o: $(l2cap-objs)
+-	$(LD) -r -o $@ $(l2cap-objs)
++bluez.o: $(bluez-objs)
++	$(LD) -r -o $@ $(bluez-objs)
+diff -urN linux-2.4.18/net/bluetooth/af_bluetooth.c linux-2.4.18-mh9/net/bluetooth/af_bluetooth.c
+--- linux-2.4.18/net/bluetooth/af_bluetooth.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/net/bluetooth/af_bluetooth.c	Mon Aug 25 18:38:12 2003
+@@ -25,14 +25,15 @@
+ /*
+  * BlueZ Bluetooth address family and sockets.
+  *
+- * $Id$
++ * $Id$
+  */
+-#define VERSION "1.1"
++#define VERSION "2.4"
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
+ 
+ #include <linux/types.h>
++#include <linux/list.h>
+ #include <linux/errno.h>
+ #include <linux/kernel.h>
+ #include <linux/major.h>
+@@ -40,6 +41,7 @@
+ #include <linux/slab.h>
+ #include <linux/skbuff.h>
+ #include <linux/init.h>
++#include <linux/poll.h>
+ #include <linux/proc_fs.h>
+ #include <net/sock.h>
+ 
+@@ -48,70 +50,79 @@
+ #endif
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
++
++#ifndef AF_BLUETOOTH_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
+ 
+ /* Bluetooth sockets */
+-static struct net_proto_family *bluez_sock[BLUEZ_MAX_PROTO];
++#define BLUEZ_MAX_PROTO	6
++static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO];
+ 
+ int bluez_sock_register(int proto, struct net_proto_family *ops)
+ {
+-	if (proto > BLUEZ_MAX_PROTO)
++	if (proto >= BLUEZ_MAX_PROTO)
+ 		return -EINVAL;
+ 
+-	if (bluez_sock[proto])
++	if (bluez_proto[proto])
+ 		return -EEXIST;
+ 
+-	bluez_sock[proto] = ops;
++	bluez_proto[proto] = ops;
+ 	return 0;
+ }
+ 
+ int bluez_sock_unregister(int proto)
+ {
+-	if (proto > BLUEZ_MAX_PROTO)
++	if (proto >= BLUEZ_MAX_PROTO)
+ 		return -EINVAL;
+ 
+-	if (!bluez_sock[proto])
++	if (!bluez_proto[proto])
+ 		return -ENOENT;
+ 
+-	bluez_sock[proto] = NULL;
++	bluez_proto[proto] = NULL;
+ 	return 0;
+ }
+ 
+ static int bluez_sock_create(struct socket *sock, int proto)
+ {
+-	if (proto > BLUEZ_MAX_PROTO)
++	if (proto >= BLUEZ_MAX_PROTO)
+ 		return -EINVAL;
+ 
+ #if defined(CONFIG_KMOD)
+-	if (!bluez_sock[proto]) {
++	if (!bluez_proto[proto]) {
+ 		char module_name[30];
+ 		sprintf(module_name, "bt-proto-%d", proto);
+ 		request_module(module_name);
+ 	}
+ #endif
+ 
+-	if (!bluez_sock[proto])
++	if (!bluez_proto[proto])
+ 		return -ENOENT;
+ 
+-	return bluez_sock[proto]->create(sock, proto);
++	return bluez_proto[proto]->create(sock, proto);
++}
++
++void bluez_sock_init(struct socket *sock, struct sock *sk)
++{ 
++	sock_init_data(sock, sk);
++	INIT_LIST_HEAD(&bluez_pi(sk)->accept_q);
+ }
+ 
+ void bluez_sock_link(struct bluez_sock_list *l, struct sock *sk)
+ {
+-	write_lock(&l->lock);
+-
++	write_lock_bh(&l->lock);
+ 	sk->next = l->head;
+ 	l->head = sk;
+ 	sock_hold(sk);
+-
+-	write_unlock(&l->lock);
++	write_unlock_bh(&l->lock);
+ }
+ 
+ void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *sk)
+ {
+ 	struct sock **skp;
+ 
+-	write_lock(&l->lock);
++	write_lock_bh(&l->lock);
+ 	for (skp = &l->head; *skp; skp = &((*skp)->next)) {
+ 		if (*skp == sk) {
+ 			*skp = sk->next;
+@@ -119,7 +130,162 @@
+ 			break;
+ 		}
+ 	}
+-	write_unlock(&l->lock);
++	write_unlock_bh(&l->lock);
++}
++
++void bluez_accept_enqueue(struct sock *parent, struct sock *sk)
++{
++	BT_DBG("parent %p, sk %p", parent, sk);
++
++	sock_hold(sk);
++	list_add_tail(&bluez_pi(sk)->accept_q, &bluez_pi(parent)->accept_q);
++	bluez_pi(sk)->parent = parent;
++	parent->ack_backlog++;
++}
++
++static void bluez_accept_unlink(struct sock *sk)
++{
++	BT_DBG("sk %p state %d", sk, sk->state);
++
++	list_del_init(&bluez_pi(sk)->accept_q);
++	bluez_pi(sk)->parent->ack_backlog--;
++	bluez_pi(sk)->parent = NULL;
++	sock_put(sk);
++}
++
++struct sock *bluez_accept_dequeue(struct sock *parent, struct socket *newsock)
++{
++	struct list_head *p, *n;
++	struct bluez_pinfo *pi;
++	struct sock *sk;
++	
++	BT_DBG("parent %p", parent);
++
++	list_for_each_safe(p, n, &bluez_pi(parent)->accept_q) {
++		pi = list_entry(p, struct bluez_pinfo, accept_q);
++		sk = bluez_sk(pi);
++		
++		lock_sock(sk);
++		if (sk->state == BT_CLOSED) {
++			release_sock(sk);
++			bluez_accept_unlink(sk);
++			continue;
++		}
++		
++		if (sk->state == BT_CONNECTED || !newsock) {
++			bluez_accept_unlink(sk);
++			if (newsock)
++				sock_graft(sk, newsock);
++			release_sock(sk);
++			return sk;
++		}
++		release_sock(sk);
++	}
++	return NULL;
++}
++
++int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
++{
++	int noblock = flags & MSG_DONTWAIT;
++	struct sock *sk = sock->sk;
++	struct sk_buff *skb;
++	int copied, err;
++
++	BT_DBG("sock %p sk %p len %d", sock, sk, len);
++
++	if (flags & (MSG_OOB))
++		return -EOPNOTSUPP;
++
++	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) {
++		if (sk->shutdown & RCV_SHUTDOWN)
++			return 0;
++		return err;
++	}
++
++	msg->msg_namelen = 0;
++
++	copied = skb->len;
++	if (len < copied) {
++		msg->msg_flags |= MSG_TRUNC;
++		copied = len;
++	}
++
++	skb->h.raw = skb->data;
++	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
++
++	skb_free_datagram(sk, skb);
++
++	return err ? : copied;
++}
++
++unsigned int bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
++{
++	struct sock *sk = sock->sk;
++	unsigned int mask;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	poll_wait(file, sk->sleep, wait);
++	mask = 0;
++
++	if (sk->err || !skb_queue_empty(&sk->error_queue))
++		mask |= POLLERR;
++
++	if (sk->shutdown == SHUTDOWN_MASK)
++		mask |= POLLHUP;
++
++	if (!skb_queue_empty(&sk->receive_queue) || 
++			!list_empty(&bluez_pi(sk)->accept_q) ||
++			(sk->shutdown & RCV_SHUTDOWN))
++		mask |= POLLIN | POLLRDNORM;
++
++	if (sk->state == BT_CLOSED)
++		mask |= POLLHUP;
++
++	if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2)
++		return mask;
++	
++	if (sock_writeable(sk))
++		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
++	else
++		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
++
++	return mask;
++}
++
++int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	add_wait_queue(sk->sleep, &wait);
++	while (sk->state != state) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->err) {
++			err = sock_error(sk);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++	return err;
+ }
+ 
+ struct net_proto_family bluez_sock_family_ops =
+@@ -129,9 +295,9 @@
+ 
+ int bluez_init(void)
+ {
+-	INF("BlueZ HCI Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
++	BT_INFO("BlueZ Core ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+ 		 VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+ 
+ 	proc_mkdir("bluetooth", NULL);
+ 
+@@ -164,5 +330,6 @@
+ module_exit(bluez_cleanup);
+ 
+ MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+-MODULE_DESCRIPTION("BlueZ HCI Core ver " VERSION);
++MODULE_DESCRIPTION("BlueZ Core ver " VERSION);
++MODULE_LICENSE("GPL");
+ #endif
+diff -urN linux-2.4.18/net/bluetooth/bnep/Config.in linux-2.4.18-mh9/net/bluetooth/bnep/Config.in
+--- linux-2.4.18/net/bluetooth/bnep/Config.in	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/Config.in	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,11 @@
++#
++# Bluetooth BNEP layer configuration
++#
++
++dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP
++
++if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then
++   bool '  Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER
++   bool '  Protocol filter support'  CONFIG_BLUEZ_BNEP_PROTO_FILTER
++fi
++
+diff -urN linux-2.4.18/net/bluetooth/bnep/Makefile linux-2.4.18-mh9/net/bluetooth/bnep/Makefile
+--- linux-2.4.18/net/bluetooth/bnep/Makefile	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/Makefile	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,10 @@
++#
++# Makefile for the Linux Bluetooth BNEP layer
++#
++
++O_TARGET := bnep.o
++
++obj-y	 := core.o sock.o netdev.o crc32.o
++obj-m    += $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.18/net/bluetooth/bnep/bnep.h linux-2.4.18-mh9/net/bluetooth/bnep/bnep.h
+--- linux-2.4.18/net/bluetooth/bnep/bnep.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/bnep.h	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,185 @@
++/*
++  BNEP protocol definition for Linux Bluetooth stack (BlueZ).
++  Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++	
++  This program is free software; you can redistribute it and/or modify
++  it under the terms of the GNU General Public License, version 2, as
++  published by the Free Software Foundation.
++
++  This program is distributed in the hope that it will be useful,
++  but WITHOUT ANY WARRANTY; without even the implied warranty of
++  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++  GNU General Public License for more details.
++
++  You should have received a copy of the GNU General Public License
++  along with this program; if not, write to the Free Software
++  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++*/
++
++/*
++ * $Id$
++ */
++
++#ifndef _BNEP_H
++#define _BNEP_H
++
++#include <linux/types.h>
++#include <net/bluetooth/bluetooth.h>
++
++#include "crc32.h"
++
++// Limits
++#define BNEP_MAX_PROTO_FILTERS     5
++#define BNEP_MAX_MULTICAST_FILTERS 20
++
++// UUIDs
++#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
++#define BNEP_UUID16    0x02
++#define BNEP_UUID32    0x04
++#define BNEP_UUID128   0x16
++
++#define BNEP_SVC_PANU  0x1115
++#define BNEP_SVC_NAP   0x1116
++#define BNEP_SVC_GN    0x1117
++
++// Packet types
++#define BNEP_GENERAL               0x00
++#define BNEP_CONTROL               0x01
++#define BNEP_COMPRESSED            0x02
++#define BNEP_COMPRESSED_SRC_ONLY   0x03
++#define BNEP_COMPRESSED_DST_ONLY   0x04
++
++// Control types
++#define BNEP_CMD_NOT_UNDERSTOOD    0x00
++#define BNEP_SETUP_CONN_REQ        0x01
++#define BNEP_SETUP_CONN_RSP        0x02
++#define BNEP_FILTER_NET_TYPE_SET   0x03
++#define BNEP_FILTER_NET_TYPE_RSP   0x04
++#define BNEP_FILTER_MULTI_ADDR_SET 0x05
++#define BNEP_FILTER_MULTI_ADDR_RSP 0x06
++
++// Extension types
++#define BNEP_EXT_CONTROL           0x00
++
++// Response messages 
++#define BNEP_SUCCESS               0x00
++
++#define BNEP_CONN_INVALID_DST      0x01
++#define BNEP_CONN_INVALID_SRC      0x02
++#define BNEP_CONN_INVALID_SVC      0x03
++#define BNEP_CONN_NOT_ALLOWED      0x04
++
++#define BNEP_FILTER_UNSUPPORTED_REQ    0x01
++#define BNEP_FILTER_INVALID_RANGE      0x02
++#define BNEP_FILTER_INVALID_MCADDR     0x02
++#define BNEP_FILTER_LIMIT_REACHED      0x03
++#define BNEP_FILTER_DENIED_SECURITY    0x04
++
++// L2CAP settings
++#define BNEP_MTU         1691
++#define BNEP_PSM	 0x0f
++#define BNEP_FLUSH_TO    0xffff
++#define BNEP_CONNECT_TO  15
++#define BNEP_FILTER_TO   15
++
++// Headers 
++#define BNEP_TYPE_MASK	 0x7f
++#define BNEP_EXT_HEADER	 0x80
++
++struct bnep_setup_conn_req {
++	__u8  type;
++	__u8  ctrl;
++	__u8  uuid_size;
++	__u8  service[0];
++} __attribute__((packed));
++
++struct bnep_set_filter_req {
++	__u8  type;
++	__u8  ctrl;
++	__u16 len;
++	__u8  list[0];
++} __attribute__((packed));
++
++struct bnep_control_rsp {
++	__u8  type;
++	__u8  ctrl;
++	__u16 resp;
++} __attribute__((packed));
++
++struct bnep_ext_hdr {
++	__u8  type;
++	__u8  len;
++	__u8  data[0];
++} __attribute__((packed));
++
++/* BNEP ioctl defines */
++#define BNEPCONNADD	_IOW('B', 200, int)
++#define BNEPCONNDEL	_IOW('B', 201, int)
++#define BNEPGETCONNLIST	_IOR('B', 210, int)
++#define BNEPGETCONNINFO	_IOR('B', 211, int)
++
++struct bnep_connadd_req {
++	int   sock;       // Connected socket
++	__u32 flags;
++	__u16 role;
++	char  device[16]; // Name of the Ethernet device
++};
++
++struct bnep_conndel_req {
++	__u32 flags;
++	__u8  dst[ETH_ALEN];
++};
++
++struct bnep_conninfo {
++	__u32 flags;
++	__u16 role;
++	__u16 state;	
++	__u8  dst[ETH_ALEN];
++	char  device[16];
++};
++
++struct bnep_connlist_req {
++	__u32  cnum;
++	struct bnep_conninfo *ci;
++};
++
++struct bnep_proto_filter {
++	__u16 start;
++	__u16 end;
++};
++
++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock);
++int bnep_del_connection(struct bnep_conndel_req *req);
++int bnep_get_connlist(struct bnep_connlist_req *req);
++int bnep_get_conninfo(struct bnep_conninfo *ci);
++
++// BNEP sessions
++struct bnep_session {
++	struct list_head list;
++	
++	unsigned int  role;
++        unsigned long state;
++        unsigned long flags;
++	atomic_t      killed;
++
++	struct ethhdr eh;
++	struct msghdr msg;
++
++	struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS];
++	u64    mc_filter;
++	
++	struct socket    *sock;
++	struct net_device dev;
++	struct net_device_stats stats;
++};
++
++int bnep_net_init(struct net_device *dev);
++int bnep_sock_init(void);
++int bnep_sock_cleanup(void);
++
++static inline int bnep_mc_hash(__u8 *addr)
++{
++        return (bnep_crc32(~0, addr, ETH_ALEN) >> 26);
++}
++
++#endif
+diff -urN linux-2.4.18/net/bluetooth/bnep/core.c linux-2.4.18-mh9/net/bluetooth/bnep/core.c
+--- linux-2.4.18/net/bluetooth/bnep/core.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/core.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,708 @@
++/* 
++   BNEP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2001-2002 Inventel Systemes
++   Written 2001-2002 by
++	Cl�ment Moreau <clement.moreau@inventel.fr>
++	David Libault  <david.libault@inventel.fr>
++
++   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */ 
++
++#define __KERNEL_SYSCALLS__
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/init.h>
++#include <linux/wait.h>
++#include <linux/errno.h>
++#include <linux/smp_lock.h>
++#include <linux/net.h>
++#include <net/sock.h>
++
++#include <linux/socket.h>
++#include <linux/file.h>
++
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/l2cap.h>
++
++#include "bnep.h"
++
++#ifndef CONFIG_BLUEZ_BNEP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define VERSION "1.1"
++
++static LIST_HEAD(bnep_session_list);
++static DECLARE_RWSEM(bnep_session_sem);
++
++static struct bnep_session *__bnep_get_session(u8 *dst)
++{
++	struct bnep_session *s;
++	struct list_head *p;
++
++	BT_DBG("");
++
++	list_for_each(p, &bnep_session_list) {
++		s = list_entry(p, struct bnep_session, list);	
++		if (!memcmp(dst, s->eh.h_source, ETH_ALEN))
++			return s;
++	}
++	return NULL;
++}
++
++static void __bnep_link_session(struct bnep_session *s)
++{
++	MOD_INC_USE_COUNT;
++	list_add(&s->list, &bnep_session_list);	
++}
++
++static void __bnep_unlink_session(struct bnep_session *s)
++{
++	list_del(&s->list);
++	MOD_DEC_USE_COUNT;
++}
++
++static int bnep_send(struct bnep_session *s, void *data, size_t len)
++{
++	struct socket *sock = s->sock;
++	struct iovec iv = { data, len };
++	s->msg.msg_iov    = &iv;
++	s->msg.msg_iovlen = 1;
++	return sock->ops->sendmsg(sock, &s->msg, len, NULL);
++}
++
++static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
++{
++	struct bnep_control_rsp rsp;
++	rsp.type = BNEP_CONTROL;
++	rsp.ctrl = ctrl;
++	rsp.resp = htons(resp);
++	return bnep_send(s, &rsp, sizeof(rsp));
++}
++
++static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
++{
++	int n;
++
++	if (len < 2)
++		return -EILSEQ;
++	
++	n = ntohs(get_unaligned(data));
++	data++; len -= 2;
++
++	if (len < n)
++		return -EILSEQ;
++
++	BT_DBG("filter len %d", n);
++
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++	n /= 4;
++	if (n <= BNEP_MAX_PROTO_FILTERS) {
++		struct bnep_proto_filter *f = s->proto_filter;
++		int i;
++
++		for (i = 0; i < n; i++) {
++			f[i].start = get_unaligned(data++);
++			f[i].end   = get_unaligned(data++);
++
++			BT_DBG("proto filter start %d end %d",
++				f[i].start, f[i].end);
++		}
++		if (i < BNEP_MAX_PROTO_FILTERS)
++			memset(f + i, 0, sizeof(*f));
++
++		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
++	} else {
++		bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
++	}
++#else
++	bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
++#endif
++	return 0;
++}
++
++static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
++{
++	int n;
++
++	if (len < 2)
++		return -EILSEQ;
++	
++	n = ntohs(get_unaligned((u16 *) data)); 
++	data += 2; len -= 2;
++
++	if (len < n)
++		return -EILSEQ;
++
++	BT_DBG("filter len %d", n);
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	n /= (ETH_ALEN * 2);
++
++	if (n > 0) {
++		s->mc_filter = 0;
++
++		/* Always send broadcast */
++		set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter);
++
++		/* Add address ranges to the multicast hash */
++		for (; n > 0; n--) {
++			u8 a1[6], *a2;
++
++			memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
++			a2 = data; data += ETH_ALEN;
++	
++			BT_DBG("mc filter %s -> %s",
++				batostr((void *) a1), batostr((void *) a2));
++
++			#define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
++
++			/* Iterate from a1 to a2 */
++			set_bit(bnep_mc_hash(a1), &s->mc_filter);
++			while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
++				INCA(a1);
++				set_bit(bnep_mc_hash(a1), &s->mc_filter);
++			}
++		}
++	}
++
++	BT_DBG("mc filter hash 0x%llx", s->mc_filter);
++
++	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
++#else
++	bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
++#endif
++	return 0;
++}
++
++static int bnep_rx_control(struct bnep_session *s, void *data, int len)
++{
++	u8  cmd = *(u8 *)data;
++	int err = 0;
++
++	data++; len--;
++	
++	switch (cmd) {
++	case BNEP_CMD_NOT_UNDERSTOOD:
++	case BNEP_SETUP_CONN_REQ:
++	case BNEP_SETUP_CONN_RSP:
++	case BNEP_FILTER_NET_TYPE_RSP:
++	case BNEP_FILTER_MULTI_ADDR_RSP:
++		/* Ignore these for now */
++		break;
++		
++	case BNEP_FILTER_NET_TYPE_SET:
++		err = bnep_ctrl_set_netfilter(s, data, len);
++		break;
++
++	case BNEP_FILTER_MULTI_ADDR_SET:
++		err = bnep_ctrl_set_mcfilter(s, data, len);
++		break;
++
++	default: {
++			u8 pkt[3];
++			pkt[0] = BNEP_CONTROL;
++			pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
++			pkt[2] = cmd;
++			bnep_send(s, pkt, sizeof(pkt));
++		}
++		break;
++	}
++
++	return err;
++}
++
++static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
++{
++	struct bnep_ext_hdr *h;
++	int err = 0;
++
++	do {
++		h = (void *) skb->data;
++		if (!skb_pull(skb, sizeof(*h))) {
++			err = -EILSEQ;
++			break;
++		}
++
++		BT_DBG("type 0x%x len %d", h->type, h->len);
++		
++		switch (h->type & BNEP_TYPE_MASK) {
++		case BNEP_EXT_CONTROL:
++			bnep_rx_control(s, skb->data, skb->len);
++			break;
++
++		default:
++			/* Unknown extension, skip it. */
++			break;
++		}
++	
++		if (!skb_pull(skb, h->len)) {
++			err = -EILSEQ;
++			break;
++		}
++	} while (!err && (h->type & BNEP_EXT_HEADER));
++	
++	return err;
++}
++
++static u8 __bnep_rx_hlen[] = {
++	ETH_HLEN,     /* BNEP_GENERAL */
++	0,            /* BNEP_CONTROL */
++	2,            /* BNEP_COMPRESSED */
++	ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
++	ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
++};
++#define BNEP_RX_TYPES	(sizeof(__bnep_rx_hlen) - 1)
++
++static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
++{
++	struct net_device *dev = &s->dev;
++	struct sk_buff *nskb;
++	u8 type;
++
++	dev->last_rx = jiffies;
++	s->stats.rx_bytes += skb->len;
++
++	type = *(u8 *) skb->data; skb_pull(skb, 1);
++
++	if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
++		goto badframe;
++	
++	if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
++		bnep_rx_control(s, skb->data, skb->len);
++		kfree_skb(skb);
++		return 0;
++	}
++
++	skb->mac.raw = skb->data;
++
++	/* Verify and pull out header */
++	if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
++		goto badframe;
++
++	s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
++
++	if (type & BNEP_EXT_HEADER) {
++		if (bnep_rx_extension(s, skb) < 0)
++			goto badframe;
++	}
++
++	/* Strip 802.1p header */
++	if (ntohs(s->eh.h_proto) == 0x8100) {
++		if (!skb_pull(skb, 4))
++			goto badframe;
++		s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
++	}
++	
++	/* We have to alloc new skb and copy data here :(. Because original skb
++	 * may not be modified and because of the alignment requirements. */
++	nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
++	if (!nskb) {
++		s->stats.rx_dropped++;
++		kfree_skb(skb);
++		return -ENOMEM;
++	}
++	skb_reserve(nskb, 2);
++
++	/* Decompress header and construct ether frame */
++	switch (type & BNEP_TYPE_MASK) {
++	case BNEP_COMPRESSED:
++		memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
++		break;
++	
++	case BNEP_COMPRESSED_SRC_ONLY:
++		memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
++		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
++		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
++		break;
++
++	case BNEP_COMPRESSED_DST_ONLY:
++		memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
++		memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
++		break;
++
++	case BNEP_GENERAL:
++		memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
++		put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
++		break;
++	}
++
++	memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
++	kfree_skb(skb);
++	
++	s->stats.rx_packets++;
++	nskb->dev       = dev;
++	nskb->ip_summed = CHECKSUM_UNNECESSARY;
++	nskb->protocol  = eth_type_trans(nskb, dev);
++	netif_rx_ni(nskb);
++	return 0;
++
++badframe:
++	s->stats.rx_errors++;
++	kfree_skb(skb);
++	return 0;
++}
++
++static u8 __bnep_tx_types[] = {
++	BNEP_GENERAL,
++	BNEP_COMPRESSED_SRC_ONLY,
++	BNEP_COMPRESSED_DST_ONLY,
++	BNEP_COMPRESSED
++};
++
++static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
++{
++	struct ethhdr *eh = (void *) skb->data;
++	struct socket *sock = s->sock;
++	struct iovec iv[3];
++	int len = 0, il = 0;
++	u8 type = 0;
++
++	BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
++
++	if (!skb->dev) {
++		/* Control frame sent by us */
++		goto send;
++	}
++
++	iv[il++] = (struct iovec) { &type, 1 };
++	len++;
++
++	if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN))
++		type |= 0x01;
++
++	if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN))
++		type |= 0x02;
++
++	if (type)
++		skb_pull(skb, ETH_ALEN * 2);
++
++	type = __bnep_tx_types[type];
++	switch (type) {
++	case BNEP_COMPRESSED_SRC_ONLY:
++		iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN };
++		len += ETH_ALEN;
++		break;
++		
++	case BNEP_COMPRESSED_DST_ONLY:
++		iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN };
++		len += ETH_ALEN;
++		break;
++	}
++
++send:
++	iv[il++] = (struct iovec) { skb->data, skb->len };
++	len += skb->len;
++	
++	/* FIXME: linearize skb */
++	
++	s->msg.msg_iov    = iv;
++	s->msg.msg_iovlen = il;
++	len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
++	kfree_skb(skb);
++
++	if (len > 0) {
++		s->stats.tx_bytes += len;
++		s->stats.tx_packets++;
++		return 0;
++	}
++
++	return len;
++}
++
++static int bnep_session(void *arg)
++{
++	struct bnep_session *s = arg;
++	struct net_device *dev = &s->dev;
++	struct sock *sk = s->sock->sk;
++	struct sk_buff *skb;
++	wait_queue_t wait;
++
++	BT_DBG("");
++
++        daemonize(); reparent_to_init();
++
++        sprintf(current->comm, "kbnepd %s", dev->name);
++	
++        sigfillset(&current->blocked);
++	flush_signals(current);
++
++	current->nice = -15;
++
++        set_fs(KERNEL_DS);
++
++	init_waitqueue_entry(&wait, current);
++	add_wait_queue(sk->sleep, &wait);
++	while (!atomic_read(&s->killed)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		// RX
++		while ((skb = skb_dequeue(&sk->receive_queue))) {
++			skb_orphan(skb);
++			bnep_rx_frame(s, skb);
++		}
++
++		if (sk->state != BT_CONNECTED)
++			break;
++	
++		// TX
++		while ((skb = skb_dequeue(&sk->write_queue)))
++			if (bnep_tx_frame(s, skb))
++				break;
++		netif_wake_queue(dev);
++	
++		schedule();
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	/* Cleanup session */
++	down_write(&bnep_session_sem);
++
++	/* Delete network device */
++	unregister_netdev(dev);
++
++	/* Release the socket */
++	fput(s->sock->file);
++
++	__bnep_unlink_session(s);
++
++	up_write(&bnep_session_sem);
++	kfree(s);
++	return 0;
++}
++
++int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
++{
++	struct net_device *dev;
++	struct bnep_session *s, *ss;
++	u8 dst[ETH_ALEN], src[ETH_ALEN];
++	int err;
++
++	BT_DBG("");
++
++	baswap((void *) dst, &bluez_pi(sock->sk)->dst);
++	baswap((void *) src, &bluez_pi(sock->sk)->src);
++
++	s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
++	if (!s) 
++		return -ENOMEM;
++	memset(s, 0, sizeof(struct bnep_session));
++
++	down_write(&bnep_session_sem);
++
++	ss = __bnep_get_session(dst);
++	if (ss && ss->state == BT_CONNECTED) {
++		err = -EEXIST;
++		goto failed;
++	}
++
++	dev = &s->dev;
++	
++	if (*req->device)
++		strcpy(dev->name, req->device);
++	else
++		strcpy(dev->name, "bnep%d");
++
++	memset(dev->broadcast, 0xff, ETH_ALEN);
++
++	/* This is rx header therefor addresses are swaped.
++	 * ie eh.h_dest is our local address. */
++	memcpy(s->eh.h_dest,   &src, ETH_ALEN);
++	memcpy(s->eh.h_source, &dst, ETH_ALEN);
++
++	s->sock  = sock;
++	s->role  = req->role;
++	s->state = BT_CONNECTED;
++	
++	s->msg.msg_flags = MSG_NOSIGNAL;
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	/* Set default mc filter */
++	set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
++#endif
++	
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++	/* Set default protocol filter */
++
++	/* (IPv4, ARP)  */
++	s->proto_filter[0].start = htons(0x0800);
++	s->proto_filter[0].end   = htons(0x0806);
++	/* (RARP, AppleTalk) */
++	s->proto_filter[1].start = htons(0x8035);
++	s->proto_filter[1].end   = htons(0x80F3);
++	/* (IPX, IPv6) */
++	s->proto_filter[2].start = htons(0x8137);
++	s->proto_filter[2].end   = htons(0x86DD);
++#endif
++	
++	dev->init = bnep_net_init;
++	dev->priv = s;
++	err = register_netdev(dev);
++	if (err) {
++		goto failed;
++	}
++
++	__bnep_link_session(s);
++	
++	err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++	if (err < 0) {
++		/* Session thread start failed, gotta cleanup. */
++		unregister_netdev(dev);
++		__bnep_unlink_session(s);
++		goto failed;
++	}
++
++	up_write(&bnep_session_sem);
++	strcpy(req->device, dev->name);
++	return 0;
++
++failed:
++	up_write(&bnep_session_sem);
++	kfree(s);
++	return err;
++}
++
++int bnep_del_connection(struct bnep_conndel_req *req)
++{
++	struct bnep_session *s;
++	int  err = 0;
++
++	BT_DBG("");
++
++	down_read(&bnep_session_sem);
++
++	s = __bnep_get_session(req->dst);
++	if (s) {
++		/* Wakeup user-space which is polling for socket errors.
++		 * This is temporary hack untill we have shutdown in L2CAP */
++		s->sock->sk->err = EUNATCH;
++		
++		/* Kill session thread */
++		atomic_inc(&s->killed);
++		wake_up_interruptible(s->sock->sk->sleep);
++	} else
++		err = -ENOENT;
++
++	up_read(&bnep_session_sem);
++	return err;
++}
++
++static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
++{
++	memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
++	strcpy(ci->device, s->dev.name);
++	ci->flags = s->flags;
++	ci->state = s->state;
++	ci->role  = s->role;
++}
++
++int bnep_get_connlist(struct bnep_connlist_req *req)
++{
++	struct list_head *p;
++	int err = 0, n = 0;
++
++	down_read(&bnep_session_sem);
++
++	list_for_each(p, &bnep_session_list) {
++		struct bnep_session *s;
++		struct bnep_conninfo ci;
++
++		s = list_entry(p, struct bnep_session, list);
++
++		__bnep_copy_ci(&ci, s);
++		
++		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
++			err = -EFAULT;
++			break;
++		}
++
++		if (++n >= req->cnum)
++			break;
++
++		req->ci++;
++	}
++	req->cnum = n;
++
++	up_read(&bnep_session_sem);
++	return err;
++}
++
++int bnep_get_conninfo(struct bnep_conninfo *ci)
++{
++	struct bnep_session *s;
++	int err = 0;
++
++	down_read(&bnep_session_sem);
++
++	s = __bnep_get_session(ci->dst);
++	if (s)
++		__bnep_copy_ci(ci, s);
++	else
++		err = -ENOENT;
++
++	up_read(&bnep_session_sem);
++	return err;
++}
++
++static int __init bnep_init_module(void)
++{
++	l2cap_load();
++
++	bnep_crc32_init();
++	bnep_sock_init();
++
++	BT_INFO("BlueZ BNEP ver %s", VERSION);
++	BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
++	BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
++	BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
++	BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
++
++	return 0;
++}
++
++static void __exit bnep_cleanup_module(void)
++{
++	bnep_sock_cleanup();
++	bnep_crc32_cleanup();
++}
++
++module_init(bnep_init_module);
++module_exit(bnep_cleanup_module);
++
++MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
++MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.c linux-2.4.18-mh9/net/bluetooth/bnep/crc32.c
+--- linux-2.4.18/net/bluetooth/bnep/crc32.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/crc32.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,59 @@
++/* 
++ * Based on linux-2.5/lib/crc32 by Matt Domsch <Matt_Domsch@dell.com>
++ *
++ * FIXME: Remove in 2.5  
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <asm/atomic.h>
++
++#include "crc32.h"
++
++#define CRCPOLY_BE 0x04c11db7
++#define CRC_BE_BITS 8
++
++static u32 *bnep_crc32_table;
++
++/*
++ * This code is in the public domain; copyright abandoned.
++ * Liability for non-performance of this code is limited to the amount
++ * you paid for it.  Since it is distributed for free, your refund will
++ * be very very small.  If it breaks, you get to keep both pieces.
++ */
++u32 bnep_crc32(u32 crc, unsigned char const *p, size_t len)
++{
++	while (len--)
++		crc = (crc << 8) ^ bnep_crc32_table[(crc >> 24) ^ *p++];
++	
++	return crc;
++}
++
++int __init bnep_crc32_init(void)
++{
++	unsigned i, j;
++	u32 crc = 0x80000000;
++
++	bnep_crc32_table = kmalloc((1 << CRC_BE_BITS) * sizeof(u32), GFP_KERNEL);
++	if (!bnep_crc32_table)
++		return -ENOMEM;
++
++	bnep_crc32_table[0] = 0;
++
++	for (i = 1; i < 1 << CRC_BE_BITS; i <<= 1) {
++		crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
++		for (j = 0; j < i; j++)
++			bnep_crc32_table[i + j] = crc ^ bnep_crc32_table[j];
++	}
++	return 0;
++}
++
++void __exit bnep_crc32_cleanup(void)
++{
++	if (bnep_crc32_table)
++		kfree(bnep_crc32_table);
++	bnep_crc32_table = NULL;
++}
+diff -urN linux-2.4.18/net/bluetooth/bnep/crc32.h linux-2.4.18-mh9/net/bluetooth/bnep/crc32.h
+--- linux-2.4.18/net/bluetooth/bnep/crc32.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/crc32.h	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,10 @@
++/*
++ * crc32.h
++ * See crc32.c for license and changes
++ *
++ * FIXME: Remove in 2.5
++ */
++
++int  bnep_crc32_init(void);
++void bnep_crc32_cleanup(void);
++u32  bnep_crc32(u32 crc, unsigned char const *p, size_t len);
+diff -urN linux-2.4.18/net/bluetooth/bnep/netdev.c linux-2.4.18-mh9/net/bluetooth/bnep/netdev.c
+--- linux-2.4.18/net/bluetooth/bnep/netdev.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/netdev.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,254 @@
++/* 
++   BNEP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2001-2002 Inventel Systemes
++   Written 2001-2002 by
++	Cl�ment Moreau <clement.moreau@inventel.fr>
++	David Libault  <david.libault@inventel.fr>
++
++   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */ 
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/socket.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/wait.h>
++
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include <net/bluetooth/l2cap.h>
++
++#include "bnep.h"
++
++#ifndef CONFIG_BLUEZ_BNEP_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++#define BNEP_TX_QUEUE_LEN 20
++
++static int bnep_net_open(struct net_device *dev)
++{
++	netif_start_queue(dev);
++	return 0;
++}
++
++static int bnep_net_close(struct net_device *dev)
++{
++	netif_stop_queue(dev);
++	return 0;
++}
++
++static struct net_device_stats *bnep_net_get_stats(struct net_device *dev)
++{
++	struct bnep_session *s = dev->priv;
++	return &s->stats;
++}
++
++static void bnep_net_set_mc_list(struct net_device *dev)
++{
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	struct bnep_session *s = dev->priv;
++	struct sock *sk = s->sock->sk;
++	struct bnep_set_filter_req *r;
++	struct sk_buff *skb;
++	int size;
++
++	BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
++
++	size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
++	skb  = alloc_skb(size, GFP_ATOMIC);
++	if (!skb) {
++		BT_ERR("%s Multicast list allocation failed", dev->name);
++		return;
++	}
++
++	r = (void *) skb->data;
++	__skb_put(skb, sizeof(*r));
++
++	r->type = BNEP_CONTROL;
++	r->ctrl = BNEP_FILTER_MULTI_ADDR_SET;
++
++        if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
++		u8 start[ETH_ALEN] = { 0x01 };
++
++		/* Request all addresses */
++		memcpy(__skb_put(skb, ETH_ALEN), start, ETH_ALEN);
++		memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
++		r->len = htons(ETH_ALEN * 2);
++	} else {
++                struct dev_mc_list *dmi = dev->mc_list;
++		int i, len = skb->len;
++
++		if (dev->flags & IFF_BROADCAST) {
++			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
++			memcpy(__skb_put(skb, ETH_ALEN), dev->broadcast, ETH_ALEN);
++		}	
++		
++		/* FIXME: We should group addresses here. */
++
++		for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
++			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
++			memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
++			dmi = dmi->next;
++		}
++		r->len = htons(skb->len - len);
++	}
++
++	skb_queue_tail(&sk->write_queue, skb);
++	wake_up_interruptible(sk->sleep);
++#endif
++}
++
++static int bnep_net_set_mac_addr(struct net_device *dev, void *arg)
++{
++	BT_DBG("%s", dev->name);
++	return 0;
++}
++
++static void bnep_net_timeout(struct net_device *dev)
++{
++	BT_DBG("net_timeout");
++	netif_wake_queue(dev);
++}
++
++static int bnep_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
++{
++	return -EINVAL;
++}
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
++{
++	struct ethhdr *eh = (void *) skb->data;
++
++	if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) {
++		BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, 
++				eh->h_dest[0], eh->h_dest[1], eh->h_dest[2],
++				eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]);
++		return 1;
++	}
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++/* Determine ether protocol. Based on eth_type_trans. */
++static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
++{
++	struct ethhdr *eh = (void *) skb->data;
++	
++	if (ntohs(eh->h_proto) >= 1536)
++		return eh->h_proto;
++		
++	if (get_unaligned((u16 *) skb->data) == 0xFFFF)
++		return htons(ETH_P_802_3);
++		
++	return htons(ETH_P_802_2);
++}
++
++static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
++{
++	u16 proto = bnep_net_eth_proto(skb);
++	struct bnep_proto_filter *f = s->proto_filter;
++	int i;
++	
++	for (i = 0; i < BNEP_MAX_PROTO_FILTERS && f[i].end; i++) {
++		if (proto >= f[i].start && proto <= f[i].end)
++			return 0;
++	}
++
++	BT_DBG("BNEP: filtered skb %p, proto 0x%.4x", skb, proto);
++	return 1;
++}
++#endif
++
++static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++	struct bnep_session *s = dev->priv;
++	struct sock *sk = s->sock->sk;
++
++	BT_DBG("skb %p, dev %p", skb, dev);
++
++#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
++	if (bnep_net_mc_filter(skb, s)) {
++		kfree_skb(skb);
++		return 0;
++	}
++#endif
++	
++#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
++	if (bnep_net_proto_filter(skb, s)) {
++		kfree_skb(skb);
++		return 0;
++	}
++#endif
++	
++	/*
++	 * We cannot send L2CAP packets from here as we are potentially in a bh.
++	 * So we have to queue them and wake up session thread which is sleeping
++	 * on the sk->sleep.
++	 */
++	dev->trans_start = jiffies;
++	skb_queue_tail(&sk->write_queue, skb);
++	wake_up_interruptible(sk->sleep);
++
++	if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) {
++		BT_DBG("tx queue is full");
++
++		/* Stop queuing.
++		 * Session thread will do netif_wake_queue() */
++		netif_stop_queue(dev);
++	}
++
++	return 0;
++}
++
++int bnep_net_init(struct net_device *dev)
++{
++	struct bnep_session *s = dev->priv;
++
++	memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
++	dev->addr_len = ETH_ALEN;
++
++	ether_setup(dev);
++
++	dev->open            = bnep_net_open;
++	dev->stop            = bnep_net_close;
++	dev->hard_start_xmit = bnep_net_xmit;
++	dev->get_stats       = bnep_net_get_stats;
++	dev->do_ioctl        = bnep_net_ioctl;
++	dev->set_mac_address = bnep_net_set_mac_addr;
++	dev->set_multicast_list = bnep_net_set_mc_list;
++
++	dev->watchdog_timeo  = HZ * 2;
++	dev->tx_timeout      = bnep_net_timeout;
++
++	return 0;
++}
+diff -urN linux-2.4.18/net/bluetooth/bnep/sock.c linux-2.4.18-mh9/net/bluetooth/bnep/sock.c
+--- linux-2.4.18/net/bluetooth/bnep/sock.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/bnep/sock.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,238 @@
++/* 
++   BNEP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2001-2002 Inventel Systemes
++   Written 2001-2002 by
++	David Libault  <david.libault@inventel.fr>
++
++   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * $Id$
++ */ 
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include "bnep.h"
++
++#ifndef CONFIG_BLUEZ_BNEP_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++static inline struct socket *socki_lookup(struct inode *inode)
++{
++	return &inode->u.socket_i;
++}
++
++static struct socket *sockfd_lookup(int fd, int *err)
++{
++	struct file *file;
++	struct inode *inode;
++	struct socket *sock;
++
++	if (!(file = fget(fd))) {
++		*err = -EBADF;
++		return NULL;
++	}
++
++	inode = file->f_dentry->d_inode;
++	if (!inode->i_sock || !(sock = socki_lookup(inode))) {
++		*err = -ENOTSOCK;
++		fput(file);
++		return NULL;
++	}
++
++	if (sock->file != file) {
++		printk(KERN_ERR "socki_lookup: socket file changed!\n");
++		sock->file = file;
++	}
++	return sock;
++}
++ 
++static int bnep_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	sock_orphan(sk);
++	sock_put(sk);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct bnep_connlist_req cl;
++	struct bnep_connadd_req  ca;
++	struct bnep_conndel_req  cd;
++	struct bnep_conninfo ci;
++	struct socket *nsock;
++	int err;
++
++	BT_DBG("cmd %x arg %lx", cmd, arg);
++
++	switch (cmd) {
++	case BNEPCONNADD:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
++			return -EFAULT;
++	
++		nsock = sockfd_lookup(ca.sock, &err);
++		if (!nsock)
++			return err;
++
++		if (nsock->sk->state != BT_CONNECTED)
++			return -EBADFD;
++
++		err = bnep_add_connection(&ca, nsock);
++		if (!err) {
++    			if (copy_to_user((void *) arg, &ca, sizeof(ca)))
++				err = -EFAULT;
++		} else
++			fput(nsock->file);
++
++		return err;
++	
++	case BNEPCONNDEL:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
++			return -EFAULT;
++	
++		return bnep_del_connection(&cd);
++
++	case BNEPGETCONNLIST:
++		if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
++			return -EFAULT;
++
++		if (cl.cnum <= 0)
++			return -EINVAL;
++	
++		err = bnep_get_connlist(&cl);
++		if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
++			return -EFAULT;
++
++		return err;
++
++	case BNEPGETCONNINFO:
++		if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
++			return -EFAULT;
++
++		err = bnep_get_conninfo(&ci);
++		if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
++			return -EFAULT;
++
++		return err;
++
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static struct proto_ops bnep_sock_ops = {
++	family:     PF_BLUETOOTH,
++	release:    bnep_sock_release,
++	ioctl:      bnep_sock_ioctl,
++	bind:       sock_no_bind,
++	getname:    sock_no_getname,
++	sendmsg:    sock_no_sendmsg,
++	recvmsg:    sock_no_recvmsg,
++	poll:       sock_no_poll,
++	listen:     sock_no_listen,
++	shutdown:   sock_no_shutdown,
++	setsockopt: sock_no_setsockopt,
++	getsockopt: sock_no_getsockopt,
++	connect:    sock_no_connect,
++	socketpair: sock_no_socketpair,
++	accept:     sock_no_accept,
++	mmap:       sock_no_mmap
++};
++
++static int bnep_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	if (sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &bnep_sock_ops;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
++		return -ENOMEM;
++
++	MOD_INC_USE_COUNT;
++
++	sock->state = SS_UNCONNECTED;
++	sock_init_data(sock, sk);
++
++	sk->destruct = NULL;
++	sk->protocol = protocol;
++
++	return 0;
++}
++
++static struct net_proto_family bnep_sock_family_ops = {
++	family: PF_BLUETOOTH,
++	create: bnep_sock_create
++};
++
++int bnep_sock_init(void)
++{
++	bluez_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
++	return 0;
++}
++
++int bnep_sock_cleanup(void)
++{
++	if (bluez_sock_unregister(BTPROTO_BNEP))
++		BT_ERR("Can't unregister BNEP socket");
++	return 0;
++}
+diff -urN linux-2.4.18/net/bluetooth/cmtp/Config.in linux-2.4.18-mh9/net/bluetooth/cmtp/Config.in
+--- linux-2.4.18/net/bluetooth/cmtp/Config.in	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/cmtp/Config.in	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,7 @@
++#
++# Bluetooth CMTP layer configuration
++#
++
++if [ "$CONFIG_ISDN" = "y" -o "$CONFIG_ISDN" = "m" ]; then 
++   dep_tristate 'CMTP protocol support' CONFIG_BLUEZ_CMTP $CONFIG_ISDN_CAPI $CONFIG_BLUEZ_L2CAP
++fi
+diff -urN linux-2.4.18/net/bluetooth/cmtp/Makefile linux-2.4.18-mh9/net/bluetooth/cmtp/Makefile
+--- linux-2.4.18/net/bluetooth/cmtp/Makefile	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/cmtp/Makefile	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,10 @@
++#
++# Makefile for the Linux Bluetooth CMTP layer
++#
++
++O_TARGET := cmtp.o
++
++obj-y	:= core.o sock.o capi.o
++obj-m	+= $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.18/net/bluetooth/cmtp/capi.c linux-2.4.18-mh9/net/bluetooth/cmtp/capi.c
+--- linux-2.4.18/net/bluetooth/cmtp/capi.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/cmtp/capi.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,707 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <linux/capi.h>
++
++#include "../drivers/isdn/avmb1/capilli.h"
++#include "../drivers/isdn/avmb1/capicmd.h"
++#include "../drivers/isdn/avmb1/capiutil.h"
++
++#include "cmtp.h"
++
++#ifndef CONFIG_BLUEZ_CMTP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define REVISION "1.0"
++
++#define CAPI_INTEROPERABILITY		0x20
++
++#define CAPI_INTEROPERABILITY_REQ	CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ)
++#define CAPI_INTEROPERABILITY_CONF	CAPICMD(CAPI_INTEROPERABILITY, CAPI_CONF)
++#define CAPI_INTEROPERABILITY_IND	CAPICMD(CAPI_INTEROPERABILITY, CAPI_IND)
++#define CAPI_INTEROPERABILITY_RESP	CAPICMD(CAPI_INTEROPERABILITY, CAPI_RESP)
++
++#define CAPI_INTEROPERABILITY_REQ_LEN	(CAPI_MSG_BASELEN + 2)
++#define CAPI_INTEROPERABILITY_CONF_LEN	(CAPI_MSG_BASELEN + 4)
++#define CAPI_INTEROPERABILITY_IND_LEN	(CAPI_MSG_BASELEN + 2)
++#define CAPI_INTEROPERABILITY_RESP_LEN	(CAPI_MSG_BASELEN + 2)
++
++#define CAPI_FUNCTION_REGISTER		0
++#define CAPI_FUNCTION_RELEASE		1
++#define CAPI_FUNCTION_GET_PROFILE	2
++#define CAPI_FUNCTION_GET_MANUFACTURER	3
++#define CAPI_FUNCTION_GET_VERSION	4
++#define CAPI_FUNCTION_GET_SERIAL_NUMBER	5
++#define CAPI_FUNCTION_MANUFACTURER	6
++#define CAPI_FUNCTION_LOOPBACK		7
++
++static struct capi_driver_interface *di;
++
++
++#define CMTP_MSGNUM	1
++#define CMTP_APPLID	2
++#define CMTP_MAPPING	3
++
++static struct cmtp_application *cmtp_application_add(struct cmtp_session *session, __u16 appl)
++{
++	struct cmtp_application *app = kmalloc(sizeof(*app), GFP_KERNEL);
++
++	BT_DBG("session %p application %p appl %d", session, app, appl);
++
++	if (!app)
++		return NULL;
++
++	memset(app, 0, sizeof(*app));
++
++	app->state = BT_OPEN;
++	app->appl = appl;
++
++	list_add_tail(&app->list, &session->applications);
++
++	return app;
++}
++
++static void cmtp_application_del(struct cmtp_session *session, struct cmtp_application *app)
++{
++	BT_DBG("session %p application %p", session, app);
++
++	if (app) {
++		list_del(&app->list);
++		kfree(app);
++	}
++}
++
++static struct cmtp_application *cmtp_application_get(struct cmtp_session *session, int pattern, __u16 value)
++{
++	struct cmtp_application *app;
++	struct list_head *p, *n;
++
++	list_for_each_safe(p, n, &session->applications) {
++		app = list_entry(p, struct cmtp_application, list);
++		switch (pattern) {
++		case CMTP_MSGNUM:
++			if (app->msgnum == value)
++				return app;
++			break;
++		case CMTP_APPLID:
++			if (app->appl == value)
++				return app;
++			break;
++		case CMTP_MAPPING:
++			if (app->mapping == value)
++				return app;
++			break;
++		}
++	}
++
++	return NULL;
++}
++
++static int cmtp_msgnum_get(struct cmtp_session *session)
++{
++	session->msgnum++;
++
++	if ((session->msgnum & 0xff) > 200)
++		session->msgnum = CMTP_INITIAL_MSGNUM + 1;
++
++	return session->msgnum;
++}
++
++
++static void cmtp_send_interopmsg(struct cmtp_session *session,
++					__u8 subcmd, __u16 appl, __u16 msgnum,
++					__u16 function, unsigned char *buf, int len)
++{
++	struct sk_buff *skb;
++	unsigned char *s;
++
++	BT_DBG("session %p subcmd 0x%02x appl %d msgnum %d", session, subcmd, appl, msgnum);
++
++	if (!(skb = alloc_skb(CAPI_MSG_BASELEN + 6 + len, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for interoperability packet");
++		return;
++	}
++
++	s = skb_put(skb, CAPI_MSG_BASELEN + 6 + len);
++
++	capimsg_setu16(s, 0, CAPI_MSG_BASELEN + 6 + len);
++	capimsg_setu16(s, 2, appl);
++	capimsg_setu8 (s, 4, CAPI_INTEROPERABILITY);
++	capimsg_setu8 (s, 5, subcmd);
++	capimsg_setu16(s, 6, msgnum);
++
++	/* Interoperability selector (Bluetooth Device Management) */
++	capimsg_setu16(s, 8, 0x0001);
++
++	capimsg_setu8 (s, 10, 3 + len);
++	capimsg_setu16(s, 11, function);
++	capimsg_setu8 (s, 13, len);
++
++	if (len > 0)
++		memcpy(s + 14, buf, len);
++
++	cmtp_send_capimsg(session, skb);
++}
++
++static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *skb)
++{
++	struct capi_ctr *ctrl = session->ctrl;
++	struct cmtp_application *application;
++	__u16 appl, msgnum, func, info;
++	__u32 controller;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	switch (CAPIMSG_SUBCOMMAND(skb->data)) {
++	case CAPI_CONF:
++		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
++		info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
++
++		switch (func) {
++		case CAPI_FUNCTION_REGISTER:
++			msgnum = CAPIMSG_MSGID(skb->data);
++
++			application = cmtp_application_get(session, CMTP_MSGNUM, msgnum);
++			if (application) {
++				application->state = BT_CONNECTED;
++				application->msgnum = 0;
++				application->mapping = CAPIMSG_APPID(skb->data);
++				wake_up_interruptible(&session->wait);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_RELEASE:
++			appl = CAPIMSG_APPID(skb->data);
++
++			application = cmtp_application_get(session, CMTP_MAPPING, appl);
++			if (application) {
++				application->state = BT_CLOSED;
++				application->msgnum = 0;
++				wake_up_interruptible(&session->wait);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_PROFILE:
++			controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
++			msgnum = CAPIMSG_MSGID(skb->data);
++
++			if (!info && (msgnum == CMTP_INITIAL_MSGNUM)) {
++				session->ncontroller = controller;
++				wake_up_interruptible(&session->wait);
++				break;
++			}
++
++			if (!info && ctrl) {
++				memcpy(&ctrl->profile,
++					skb->data + CAPI_MSG_BASELEN + 11,
++					sizeof(capi_profile));
++				session->state = BT_CONNECTED;
++				ctrl->ready(ctrl);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_MANUFACTURER:
++			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
++
++			if (!info && ctrl) {
++				strncpy(ctrl->manu,
++					skb->data + CAPI_MSG_BASELEN + 15,
++					skb->data[CAPI_MSG_BASELEN + 14]);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_VERSION:
++			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
++
++			if (!info && ctrl) {
++				ctrl->version.majorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 16);
++				ctrl->version.minorversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 20);
++				ctrl->version.majormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 24);
++				ctrl->version.minormanuversion = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 28);
++			}
++
++			break;
++
++		case CAPI_FUNCTION_GET_SERIAL_NUMBER:
++			controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
++
++			if (!info && ctrl) {
++				memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
++				strncpy(ctrl->serial,
++					skb->data + CAPI_MSG_BASELEN + 17,
++					skb->data[CAPI_MSG_BASELEN + 16]);
++			}
++
++			break;
++		}
++
++		break;
++
++	case CAPI_IND:
++		func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
++
++		if (func == CAPI_FUNCTION_LOOPBACK) {
++			appl = CAPIMSG_APPID(skb->data);
++			msgnum = CAPIMSG_MSGID(skb->data);
++			cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
++						skb->data + CAPI_MSG_BASELEN + 6,
++						skb->data[CAPI_MSG_BASELEN + 5]);
++		}
++
++		break;
++	}
++
++	kfree_skb(skb);
++}
++
++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
++{
++	struct capi_ctr *ctrl = session->ctrl;
++	struct cmtp_application *application;
++	__u16 cmd, appl, info;
++	__u32 ncci, contr;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
++		cmtp_recv_interopmsg(session, skb);
++		return;
++	}
++
++	if (session->flags & (1 << CMTP_LOOPBACK)) {
++		kfree_skb(skb);
++		return;
++	}
++
++	cmd = CAPICMD(CAPIMSG_COMMAND(skb->data), CAPIMSG_SUBCOMMAND(skb->data));
++	appl = CAPIMSG_APPID(skb->data);
++	contr = CAPIMSG_CONTROL(skb->data);
++
++	application = cmtp_application_get(session, CMTP_MAPPING, appl);
++	if (application) {
++		appl = application->appl;
++		CAPIMSG_SETAPPID(skb->data, appl);
++	} else {
++		BT_ERR("Can't find application with id %d", appl);
++		kfree_skb(skb);
++		return;
++	}
++
++	if ((contr & 0x7f) == 0x01) {
++		contr = (contr & 0xffffff80) | session->num;
++		CAPIMSG_SETCONTROL(skb->data, contr);
++	}
++
++	if (!ctrl) {
++		BT_ERR("Can't find controller %d for message", session->num);
++		kfree_skb(skb);
++		return;
++	}
++
++	switch (cmd) {
++	case CAPI_CONNECT_B3_CONF:
++		ncci = CAPIMSG_NCCI(skb->data);
++		info = CAPIMSG_U16(skb->data, 12);
++
++		BT_DBG("CONNECT_B3_CONF ncci 0x%02x info 0x%02x", ncci, info);
++
++		if (info == 0)
++			ctrl->new_ncci(ctrl, appl, ncci, 8);
++
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		break;
++
++	case CAPI_CONNECT_B3_IND:
++		ncci = CAPIMSG_NCCI(skb->data);
++
++		BT_DBG("CONNECT_B3_IND ncci 0x%02x", ncci);
++
++		ctrl->new_ncci(ctrl, appl, ncci, 8);
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		break;
++
++	case CAPI_DISCONNECT_B3_IND:
++		ncci = CAPIMSG_NCCI(skb->data);
++
++		BT_DBG("DISCONNECT_B3_IND ncci 0x%02x", ncci);
++
++		if (ncci == 0xffffffff)
++			BT_ERR("DISCONNECT_B3_IND with ncci 0xffffffff");
++
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		ctrl->free_ncci(ctrl, appl, ncci);
++		break;
++
++	default:
++		ctrl->handle_capimsg(ctrl, appl, skb);
++		break;
++	}
++}
++
++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb)
++{
++	struct cmtp_scb *scb = (void *) skb->cb;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	scb->id = -1;
++	scb->data = (CAPIMSG_COMMAND(skb->data) == CAPI_DATA_B3);
++
++	skb_queue_tail(&session->transmit, skb);
++
++	cmtp_schedule(session);
++}
++
++
++static int cmtp_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
++{
++	BT_DBG("ctrl %p data %p", ctrl, data);
++
++	return -EIO;
++}
++
++static void cmtp_reset_ctr(struct capi_ctr *ctrl)
++{
++	BT_DBG("ctrl %p", ctrl);
++
++	ctrl->reseted(ctrl);
++}
++
++static void cmtp_remove_ctr(struct capi_ctr *ctrl)
++{
++	struct cmtp_session *session = ctrl->driverdata;
++
++	BT_DBG("ctrl %p", ctrl);
++
++	ctrl->suspend_output(ctrl);
++
++	atomic_inc(&session->terminate);
++	cmtp_schedule(session);
++}
++
++static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *application;
++	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
++	unsigned char buf[8];
++	int err = 0, nconn, want = rp->level3cnt;
++
++	BT_DBG("ctrl %p appl %d level3cnt %d datablkcnt %d datablklen %d",
++		ctrl, appl, rp->level3cnt, rp->datablkcnt, rp->datablklen);
++
++	application = cmtp_application_add(session, appl);
++	if (!application) {
++		BT_ERR("Can't allocate memory for new application");
++		ctrl->appl_released(ctrl, appl);
++		return;
++	}
++
++	if (want < 0)
++		nconn = ctrl->profile.nbchannel * -want;
++	else
++		nconn = want;
++
++	if (nconn == 0)
++		nconn = ctrl->profile.nbchannel;
++
++	capimsg_setu16(buf, 0, nconn);
++	capimsg_setu16(buf, 2, rp->datablkcnt);
++	capimsg_setu16(buf, 4, rp->datablklen);
++
++	application->state = BT_CONFIG;
++	application->msgnum = cmtp_msgnum_get(session);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0x0000, application->msgnum,
++				CAPI_FUNCTION_REGISTER, buf, 6);
++
++	add_wait_queue(&session->wait, &wait);
++	while (1) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		if (application->state == BT_CLOSED) {
++			err = -application->err;
++			break;
++		}
++
++		if (application->state == BT_CONNECTED)
++			break;
++
++		if (signal_pending(current)) {
++			err = -EINTR;
++			break;
++		}
++
++		timeo = schedule_timeout(timeo);
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&session->wait, &wait);
++
++	if (err) {
++		ctrl->appl_released(ctrl, appl);
++		cmtp_application_del(session, application);
++		return;
++	}
++
++	ctrl->appl_registered(ctrl, appl);
++}
++
++static void cmtp_release_appl(struct capi_ctr *ctrl, __u16 appl)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *application;
++	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
++
++	BT_DBG("ctrl %p appl %d", ctrl, appl);
++
++	application = cmtp_application_get(session, CMTP_APPLID, appl);
++	if (!application) {
++		BT_ERR("Can't find application");
++		return;
++	}
++
++	application->msgnum = cmtp_msgnum_get(session);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, application->mapping, application->msgnum,
++				CAPI_FUNCTION_RELEASE, NULL, 0);
++
++	add_wait_queue(&session->wait, &wait);
++	while (timeo) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (application->state == BT_CLOSED)
++			break;
++
++		if (signal_pending(current))
++			break;
++
++		timeo = schedule_timeout(timeo);
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&session->wait, &wait);
++
++	cmtp_application_del(session, application);
++	ctrl->appl_released(ctrl, appl);
++}
++
++static void cmtp_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
++{
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *application;
++	__u16 appl;
++	__u32 contr;
++
++	BT_DBG("ctrl %p skb %p", ctrl, skb);
++
++	appl = CAPIMSG_APPID(skb->data);
++	contr = CAPIMSG_CONTROL(skb->data);
++
++	application = cmtp_application_get(session, CMTP_APPLID, appl);
++	if ((!application) || (application->state != BT_CONNECTED)) {
++		BT_ERR("Can't find application with id %d", appl);
++		kfree_skb(skb);
++		return;
++	}
++
++	CAPIMSG_SETAPPID(skb->data, application->mapping);
++
++	if ((contr & 0x7f) == session->num) {
++		contr = (contr & 0xffffff80) | 0x01;
++		CAPIMSG_SETCONTROL(skb->data, contr);
++	}
++
++	cmtp_send_capimsg(session, skb);
++}
++
++static char *cmtp_procinfo(struct capi_ctr *ctrl)
++{
++	return "CAPI Message Transport Protocol";
++}
++
++static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
++{
++	struct cmtp_session *session = ctrl->driverdata;
++	struct cmtp_application *app;
++	struct list_head *p, *n;
++	int len = 0;
++
++	len += sprintf(page + len, "%s (Revision %s)\n\n", cmtp_procinfo(ctrl), REVISION);
++	len += sprintf(page + len, "addr %s\n", session->name);
++	len += sprintf(page + len, "ctrl %d\n", session->num);
++
++	list_for_each_safe(p, n, &session->applications) {
++		app = list_entry(p, struct cmtp_application, list);
++		len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
++	}
++
++	if (off + count >= len)
++		*eof = 1;
++
++	if (len < off)
++		return 0;
++
++	*start = page + off;
++
++	return ((count < len - off) ? count : len - off);
++}
++
++static struct capi_driver cmtp_driver = {
++	name:		"cmtp",
++	revision:	REVISION,
++	load_firmware:	cmtp_load_firmware,
++	reset_ctr:	cmtp_reset_ctr,
++	remove_ctr:	cmtp_remove_ctr,
++	register_appl:	cmtp_register_appl,
++	release_appl:	cmtp_release_appl,
++	send_message:	cmtp_send_message,
++	procinfo:	cmtp_procinfo,
++	ctr_read_proc:	cmtp_ctr_read_proc,
++
++	driver_read_proc:	0,
++	add_card:		0,
++};
++
++
++int cmtp_attach_device(struct cmtp_session *session)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	unsigned long timeo = CMTP_INTEROP_TIMEOUT;
++	unsigned char buf[4];
++
++	BT_DBG("session %p", session);
++
++	capimsg_setu32(buf, 0, 0);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, CMTP_INITIAL_MSGNUM,
++				CAPI_FUNCTION_GET_PROFILE, buf, 4);
++
++	add_wait_queue(&session->wait, &wait);
++	while (timeo) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (session->ncontroller)
++			break;
++
++		if (signal_pending(current))
++			break;
++
++		timeo = schedule_timeout(timeo);
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&session->wait, &wait);
++
++	BT_INFO("Found %d CAPI controller(s) on device %s", session->ncontroller, session->name);
++
++	if (!timeo)
++		return -ETIMEDOUT;
++
++	if (!session->ncontroller)
++		return -ENODEV;
++
++
++	if (session->ncontroller > 1)
++		BT_INFO("Setting up only CAPI controller 1");
++
++	if (!(session->ctrl = di->attach_ctr(&cmtp_driver, session->name, session))) {
++		BT_ERR("Can't attach new controller");
++		return -EBUSY;
++	}
++
++	session->num = session->ctrl->cnr;
++
++	BT_DBG("session %p ctrl %p num %d", session, session->ctrl, session->num);
++
++	capimsg_setu32(buf, 0, 1);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_MANUFACTURER, buf, 4);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_VERSION, buf, 4);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_SERIAL_NUMBER, buf, 4);
++
++	cmtp_send_interopmsg(session, CAPI_REQ, 0xffff, cmtp_msgnum_get(session),
++				CAPI_FUNCTION_GET_PROFILE, buf, 4);
++
++	return 0;
++}
++
++void cmtp_detach_device(struct cmtp_session *session)
++{
++	struct capi_ctr *ctrl = session->ctrl;
++
++	BT_DBG("session %p ctrl %p", session, ctrl);
++
++	if (!ctrl)
++		return;
++
++	ctrl->reseted(ctrl);
++
++	di->detach_ctr(ctrl);
++}
++
++int cmtp_init_capi(void)
++{
++	if (!(di = attach_capi_driver(&cmtp_driver))) {
++		BT_ERR("Can't attach CAPI driver");
++		return -EIO;
++	}
++
++	return 0;
++}
++
++void cmtp_cleanup_capi(void)
++{
++	detach_capi_driver(&cmtp_driver);
++}
+diff -urN linux-2.4.18/net/bluetooth/cmtp/cmtp.h linux-2.4.18-mh9/net/bluetooth/cmtp/cmtp.h
+--- linux-2.4.18/net/bluetooth/cmtp/cmtp.h	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/cmtp/cmtp.h	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,138 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#ifndef __CMTP_H
++#define __CMTP_H
++
++#include <linux/types.h>
++#include <net/bluetooth/bluetooth.h>
++
++#define BTNAMSIZ 18
++
++/* CMTP ioctl defines */
++#define CMTPCONNADD	_IOW('C', 200, int)
++#define CMTPCONNDEL	_IOW('C', 201, int)
++#define CMTPGETCONNLIST	_IOR('C', 210, int)
++#define CMTPGETCONNINFO	_IOR('C', 211, int)
++
++#define CMTP_LOOPBACK	0
++
++struct cmtp_connadd_req {
++	int   sock;	// Connected socket
++	__u32 flags;
++};
++
++struct cmtp_conndel_req {
++	bdaddr_t bdaddr;
++	__u32    flags;
++};
++
++struct cmtp_conninfo {
++	bdaddr_t bdaddr;
++	__u32    flags;
++	__u16    state;
++	int      num;
++};
++
++struct cmtp_connlist_req {
++	__u32  cnum;
++	struct cmtp_conninfo *ci;
++};
++
++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock);
++int cmtp_del_connection(struct cmtp_conndel_req *req);
++int cmtp_get_connlist(struct cmtp_connlist_req *req);
++int cmtp_get_conninfo(struct cmtp_conninfo *ci);
++
++/* CMTP session defines */
++#define CMTP_INTEROP_TIMEOUT	(HZ * 5)
++#define CMTP_INITIAL_MSGNUM	0xff00
++
++struct cmtp_session {
++	struct list_head list;
++
++	struct socket *sock;
++
++	bdaddr_t bdaddr;
++
++	unsigned long state;
++	unsigned long flags;
++
++	uint mtu;
++
++	char name[BTNAMSIZ];
++
++	atomic_t terminate;
++
++	wait_queue_head_t wait;
++
++	int ncontroller;
++	int num;
++	struct capi_ctr *ctrl;
++
++	struct list_head applications;
++
++	unsigned long blockids;
++	int msgnum;
++
++	struct sk_buff_head transmit;
++
++	struct sk_buff *reassembly[16];
++};
++
++struct cmtp_application {
++	struct list_head list;
++
++	unsigned long state;
++	int err;
++
++	__u16 appl;
++	__u16 mapping;
++
++	__u16 msgnum;
++};
++
++struct cmtp_scb {
++	int id;
++	int data;
++};
++
++int  cmtp_attach_device(struct cmtp_session *session);
++void cmtp_detach_device(struct cmtp_session *session);
++
++void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb);
++void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb);
++
++static inline void cmtp_schedule(struct cmtp_session *session)
++{
++	struct sock *sk = session->sock->sk;
++
++	wake_up_interruptible(sk->sleep);
++}
++
++/* CMTP init defines */
++int cmtp_init_capi(void);
++int cmtp_init_sockets(void);
++void cmtp_cleanup_capi(void);
++void cmtp_cleanup_sockets(void);
++
++#endif /* __CMTP_H */
+diff -urN linux-2.4.18/net/bluetooth/cmtp/core.c linux-2.4.18-mh9/net/bluetooth/cmtp/core.c
+--- linux-2.4.18/net/bluetooth/cmtp/core.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/cmtp/core.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,515 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <linux/init.h>
++#include <net/sock.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/l2cap.h>
++
++#include "cmtp.h"
++
++#ifndef CONFIG_BLUEZ_CMTP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define VERSION "1.0"
++
++static DECLARE_RWSEM(cmtp_session_sem);
++static LIST_HEAD(cmtp_session_list);
++
++static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
++{
++	struct cmtp_session *session;
++	struct list_head *p;
++
++	BT_DBG("");
++
++	list_for_each(p, &cmtp_session_list) {
++		session = list_entry(p, struct cmtp_session, list);
++		if (!bacmp(bdaddr, &session->bdaddr))
++			return session;
++	}
++	return NULL;
++}
++
++static void __cmtp_link_session(struct cmtp_session *session)
++{
++	MOD_INC_USE_COUNT;
++	list_add(&session->list, &cmtp_session_list);
++}
++
++static void __cmtp_unlink_session(struct cmtp_session *session)
++{
++	list_del(&session->list);
++	MOD_DEC_USE_COUNT;
++}
++
++static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
++{
++	bacpy(&ci->bdaddr, &session->bdaddr);
++
++	ci->flags = session->flags;
++	ci->state = session->state;
++
++	ci->num = session->num;
++}
++
++
++static inline int cmtp_alloc_block_id(struct cmtp_session *session)
++{
++	int i, id = -1;
++
++	for (i = 0; i < 16; i++)
++		if (!test_and_set_bit(i, &session->blockids)) {
++			id = i;
++			break;
++		}
++
++	return id;
++}
++
++static inline void cmtp_free_block_id(struct cmtp_session *session, int id)
++{
++	clear_bit(id, &session->blockids);
++}
++
++static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const unsigned char *buf, int count)
++{
++	struct sk_buff *skb = session->reassembly[id], *nskb;
++	int size;
++
++	BT_DBG("session %p buf %p count %d", session, buf, count);
++
++	size = (skb) ? skb->len + count : count;
++
++	if (!(nskb = alloc_skb(size, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for CAPI message");
++		return;
++	}
++
++	if (skb && (skb->len > 0))
++		memcpy(skb_put(nskb, skb->len), skb->data, skb->len);
++
++	memcpy(skb_put(nskb, count), buf, count);
++
++	session->reassembly[id] = nskb;
++
++	if (skb)
++		kfree_skb(skb);
++}
++
++static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
++{
++	__u8 hdr, hdrlen, id;
++	__u16 len;
++
++	BT_DBG("session %p skb %p len %d", session, skb, skb->len);
++
++	while (skb->len > 0) {
++		hdr = skb->data[0];
++
++		switch (hdr & 0xc0) {
++		case 0x40:
++			hdrlen = 2;
++			len = skb->data[1];
++			break;
++		case 0x80:
++			hdrlen = 3;
++			len = skb->data[1] | (skb->data[2] << 8);
++			break;
++		default:
++			hdrlen = 1;
++			len = 0;
++			break;
++		}
++
++		id = (hdr & 0x3c) >> 2;
++
++		BT_DBG("hdr 0x%02x hdrlen %d len %d id %d", hdr, hdrlen, len, id);
++
++		if (hdrlen + len > skb->len) {
++			BT_ERR("Wrong size or header information in CMTP frame");
++			break;
++		}
++
++		if (len == 0) {
++			skb_pull(skb, hdrlen);
++			continue;
++		}
++
++		switch (hdr & 0x03) {
++		case 0x00:
++			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
++			cmtp_recv_capimsg(session, session->reassembly[id]);
++			session->reassembly[id] = NULL;
++			break;
++		case 0x01:
++			cmtp_add_msgpart(session, id, skb->data + hdrlen, len);
++			break;
++		default:
++			if (session->reassembly[id] != NULL)
++				kfree_skb(session->reassembly[id]);
++			session->reassembly[id] = NULL;
++			break;
++		}
++
++		skb_pull(skb, hdrlen + len);
++	}
++
++	kfree_skb(skb);
++	return 0;
++}
++
++static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, int len)
++{
++	struct socket *sock = session->sock;
++	struct iovec iv = { data, len };
++	struct msghdr msg;
++	int err;
++
++	BT_DBG("session %p data %p len %d", session, data, len);
++
++	if (!len)
++		return 0;
++
++	memset(&msg, 0, sizeof(msg));
++	msg.msg_iovlen = 1;
++	msg.msg_iov = &iv;
++
++	err = sock->ops->sendmsg(sock, &msg, len, 0);
++	return err;
++}
++
++static int cmtp_process_transmit(struct cmtp_session *session)
++{
++	struct sk_buff *skb, *nskb;
++	unsigned char *hdr;
++	unsigned int size, tail;
++
++	BT_DBG("session %p", session);
++
++	if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
++		BT_ERR("Can't allocate memory for new frame");
++		return -ENOMEM;
++	}
++
++	while ((skb = skb_dequeue(&session->transmit))) {
++		struct cmtp_scb *scb = (void *) skb->cb;
++
++		if ((tail = (session->mtu - nskb->len)) < 5) {
++			cmtp_send_frame(session, nskb->data, nskb->len);
++			skb_trim(nskb, 0);
++			tail = session->mtu;
++		}
++
++		size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len);
++
++		if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) {
++			skb_queue_head(&session->transmit, skb);
++			break;
++		}
++
++		if (size < 256) {
++			hdr = skb_put(nskb, 2);
++			hdr[0] = 0x40
++				| ((scb->id << 2) & 0x3c)
++				| ((skb->len == size) ? 0x00 : 0x01);
++			hdr[1] = size;
++		} else {
++			hdr = skb_put(nskb, 3);
++			hdr[0] = 0x80
++				| ((scb->id << 2) & 0x3c)
++				| ((skb->len == size) ? 0x00 : 0x01);
++			hdr[1] = size & 0xff;
++			hdr[2] = size >> 8;
++		}
++
++		memcpy(skb_put(nskb, size), skb->data, size);
++		skb_pull(skb, size);
++
++		if (skb->len > 0) {
++			skb_queue_head(&session->transmit, skb);
++		} else {
++			cmtp_free_block_id(session, scb->id);
++			if (scb->data) {
++				cmtp_send_frame(session, nskb->data, nskb->len);
++				skb_trim(nskb, 0);
++			}
++			kfree_skb(skb);
++		}
++	}
++
++	cmtp_send_frame(session, nskb->data, nskb->len);
++
++	kfree_skb(nskb);
++
++	return skb_queue_len(&session->transmit);
++}
++
++static int cmtp_session(void *arg)
++{
++	struct cmtp_session *session = arg;
++	struct sock *sk = session->sock->sk;
++	struct sk_buff *skb;
++	wait_queue_t wait;
++
++	BT_DBG("session %p", session);
++
++	daemonize(); reparent_to_init();
++
++	sprintf(current->comm, "kcmtpd_ctr_%d", session->num);
++
++	sigfillset(&current->blocked);
++	flush_signals(current);
++
++	current->nice = -15;
++
++	set_fs(KERNEL_DS);
++
++	init_waitqueue_entry(&wait, current);
++	add_wait_queue(sk->sleep, &wait);
++	while (!atomic_read(&session->terminate)) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (sk->state != BT_CONNECTED)
++			break;
++
++		while ((skb = skb_dequeue(&sk->receive_queue))) {
++			skb_orphan(skb);
++			cmtp_recv_frame(session, skb);
++		}
++
++		cmtp_process_transmit(session);
++
++		schedule();
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	down_write(&cmtp_session_sem);
++
++	if (!(session->flags & (1 << CMTP_LOOPBACK)))
++		cmtp_detach_device(session);
++
++	fput(session->sock->file);
++
++	__cmtp_unlink_session(session);
++
++	up_write(&cmtp_session_sem);
++
++	kfree(session);
++	return 0;
++}
++
++int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
++{
++	struct cmtp_session *session, *s;
++	bdaddr_t src, dst;
++	int i, err;
++
++	BT_DBG("");
++
++	baswap(&src, &bluez_pi(sock->sk)->src);
++	baswap(&dst, &bluez_pi(sock->sk)->dst);
++
++	session = kmalloc(sizeof(struct cmtp_session), GFP_KERNEL);
++	if (!session) 
++		return -ENOMEM;
++	memset(session, 0, sizeof(struct cmtp_session));
++
++	down_write(&cmtp_session_sem);
++
++	s = __cmtp_get_session(&bluez_pi(sock->sk)->dst);
++	if (s && s->state == BT_CONNECTED) {
++		err = -EEXIST;
++		goto failed;
++	}
++
++	bacpy(&session->bdaddr, &bluez_pi(sock->sk)->dst);
++
++	session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu);
++
++	BT_DBG("mtu %d", session->mtu);
++
++	sprintf(session->name, "%s", batostr(&dst));
++
++	session->sock  = sock;
++	session->state = BT_CONFIG;
++
++	init_waitqueue_head(&session->wait);
++
++	session->ctrl   = NULL;
++	session->msgnum = CMTP_INITIAL_MSGNUM;
++
++	INIT_LIST_HEAD(&session->applications);
++
++	skb_queue_head_init(&session->transmit);
++
++	for (i = 0; i < 16; i++)
++		session->reassembly[i] = NULL;
++
++	session->flags = req->flags;
++
++	__cmtp_link_session(session);
++
++	err = kernel_thread(cmtp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++	if (err < 0)
++		goto unlink;
++
++	if (!(session->flags & (1 << CMTP_LOOPBACK))) {
++		err = cmtp_attach_device(session);
++		if (err < 0)
++			goto detach;
++	}
++
++	up_write(&cmtp_session_sem);
++	return 0;
++
++detach:
++	cmtp_detach_device(session);
++
++unlink:
++	__cmtp_unlink_session(session);
++
++failed:
++	up_write(&cmtp_session_sem);
++	kfree(session);
++	return err;
++}
++
++int cmtp_del_connection(struct cmtp_conndel_req *req)
++{
++	struct cmtp_session *session;
++	int err = 0;
++
++	BT_DBG("");
++
++	down_read(&cmtp_session_sem);
++
++	session = __cmtp_get_session(&req->bdaddr);
++	if (session) {
++		/* Flush the transmit queue */
++		skb_queue_purge(&session->transmit);
++
++		/* Kill session thread */
++		atomic_inc(&session->terminate);
++		cmtp_schedule(session);
++	} else
++		err = -ENOENT;
++
++	up_read(&cmtp_session_sem);
++	return err;
++}
++
++int cmtp_get_connlist(struct cmtp_connlist_req *req)
++{
++	struct list_head *p;
++	int err = 0, n = 0;
++
++	BT_DBG("");
++
++	down_read(&cmtp_session_sem);
++
++	list_for_each(p, &cmtp_session_list) {
++		struct cmtp_session *session;
++		struct cmtp_conninfo ci;
++
++		session = list_entry(p, struct cmtp_session, list);
++
++		__cmtp_copy_session(session, &ci);
++
++		if (copy_to_user(req->ci, &ci, sizeof(ci))) {
++			err = -EFAULT;
++			break;
++		}
++
++		if (++n >= req->cnum)
++			break;
++
++		req->ci++;
++	}
++	req->cnum = n;
++
++	up_read(&cmtp_session_sem);
++	return err;
++}
++
++int cmtp_get_conninfo(struct cmtp_conninfo *ci)
++{
++	struct cmtp_session *session;
++	int err = 0;
++
++	down_read(&cmtp_session_sem);
++
++	session = __cmtp_get_session(&ci->bdaddr);
++	if (session)
++		__cmtp_copy_session(session, ci);
++	else
++		err = -ENOENT;
++
++	up_read(&cmtp_session_sem);
++	return err;
++}
++
++
++int __init init_cmtp(void)
++{
++	l2cap_load();
++
++	cmtp_init_capi();
++	cmtp_init_sockets();
++
++	BT_INFO("BlueZ CMTP ver %s", VERSION);
++	BT_INFO("Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>");
++
++	return 0;
++}
++
++void __exit exit_cmtp(void)
++{
++	cmtp_cleanup_sockets();
++	cmtp_cleanup_capi();
++}
++
++module_init(init_cmtp);
++module_exit(exit_cmtp);
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ CMTP ver " VERSION);
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/net/bluetooth/cmtp/sock.c linux-2.4.18-mh9/net/bluetooth/cmtp/sock.c
+--- linux-2.4.18/net/bluetooth/cmtp/sock.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/cmtp/sock.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,236 @@
++/* 
++   CMTP implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002-2003 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/skbuff.h>
++#include <linux/socket.h>
++#include <linux/ioctl.h>
++#include <linux/file.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include "cmtp.h"
++
++#ifndef CONFIG_BLUEZ_CMTP_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++static inline struct socket *socki_lookup(struct inode *inode)
++{
++	return &inode->u.socket_i;
++}
++
++static struct socket *sockfd_lookup(int fd, int *err)
++{
++	struct file *file;
++	struct inode *inode;
++	struct socket *sock;
++
++	if (!(file = fget(fd))) {
++		*err = -EBADF;
++		return NULL;
++	}
++
++	inode = file->f_dentry->d_inode;
++	if (!inode->i_sock || !(sock = socki_lookup(inode))) {
++		*err = -ENOTSOCK;
++		fput(file);
++		return NULL;
++	}
++
++	if (sock->file != file) {
++		printk(KERN_ERR "socki_lookup: socket file changed!\n");
++		sock->file = file;
++	}
++	return sock;
++}
++
++static int cmtp_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	sock_orphan(sk);
++	sock_put(sk);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct cmtp_connadd_req ca;
++	struct cmtp_conndel_req cd;
++	struct cmtp_connlist_req cl;
++	struct cmtp_conninfo ci;
++	struct socket *nsock;
++	int err;
++
++	BT_DBG("cmd %x arg %lx", cmd, arg);
++
++	switch (cmd) {
++	case CMTPCONNADD:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
++			return -EFAULT;
++
++		nsock = sockfd_lookup(ca.sock, &err);
++		if (!nsock)
++			return err;
++
++		if (nsock->sk->state != BT_CONNECTED)
++			return -EBADFD;
++
++		err = cmtp_add_connection(&ca, nsock);
++		if (!err) {
++			if (copy_to_user((void *) arg, &ca, sizeof(ca)))
++				err = -EFAULT;
++		} else
++			fput(nsock->file);
++
++		return err;
++
++	case CMTPCONNDEL:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
++
++		if (copy_from_user(&cd, (void *) arg, sizeof(cd)))
++			return -EFAULT;
++
++		return cmtp_del_connection(&cd);
++
++	case CMTPGETCONNLIST:
++		if (copy_from_user(&cl, (void *) arg, sizeof(cl)))
++			return -EFAULT;
++
++		if (cl.cnum <= 0)
++			return -EINVAL;
++
++		err = cmtp_get_connlist(&cl);
++		if (!err && copy_to_user((void *) arg, &cl, sizeof(cl)))
++			return -EFAULT;
++
++		return err;
++
++	case CMTPGETCONNINFO:
++		if (copy_from_user(&ci, (void *) arg, sizeof(ci)))
++			return -EFAULT;
++
++		err = cmtp_get_conninfo(&ci);
++		if (!err && copy_to_user((void *) arg, &ci, sizeof(ci)))
++			return -EFAULT;
++
++		return err;
++	}
++
++	return -EINVAL;
++}
++
++static struct proto_ops cmtp_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	cmtp_sock_release,
++	ioctl:		cmtp_sock_ioctl,
++	bind:		sock_no_bind,
++	getname:	sock_no_getname,
++	sendmsg:	sock_no_sendmsg,
++	recvmsg:	sock_no_recvmsg,
++	poll:		sock_no_poll,
++	listen:		sock_no_listen,
++	shutdown:	sock_no_shutdown,
++	setsockopt:	sock_no_setsockopt,
++	getsockopt:	sock_no_getsockopt,
++	connect:	sock_no_connect,
++	socketpair:	sock_no_socketpair,
++	accept:		sock_no_accept,
++	mmap:		sock_no_mmap
++};
++
++static int cmtp_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	if (sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &cmtp_sock_ops;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1)))
++		return -ENOMEM;
++
++	MOD_INC_USE_COUNT;
++
++	sock->state = SS_UNCONNECTED;
++	sock_init_data(sock, sk);
++
++	sk->destruct = NULL;
++	sk->protocol = protocol;
++
++	return 0;
++}
++
++static struct net_proto_family cmtp_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		cmtp_sock_create
++};
++
++int cmtp_init_sockets(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops))) {
++		BT_ERR("Can't register CMTP socket layer (%d)", err);
++		return err;
++	}
++
++	return 0;
++}
++
++void cmtp_cleanup_sockets(void)
++{
++	int err;
++
++	if ((err = bluez_sock_unregister(BTPROTO_CMTP)))
++		BT_ERR("Can't unregister CMTP socket layer (%d)", err);
++
++	return;
++}
+diff -urN linux-2.4.18/net/bluetooth/hci_conn.c linux-2.4.18-mh9/net/bluetooth/hci_conn.c
+--- linux-2.4.18/net/bluetooth/hci_conn.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/hci_conn.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,441 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * HCI Connection handling.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/notifier.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++#ifndef HCI_CORE_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++void hci_acl_connect(struct hci_conn *conn)
++{
++	struct hci_dev *hdev = conn->hdev;
++	struct inquiry_entry *ie;
++	create_conn_cp cp;
++
++	BT_DBG("%p", conn);
++
++	conn->state = BT_CONNECT;
++	conn->out   = 1;
++	conn->link_mode = HCI_LM_MASTER;
++
++	memset(&cp, 0, sizeof(cp));
++	bacpy(&cp.bdaddr, &conn->dst);
++	cp.pscan_rep_mode = 0x01;
++
++	if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
++			inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
++		cp.pscan_rep_mode = ie->info.pscan_rep_mode;
++		cp.pscan_mode     = ie->info.pscan_mode;
++		cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
++	}
++
++	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
++	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
++		cp.role_switch	= 0x01;
++	else
++		cp.role_switch	= 0x00;
++		
++	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
++				CREATE_CONN_CP_SIZE, &cp);
++}
++
++void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
++{
++	disconnect_cp cp;
++
++	BT_DBG("%p", conn);
++
++	conn->state = BT_DISCONN;
++
++	cp.handle = __cpu_to_le16(conn->handle);
++	cp.reason = reason;
++	hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
++				DISCONNECT_CP_SIZE, &cp);
++}
++
++void hci_add_sco(struct hci_conn *conn, __u16 handle)
++{
++	struct hci_dev *hdev = conn->hdev;
++	add_sco_cp cp;
++
++	BT_DBG("%p", conn);
++
++	conn->state = BT_CONNECT;
++	conn->out = 1;
++
++	cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
++	cp.handle   = __cpu_to_le16(handle);
++
++	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
++}
++
++static void hci_conn_timeout(unsigned long arg)
++{
++	struct hci_conn *conn = (void *)arg;
++	struct hci_dev  *hdev = conn->hdev;
++
++	BT_DBG("conn %p state %d", conn, conn->state);
++
++	if (atomic_read(&conn->refcnt))
++		return;
++
++	hci_dev_lock(hdev);
++ 	if (conn->state == BT_CONNECTED)
++		hci_acl_disconn(conn, 0x13);
++	else
++		conn->state = BT_CLOSED;
++	hci_dev_unlock(hdev);
++	return;
++}
++
++static void hci_conn_init_timer(struct hci_conn *conn)
++{
++	init_timer(&conn->timer);
++	conn->timer.function = hci_conn_timeout;
++	conn->timer.data = (unsigned long)conn;
++}
++
++struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
++{
++	struct hci_conn *conn;
++
++	BT_DBG("%s dst %s", hdev->name, batostr(dst));
++
++	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
++		return NULL;
++	memset(conn, 0, sizeof(struct hci_conn));
++
++	bacpy(&conn->dst, dst);
++	conn->type   = type;
++	conn->hdev   = hdev;
++	conn->state  = BT_OPEN;
++
++	skb_queue_head_init(&conn->data_q);
++	hci_conn_init_timer(conn);
++
++	atomic_set(&conn->refcnt, 0);
++
++	hci_dev_hold(hdev);
++
++	if (hdev->notify)
++		hdev->notify(hdev, HCI_NOTIFY_CONN_ADD, (unsigned long) conn);
++
++	tasklet_disable(&hdev->tx_task);
++	conn_hash_add(hdev, conn);
++	tasklet_enable(&hdev->tx_task);
++
++	return conn;
++}
++
++int hci_conn_del(struct hci_conn *conn)
++{
++	struct hci_dev  *hdev = conn->hdev;
++
++	BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
++	
++	hci_conn_del_timer(conn);
++
++	if (conn->type == SCO_LINK) {
++		struct hci_conn *acl = conn->link;
++		if (acl) {
++			acl->link = NULL;
++			hci_conn_put(acl);
++		}
++	} else {
++		struct hci_conn *sco = conn->link;
++		if (sco)
++			sco->link = NULL;
++
++		/* Unacked frames */
++		hdev->acl_cnt += conn->sent;
++	}
++
++	tasklet_disable(&hdev->tx_task);
++	conn_hash_del(hdev, conn);
++	tasklet_enable(&hdev->tx_task);
++
++	skb_queue_purge(&conn->data_q);
++
++	if (hdev->notify)
++		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL, (unsigned long) conn);
++
++	hci_dev_put(hdev);
++
++	kfree(conn);
++	return 0;
++}
++
++struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
++{
++	int use_src = bacmp(src, BDADDR_ANY);
++	struct hci_dev *hdev = NULL;
++	struct list_head *p;
++
++	BT_DBG("%s -> %s", batostr(src), batostr(dst));
++
++	read_lock_bh(&hdev_list_lock);
++
++	list_for_each(p, &hdev_list) {
++		struct hci_dev *d;
++		d = list_entry(p, struct hci_dev, list);
++		
++		if (!test_bit(HCI_UP, &d->flags))
++			continue;
++
++		/* Simple routing: 
++	 	 * 	No source address - find interface with bdaddr != dst 
++	 	 *	Source address 	  - find interface with bdaddr == src 
++	 	 */
++
++		if (use_src) {
++			if (!bacmp(&d->bdaddr, src)) {
++				hdev = d; break;
++			}
++		} else {
++			if (bacmp(&d->bdaddr, dst)) {
++				hdev = d; break;
++			}
++		}
++	}
++
++	if (hdev)
++		hci_dev_hold(hdev);
++
++	read_unlock_bh(&hdev_list_lock);
++	return hdev;
++}
++
++/* Create SCO or ACL connection.
++ * Device _must_ be locked */
++struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
++{
++	struct hci_conn *acl;
++
++	BT_DBG("%s dst %s", hdev->name, batostr(dst));
++
++	if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
++		if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
++			return NULL;
++	}
++
++	hci_conn_hold(acl);
++
++	if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
++		hci_acl_connect(acl);
++
++	if (type == SCO_LINK) {
++		struct hci_conn *sco;
++
++		if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
++			if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
++				hci_conn_put(acl);
++				return NULL;
++			}
++		}
++		acl->link = sco;
++		sco->link = acl;
++
++		hci_conn_hold(sco);
++
++		if (acl->state == BT_CONNECTED && 
++				(sco->state == BT_OPEN || sco->state == BT_CLOSED))
++			hci_add_sco(sco, acl->handle);
++
++		return sco;
++	} else {
++		return acl;
++	}
++}
++
++/* Authenticate remote device */
++int hci_conn_auth(struct hci_conn *conn)
++{
++	BT_DBG("conn %p", conn);
++	
++	if (conn->link_mode & HCI_LM_AUTH)
++		return 1;
++	
++	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
++		auth_requested_cp ar;
++		ar.handle = __cpu_to_le16(conn->handle);
++		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
++				AUTH_REQUESTED_CP_SIZE, &ar);
++	}
++	return 0;
++}
++
++/* Enable encryption */
++int hci_conn_encrypt(struct hci_conn *conn)
++{
++	BT_DBG("conn %p", conn);
++	
++	if (conn->link_mode & HCI_LM_ENCRYPT)
++		return 1;
++	
++	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
++		return 0;
++
++	if (hci_conn_auth(conn)) {
++		set_conn_encrypt_cp ce;
++		ce.handle  = __cpu_to_le16(conn->handle);
++		ce.encrypt = 1; 
++		hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
++				SET_CONN_ENCRYPT_CP_SIZE, &ce);
++	}
++	return 0;
++}
++
++/* Drop all connection on the device */
++void hci_conn_hash_flush(struct hci_dev *hdev)
++{
++	struct conn_hash *h = &hdev->conn_hash;
++        struct list_head *p;
++
++	BT_DBG("hdev %s", hdev->name);
++
++	p = h->list.next;
++	while (p != &h->list) {
++		struct hci_conn *c;
++
++		c = list_entry(p, struct hci_conn, list);
++		p = p->next;
++
++		c->state = BT_CLOSED;
++
++		hci_proto_disconn_ind(c, 0x16);
++		hci_conn_del(c);
++	}
++}
++
++int hci_get_conn_list(unsigned long arg)
++{
++	struct hci_conn_list_req req, *cl;
++	struct hci_conn_info *ci;
++	struct hci_dev *hdev;
++	struct list_head *p;
++	int n = 0, size;
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	if (!(hdev = hci_dev_get(req.dev_id)))
++		return -ENODEV;
++
++	size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
++
++	if (verify_area(VERIFY_WRITE, (void *)arg, size))
++		return -EFAULT;
++
++	if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
++		return -ENOMEM;
++	ci = cl->conn_info;
++
++	hci_dev_lock_bh(hdev);
++	list_for_each(p, &hdev->conn_hash.list) {
++		register struct hci_conn *c;
++		c = list_entry(p, struct hci_conn, list);
++
++		bacpy(&(ci + n)->bdaddr, &c->dst);
++		(ci + n)->handle = c->handle;
++		(ci + n)->type  = c->type;
++		(ci + n)->out   = c->out;
++		(ci + n)->state = c->state;
++		(ci + n)->link_mode = c->link_mode;
++		n++;
++	}
++	hci_dev_unlock_bh(hdev);
++
++	cl->dev_id = hdev->id;
++	cl->conn_num = n;
++	size = n * sizeof(struct hci_conn_info) + sizeof(req);
++
++	hci_dev_put(hdev);
++
++	copy_to_user((void *) arg, cl, size);
++	kfree(cl);
++
++	return 0;
++}
++
++int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
++{
++	struct hci_conn_info_req req;
++	struct hci_conn_info ci;
++	struct hci_conn *conn;
++	char *ptr = (void *) arg + sizeof(req);
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	if (verify_area(VERIFY_WRITE, ptr, sizeof(ci)))
++		return -EFAULT;
++
++	hci_dev_lock_bh(hdev);
++	conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
++	if (conn) {
++		bacpy(&ci.bdaddr, &conn->dst);
++		ci.handle = conn->handle;
++		ci.type  = conn->type;
++		ci.out   = conn->out;
++		ci.state = conn->state;
++		ci.link_mode = conn->link_mode;
++	}
++	hci_dev_unlock_bh(hdev);
++
++	if (!conn)
++		return -ENOENT;
++
++	copy_to_user(ptr, &ci, sizeof(ci));
++	return 0;
++}
+diff -urN linux-2.4.18/net/bluetooth/hci_core.c linux-2.4.18-mh9/net/bluetooth/hci_core.c
+--- linux-2.4.18/net/bluetooth/hci_core.c	Fri Nov  9 23:21:21 2001
++++ linux-2.4.18-mh9/net/bluetooth/hci_core.c	Mon Aug 25 18:38:12 2003
+@@ -25,11 +25,12 @@
+ /*
+  * BlueZ HCI Core.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/config.h>
+ #include <linux/module.h>
++#include <linux/kmod.h>
+ 
+ #include <linux/types.h>
+ #include <linux/errno.h>
+@@ -50,12 +51,11 @@
+ #include <asm/unaligned.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+ 
+ #ifndef HCI_CORE_DEBUG
+-#undef  DBG
+-#define DBG( A... )
++#undef  BT_DBG
++#define BT_DBG( A... )
+ #endif
+ 
+ static void hci_cmd_task(unsigned long arg);
+@@ -63,279 +63,69 @@
+ static void hci_tx_task(unsigned long arg);
+ static void hci_notify(struct hci_dev *hdev, int event);
+ 
+-static rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
++rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
+ 
+ /* HCI device list */
+-struct hci_dev *hdev_list[HCI_MAX_DEV];
+-spinlock_t hdev_list_lock;
+-#define GET_HDEV(a) (hdev_list[a])
+-
+-/* HCI protocol list */
+-struct hci_proto *hproto_list[HCI_MAX_PROTO];
+-#define GET_HPROTO(a) (hproto_list[a])
++LIST_HEAD(hdev_list);
++rwlock_t hdev_list_lock = RW_LOCK_UNLOCKED;
+ 
+-/* HCI notifiers list */
+-struct notifier_block *hci_dev_notifier;
+-
+-/* HCI device notifications */
+-int hci_register_notifier(struct notifier_block *nb)
+-{
+-	int err, i;
+-	struct hci_dev *hdev;
+-
+-	if ((err = notifier_chain_register(&hci_dev_notifier, nb)))
+-		return err;
+-
+-	/* Notify about already registered devices */
+-	spin_lock(&hdev_list_lock);
+-	for (i = 0; i < HCI_MAX_DEV; i++) {
+-		if (!(hdev = GET_HDEV(i)))
+-			continue;
+-		if (hdev->flags & HCI_UP)
+-			(*nb->notifier_call)(nb, HCI_DEV_UP, hdev);
+-	}
+-	spin_unlock(&hdev_list_lock);
+-
+-	return 0;
+-}
+-
+-int hci_unregister_notifier(struct notifier_block *nb)
+-{
+-	return notifier_chain_unregister(&hci_dev_notifier, nb);
+-}
+-
+-static inline void hci_notify(struct hci_dev *hdev, int event)
+-{
+-	notifier_call_chain(&hci_dev_notifier, event, hdev);
+-}
+-
+-/* Get HCI device by index (device is locked on return)*/
+-struct hci_dev *hci_dev_get(int index)
+-{
+-	struct hci_dev *hdev;
+-	DBG("%d", index);
+-
+-	if (index < 0 || index >= HCI_MAX_DEV)
+-		return NULL;
+-
+-	spin_lock(&hdev_list_lock);
+-	if ((hdev = GET_HDEV(index)))
+-		hci_dev_hold(hdev);
+-	spin_unlock(&hdev_list_lock);
+-
+-	return hdev;
+-}
+-
+-/* Flush inquiry cache */
+-void inquiry_cache_flush(struct inquiry_cache *cache)
+-{
+-	struct inquiry_entry *next = cache->list, *e;
+-
+-	DBG("cache %p", cache);
+-
+-	cache->list = NULL;
+-	while ((e = next)) {
+-		next = e->next;
+-		kfree(e);
+-	}
+-}
+-
+-/* Lookup by bdaddr.
+- * Cache must be locked. */
+-static struct inquiry_entry * __inquiry_cache_lookup(struct inquiry_cache *cache, bdaddr_t *bdaddr)
+-{
+-	struct inquiry_entry *e;
+-
+-	DBG("cache %p, %s", cache, batostr(bdaddr));
+-
+-	for (e = cache->list; e; e = e->next)
+-		if (!bacmp(&e->info.bdaddr, bdaddr))
+-			break;
+-
+-	return e;
+-}
+-
+-static void inquiry_cache_update(struct inquiry_cache *cache, inquiry_info *info)
+-{
+-	struct inquiry_entry *e;
+-
+-	DBG("cache %p, %s", cache, batostr(&info->bdaddr));
+-
+-	inquiry_cache_lock(cache);
+-
+-	if (!(e = __inquiry_cache_lookup(cache, &info->bdaddr))) {
+-		/* Entry not in the cache. Add new one. */
+-		if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
+-			goto unlock;
+-		memset(e, 0, sizeof(struct inquiry_entry));
+-		e->next     = cache->list;
+-		cache->list = e;
+-	}
+-
+-	memcpy(&e->info, info, sizeof(inquiry_info));
+-	e->timestamp = jiffies;
+-	cache->timestamp = jiffies;
+-unlock:
+-	inquiry_cache_unlock(cache);
+-}
+-
+-static int inquiry_cache_dump(struct inquiry_cache *cache, int num, __u8 *buf)
+-{
+-	inquiry_info *info = (inquiry_info *) buf;
+-	struct inquiry_entry *e;
+-	int copied = 0;
++/* HCI protocols */
++#define HCI_MAX_PROTO	2
++struct hci_proto *hci_proto[HCI_MAX_PROTO];
+ 
+-	inquiry_cache_lock(cache);
+-
+-	for (e = cache->list; e && copied < num; e = e->next, copied++)
+-		memcpy(info++, &e->info, sizeof(inquiry_info));
++/* HCI notifiers list */
++static struct notifier_block *hci_notifier;
+ 
+-	inquiry_cache_unlock(cache);
+ 
+-	DBG("cache %p, copied %d", cache, copied);
+-	return copied;
+-}
++/* ---- HCI notifications ---- */
+ 
+-/* --------- BaseBand connections --------- */
+-static struct hci_conn *hci_conn_add(struct hci_dev *hdev, __u16 handle, __u8 type, bdaddr_t *dst)
++int hci_register_notifier(struct notifier_block *nb)
+ {
+-	struct hci_conn *conn;
+-
+-	DBG("%s handle %d dst %s", hdev->name, handle, batostr(dst));
+-
+-	if ( conn_hash_lookup(&hdev->conn_hash, handle)) {
+-		ERR("%s handle 0x%x already exists", hdev->name, handle);
+-		return NULL;
+-	}
+-
+-	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
+-		return NULL;
+-	memset(conn, 0, sizeof(struct hci_conn));
+-
+-	bacpy(&conn->dst, dst);
+-	conn->handle = handle;
+-	conn->type   = type;
+-	conn->hdev   = hdev;
+-
+-	skb_queue_head_init(&conn->data_q);
+-
+-	hci_dev_hold(hdev);
+-	conn_hash_add(&hdev->conn_hash, handle, conn);
+-
+-	return conn;
++	return notifier_chain_register(&hci_notifier, nb);
+ }
+ 
+-static int hci_conn_del(struct hci_dev *hdev, struct hci_conn *conn)
++int hci_unregister_notifier(struct notifier_block *nb)
+ {
+-	DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
+-
+-	conn_hash_del(&hdev->conn_hash, conn);
+-	hci_dev_put(hdev);
+-
+-	/* Unacked frames */
+-	hdev->acl_cnt += conn->sent;
+-
+-	skb_queue_purge(&conn->data_q);
+-
+-	kfree(conn);
+-	return 0;
++	return notifier_chain_unregister(&hci_notifier, nb);
+ }
+ 
+-/* Drop all connection on the device */
+-static void hci_conn_hash_flush(struct hci_dev *hdev)
++void hci_notify(struct hci_dev *hdev, int event)
+ {
+-	struct conn_hash *h = &hdev->conn_hash;
+-	struct hci_proto *hp;
+-        struct list_head *p;
+-
+-	DBG("hdev %s", hdev->name);
+-
+-	p = h->list.next;
+-	while (p != &h->list) {
+-		struct hci_conn *c;
+-
+-		c = list_entry(p, struct hci_conn, list);
+-		p = p->next;
+-
+-		if (c->type == ACL_LINK) {
+-			/* ACL link notify L2CAP layer */
+-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
+-				hp->disconn_ind(c, 0x16);
+-		} else {
+-			/* SCO link (no notification) */
+-		}
+-
+-		hci_conn_del(hdev, c);
+-	}
++	notifier_call_chain(&hci_notifier, event, hdev);
+ }
+ 
+-int hci_connect(struct hci_dev *hdev, bdaddr_t *bdaddr)
+-{
+-	struct inquiry_cache *cache = &hdev->inq_cache;
+-	struct inquiry_entry *e;
+-	create_conn_cp cc;
+-	__u16 clock_offset;
+-
+-	DBG("%s bdaddr %s", hdev->name, batostr(bdaddr));
+-
+-	if (!(hdev->flags & HCI_UP))
+-		return -ENODEV;
+-
+-	inquiry_cache_lock_bh(cache);
+-
+-	if (!(e = __inquiry_cache_lookup(cache, bdaddr)) || inquiry_entry_age(e) > INQUIRY_ENTRY_AGE_MAX) {
+-		cc.pscan_rep_mode = 0;
+-		cc.pscan_mode     = 0;
+-		clock_offset      = 0;
+-	} else {
+-		cc.pscan_rep_mode = e->info.pscan_rep_mode;
+-		cc.pscan_mode     = e->info.pscan_mode;
+-		clock_offset      = __le16_to_cpu(e->info.clock_offset) & 0x8000;
+-	}
+-
+-	inquiry_cache_unlock_bh(cache);
+-
+-	bacpy(&cc.bdaddr, bdaddr);
+-	cc.pkt_type	= __cpu_to_le16(hdev->pkt_type);
+-	cc.clock_offset	= __cpu_to_le16(clock_offset);
+-
+-	if (lmp_rswitch_capable(hdev))
+-		cc.role_switch	= 0x01;
+-	else
+-		cc.role_switch	= 0x00;
+-		
+-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, CREATE_CONN_CP_SIZE, &cc);
++/* ---- HCI hotplug support ---- */
+ 
+-	return 0;
+-}
++#ifdef CONFIG_HOTPLUG
+ 
+-int hci_disconnect(struct hci_conn *conn, __u8 reason)
++static int hci_run_hotplug(char *dev, char *action)
+ {
+-	disconnect_cp dc;
+-
+-	DBG("conn %p handle %d", conn, conn->handle);
++	char *argv[3], *envp[5], dstr[20], astr[32];
+ 
+-	dc.handle = __cpu_to_le16(conn->handle);
+-	dc.reason = reason;
+-	hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, DISCONNECT_CP_SIZE, &dc);
++	sprintf(dstr, "DEVICE=%s", dev);
++	sprintf(astr, "ACTION=%s", action);
+ 
+-	return 0;
+-}
++        argv[0] = hotplug_path;
++        argv[1] = "bluetooth";
++        argv[2] = NULL;
+ 
+-/* --------- HCI request handling ------------ */
+-static inline void hci_req_lock(struct hci_dev *hdev)
+-{
+-	down(&hdev->req_lock);
++	envp[0] = "HOME=/";
++	envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
++	envp[2] = dstr;
++	envp[3] = astr;
++	envp[4] = NULL;
++	
++	return call_usermodehelper(argv[0], argv, envp);
+ }
++#else
++#define hci_run_hotplug(A...)
++#endif
+ 
+-static inline void hci_req_unlock(struct hci_dev *hdev)
+-{
+-	up(&hdev->req_lock);
+-}
++/* ---- HCI requests ---- */
+ 
+-static inline void hci_req_complete(struct hci_dev *hdev, int result)
++void hci_req_complete(struct hci_dev *hdev, int result)
+ {
+-	DBG("%s result 0x%2.2x", hdev->name, result);
++	BT_DBG("%s result 0x%2.2x", hdev->name, result);
+ 
+ 	if (hdev->req_status == HCI_REQ_PEND) {
+ 		hdev->req_result = result;
+@@ -344,9 +134,9 @@
+ 	}
+ }
+ 
+-static inline void hci_req_cancel(struct hci_dev *hdev, int err)
++void hci_req_cancel(struct hci_dev *hdev, int err)
+ {
+-	DBG("%s err 0x%2.2x", hdev->name, err);
++	BT_DBG("%s err 0x%2.2x", hdev->name, err);
+ 
+ 	if (hdev->req_status == HCI_REQ_PEND) {
+ 		hdev->req_result = err;
+@@ -356,23 +146,22 @@
+ }
+ 
+ /* Execute request and wait for completion. */
+-static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
+-                         unsigned long opt, __u32 timeout)
++static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), unsigned long opt, __u32 timeout)
+ {
+ 	DECLARE_WAITQUEUE(wait, current);
+ 	int err = 0;
+ 
+-	DBG("%s start", hdev->name);
++	BT_DBG("%s start", hdev->name);
+ 
+ 	hdev->req_status = HCI_REQ_PEND;
+ 
+ 	add_wait_queue(&hdev->req_wait_q, &wait);
+-	current->state = TASK_INTERRUPTIBLE;
++	set_current_state(TASK_INTERRUPTIBLE);
+ 
+ 	req(hdev, opt);
+ 	schedule_timeout(timeout);
+ 
+-	current->state = TASK_RUNNING;
++	set_current_state(TASK_RUNNING);
+ 	remove_wait_queue(&hdev->req_wait_q, &wait);
+ 
+ 	if (signal_pending(current))
+@@ -394,7 +183,7 @@
+ 
+ 	hdev->req_status = hdev->req_result = 0;
+ 
+-	DBG("%s end: err %d", hdev->name, err);
++	BT_DBG("%s end: err %d", hdev->name, err);
+ 
+ 	return err;
+ }
+@@ -412,10 +201,9 @@
+ 	return ret;
+ }
+ 
+-/* --------- HCI requests ---------- */
+ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
+ {
+-	DBG("%s %ld", hdev->name, opt);
++	BT_DBG("%s %ld", hdev->name, opt);
+ 
+ 	/* Reset device */
+ 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_RESET, 0, NULL);
+@@ -423,10 +211,10 @@
+ 
+ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
+ {
+-	set_event_flt_cp ec;
++	set_event_flt_cp ef;
+ 	__u16 param;
+ 
+-	DBG("%s %ld", hdev->name, opt);
++	BT_DBG("%s %ld", hdev->name, opt);
+ 
+ 	/* Mandatory initialization */
+ 
+@@ -436,14 +224,30 @@
+ 	/* Read Buffer Size (ACL mtu, max pkt, etc.) */
+ 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
+ 
++#if 0
++	/* Host buffer size */
++	{
++		host_buffer_size_cp bs;
++		bs.acl_mtu = __cpu_to_le16(HCI_MAX_ACL_SIZE);
++		bs.sco_mtu = HCI_MAX_SCO_SIZE;
++		bs.acl_max_pkt = __cpu_to_le16(0xffff);
++		bs.sco_max_pkt = __cpu_to_le16(0xffff);
++		hci_send_cmd(hdev, OGF_HOST_CTL, OCF_HOST_BUFFER_SIZE,
++				HOST_BUFFER_SIZE_CP_SIZE, &bs);
++	}
++#endif
++
+ 	/* Read BD Address */
+ 	hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BD_ADDR, 0, NULL);
+ 
++        /* Read Voice Setting */
++	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_READ_VOICE_SETTING, 0, NULL);
++
+ 	/* Optional initialization */
+ 
+ 	/* Clear Event Filters */
+-	ec.flt_type  = FLT_CLEAR_ALL;
+-	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ec);
++	ef.flt_type  = FLT_CLEAR_ALL;
++	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_SET_EVENT_FLT, 1, &ef);
+ 
+ 	/* Page timeout ~20 secs */
+ 	param = __cpu_to_le16(0x8000);
+@@ -458,7 +262,7 @@
+ {
+ 	__u8 scan = opt;
+ 
+-	DBG("%s %x", hdev->name, scan);
++	BT_DBG("%s %x", hdev->name, scan);
+ 
+ 	/* Inquiry and Page scans */
+ 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &scan);
+@@ -468,116 +272,272 @@
+ {
+ 	__u8 auth = opt;
+ 
+-	DBG("%s %x", hdev->name, auth);
++	BT_DBG("%s %x", hdev->name, auth);
+ 
+ 	/* Authentication */
+ 	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE, 1, &auth);
+ }
+ 
+-static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
++static void hci_encrypt_req(struct hci_dev *hdev, unsigned long opt)
+ {
+-	struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
+-	inquiry_cp ic;
++	__u8 encrypt = opt;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s %x", hdev->name, encrypt);
+ 
+-	/* Start Inquiry */
+-	memcpy(&ic.lap, &ir->lap, 3);
+-	ic.lenght  = ir->length;
+-	ic.num_rsp = ir->num_rsp;
+-	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
++	/* Authentication */
++	hci_send_cmd(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE, 1, &encrypt);
+ }
+ 
+-/* HCI ioctl helpers */
+-int hci_dev_open(__u16 dev)
++/* Get HCI device by index. 
++ * Device is locked on return. */
++struct hci_dev *hci_dev_get(int index)
+ {
+ 	struct hci_dev *hdev;
+-	int ret = 0;
+-
+-	if (!(hdev = hci_dev_get(dev)))
+-		return -ENODEV;
++	struct list_head *p;
+ 
+-	DBG("%s %p", hdev->name, hdev);
++	BT_DBG("%d", index);
+ 
+-	hci_req_lock(hdev);
++	if (index < 0)
++		return NULL;
+ 
+-	if (hdev->flags & HCI_UP) {
+-		ret = -EALREADY;
+-		goto done;
++	read_lock(&hdev_list_lock);
++	list_for_each(p, &hdev_list) {
++		hdev = list_entry(p, struct hci_dev, list);
++		if (hdev->id == index) {
++			hci_dev_hold(hdev);
++			goto done;
++		}
+ 	}
++	hdev = NULL;
++done:
++	read_unlock(&hdev_list_lock);
++	return hdev;
++}
+ 
+-	if (hdev->open(hdev)) {
+-		ret = -EIO;
+-		goto done;
+-	}
++/* ---- Inquiry support ---- */
++void inquiry_cache_flush(struct hci_dev *hdev)
++{
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	struct inquiry_entry *next  = cache->list, *e;
+ 
+-	if (hdev->flags & HCI_NORMAL) {
+-		atomic_set(&hdev->cmd_cnt, 1);
+-		hdev->flags |= HCI_INIT;
++	BT_DBG("cache %p", cache);
+ 
+-		//__hci_request(hdev, hci_reset_req, 0, HZ);
+-		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
+-       
+-		hdev->flags &= ~HCI_INIT;
++	cache->list = NULL;
++	while ((e = next)) {
++		next = e->next;
++		kfree(e);
+ 	}
++}
+ 
+-	if (!ret) {
+-		hdev->flags |= HCI_UP;
+-		hci_notify(hdev, HCI_DEV_UP);
+-	} else {	
+-		/* Init failed, cleanup */
+-		tasklet_kill(&hdev->rx_task);
+-		tasklet_kill(&hdev->tx_task);
+-		tasklet_kill(&hdev->cmd_task);
++struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
++{
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	struct inquiry_entry *e;
+ 
+-		skb_queue_purge(&hdev->cmd_q);
+-		skb_queue_purge(&hdev->rx_q);
++	BT_DBG("cache %p, %s", cache, batostr(bdaddr));
+ 
+-		if (hdev->flush)
+-			hdev->flush(hdev);
++	for (e = cache->list; e; e = e->next)
++		if (!bacmp(&e->info.bdaddr, bdaddr))
++			break;
++	return e;
++}
+ 
+-		if (hdev->sent_cmd) {
+-			kfree_skb(hdev->sent_cmd);
+-			hdev->sent_cmd = NULL;
+-		}
++void inquiry_cache_update(struct hci_dev *hdev, inquiry_info *info)
++{
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	struct inquiry_entry *e;
+ 
+-		hdev->close(hdev);
+-	}
++	BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr));
+ 
+-done:
+-	hci_req_unlock(hdev);
+-	hci_dev_put(hdev);
++	if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) {
++		/* Entry not in the cache. Add new one. */
++		if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
++			return;
++		memset(e, 0, sizeof(struct inquiry_entry));
++		e->next     = cache->list;
++		cache->list = e;
++	}
+ 
+-	return ret;
++	memcpy(&e->info, info, sizeof(inquiry_info));
++	e->timestamp = jiffies;
++	cache->timestamp = jiffies;
+ }
+ 
+-int hci_dev_close(__u16 dev)
++int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
+ {
+-	struct hci_dev *hdev;
+-
+-	if (!(hdev = hci_dev_get(dev)))
+-		return -ENODEV;
++	struct inquiry_cache *cache = &hdev->inq_cache;
++	inquiry_info *info = (inquiry_info *) buf;
++	struct inquiry_entry *e;
++	int copied = 0;
+ 
+-	DBG("%s %p", hdev->name, hdev);
++	for (e = cache->list; e && copied < num; e = e->next, copied++)
++		memcpy(info++, &e->info, sizeof(inquiry_info));
+ 
+-	hci_req_cancel(hdev, ENODEV);
+-	hci_req_lock(hdev);
++	BT_DBG("cache %p, copied %d", cache, copied);
++	return copied;
++}
+ 
+-	if (!(hdev->flags & HCI_UP))
+-		goto done;
++static void hci_inq_req(struct hci_dev *hdev, unsigned long opt)
++{
++	struct hci_inquiry_req *ir = (struct hci_inquiry_req *) opt;
++	inquiry_cp ic;
+ 
+-	/* Kill RX and TX tasks */
+-	tasklet_kill(&hdev->rx_task);
+-	tasklet_kill(&hdev->tx_task);
++	BT_DBG("%s", hdev->name);
+ 
+-	inquiry_cache_flush(&hdev->inq_cache);
++	if (test_bit(HCI_INQUIRY, &hdev->flags))
++		return;
+ 
+-	hci_conn_hash_flush(hdev);
++	/* Start Inquiry */
++	memcpy(&ic.lap, &ir->lap, 3);
++	ic.length  = ir->length;
++	ic.num_rsp = ir->num_rsp;
++	hci_send_cmd(hdev, OGF_LINK_CTL, OCF_INQUIRY, INQUIRY_CP_SIZE, &ic);
++}
+ 
+-	/* Clear flags */
+-	hdev->flags &= HCI_SOCK;
+-	hdev->flags |= HCI_NORMAL;
++int hci_inquiry(unsigned long arg)
++{
++	struct hci_inquiry_req ir;
++	struct hci_dev *hdev;
++	int err = 0, do_inquiry = 0, max_rsp;
++	long timeo;
++	__u8 *buf, *ptr;
+ 
++	ptr = (void *) arg;
++	if (copy_from_user(&ir, ptr, sizeof(ir)))
++		return -EFAULT;
++
++	if (!(hdev = hci_dev_get(ir.dev_id)))
++		return -ENODEV;
++
++	hci_dev_lock_bh(hdev);
++	if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || 
++					ir.flags & IREQ_CACHE_FLUSH) {
++		inquiry_cache_flush(hdev);
++		do_inquiry = 1;
++	}
++	hci_dev_unlock_bh(hdev);
++
++	timeo = ir.length * 2 * HZ;
++	if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
++		goto done;
++
++	/* for unlimited number of responses we will use buffer with 255 entries */
++	max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
++
++	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
++	 * copy it to the user space.
++	 */
++	if (!(buf = kmalloc(sizeof(inquiry_info) * max_rsp, GFP_KERNEL))) {
++		err = -ENOMEM;
++		goto done;
++	}
++
++	hci_dev_lock_bh(hdev);
++	ir.num_rsp = inquiry_cache_dump(hdev, max_rsp, buf);
++	hci_dev_unlock_bh(hdev);
++
++	BT_DBG("num_rsp %d", ir.num_rsp);
++
++	if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + 
++				(sizeof(inquiry_info) * ir.num_rsp))) {
++		copy_to_user(ptr, &ir, sizeof(ir));
++		ptr += sizeof(ir);
++	        copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
++	} else 
++		err = -EFAULT;
++
++	kfree(buf);
++
++done:
++	hci_dev_put(hdev);
++	return err;
++}
++
++/* ---- HCI ioctl helpers ---- */
++
++int hci_dev_open(__u16 dev)
++{
++	struct hci_dev *hdev;
++	int ret = 0;
++
++	if (!(hdev = hci_dev_get(dev)))
++		return -ENODEV;
++
++	BT_DBG("%s %p", hdev->name, hdev);
++
++	hci_req_lock(hdev);
++
++	if (test_bit(HCI_UP, &hdev->flags)) {
++		ret = -EALREADY;
++		goto done;
++	}
++
++	if (hdev->open(hdev)) {
++		ret = -EIO;
++		goto done;
++	}
++
++	if (!test_bit(HCI_RAW, &hdev->flags)) {
++		atomic_set(&hdev->cmd_cnt, 1);
++		set_bit(HCI_INIT, &hdev->flags);
++
++		//__hci_request(hdev, hci_reset_req, 0, HZ);
++		ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
++       
++		clear_bit(HCI_INIT, &hdev->flags);
++	}
++
++	if (!ret) {
++		set_bit(HCI_UP, &hdev->flags);
++		hci_notify(hdev, HCI_DEV_UP);
++	} else {	
++		/* Init failed, cleanup */
++		tasklet_kill(&hdev->rx_task);
++		tasklet_kill(&hdev->tx_task);
++		tasklet_kill(&hdev->cmd_task);
++
++		skb_queue_purge(&hdev->cmd_q);
++		skb_queue_purge(&hdev->rx_q);
++
++		if (hdev->flush)
++			hdev->flush(hdev);
++
++		if (hdev->sent_cmd) {
++			kfree_skb(hdev->sent_cmd);
++			hdev->sent_cmd = NULL;
++		}
++
++		hdev->close(hdev);
++		hdev->flags = 0;
++	}
++
++done:
++	hci_req_unlock(hdev);
++	hci_dev_put(hdev);
++	return ret;
++}
++
++static int hci_dev_do_close(struct hci_dev *hdev)
++{
++	BT_DBG("%s %p", hdev->name, hdev);
++
++	hci_req_cancel(hdev, ENODEV);
++	hci_req_lock(hdev);
++
++	if (!test_and_clear_bit(HCI_UP, &hdev->flags)) {
++		hci_req_unlock(hdev);
++		return 0;
++	}
++
++	/* Kill RX and TX tasks */
++	tasklet_kill(&hdev->rx_task);
++	tasklet_kill(&hdev->tx_task);
++
++	hci_dev_lock_bh(hdev);
++	inquiry_cache_flush(hdev);
++	hci_conn_hash_flush(hdev);
++	hci_dev_unlock_bh(hdev);
++	
+ 	hci_notify(hdev, HCI_DEV_DOWN);
+ 
+ 	if (hdev->flush)
+@@ -586,9 +546,9 @@
+ 	/* Reset device */
+ 	skb_queue_purge(&hdev->cmd_q);
+ 	atomic_set(&hdev->cmd_cnt, 1);
+-	hdev->flags |= HCI_INIT;
+-	__hci_request(hdev, hci_reset_req, 0, HZ);
+-	hdev->flags &= ~HCI_INIT;
++	set_bit(HCI_INIT, &hdev->flags);
++	__hci_request(hdev, hci_reset_req, 0, HZ/4);
++	clear_bit(HCI_INIT, &hdev->flags);
+ 
+ 	/* Kill cmd task */
+ 	tasklet_kill(&hdev->cmd_task);
+@@ -605,17 +565,28 @@
+ 	}
+ 
+ 	/* After this point our queues are empty
+-	 * and no tasks are scheduled.
+-	 */
++	 * and no tasks are scheduled. */
+ 	hdev->close(hdev);
+ 
+-done:
+-	hci_req_unlock(hdev);
+-	hci_dev_put(hdev);
++	/* Clear flags */
++	hdev->flags = 0;
+ 
++	hci_req_unlock(hdev);
+ 	return 0;
+ }
+ 
++int hci_dev_close(__u16 dev)
++{
++	struct hci_dev *hdev;
++	int err;
++	
++	if (!(hdev = hci_dev_get(dev)))
++		return -ENODEV;
++	err = hci_dev_do_close(hdev);
++	hci_dev_put(hdev);
++	return err;
++}
++
+ int hci_dev_reset(__u16 dev)
+ {
+ 	struct hci_dev *hdev;
+@@ -627,16 +598,17 @@
+ 	hci_req_lock(hdev);
+ 	tasklet_disable(&hdev->tx_task);
+ 
+-	if (!(hdev->flags & HCI_UP))
++	if (!test_bit(HCI_UP, &hdev->flags))
+ 		goto done;
+ 
+ 	/* Drop queues */
+ 	skb_queue_purge(&hdev->rx_q);
+ 	skb_queue_purge(&hdev->cmd_q);
+ 
+-	inquiry_cache_flush(&hdev->inq_cache);
+-
++	hci_dev_lock_bh(hdev);
++	inquiry_cache_flush(hdev);
+ 	hci_conn_hash_flush(hdev);
++	hci_dev_unlock_bh(hdev);
+ 
+ 	if (hdev->flush)
+ 		hdev->flush(hdev);
+@@ -650,7 +622,6 @@
+ 	tasklet_enable(&hdev->tx_task);
+ 	hci_req_unlock(hdev);
+ 	hci_dev_put(hdev);
+-
+ 	return ret;
+ }
+ 
+@@ -669,30 +640,11 @@
+ 	return ret;
+ }
+ 
+-int hci_dev_setauth(unsigned long arg)
+-{
+-	struct hci_dev *hdev;
+-	struct hci_dev_req dr;
+-	int ret = 0;
+-
+-	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+-		return -EFAULT;
+-
+-	if (!(hdev = hci_dev_get(dr.dev_id)))
+-		return -ENODEV;
+-
+-	ret = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+-
+-	hci_dev_put(hdev);
+-
+-	return ret;
+-}
+-
+-int hci_dev_setscan(unsigned long arg)
++int hci_dev_cmd(unsigned int cmd, unsigned long arg)
+ {
+ 	struct hci_dev *hdev;
+ 	struct hci_dev_req dr;
+-	int ret = 0;
++	int err = 0;
+ 
+ 	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+ 		return -EFAULT;
+@@ -700,48 +652,78 @@
+ 	if (!(hdev = hci_dev_get(dr.dev_id)))
+ 		return -ENODEV;
+ 
+-	ret = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+-
+-	hci_dev_put(hdev);
++	switch (cmd) {
++	case HCISETAUTH:
++		err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
++		break;
+ 
+-	return ret;
+-}
++	case HCISETENCRYPT:
++		if (!lmp_encrypt_capable(hdev)) {
++			err = -EOPNOTSUPP;
++			break;
++		}
+ 
+-int hci_dev_setptype(unsigned long arg)
+-{
+-	struct hci_dev *hdev;
+-	struct hci_dev_req dr;
+-	int ret = 0;
++		if (!test_bit(HCI_AUTH, &hdev->flags)) {
++			/* Auth must be enabled first */
++			err = hci_request(hdev, hci_auth_req,
++					dr.dev_opt, HCI_INIT_TIMEOUT);
++			if (err)
++				break;
++		}
++			
++		err = hci_request(hdev, hci_encrypt_req,
++					dr.dev_opt, HCI_INIT_TIMEOUT);
++		break;
++	
++	case HCISETSCAN:
++		err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
++		break;
++	
++	case HCISETPTYPE:
++		hdev->pkt_type = (__u16) dr.dev_opt;
++		break;
++		
++	case HCISETLINKPOL:
++		hdev->link_policy = (__u16) dr.dev_opt;
++		break;
+ 
+-	if (copy_from_user(&dr, (void *) arg, sizeof(dr)))
+-		return -EFAULT;
++	case HCISETLINKMODE:
++		hdev->link_mode = ((__u16) dr.dev_opt) & (HCI_LM_MASTER | HCI_LM_ACCEPT);
++		break;
+ 
+-	if (!(hdev = hci_dev_get(dr.dev_id)))
+-		return -ENODEV;
++	case HCISETACLMTU:
++		hdev->acl_mtu  = *((__u16 *)&dr.dev_opt + 1);
++		hdev->acl_pkts = *((__u16 *)&dr.dev_opt + 0);
++		break;
+ 
+-	hdev->pkt_type = (__u16) dr.dev_opt;
++	case HCISETSCOMTU:
++		hdev->sco_mtu  = *((__u16 *)&dr.dev_opt + 1);
++		hdev->sco_pkts = *((__u16 *)&dr.dev_opt + 0);
++		break;
+ 
++	default:
++		err = -EINVAL;
++		break;
++	}	
+ 	hci_dev_put(hdev);
+-
+-	return ret;
++	return err;
+ }
+ 
+-int hci_dev_list(unsigned long arg)
++int hci_get_dev_list(unsigned long arg)
+ {
+ 	struct hci_dev_list_req *dl;
+ 	struct hci_dev_req *dr;
+-	struct hci_dev *hdev;
+-	int i, n, size;
++	struct list_head *p;
++	int n = 0, size;
+ 	__u16 dev_num;
+ 
+ 	if (get_user(dev_num, (__u16 *) arg))
+ 		return -EFAULT;
+ 
+-	/* Avoid long loop, overflow */
+-	if (dev_num > 2048)
++	if (!dev_num)
+ 		return -EINVAL;
+ 	
+-	size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16);
++	size = dev_num * sizeof(*dr) + sizeof(*dl);
+ 
+ 	if (verify_area(VERIFY_WRITE, (void *) arg, size))
+ 		return -EFAULT;
+@@ -750,25 +732,27 @@
+ 		return -ENOMEM;
+ 	dr = dl->dev_req;
+ 
+-	spin_lock_bh(&hdev_list_lock);
+-	for (i = 0, n = 0; i < HCI_MAX_DEV && n < dev_num; i++) {
+-		if ((hdev = hdev_list[i])) {
+-			(dr + n)->dev_id  = hdev->id;
+-			(dr + n)->dev_opt = hdev->flags;
+-			n++;
+-		}
++	read_lock_bh(&hdev_list_lock);
++	list_for_each(p, &hdev_list) {
++		struct hci_dev *hdev;
++		hdev = list_entry(p, struct hci_dev, list);
++		(dr + n)->dev_id  = hdev->id;
++		(dr + n)->dev_opt = hdev->flags;
++		if (++n >= dev_num)
++			break;
+ 	}
+-	spin_unlock_bh(&hdev_list_lock);
++	read_unlock_bh(&hdev_list_lock);
+ 
+ 	dl->dev_num = n;
+-	size = n * sizeof(struct hci_dev_req) + sizeof(__u16);
++	size = n * sizeof(*dr) + sizeof(*dl);
+ 
+ 	copy_to_user((void *) arg, dl, size);
++	kfree(dl);
+ 
+ 	return 0;
+ }
+ 
+-int hci_dev_info(unsigned long arg)
++int hci_get_dev_info(unsigned long arg)
+ {
+ 	struct hci_dev *hdev;
+ 	struct hci_dev_info di;
+@@ -786,9 +770,11 @@
+ 	di.flags    = hdev->flags;
+ 	di.pkt_type = hdev->pkt_type;
+ 	di.acl_mtu  = hdev->acl_mtu;
+-	di.acl_max  = hdev->acl_max;
++	di.acl_pkts = hdev->acl_pkts;
+ 	di.sco_mtu  = hdev->sco_mtu;
+-	di.sco_max  = hdev->sco_max;
++	di.sco_pkts = hdev->sco_pkts;
++	di.link_policy = hdev->link_policy;
++	di.link_mode   = hdev->link_mode;
+ 
+ 	memcpy(&di.stat, &hdev->stat, sizeof(di.stat));
+ 	memcpy(&di.features, &hdev->features, sizeof(di.features));
+@@ -801,258 +787,168 @@
+ 	return err;
+ }
+ 
+-__u32 hci_dev_setmode(struct hci_dev *hdev, __u32 mode)
+-{
+-	__u32 omode = hdev->flags & HCI_MODE_MASK;
+-
+-	hdev->flags &= ~HCI_MODE_MASK;
+-	hdev->flags |= (mode & HCI_MODE_MASK);
+ 
+-	return omode;
+-}
++/* ---- Interface to HCI drivers ---- */
+ 
+-__u32 hci_dev_getmode(struct hci_dev *hdev)
++/* Register HCI device */
++int hci_register_dev(struct hci_dev *hdev)
+ {
+-	return hdev->flags & HCI_MODE_MASK;
+-}
++	struct list_head *head = &hdev_list, *p;
++	int id = 0;
+ 
+-int hci_conn_list(unsigned long arg)
+-{
+-	struct hci_conn_list_req req, *cl;
+-	struct hci_conn_info *ci;
+-	struct hci_dev *hdev;
+-	struct list_head *p;
+-	int n = 0, size;
++	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+ 
+-	if (copy_from_user(&req, (void *) arg, sizeof(req)))
+-		return -EFAULT;
++	if (!hdev->open || !hdev->close || !hdev->destruct)
++		return -EINVAL;
+ 
+-	if (!(hdev = hci_dev_get(req.dev_id)))
+-		return -ENODEV;
++	write_lock_bh(&hdev_list_lock);
+ 
+-	/* Set a limit to avoid overlong loops, and also numeric overflow - AC */
+-	if(req.conn_num < 2048)
+-		return -EINVAL;
++	/* Find first available device id */
++	list_for_each(p, &hdev_list) {
++	       	if (list_entry(p, struct hci_dev, list)->id != id)
++			break;
++		head = p; id++;
++	}
+ 	
+-	size = req.conn_num * sizeof(struct hci_conn_info) + sizeof(req);
+-
+-	if (!(cl = kmalloc(size, GFP_KERNEL)))
+-		return -ENOMEM;
+-	ci = cl->conn_info;
++	sprintf(hdev->name, "hci%d", id);
++	hdev->id = id;
++	list_add(&hdev->list, head);
+ 
+-	local_bh_disable();
+-	conn_hash_lock(&hdev->conn_hash);
+-	list_for_each(p, &hdev->conn_hash.list) {
+-		register struct hci_conn *c;
+-		c = list_entry(p, struct hci_conn, list);
++	atomic_set(&hdev->refcnt, 1);
++	spin_lock_init(&hdev->lock);
++			
++	hdev->flags = 0;
++	hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
++	hdev->link_mode = (HCI_LM_ACCEPT);
+ 
+-		(ci + n)->handle = c->handle;
+-		bacpy(&(ci + n)->bdaddr, &c->dst);
+-		n++;
+-	}
+-	conn_hash_unlock(&hdev->conn_hash);
+-	local_bh_enable();
+-
+-	cl->dev_id = hdev->id;
+-	cl->conn_num = n;
+-	size = n * sizeof(struct hci_conn_info) + sizeof(req);
++	tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
++	tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
++	tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
+ 
+-	hci_dev_put(hdev);
++	skb_queue_head_init(&hdev->rx_q);
++	skb_queue_head_init(&hdev->cmd_q);
++	skb_queue_head_init(&hdev->raw_q);
+ 
+-	if(copy_to_user((void *) arg, cl, size))
+-		return -EFAULT;
+-	return 0;
+-}
++	init_waitqueue_head(&hdev->req_wait_q);
++	init_MUTEX(&hdev->req_lock);
+ 
+-int hci_inquiry(unsigned long arg)
+-{
+-	struct inquiry_cache *cache;
+-	struct hci_inquiry_req ir;
+-	struct hci_dev *hdev;
+-	int err = 0, do_inquiry = 0;
+-	long timeo;
+-	__u8 *buf, *ptr;
++	inquiry_cache_init(hdev);
+ 
+-	ptr = (void *) arg;
+-	if (copy_from_user(&ir, ptr, sizeof(ir)))
+-		return -EFAULT;
++	conn_hash_init(hdev);
+ 
+-	if (!(hdev = hci_dev_get(ir.dev_id)))
+-		return -ENODEV;
++	memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
+ 
+-	cache = &hdev->inq_cache;
++	atomic_set(&hdev->promisc, 0);
+ 
+-	inquiry_cache_lock(cache);
+-	if (inquiry_cache_age(cache) > INQUIRY_CACHE_AGE_MAX || ir.flags & IREQ_CACHE_FLUSH) {
+-		inquiry_cache_flush(cache);
+-		do_inquiry = 1;
+-	}
+-	inquiry_cache_unlock(cache);
++	MOD_INC_USE_COUNT;
+ 
+-	/* Limit inquiry time, also avoid overflows */
++	write_unlock_bh(&hdev_list_lock);
+ 
+-	if(ir.length > 2048 || ir.num_rsp > 2048)
+-	{
+-		err = -EINVAL;
+-		goto done;
+-	}
++	hci_notify(hdev, HCI_DEV_REG);
++	hci_run_hotplug(hdev->name, "register");
+ 
+-	timeo = ir.length * 2 * HZ;
+-	if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
+-		goto done;
++	return id;
++}
+ 
+-	/* cache_dump can't sleep. Therefore we allocate temp buffer and then
+-	 * copy it to the user space.
+-	 */
+-	if (!(buf = kmalloc(sizeof(inquiry_info) * ir.num_rsp, GFP_KERNEL))) {
+-		err = -ENOMEM;
+-		goto done;
+-	}
+-	ir.num_rsp = inquiry_cache_dump(cache, ir.num_rsp, buf);
++/* Unregister HCI device */
++int hci_unregister_dev(struct hci_dev *hdev)
++{
++	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+ 
+-	DBG("num_rsp %d", ir.num_rsp);
++	write_lock_bh(&hdev_list_lock);
++	list_del(&hdev->list);
++	write_unlock_bh(&hdev_list_lock);
+ 
+-	if (!verify_area(VERIFY_WRITE, ptr, sizeof(ir) + (sizeof(inquiry_info) * ir.num_rsp))) {
+-		copy_to_user(ptr, &ir, sizeof(ir));
+-		ptr += sizeof(ir);
+-	        copy_to_user(ptr, buf, sizeof(inquiry_info) * ir.num_rsp);
+-	} else 
+-		err = -EFAULT;
++	hci_dev_do_close(hdev);
+ 
+-	kfree(buf);
++	hci_notify(hdev, HCI_DEV_UNREG);
++	hci_run_hotplug(hdev->name, "unregister");
+ 
+-done:
+ 	hci_dev_put(hdev);
+ 
+-	return err;
++	MOD_DEC_USE_COUNT;
++	return 0;
+ }
+ 
+-/* Interface to HCI drivers */
+-
+-/* Register HCI device */
+-int hci_register_dev(struct hci_dev *hdev)
++/* Suspend HCI device */
++int hci_suspend_dev(struct hci_dev *hdev)
+ {
+-	int i;
+-
+-	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+-
+-	/* Find free slot */
+-	spin_lock_bh(&hdev_list_lock);
+-	for (i = 0; i < HCI_MAX_DEV; i++) {
+-		if (!hdev_list[i]) {
+-			hdev_list[i] = hdev;
++	hci_notify(hdev, HCI_DEV_SUSPEND);
++	hci_run_hotplug(hdev->name, "suspend");
++	return 0;
++}
+ 
+-			sprintf(hdev->name, "hci%d", i);
+-			atomic_set(&hdev->refcnt, 0);
+-			hdev->id    = i;
+-			hdev->flags = HCI_NORMAL;
++/* Resume HCI device */
++int hci_resume_dev(struct hci_dev *hdev)
++{
++	hci_notify(hdev, HCI_DEV_RESUME);
++	hci_run_hotplug(hdev->name, "resume");
++	return 0;
++}       
+ 
+-			hdev->pkt_type = (HCI_DM1 | HCI_DH1);
+-
+-			tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
+-			tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
+-			tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
+-
+-			skb_queue_head_init(&hdev->rx_q);
+-			skb_queue_head_init(&hdev->cmd_q);
+-			skb_queue_head_init(&hdev->raw_q);
+-
+-			init_waitqueue_head(&hdev->req_wait_q);
+-			init_MUTEX(&hdev->req_lock);
+-
+-			inquiry_cache_init(&hdev->inq_cache);
+-
+-			conn_hash_init(&hdev->conn_hash);
+-
+-			memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
+-
+-			hci_notify(hdev, HCI_DEV_REG);
+-
+-			MOD_INC_USE_COUNT;
+-			break;
+-		}
+-	}
+-	spin_unlock_bh(&hdev_list_lock);
+-
+-	return (i == HCI_MAX_DEV) ? -1 : i;
+-}
+-
+-/* Unregister HCI device */
+-int hci_unregister_dev(struct hci_dev *hdev)
++/* Receive frame from HCI drivers */
++int hci_recv_frame(struct sk_buff *skb)
+ {
+-	int i;
+-
+-	DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
+-
+-	if (hdev->flags & HCI_UP)
+-		hci_dev_close(hdev->id);
++	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+ 
+-	/* Find device slot */
+-	spin_lock(&hdev_list_lock);
+-	for (i = 0; i < HCI_MAX_DEV; i++) {
+-		if (hdev_list[i] == hdev) {
+-			hdev_list[i] = NULL;
+-			MOD_DEC_USE_COUNT;
+-			break;
+-		}
++	if (!hdev || (!test_bit(HCI_UP, &hdev->flags) && 
++				!test_bit(HCI_INIT, &hdev->flags)) ) {
++		kfree_skb(skb);
++		return -1;
+ 	}
+-	spin_unlock(&hdev_list_lock);
+-
+-	hci_notify(hdev, HCI_DEV_UNREG);
+ 
+-	/* Sleep while device is in use */
+-	while (atomic_read(&hdev->refcnt)) {
+-		int sleep_cnt = 100;
++	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+ 
+-		DBG("%s sleeping on lock %d", hdev->name, atomic_read(&hdev->refcnt));
++	/* Incomming skb */
++	bluez_cb(skb)->incomming = 1;
+ 
+-		sleep_on_timeout(&hdev->req_wait_q, HZ*10);
+-		if (!(--sleep_cnt))
+-			break;
+-	}
++	/* Time stamp */
++	do_gettimeofday(&skb->stamp);
+ 
++	/* Queue frame for rx task */
++	skb_queue_tail(&hdev->rx_q, skb);
++	hci_sched_rx(hdev);
+ 	return 0;
+ }
+ 
+-/* Interface to upper protocols */
++/* ---- Interface to upper protocols ---- */
+ 
+ /* Register/Unregister protocols.
+- * hci_task_lock is used to ensure that no tasks are running.
+- */
+-int hci_register_proto(struct hci_proto *hproto)
++ * hci_task_lock is used to ensure that no tasks are running. */
++int hci_register_proto(struct hci_proto *hp)
+ {
+ 	int err = 0;
+ 
+-	DBG("%p name %s", hproto, hproto->name);
++	BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
+ 
+-	if (hproto->id >= HCI_MAX_PROTO)
++	if (hp->id >= HCI_MAX_PROTO)
+ 		return -EINVAL;
+ 
+ 	write_lock_bh(&hci_task_lock);
+ 
+-	if (!hproto_list[hproto->id])
+-		hproto_list[hproto->id] = hproto;
++	if (!hci_proto[hp->id])
++		hci_proto[hp->id] = hp;
+ 	else
+-		err = -1;
++		err = -EEXIST;
+ 
+ 	write_unlock_bh(&hci_task_lock);
+ 
+ 	return err;
+ }
+ 
+-int hci_unregister_proto(struct hci_proto *hproto)
++int hci_unregister_proto(struct hci_proto *hp)
+ {
+ 	int err = 0;
+ 
+-	DBG("%p name %s", hproto, hproto->name);
++	BT_DBG("%p name %s id %d", hp, hp->name, hp->id);
+ 
+-	if (hproto->id > HCI_MAX_PROTO)
++	if (hp->id >= HCI_MAX_PROTO)
+ 		return -EINVAL;
+ 
+ 	write_lock_bh(&hci_task_lock);
+ 
+-	if (hproto_list[hproto->id])
+-		hproto_list[hproto->id] = NULL;
++	if (hci_proto[hp->id])
++		hci_proto[hp->id] = NULL;
+ 	else
+ 		err = -ENOENT;
+ 
+@@ -1070,10 +966,14 @@
+ 		return -ENODEV;
+ 	}
+ 
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
++	BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
++
++	if (atomic_read(&hdev->promisc)) {
++		/* Time stamp */
++	        do_gettimeofday(&skb->stamp);
+ 
+-	if (hdev->flags & HCI_SOCK)
+ 		hci_send_to_sock(hdev, skb);
++	}
+ 
+ 	/* Get rid of skb owner, prior to sending to the driver. */
+ 	skb_orphan(skb);
+@@ -1081,128 +981,6 @@
+ 	return hdev->send(skb);
+ }
+ 
+-/* Connection scheduler */
+-static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+-{
+-	struct conn_hash *h = &hdev->conn_hash;
+-	struct hci_conn *conn = NULL;
+-	int num = 0, min = 0xffff;
+-        struct list_head *p;
+-
+-	conn_hash_lock(h);
+-	list_for_each(p, &h->list) {
+-		register struct hci_conn *c;
+-
+-		c = list_entry(p, struct hci_conn, list);
+-
+-		if (c->type != type || skb_queue_empty(&c->data_q))
+-			continue;
+-		num++;
+-
+-		if (c->sent < min) {
+-			min  = c->sent;
+-			conn = c;
+-		}
+-	}
+-	conn_hash_unlock(h);
+-
+-	if (conn) {
+-		int q = hdev->acl_cnt / num;
+-		*quote = q ? q : 1;
+-	} else
+-		*quote = 0;
+-
+-	DBG("conn %p quote %d", conn, *quote);
+-
+-	return conn;
+-}
+-
+-static inline void hci_sched_acl(struct hci_dev *hdev)
+-{
+-	struct hci_conn *conn;
+-	struct sk_buff *skb;
+-	int quote;
+-
+-	DBG("%s", hdev->name);
+-
+-	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
+-		while (quote && (skb = skb_dequeue(&conn->data_q))) {
+-			DBG("skb %p len %d", skb, skb->len);
+-
+-			hci_send_frame(skb);
+-
+-			conn->sent++;
+-			hdev->acl_cnt--;
+-			quote--;
+-		}
+-	}
+-}
+-
+-/* Schedule SCO */
+-static inline void hci_sched_sco(struct hci_dev *hdev)
+-{
+-	/* FIXME: For now we queue SCO packets to the raw queue 
+-
+-		while (hdev->sco_cnt && (skb = skb_dequeue(&conn->data_q))) {
+-			hci_send_frame(skb);
+-			conn->sco_sent++;
+-			hdev->sco_cnt--;
+-		}
+-	*/
+-}
+-
+-/* Get data from the previously sent command */
+-static void * hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
+-{
+-	hci_command_hdr *hc;
+-
+-	if (!hdev->sent_cmd)
+-		return NULL;
+-
+-	hc = (void *) hdev->sent_cmd->data;
+-
+-	if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
+-		return NULL;
+-
+-	DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
+-
+-	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
+-}
+-
+-/* Send raw HCI frame */
+-int hci_send_raw(struct sk_buff *skb)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+-
+-	if (!hdev) {
+-		kfree_skb(skb);
+-		return -ENODEV;
+-	}
+-
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+-
+-	if (hdev->flags & HCI_NORMAL) {
+-		/* Queue frame according it's type */
+-		switch (skb->pkt_type) {
+-		case HCI_COMMAND_PKT:
+-			skb_queue_tail(&hdev->cmd_q, skb);
+-			hci_sched_cmd(hdev);
+-			return 0;
+-
+-		case HCI_ACLDATA_PKT:
+-		case HCI_SCODATA_PKT:
+-			/* FIXME:
+-		 	 * Check header here and queue to apropriate connection.
+-		 	 */
+-			break;
+-		}
+-	}
+-
+-	skb_queue_tail(&hdev->raw_q, skb);
+-	hci_sched_tx(hdev);
+-	return 0;
+-}
+-
+ /* Send HCI command */
+ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param)
+ {
+@@ -1210,10 +988,10 @@
+ 	hci_command_hdr *hc;
+ 	struct sk_buff *skb;
+ 
+-	DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
++	BT_DBG("%s ogf 0x%x ocf 0x%x plen %d", hdev->name, ogf, ocf, plen);
+ 
+ 	if (!(skb = bluez_skb_alloc(len, GFP_ATOMIC))) {
+-		ERR("%s Can't allocate memory for HCI command", hdev->name);
++		BT_ERR("%s Can't allocate memory for HCI command", hdev->name);
+ 		return -ENOMEM;
+ 	}
+ 	
+@@ -1224,7 +1002,7 @@
+ 	if (plen)
+ 		memcpy(skb_put(skb, plen), param, plen);
+ 
+-	DBG("skb len %d", skb->len);
++	BT_DBG("skb len %d", skb->len);
+ 
+ 	skb->pkt_type = HCI_COMMAND_PKT;
+ 	skb->dev = (void *) hdev;
+@@ -1234,10 +1012,28 @@
+ 	return 0;
+ }
+ 
++/* Get data from the previously sent command */
++void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
++{
++	hci_command_hdr *hc;
++
++	if (!hdev->sent_cmd)
++		return NULL;
++
++	hc = (void *) hdev->sent_cmd->data;
++
++	if (hc->opcode != __cpu_to_le16(cmd_opcode_pack(ogf, ocf)))
++		return NULL;
++
++	BT_DBG("%s ogf 0x%x ocf 0x%x", hdev->name, ogf, ocf);
++
++	return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
++}
++
+ /* Send ACL data */
+ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
+ {
+-	int len = skb->len;	
++	int len = skb->len;
+ 	hci_acl_hdr *ah;
+ 
+ 	ah = (hci_acl_hdr *) skb_push(skb, HCI_ACL_HDR_SIZE);
+@@ -1252,7 +1048,7 @@
+ 	struct hci_dev *hdev = conn->hdev;
+ 	struct sk_buff *list;
+ 
+-	DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
++	BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
+ 
+ 	skb->dev = (void *) hdev;
+ 	skb->pkt_type = HCI_ACLDATA_PKT;
+@@ -1260,12 +1056,12 @@
+ 
+ 	if (!(list = skb_shinfo(skb)->frag_list)) {
+ 		/* Non fragmented */
+-		DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
++		BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
+ 		
+ 		skb_queue_tail(&conn->data_q, skb);
+ 	} else {
+ 		/* Fragmented */
+-		DBG("%s frag %p len %d", hdev->name, skb, skb->len);
++		BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
+ 
+ 		skb_shinfo(skb)->frag_list = NULL;
+ 
+@@ -1280,7 +1076,7 @@
+ 			skb->pkt_type = HCI_ACLDATA_PKT;
+ 			hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
+ 		
+-			DBG("%s frag %p len %d", hdev->name, skb, skb->len);
++			BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
+ 
+ 			__skb_queue_tail(&conn->data_q, skb);
+ 		} while (list);
+@@ -1298,7 +1094,7 @@
+ 	struct hci_dev *hdev = conn->hdev;
+ 	hci_sco_hdr hs;
+ 
+-	DBG("%s len %d", hdev->name, skb->len);
++	BT_DBG("%s len %d", hdev->name, skb->len);
+ 
+ 	if (skb->len > hdev->sco_mtu) {
+ 		kfree_skb(skb);
+@@ -1315,544 +1111,136 @@
+ 	skb->pkt_type = HCI_SCODATA_PKT;
+ 	skb_queue_tail(&conn->data_q, skb);
+ 	hci_sched_tx(hdev);
+-
+ 	return 0;
+ }
+ 
+-/* Handle HCI Event packets */
+-
+-/* Command Complete OGF LINK_CTL  */
+-static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Complete OGF LINK_POLICY  */
+-static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Complete OGF HOST_CTL  */
+-static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
+-{
+-	__u8 status, param;
+-	void *sent;
+-
+-
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	case OCF_RESET:
+-		status = *((__u8 *) skb->data);
+-
+-		hci_req_complete(hdev, status);
+-		break;
+-
+-	case OCF_SET_EVENT_FLT:
+-		status = *((__u8 *) skb->data);
+-
+-		if (status) {
+-			DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
+-		} else {
+-			DBG("%s SET_EVENT_FLT succeseful", hdev->name);
+-		}
+-		break;
+-
+-	case OCF_WRITE_AUTH_ENABLE:
+-		if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE)))
+-			break;
+-
+-		status = *((__u8 *) skb->data);
+-		param  = *((__u8 *) sent);
++/* ---- HCI TX task (outgoing data) ---- */
+ 
+-		if (!status) {
+-			if (param == AUTH_ENABLED)
+-				hdev->flags |= HCI_AUTH;
+-			else
+-				hdev->flags &= ~HCI_AUTH;
+-		}
+-		hci_req_complete(hdev, status);
+-		break;
+-
+-	case OCF_WRITE_CA_TIMEOUT:
+-		status = *((__u8 *) skb->data);
+-
+-		if (status) {
+-			DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
+-		} else {
+-			DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
+-		}
+-		break;
+-
+-	case OCF_WRITE_PG_TIMEOUT:
+-		status = *((__u8 *) skb->data);
+-
+-		if (status) {
+-			DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
+-		} else {
+-			DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
+-		}
+-		break;
+-
+-	case OCF_WRITE_SCAN_ENABLE:
+-		if (!(sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE)))
+-			break;
+-		status = *((__u8 *) skb->data);
+-		param  = *((__u8 *) sent);
+-
+-		DBG("param 0x%x", param);
+-
+-		if (!status) {
+-			switch (param) {
+-			case IS_ENA_PS_ENA:
+-				hdev->flags |=  HCI_PSCAN | HCI_ISCAN;
+-				break;
+-
+-			case IS_ENA_PS_DIS:
+-				hdev->flags &= ~HCI_PSCAN;
+-				hdev->flags |=  HCI_ISCAN;
+-				break;
+-
+-			case IS_DIS_PS_ENA:
+-				hdev->flags &= ~HCI_ISCAN;
+-				hdev->flags |=  HCI_PSCAN;
+-				break;
+-
+-			default:
+-				hdev->flags &= ~(HCI_ISCAN | HCI_PSCAN);
+-				break;
+-			};
+-		}
+-		hci_req_complete(hdev, status);
+-		break;
+-
+-	default:
+-		DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Complete OGF INFO_PARAM  */
+-static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++/* HCI Connection scheduler */
++static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
+ {
+-	read_local_features_rp *lf;
+-	read_buffer_size_rp *bs;
+-	read_bd_addr_rp *ba;
+-
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	case OCF_READ_LOCAL_FEATURES:
+-		lf = (read_local_features_rp *) skb->data;
+-
+-		if (lf->status) {
+-			DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
+-			break;
+-		}
+-
+-		memcpy(hdev->features, lf->features, sizeof(hdev->features));
+-
+-		/* Adjust default settings according to features 
+-		 * supported by device. */
+-		if (hdev->features[0] & LMP_3SLOT)
+-			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
+-
+-		if (hdev->features[0] & LMP_5SLOT)
+-			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
+-
+-		DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
+-
+-		break;
+-
+-	case OCF_READ_BUFFER_SIZE:
+-		bs = (read_buffer_size_rp *) skb->data;
+-
+-		if (bs->status) {
+-			DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
+-			break;
+-		}
+-
+-		hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu);
+-		hdev->sco_mtu = bs->sco_mtu;
+-		hdev->acl_max = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
+-		hdev->sco_max = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
+-
+-		DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
+-		    hdev->acl_mtu, hdev->sco_mtu, hdev->acl_max, hdev->sco_max);
++	struct conn_hash *h = &hdev->conn_hash;
++	struct hci_conn  *conn = NULL;
++	int num = 0, min = ~0;
++        struct list_head *p;
+ 
+-		break;
++	/* We don't have to lock device here. Connections are always 
++	 * added and removed with TX task disabled. */
++	list_for_each(p, &h->list) {
++		struct hci_conn *c;
++		c = list_entry(p, struct hci_conn, list);
+ 
+-	case OCF_READ_BD_ADDR:
+-		ba = (read_bd_addr_rp *) skb->data;
++		if (c->type != type || c->state != BT_CONNECTED
++				|| skb_queue_empty(&c->data_q))
++			continue;
++		num++;
+ 
+-		if (!ba->status) {
+-			bacpy(&hdev->bdaddr, &ba->bdaddr);
+-		} else {
+-			DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
++		if (c->sent < min) {
++			min  = c->sent;
++			conn = c;
+ 		}
++	}
+ 
+-		hci_req_complete(hdev, ba->status);
+-		break;
++	if (conn) {
++		int cnt = (type == ACL_LINK ? hdev->acl_cnt : hdev->sco_cnt);
++		int q = cnt / num;
++		*quote = q ? q : 1;
++	} else
++		*quote = 0;
+ 
+-	default:
+-		DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+-		break;
+-	};
++	BT_DBG("conn %p quote %d", conn, *quote);
++	return conn;
+ }
+ 
+-/* Command Status OGF LINK_CTL  */
+-static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
++static inline void hci_acl_tx_to(struct hci_dev *hdev)
+ {
+-	struct hci_proto * hp;
+-
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	case OCF_CREATE_CONN:
+-		if (status) {
+-			create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
+-
+-			if (!cc)
+-				break;
+-
+-			DBG("%s Create connection error: status 0x%x %s", hdev->name,
+-			    status, batostr(&cc->bdaddr));
++	struct conn_hash *h = &hdev->conn_hash;
++	struct list_head *p;
++	struct hci_conn  *c;
+ 
+-			/* Notify upper protocols */
+-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm) {
+-				tasklet_disable(&hdev->tx_task);
+-				hp->connect_cfm(hdev, &cc->bdaddr, status, NULL);
+-				tasklet_enable(&hdev->tx_task);
+-			}
+-		}
+-		break;
++	BT_ERR("%s ACL tx timeout", hdev->name);
+ 
+-	case OCF_INQUIRY:
+-		if (status) {
+-			DBG("%s Inquiry error: status 0x%x", hdev->name, status);
+-			hci_req_complete(hdev, status);
++	/* Kill stalled connections */
++	list_for_each(p, &h->list) {
++		c = list_entry(p, struct hci_conn, list);
++		if (c->type == ACL_LINK && c->sent) {
++			BT_ERR("%s killing stalled ACL connection %s",
++				hdev->name, batostr(&c->dst));
++			hci_acl_disconn(c, 0x13);
+ 		}
+-		break;
+-
+-	default:
+-		DBG("%s Command status: ogf LINK_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Status OGF LINK_POLICY */
+-static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Status OGF HOST_CTL */
+-static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
+-{
+-	DBG("%s ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Command Status OGF INFO_PARAM  */
+-static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
+-{
+-	DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
+-
+-	switch (ocf) {
+-	default:
+-		DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
+-		break;
+-	};
+-}
+-
+-/* Inquiry Complete */
+-static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+-{
+-	__u8 status = *((__u8 *) skb->data);
+-
+-	DBG("%s status %d", hdev->name, status);
+-
+-	hci_req_complete(hdev, status);
++	}
+ }
+ 
+-/* Inquiry Result */
+-static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
++static inline void hci_sched_acl(struct hci_dev *hdev)
+ {
+-	inquiry_info *info = (inquiry_info *) (skb->data + 1);
+-	int num_rsp = *((__u8 *) skb->data);
+-
+-	DBG("%s num_rsp %d", hdev->name, num_rsp);
++	struct hci_conn *conn;
++	struct sk_buff *skb;
++	int quote;
+ 
+-	for (; num_rsp; num_rsp--)
+-		inquiry_cache_update(&hdev->inq_cache, info++);
+-}
++	BT_DBG("%s", hdev->name);
+ 
+-/* Connect Request */
+-static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
+-{
+-	evt_conn_request *cr = (evt_conn_request *) skb->data;
+-	struct hci_proto *hp;
+-	accept_conn_req_cp ac;
+-	int accept = 0;
++	/* ACL tx timeout must be longer than maximum
++	 * link supervision timeout (40.9 seconds) */
++	if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
++		hci_acl_tx_to(hdev);
+ 
+-	DBG("%s Connection request: %s type 0x%x", hdev->name, batostr(&cr->bdaddr), cr->link_type);
++	while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
++		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
++			BT_DBG("skb %p len %d", skb, skb->len);
++			hci_send_frame(skb);
++			hdev->acl_last_tx = jiffies;
+ 
+-	/* Notify upper protocols */
+-	if (cr->link_type == ACL_LINK) {
+-		/* ACL link notify L2CAP */
+-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_ind) {
+-			tasklet_disable(&hdev->tx_task);
+-			accept = hp->connect_ind(hdev, &cr->bdaddr);
+-			tasklet_enable(&hdev->tx_task);
++			hdev->acl_cnt--;
++			conn->sent++;
+ 		}
+-	} else {
+-		/* SCO link (no notification) */
+-		/* FIXME: Should be accept it here or let the requester (app) accept it ? */
+-		accept = 1;
+-	}
+-
+-	if (accept) {
+-		/* Connection accepted by upper layer */
+-		bacpy(&ac.bdaddr, &cr->bdaddr);
+-		ac.role = 0x01; /* Remain slave */
+-		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, ACCEPT_CONN_REQ_CP_SIZE, &ac);
+-	} else {
+-		/* Connection rejected by upper layer */
+-		/* FIXME: 
+-		 * Should we use HCI reject here ?
+-		 */
+-		return;
+ 	}
+ }
+ 
+-/* Connect Complete */
+-static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++/* Schedule SCO */
++static inline void hci_sched_sco(struct hci_dev *hdev)
+ {
+-	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
+-	struct hci_conn *conn = NULL;
+-	struct hci_proto *hp;
+-
+-	DBG("%s", hdev->name);
+-
+-	tasklet_disable(&hdev->tx_task);
+-
+-	if (!cc->status)
+- 		conn = hci_conn_add(hdev, __le16_to_cpu(cc->handle), cc->link_type, &cc->bdaddr);
++	struct hci_conn *conn;
++	struct sk_buff *skb;
++	int quote;
+ 
+-	/* Notify upper protocols */
+-	if (cc->link_type == ACL_LINK) {
+-		/* ACL link notify L2CAP layer */
+-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->connect_cfm)
+-			hp->connect_cfm(hdev, &cc->bdaddr, cc->status, conn);
+-	} else {
+-		/* SCO link (no notification) */
+-	}
++	BT_DBG("%s", hdev->name);
+ 
+-	tasklet_enable(&hdev->tx_task);
+-}
++	while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
++		while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
++			BT_DBG("skb %p len %d", skb, skb->len);
++			hci_send_frame(skb);
+ 
+-/* Disconnect Complete */
+-static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+-{
+-	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
+-	struct hci_conn *conn = NULL;
+-	struct hci_proto *hp;
+-	__u16 handle = __le16_to_cpu(dc->handle);
+-
+-	DBG("%s", hdev->name);
+-
+-	if (!dc->status && (conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
+-		tasklet_disable(&hdev->tx_task);
+-
+-		/* Notify upper protocols */
+-		if (conn->type == ACL_LINK) {
+-			/* ACL link notify L2CAP layer */
+-			if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->disconn_ind)
+-				hp->disconn_ind(conn, dc->reason);
+-		} else {
+-			/* SCO link (no notification) */
++			conn->sent++;
++			if (conn->sent == ~0)
++				conn->sent = 0;
+ 		}
+-
+-		hci_conn_del(hdev, conn);
+-
+-		tasklet_enable(&hdev->tx_task);
+ 	}
+ }
+ 
+-/* Number of completed packets */
+-static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
++static void hci_tx_task(unsigned long arg)
+ {
+-	evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
+-	__u16 *ptr;
+-	int i;
+-
+-	skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
+-
+-	DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
++	struct hci_dev *hdev = (struct hci_dev *) arg;
++	struct sk_buff *skb;
+ 
+-	if (skb->len < nc->num_hndl * 4) {
+-		DBG("%s bad parameters", hdev->name);
+-		return;
+-	}
++	read_lock(&hci_task_lock);
+ 
+-	tasklet_disable(&hdev->tx_task);
++	BT_DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
+ 
+-	for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
+-		struct hci_conn *conn;
+-		__u16 handle, count;
++	/* Schedule queues and send stuff to HCI driver */
+ 
+-		handle = __le16_to_cpu(get_unaligned(ptr++));
+-		count  = __le16_to_cpu(get_unaligned(ptr++));
++	hci_sched_acl(hdev);
+ 
+-		hdev->acl_cnt += count;
++	hci_sched_sco(hdev);
+ 
+-		if ((conn = conn_hash_lookup(&hdev->conn_hash, handle)))
+-			conn->sent -= count;
+-	}
++	/* Send next queued raw (unknown type) packet */
++	while ((skb = skb_dequeue(&hdev->raw_q)))
++		hci_send_frame(skb);
+ 
+-	tasklet_enable(&hdev->tx_task);
+-	
+-	hci_sched_tx(hdev);
++	read_unlock(&hci_task_lock);
+ }
+ 
+-static inline void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
+-{
+-	hci_event_hdr *he = (hci_event_hdr *) skb->data;
+-	evt_cmd_status *cs;
+-	evt_cmd_complete *ec;
+-	__u16 opcode, ocf, ogf;
+-
+-	skb_pull(skb, HCI_EVENT_HDR_SIZE);
+-
+-	DBG("%s evt 0x%x", hdev->name, he->evt);
+-
+-	switch (he->evt) {
+-	case EVT_NUM_COMP_PKTS:
+-		hci_num_comp_pkts_evt(hdev, skb);
+-		break;
+-
+-	case EVT_INQUIRY_COMPLETE:
+-		hci_inquiry_complete_evt(hdev, skb);
+-		break;
+-
+-	case EVT_INQUIRY_RESULT:
+-		hci_inquiry_result_evt(hdev, skb);
+-		break;
+-
+-	case EVT_CONN_REQUEST:
+-		hci_conn_request_evt(hdev, skb);
+-		break;
+-
+-	case EVT_CONN_COMPLETE:
+-		hci_conn_complete_evt(hdev, skb);
+-		break;
+-
+-	case EVT_DISCONN_COMPLETE:
+-		hci_disconn_complete_evt(hdev, skb);
+-		break;
+-
+-	case EVT_CMD_STATUS:
+-		cs = (evt_cmd_status *) skb->data;
+-		skb_pull(skb, EVT_CMD_STATUS_SIZE);
+-				
+-		opcode = __le16_to_cpu(cs->opcode);
+-		ogf = cmd_opcode_ogf(opcode);
+-		ocf = cmd_opcode_ocf(opcode);
+-
+-		switch (ogf) {
+-		case OGF_INFO_PARAM:
+-			hci_cs_info_param(hdev, ocf, cs->status);
+-			break;
+-
+-		case OGF_HOST_CTL:
+-			hci_cs_host_ctl(hdev, ocf, cs->status);
+-			break;
+-
+-		case OGF_LINK_CTL:
+-			hci_cs_link_ctl(hdev, ocf, cs->status);
+-			break;
+-
+-		case OGF_LINK_POLICY:
+-			hci_cs_link_policy(hdev, ocf, cs->status);
+-			break;
+-
+-		default:
+-			DBG("%s Command Status OGF %x", hdev->name, ogf);
+-			break;
+-		};
+-
+-		if (cs->ncmd) {
+-			atomic_set(&hdev->cmd_cnt, 1);
+-			if (!skb_queue_empty(&hdev->cmd_q))
+-				hci_sched_cmd(hdev);
+-		}
+-		break;
+-
+-	case EVT_CMD_COMPLETE:
+-		ec = (evt_cmd_complete *) skb->data;
+-		skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
+-
+-		opcode = __le16_to_cpu(ec->opcode);
+-		ogf = cmd_opcode_ogf(opcode);
+-		ocf = cmd_opcode_ocf(opcode);
+-
+-		switch (ogf) {
+-		case OGF_INFO_PARAM:
+-			hci_cc_info_param(hdev, ocf, skb);
+-			break;
+-
+-		case OGF_HOST_CTL:
+-			hci_cc_host_ctl(hdev, ocf, skb);
+-			break;
+-
+-		case OGF_LINK_CTL:
+-			hci_cc_link_ctl(hdev, ocf, skb);
+-			break;
+-
+-		case OGF_LINK_POLICY:
+-			hci_cc_link_policy(hdev, ocf, skb);
+-			break;
+ 
+-		default:
+-			DBG("%s Command Completed OGF %x", hdev->name, ogf);
+-			break;
+-		};
+-
+-		if (ec->ncmd) {
+-			atomic_set(&hdev->cmd_cnt, 1);
+-			if (!skb_queue_empty(&hdev->cmd_q))
+-				hci_sched_cmd(hdev);
+-		}
+-		break;
+-	};
+-
+-	kfree_skb(skb);
+-	hdev->stat.evt_rx++;
+-}
++/* ----- HCI RX task (incomming data proccessing) ----- */
+ 
+ /* ACL data packet */
+ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+@@ -1867,51 +1255,86 @@
+ 	flags  = acl_flags(handle);
+ 	handle = acl_handle(handle);
+ 
+-	DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
++	BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
++
++	hdev->stat.acl_rx++;
+ 
+-	if ((conn = conn_hash_lookup(&hdev->conn_hash, handle))) {
++	hci_dev_lock(hdev);
++	conn = conn_hash_lookup_handle(hdev, handle);
++	hci_dev_unlock(hdev);
++	
++	if (conn) {
+ 		register struct hci_proto *hp;
+ 
+ 		/* Send to upper protocol */
+-		if ((hp = GET_HPROTO(HCI_PROTO_L2CAP)) && hp->recv_acldata) {
++		if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
+ 			hp->recv_acldata(conn, skb, flags);
+-			goto sent;
++			return;
+ 		}
+ 	} else {
+-		ERR("%s ACL packet for unknown connection handle %d", hdev->name, handle);
++		BT_ERR("%s ACL packet for unknown connection handle %d", 
++			hdev->name, handle);
+ 	}
+ 
+ 	kfree_skb(skb);
+-sent:
+-	hdev->stat.acl_rx++;
+ }
+ 
+ /* SCO data packet */
+ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+-	DBG("%s len %d", hdev->name, skb->len);
++	hci_sco_hdr *sh = (void *) skb->data;
++	struct hci_conn *conn;
++	__u16 handle;
++
++	skb_pull(skb, HCI_SCO_HDR_SIZE);
++
++	handle = __le16_to_cpu(sh->handle);
++
++	BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle);
+ 
+-	kfree_skb(skb);
+ 	hdev->stat.sco_rx++;
++
++	hci_dev_lock(hdev);
++	conn = conn_hash_lookup_handle(hdev, handle);
++	hci_dev_unlock(hdev);
++	
++	if (conn) {
++		register struct hci_proto *hp;
++
++		/* Send to upper protocol */
++		if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) {
++			hp->recv_scodata(conn, skb);
++			return;
++		}
++	} else {
++		BT_ERR("%s SCO packet for unknown connection handle %d", 
++			hdev->name, handle);
++	}
++
++	kfree_skb(skb);
+ }
+ 
+-/* ----- HCI tasks ----- */
+ void hci_rx_task(unsigned long arg)
+ {
+ 	struct hci_dev *hdev = (struct hci_dev *) arg;
+ 	struct sk_buff *skb;
+ 
+-	DBG("%s", hdev->name);
++	BT_DBG("%s", hdev->name);
+ 
+ 	read_lock(&hci_task_lock);
+ 
+ 	while ((skb = skb_dequeue(&hdev->rx_q))) {
+-		if (hdev->flags & HCI_SOCK) {
++		if (atomic_read(&hdev->promisc)) {
+ 			/* Send copy to the sockets */
+ 			hci_send_to_sock(hdev, skb);
+ 		}
+ 
+-		if (hdev->flags & HCI_INIT) {
++		if (test_bit(HCI_RAW, &hdev->flags)) {
++			kfree_skb(skb);
++			continue;
++		}
++
++		if (test_bit(HCI_INIT, &hdev->flags)) {
+ 			/* Don't process data packets in this states. */
+ 			switch (skb->pkt_type) {
+ 			case HCI_ACLDATA_PKT:
+@@ -1921,64 +1344,43 @@
+ 			};
+ 		}
+ 
+-		if (hdev->flags & HCI_NORMAL) {
+-			/* Process frame */
+-			switch (skb->pkt_type) {
+-			case HCI_EVENT_PKT:
+-				hci_event_packet(hdev, skb);
+-				break;
++		/* Process frame */
++		switch (skb->pkt_type) {
++		case HCI_EVENT_PKT:
++			hci_event_packet(hdev, skb);
++			break;
+ 
+-			case HCI_ACLDATA_PKT:
+-				DBG("%s ACL data packet", hdev->name);
+-				hci_acldata_packet(hdev, skb);
+-				break;
++		case HCI_ACLDATA_PKT:
++			BT_DBG("%s ACL data packet", hdev->name);
++			hci_acldata_packet(hdev, skb);
++			break;
+ 
+-			case HCI_SCODATA_PKT:
+-				DBG("%s SCO data packet", hdev->name);
+-				hci_scodata_packet(hdev, skb);
+-				break;
++		case HCI_SCODATA_PKT:
++			BT_DBG("%s SCO data packet", hdev->name);
++			hci_scodata_packet(hdev, skb);
++			break;
+ 
+-			default:
+-				kfree_skb(skb);
+-				break;
+-			};
+-		} else {
++		default:
+ 			kfree_skb(skb);
++			break;
+ 		}
+ 	}
+ 
+ 	read_unlock(&hci_task_lock);
+ }
+ 
+-static void hci_tx_task(unsigned long arg)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) arg;
+-	struct sk_buff *skb;
+-
+-	read_lock(&hci_task_lock);
+-
+-	DBG("%s acl %d sco %d", hdev->name, hdev->acl_cnt, hdev->sco_cnt);
+-
+-	/* Schedule queues and send stuff to HCI driver */
+-
+-	hci_sched_acl(hdev);
+-
+-	hci_sched_sco(hdev);
+-
+-	/* Send next queued raw (unknown type) packet */
+-	while ((skb = skb_dequeue(&hdev->raw_q)))
+-		hci_send_frame(skb);
+-
+-	read_unlock(&hci_task_lock);
+-}
+-
+ static void hci_cmd_task(unsigned long arg)
+ {
+ 	struct hci_dev *hdev = (struct hci_dev *) arg;
+ 	struct sk_buff *skb;
+ 
+-	DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
++	BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt));
+ 
++	if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) {
++		BT_ERR("%s command tx timeout", hdev->name);
++		atomic_set(&hdev->cmd_cnt, 1);
++	}
++	
+ 	/* Send queued commands */
+ 	if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
+ 		if (hdev->sent_cmd)
+@@ -1987,6 +1389,7 @@
+ 		if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
+ 			atomic_dec(&hdev->cmd_cnt);
+ 			hci_send_frame(skb);
++			hdev->cmd_last_tx = jiffies;
+ 		} else {
+ 			skb_queue_head(&hdev->cmd_q, skb);
+ 			hci_sched_cmd(hdev);
+@@ -1994,33 +1397,10 @@
+ 	}
+ }
+ 
+-/* Receive frame from HCI drivers */
+-int hci_recv_frame(struct sk_buff *skb)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) skb->dev;
+-
+-	if (!hdev || !(hdev->flags & (HCI_UP | HCI_INIT))) {
+-		kfree_skb(skb);
+-		return -1;
+-	}
+-
+-	DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+-
+-	/* Incomming skb */
+-	bluez_cb(skb)->incomming = 1;
+-
+-	/* Queue frame for rx task */
+-	skb_queue_tail(&hdev->rx_q, skb);
+-	hci_sched_rx(hdev);
+-
+-	return 0;
+-}
++/* ---- Initialization ---- */
+ 
+ int hci_core_init(void)
+ {
+-	/* Init locks */
+-	spin_lock_init(&hdev_list_lock);
+-
+ 	return 0;
+ }
+ 
+@@ -2028,5 +1408,3 @@
+ {
+ 	return 0;
+ }
+-
+-MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/net/bluetooth/hci_event.c linux-2.4.18-mh9/net/bluetooth/hci_event.c
+--- linux-2.4.18/net/bluetooth/hci_event.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/hci_event.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,927 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * HCI Events.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/notifier.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++#ifndef HCI_CORE_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++/* Handle HCI Event packets */
++
++/* Command Complete OGF LINK_CTL  */
++static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	__u8 status;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_INQUIRY_CANCEL:
++		status = *((__u8 *) skb->data);
++
++		if (status) {
++			BT_DBG("%s Inquiry cancel error: status 0x%x", hdev->name, status);
++		} else {
++			clear_bit(HCI_INQUIRY, &hdev->flags);
++			hci_req_complete(hdev, status);
++		}
++		break;
++
++	default:
++		BT_DBG("%s Command complete: ogf LINK_CTL ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Complete OGF LINK_POLICY  */
++static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	struct hci_conn *conn;
++	role_discovery_rp *rd;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_ROLE_DISCOVERY: 
++		rd = (void *) skb->data;
++
++		if (rd->status)
++			break;
++		
++		hci_dev_lock(hdev);
++	
++		conn = conn_hash_lookup_handle(hdev, __le16_to_cpu(rd->handle));
++		if (conn) {
++			if (rd->role)
++				conn->link_mode &= ~HCI_LM_MASTER;
++			else
++				conn->link_mode |= HCI_LM_MASTER;
++		}
++			
++		hci_dev_unlock(hdev);
++		break;
++
++	default:
++		BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", 
++				hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Complete OGF HOST_CTL  */
++static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	__u8 status, param;
++	__u16 setting;
++	read_voice_setting_rp *vs;
++	void *sent;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_RESET:
++		status = *((__u8 *) skb->data);
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_SET_EVENT_FLT:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s SET_EVENT_FLT failed %d", hdev->name, status);
++		} else {
++			BT_DBG("%s SET_EVENT_FLT succeseful", hdev->name);
++		}
++		break;
++
++	case OCF_WRITE_AUTH_ENABLE:
++		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_AUTH_ENABLE);
++		if (!sent)
++			break;
++
++		status = *((__u8 *) skb->data);
++		param  = *((__u8 *) sent);
++
++		if (!status) {
++			if (param == AUTH_ENABLED)
++				set_bit(HCI_AUTH, &hdev->flags);
++			else
++				clear_bit(HCI_AUTH, &hdev->flags);
++		}
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_WRITE_ENCRYPT_MODE:
++		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_ENCRYPT_MODE);
++		if (!sent)
++			break;
++
++		status = *((__u8 *) skb->data);
++		param  = *((__u8 *) sent);
++
++		if (!status) {
++			if (param)
++				set_bit(HCI_ENCRYPT, &hdev->flags);
++			else
++				clear_bit(HCI_ENCRYPT, &hdev->flags);
++		}
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_WRITE_CA_TIMEOUT:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s OCF_WRITE_CA_TIMEOUT failed %d", hdev->name, status);
++		} else {
++			BT_DBG("%s OCF_WRITE_CA_TIMEOUT succeseful", hdev->name);
++		}
++		break;
++
++	case OCF_WRITE_PG_TIMEOUT:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s OCF_WRITE_PG_TIMEOUT failed %d", hdev->name, status);
++		} else {
++			BT_DBG("%s: OCF_WRITE_PG_TIMEOUT succeseful", hdev->name);
++		}
++		break;
++
++	case OCF_WRITE_SCAN_ENABLE:
++		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE);
++		if (!sent)
++			break;
++
++		status = *((__u8 *) skb->data);
++		param  = *((__u8 *) sent);
++
++		BT_DBG("param 0x%x", param);
++
++		if (!status) {
++			clear_bit(HCI_PSCAN, &hdev->flags);
++			clear_bit(HCI_ISCAN, &hdev->flags);
++			if (param & SCAN_INQUIRY) 
++				set_bit(HCI_ISCAN, &hdev->flags);
++
++			if (param & SCAN_PAGE) 
++				set_bit(HCI_PSCAN, &hdev->flags);
++		}
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_READ_VOICE_SETTING:
++		vs = (read_voice_setting_rp *) skb->data;
++
++		if (vs->status) { 
++			BT_DBG("%s READ_VOICE_SETTING failed %d", hdev->name, vc->status);
++			break;
++		}
++
++		setting = __le16_to_cpu(vs->voice_setting);
++
++		if (hdev->voice_setting != setting ) {
++			hdev->voice_setting = setting;
++
++			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
++
++			if (hdev->notify)
++				hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING, 0);
++		}
++
++		break;
++
++	case OCF_WRITE_VOICE_SETTING:
++		sent = hci_sent_cmd_data(hdev, OGF_HOST_CTL, OCF_WRITE_VOICE_SETTING);
++		if (!sent)
++			break;
++
++		status = *((__u8 *) skb->data);
++		setting = __le16_to_cpu(get_unaligned((__u16 *) sent));
++
++		if (!status && hdev->voice_setting != setting) {
++			hdev->voice_setting = setting;
++
++			BT_DBG("%s: voice setting 0x%04x", hdev->name, setting);
++
++			if (hdev->notify)
++				hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING, 0);
++		}
++		hci_req_complete(hdev, status);
++		break;
++
++	case OCF_HOST_BUFFER_SIZE:
++		status = *((__u8 *) skb->data);
++		if (status) {
++			BT_DBG("%s OCF_BUFFER_SIZE failed %d", hdev->name, status);
++			hci_req_complete(hdev, status);
++		}
++		break;
++
++	default:
++		BT_DBG("%s Command complete: ogf HOST_CTL ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Complete OGF INFO_PARAM  */
++static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
++{
++	read_local_features_rp *lf;
++	read_buffer_size_rp *bs;
++	read_bd_addr_rp *ba;
++
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_READ_LOCAL_FEATURES:
++		lf = (read_local_features_rp *) skb->data;
++
++		if (lf->status) {
++			BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status);
++			break;
++		}
++
++		memcpy(hdev->features, lf->features, sizeof(hdev->features));
++
++		/* Adjust default settings according to features 
++		 * supported by device. */
++		if (hdev->features[0] & LMP_3SLOT)
++			hdev->pkt_type |= (HCI_DM3 | HCI_DH3);
++
++		if (hdev->features[0] & LMP_5SLOT)
++			hdev->pkt_type |= (HCI_DM5 | HCI_DH5);
++
++		if (hdev->features[1] & LMP_HV2)
++			hdev->pkt_type |= (HCI_HV2);
++
++		if (hdev->features[1] & LMP_HV3)
++			hdev->pkt_type |= (HCI_HV3);
++
++		BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
++
++		break;
++
++	case OCF_READ_BUFFER_SIZE:
++		bs = (read_buffer_size_rp *) skb->data;
++
++		if (bs->status) {
++			BT_DBG("%s READ_BUFFER_SIZE failed %d", hdev->name, bs->status);
++			hci_req_complete(hdev, bs->status);
++			break;
++		}
++
++		hdev->acl_mtu  = __le16_to_cpu(bs->acl_mtu);
++		hdev->sco_mtu  = bs->sco_mtu ? bs->sco_mtu : 64;
++		hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt);
++		hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt);
++
++		BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name,
++			hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts);
++
++		break;
++
++	case OCF_READ_BD_ADDR:
++		ba = (read_bd_addr_rp *) skb->data;
++
++		if (!ba->status) {
++			bacpy(&hdev->bdaddr, &ba->bdaddr);
++		} else {
++			BT_DBG("%s: READ_BD_ADDR failed %d", hdev->name, ba->status);
++		}
++
++		hci_req_complete(hdev, ba->status);
++		break;
++
++	default:
++		BT_DBG("%s Command complete: ogf INFO_PARAM ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Status OGF LINK_CTL  */
++static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
++{
++	struct hci_conn *conn;
++	create_conn_cp *cc = hci_sent_cmd_data(hdev, OGF_LINK_CTL, OCF_CREATE_CONN);
++
++	if (!cc)
++		return;
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_ba(hdev, ACL_LINK, &cc->bdaddr);
++
++	BT_DBG("%s status 0x%x bdaddr %s conn %p", hdev->name, 
++			status, batostr(&cc->bdaddr), conn);
++
++	if (status) {
++		if (conn) {
++			conn->state = BT_CLOSED;
++			hci_proto_connect_cfm(conn, status);
++			hci_conn_del(conn);
++		}
++	} else {
++		if (!conn) {
++			conn = hci_conn_add(hdev, ACL_LINK, &cc->bdaddr);
++			if (conn) {
++				conn->out = 1;
++				conn->link_mode |= HCI_LM_MASTER;
++			} else
++				BT_ERR("No memmory for new connection");
++		}
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++static void hci_cs_link_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	case OCF_CREATE_CONN:
++		hci_cs_create_conn(hdev, status);
++		break;
++
++	case OCF_ADD_SCO:
++		if (status) {
++			struct hci_conn *acl, *sco;
++			add_sco_cp *cp = hci_sent_cmd_data(hdev, 
++						OGF_LINK_CTL, OCF_ADD_SCO);
++			__u16 handle;
++
++			if (!cp)
++				break;
++
++			handle = __le16_to_cpu(cp->handle);
++
++			BT_DBG("%s Add SCO error: handle %d status 0x%x", hdev->name, handle, status);
++
++			hci_dev_lock(hdev);
++	
++			acl = conn_hash_lookup_handle(hdev, handle);
++			if (acl && (sco = acl->link)) {
++				sco->state = BT_CLOSED;
++				hci_proto_connect_cfm(sco, status);
++				hci_conn_del(sco);
++			}
++
++			hci_dev_unlock(hdev);
++		}
++		break;
++
++	case OCF_INQUIRY:
++		if (status) {
++			BT_DBG("%s Inquiry error: status 0x%x", hdev->name, status);
++			hci_req_complete(hdev, status);
++		} else {
++			set_bit(HCI_INQUIRY, &hdev->flags);
++		}
++		break;
++
++	default:
++		BT_DBG("%s Command status: ogf LINK_CTL ocf %x status %d", 
++			hdev->name, ocf, status);
++		break;
++	};
++}
++
++/* Command Status OGF LINK_POLICY */
++static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	default:
++		BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Status OGF HOST_CTL */
++static void hci_cs_host_ctl(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	default:
++		BT_DBG("%s Command status: ogf HOST_CTL ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Command Status OGF INFO_PARAM  */
++static void hci_cs_info_param(struct hci_dev *hdev, __u16 ocf, __u8 status)
++{
++	BT_DBG("%s: hci_cs_info_param: ocf 0x%x", hdev->name, ocf);
++
++	switch (ocf) {
++	default:
++		BT_DBG("%s Command status: ogf INFO_PARAM ocf %x", hdev->name, ocf);
++		break;
++	};
++}
++
++/* Inquiry Complete */
++static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	__u8 status = *((__u8 *) skb->data);
++
++	BT_DBG("%s status %d", hdev->name, status);
++
++	clear_bit(HCI_INQUIRY, &hdev->flags);
++	hci_req_complete(hdev, status);
++}
++
++/* Inquiry Result */
++static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	inquiry_info *info = (inquiry_info *) (skb->data + 1);
++	int num_rsp = *((__u8 *) skb->data);
++
++	BT_DBG("%s num_rsp %d", hdev->name, num_rsp);
++
++	hci_dev_lock(hdev);
++	for (; num_rsp; num_rsp--)
++		inquiry_cache_update(hdev, info++);
++	hci_dev_unlock(hdev);
++}
++
++/* Connect Request */
++static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_conn_request *cr = (evt_conn_request *) skb->data;
++	int mask = hdev->link_mode;
++
++	BT_DBG("%s Connection request: %s type 0x%x", hdev->name,
++			batostr(&cr->bdaddr), cr->link_type);
++
++	mask |= hci_proto_connect_ind(hdev, &cr->bdaddr, cr->link_type);
++
++	if (mask & HCI_LM_ACCEPT) {
++		/* Connection accepted */
++		struct hci_conn *conn;
++		accept_conn_req_cp ac;
++
++		hci_dev_lock(hdev);
++		conn = conn_hash_lookup_ba(hdev, cr->link_type, &cr->bdaddr);
++		if (!conn) {
++			if (!(conn = hci_conn_add(hdev, cr->link_type, &cr->bdaddr))) {
++				BT_ERR("No memmory for new connection");
++				hci_dev_unlock(hdev);
++				return;
++			}
++		}
++		conn->state = BT_CONNECT;
++		hci_dev_unlock(hdev);
++
++		bacpy(&ac.bdaddr, &cr->bdaddr);
++	
++		if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER))
++			ac.role = 0x00; /* Become master */
++		else
++			ac.role = 0x01; /* Remain slave */
++
++		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, 
++				ACCEPT_CONN_REQ_CP_SIZE, &ac);
++	} else {
++		/* Connection rejected */
++		reject_conn_req_cp rc;
++
++		bacpy(&rc.bdaddr, &cr->bdaddr);
++		rc.reason = 0x0f;
++		hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ,
++				REJECT_CONN_REQ_CP_SIZE, &rc);
++	}
++}
++
++/* Connect Complete */
++static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_conn_complete *cc = (evt_conn_complete *) skb->data;
++	struct hci_conn *conn = NULL;
++
++	BT_DBG("%s", hdev->name);
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_ba(hdev, cc->link_type, &cc->bdaddr);
++	if (!conn) {
++		hci_dev_unlock(hdev);
++		return;
++	}
++
++	if (!cc->status) {
++		conn->handle = __le16_to_cpu(cc->handle);
++		conn->state  = BT_CONNECTED;
++
++		if (test_bit(HCI_AUTH, &hdev->flags))
++			conn->link_mode |= HCI_LM_AUTH;
++		
++		if (test_bit(HCI_ENCRYPT, &hdev->flags))
++			conn->link_mode |= HCI_LM_ENCRYPT;
++
++
++		/* Set link policy */
++		if (conn->type == ACL_LINK && hdev->link_policy) {
++			write_link_policy_cp lp;
++			lp.handle = cc->handle;
++			lp.policy = __cpu_to_le16(hdev->link_policy);
++			hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY,
++				WRITE_LINK_POLICY_CP_SIZE, &lp);
++		}
++
++		/* Set packet type for incomming connection */
++		if (!conn->out) {
++			change_conn_ptype_cp cp;
++			cp.handle = cc->handle;
++			cp.pkt_type = (conn->type == ACL_LINK) ? 
++				__cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK):
++				__cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
++
++			hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE,
++				CHANGE_CONN_PTYPE_CP_SIZE, &cp);
++		}
++	} else
++		conn->state = BT_CLOSED;
++
++	if (conn->type == ACL_LINK) {
++		struct hci_conn *sco = conn->link;
++		if (sco) {
++			if (!cc->status)
++				hci_add_sco(sco, conn->handle);
++			else {
++				hci_proto_connect_cfm(sco, cc->status);
++				hci_conn_del(sco);
++			}
++		}
++	}
++
++	hci_proto_connect_cfm(conn, cc->status);
++	if (cc->status)
++		hci_conn_del(conn);
++
++	hci_dev_unlock(hdev);
++}
++
++/* Disconnect Complete */
++static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_disconn_complete *dc = (evt_disconn_complete *) skb->data;
++	struct hci_conn *conn = NULL;
++	__u16 handle = __le16_to_cpu(dc->handle);
++
++	BT_DBG("%s status %d", hdev->name, dc->status);
++
++	if (dc->status)
++		return;
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_handle(hdev, handle);
++	if (conn) {
++		conn->state = BT_CLOSED;
++		hci_proto_disconn_ind(conn, dc->reason);
++		hci_conn_del(conn);
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++/* Number of completed packets */
++static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_num_comp_pkts *nc = (evt_num_comp_pkts *) skb->data;
++	__u16 *ptr;
++	int i;
++
++	skb_pull(skb, EVT_NUM_COMP_PKTS_SIZE);
++
++	BT_DBG("%s num_hndl %d", hdev->name, nc->num_hndl);
++
++	if (skb->len < nc->num_hndl * 4) {
++		BT_DBG("%s bad parameters", hdev->name);
++		return;
++	}
++
++	tasklet_disable(&hdev->tx_task);
++
++	for (i = 0, ptr = (__u16 *) skb->data; i < nc->num_hndl; i++) {
++		struct hci_conn *conn;
++		__u16  handle, count;
++
++		handle = __le16_to_cpu(get_unaligned(ptr++));
++		count  = __le16_to_cpu(get_unaligned(ptr++));
++
++		conn = conn_hash_lookup_handle(hdev, handle);
++		if (conn) {
++			conn->sent -= count;
++
++			if (conn->type == SCO_LINK) {
++				if ((hdev->sco_cnt += count) > hdev->sco_pkts)
++					hdev->sco_cnt = hdev->sco_pkts;
++			} else {
++				if ((hdev->acl_cnt += count) > hdev->acl_pkts)
++					hdev->acl_cnt = hdev->acl_pkts;
++			}
++		}
++	}
++	hci_sched_tx(hdev);
++
++	tasklet_enable(&hdev->tx_task);
++}
++
++/* Role Change */
++static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_role_change *rc = (evt_role_change *) skb->data;
++	struct hci_conn *conn = NULL;
++
++	BT_DBG("%s status %d", hdev->name, rc->status);
++
++	if (rc->status)
++		return;
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_ba(hdev, ACL_LINK, &rc->bdaddr);
++	if (conn) {
++		if (rc->role)
++			conn->link_mode &= ~HCI_LM_MASTER;
++		else 
++			conn->link_mode |= HCI_LM_MASTER;
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++/* Authentication Complete */
++static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_auth_complete *ac = (evt_auth_complete *) skb->data;
++	struct hci_conn *conn = NULL;
++	__u16 handle = __le16_to_cpu(ac->handle);
++
++	BT_DBG("%s status %d", hdev->name, ac->status);
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_handle(hdev, handle);
++	if (conn) {
++		if (!ac->status)
++			conn->link_mode |= HCI_LM_AUTH;
++		clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
++
++		hci_proto_auth_cfm(conn, ac->status);
++		
++		if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
++			if (!ac->status) {
++				set_conn_encrypt_cp ce;
++				ce.handle  = __cpu_to_le16(conn->handle);
++				ce.encrypt = 1;
++				hci_send_cmd(conn->hdev, OGF_LINK_CTL,
++						OCF_SET_CONN_ENCRYPT,
++						SET_CONN_ENCRYPT_CP_SIZE, &ce);
++			} else {
++				clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
++				hci_proto_encrypt_cfm(conn, ac->status);
++			}
++		}
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++/* Encryption Change */
++static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	evt_encrypt_change *ec = (evt_encrypt_change *) skb->data;
++	struct hci_conn *conn = NULL;
++	__u16 handle = __le16_to_cpu(ec->handle);
++
++	BT_DBG("%s status %d", hdev->name, ec->status);
++
++	hci_dev_lock(hdev);
++	
++	conn = conn_hash_lookup_handle(hdev, handle);
++	if (conn) {
++		if (!ec->status) {
++		       	if (ec->encrypt)
++				conn->link_mode |= HCI_LM_ENCRYPT;
++			else
++				conn->link_mode &= ~HCI_LM_ENCRYPT;
++		}
++		clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
++		
++		hci_proto_encrypt_cfm(conn, ec->status);
++	}
++
++	hci_dev_unlock(hdev);
++}
++
++void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
++{
++	hci_event_hdr *he = (hci_event_hdr *) skb->data;
++	evt_cmd_status *cs;
++	evt_cmd_complete *ec;
++	__u16 opcode, ocf, ogf;
++
++	skb_pull(skb, HCI_EVENT_HDR_SIZE);
++
++	BT_DBG("%s evt 0x%x", hdev->name, he->evt);
++
++	switch (he->evt) {
++	case EVT_NUM_COMP_PKTS:
++		hci_num_comp_pkts_evt(hdev, skb);
++		break;
++
++	case EVT_INQUIRY_COMPLETE:
++		hci_inquiry_complete_evt(hdev, skb);
++		break;
++
++	case EVT_INQUIRY_RESULT:
++		hci_inquiry_result_evt(hdev, skb);
++		break;
++
++	case EVT_CONN_REQUEST:
++		hci_conn_request_evt(hdev, skb);
++		break;
++
++	case EVT_CONN_COMPLETE:
++		hci_conn_complete_evt(hdev, skb);
++		break;
++
++	case EVT_DISCONN_COMPLETE:
++		hci_disconn_complete_evt(hdev, skb);
++		break;
++
++	case EVT_ROLE_CHANGE:
++		hci_role_change_evt(hdev, skb);
++		break;
++
++	case EVT_AUTH_COMPLETE:
++		hci_auth_complete_evt(hdev, skb);
++		break;
++
++	case EVT_ENCRYPT_CHANGE:
++		hci_encrypt_change_evt(hdev, skb);
++		break;
++
++	case EVT_CMD_STATUS:
++		cs = (evt_cmd_status *) skb->data;
++		skb_pull(skb, EVT_CMD_STATUS_SIZE);
++				
++		opcode = __le16_to_cpu(cs->opcode);
++		ogf = cmd_opcode_ogf(opcode);
++		ocf = cmd_opcode_ocf(opcode);
++
++		switch (ogf) {
++		case OGF_INFO_PARAM:
++			hci_cs_info_param(hdev, ocf, cs->status);
++			break;
++
++		case OGF_HOST_CTL:
++			hci_cs_host_ctl(hdev, ocf, cs->status);
++			break;
++
++		case OGF_LINK_CTL:
++			hci_cs_link_ctl(hdev, ocf, cs->status);
++			break;
++
++		case OGF_LINK_POLICY:
++			hci_cs_link_policy(hdev, ocf, cs->status);
++			break;
++
++		default:
++			BT_DBG("%s Command Status OGF %x", hdev->name, ogf);
++			break;
++		};
++
++		if (cs->ncmd) {
++			atomic_set(&hdev->cmd_cnt, 1);
++			if (!skb_queue_empty(&hdev->cmd_q))
++				hci_sched_cmd(hdev);
++		}
++		break;
++
++	case EVT_CMD_COMPLETE:
++		ec = (evt_cmd_complete *) skb->data;
++		skb_pull(skb, EVT_CMD_COMPLETE_SIZE);
++
++		opcode = __le16_to_cpu(ec->opcode);
++		ogf = cmd_opcode_ogf(opcode);
++		ocf = cmd_opcode_ocf(opcode);
++
++		switch (ogf) {
++		case OGF_INFO_PARAM:
++			hci_cc_info_param(hdev, ocf, skb);
++			break;
++
++		case OGF_HOST_CTL:
++			hci_cc_host_ctl(hdev, ocf, skb);
++			break;
++
++		case OGF_LINK_CTL:
++			hci_cc_link_ctl(hdev, ocf, skb);
++			break;
++
++		case OGF_LINK_POLICY:
++			hci_cc_link_policy(hdev, ocf, skb);
++			break;
++
++		default:
++			BT_DBG("%s Command Completed OGF %x", hdev->name, ogf);
++			break;
++		};
++
++		if (ec->ncmd) {
++			atomic_set(&hdev->cmd_cnt, 1);
++			if (!skb_queue_empty(&hdev->cmd_q))
++				hci_sched_cmd(hdev);
++		}
++		break;
++	};
++
++	kfree_skb(skb);
++	hdev->stat.evt_rx++;
++}
++
++/* General internal stack event */
++void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
++{
++	hci_event_hdr *eh;
++	evt_stack_internal *si;
++	struct sk_buff *skb;
++	int size;
++	void *ptr;
++
++	size = HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE + dlen;
++	skb  = bluez_skb_alloc(size, GFP_ATOMIC);
++	if (!skb)
++		return;
++
++	ptr = skb_put(skb, size);
++
++	eh = ptr;
++       	eh->evt  = EVT_STACK_INTERNAL;
++	eh->plen = EVT_STACK_INTERNAL_SIZE + dlen;
++	ptr += HCI_EVENT_HDR_SIZE;
++
++	si = ptr;
++	si->type = type;
++	memcpy(si->data, data, dlen);
++	
++	skb->pkt_type = HCI_EVENT_PKT;
++	skb->dev = (void *) hdev;
++	hci_send_to_sock(hdev, skb);
++	kfree_skb(skb);
++}
+diff -urN linux-2.4.18/net/bluetooth/hci_sock.c linux-2.4.18-mh9/net/bluetooth/hci_sock.c
+--- linux-2.4.18/net/bluetooth/hci_sock.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/net/bluetooth/hci_sock.c	Mon Aug 25 18:38:12 2003
+@@ -25,7 +25,7 @@
+ /*
+  * BlueZ HCI socket layer.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/config.h>
+@@ -49,45 +49,54 @@
+ 
+ #include <asm/system.h>
+ #include <asm/uaccess.h>
++#include <asm/unaligned.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+ 
+ #ifndef HCI_SOCK_DEBUG
+-#undef  DBG
+-#define DBG( A... )
++#undef  BT_DBG
++#define BT_DBG( A... )
+ #endif
+ 
+-/* HCI socket interface */
++/* ----- HCI socket interface ----- */
++
++/* Security filter */
++static struct hci_sec_filter hci_sec_filter = {
++	/* Packet types */
++	0x10,
++	/* Events */
++	{ 0xd9fe, 0x0 },
++	/* Commands */
++	{
++		{ 0x0 },
++		/* OGF_LINK_CTL */
++		{ 0x2a000002, 0x0, 0x0, 0x0  },
++		/* OGF_LINK_POLICY */
++		{ 0x1200, 0x0, 0x0, 0x0      },
++		/* OGF_HOST_CTL */
++		{ 0x80100000, 0x202a, 0x0, 0x0 },
++		/* OGF_INFO_PARAM */
++		{ 0x22a, 0x0, 0x0, 0x0       },
++		/* OGF_STATUS_PARAM */
++		{ 0x2e, 0x0, 0x0, 0x0        }
++	}
++};
+ 
+ static struct bluez_sock_list hci_sk_list = {
+ 	lock: RW_LOCK_UNLOCKED
+ };
+ 
+-static struct sock *hci_sock_lookup(struct hci_dev *hdev)
+-{
+-	struct sock *sk;
+-
+-	read_lock(&hci_sk_list.lock);
+-	for (sk = hci_sk_list.head; sk; sk = sk->next) {
+-		if (hci_pi(sk)->hdev == hdev)
+-			break;
+-	}
+-	read_unlock(&hci_sk_list.lock);
+-	return sk;
+-}
+-
+ /* Send frame to RAW socket */
+ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+ 	struct sock * sk;
+ 
+-	DBG("hdev %p len %d", hdev, skb->len);
++	BT_DBG("hdev %p len %d", hdev, skb->len);
+ 
+ 	read_lock(&hci_sk_list.lock);
+ 	for (sk = hci_sk_list.head; sk; sk = sk->next) {
+-		struct hci_filter *flt;	
++		struct hci_filter *flt;
+ 		struct sk_buff *nskb;
+ 
+ 		if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev)
+@@ -100,13 +109,19 @@
+ 		/* Apply filter */
+ 		flt = &hci_pi(sk)->filter;
+ 
+-		if (!test_bit(skb->pkt_type, &flt->type_mask))
++		if (!hci_test_bit((skb->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
+ 			continue;
+ 
+ 		if (skb->pkt_type == HCI_EVENT_PKT) {
+-			register int evt = (*(__u8 *)skb->data & 63);
++			register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
++			
++			if (!hci_test_bit(evt, &flt->event_mask))
++				continue;
+ 
+-			if (!test_bit(evt, &flt->event_mask))
++			if (flt->opcode && ((evt == EVT_CMD_COMPLETE && 
++					flt->opcode != *(__u16 *)(skb->data + 3)) ||
++					(evt == EVT_CMD_STATUS && 
++					flt->opcode != *(__u16 *)(skb->data + 4))))
+ 				continue;
+ 		}
+ 
+@@ -116,8 +131,8 @@
+ 		/* Put type byte before the data */
+ 		memcpy(skb_push(nskb, 1), &nskb->pkt_type, 1);
+ 
+-		skb_queue_tail(&sk->receive_queue, nskb);
+-		sk->data_ready(sk, nskb->len);
++		if (sock_queue_rcv_skb(sk, nskb))
++			kfree_skb(nskb);
+ 	}
+ 	read_unlock(&hci_sk_list.lock);
+ }
+@@ -127,7 +142,7 @@
+ 	struct sock *sk = sock->sk;
+ 	struct hci_dev *hdev = hci_pi(sk)->hdev;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p sk %p", sock, sk);
+ 
+ 	if (!sk)
+ 		return 0;
+@@ -135,9 +150,7 @@
+ 	bluez_sock_unlink(&hci_sk_list, sk);
+ 
+ 	if (hdev) {
+-		if (!hci_sock_lookup(hdev))
+-			hdev->flags &= ~HCI_SOCK;
+-
++		atomic_dec(&hdev->promisc);
+ 		hci_dev_put(hdev);
+ 	}
+ 
+@@ -149,24 +162,55 @@
+ 	sock_put(sk);
+ 
+ 	MOD_DEC_USE_COUNT;
+-
+ 	return 0;
+ }
+ 
+-static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++/* Ioctls that require bound socket */ 
++static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
+ {
+-	struct sock *sk = sock->sk;
+ 	struct hci_dev *hdev = hci_pi(sk)->hdev;
+-	__u32 mode;
+ 
+-	DBG("cmd %x arg %lx", cmd, arg);
++	if (!hdev)
++		return -EBADFD;
+ 
+ 	switch (cmd) {
+-	case HCIGETINFO:
+-		return hci_dev_info(arg);
++	case HCISETRAW:
++		if (!capable(CAP_NET_ADMIN))
++			return -EACCES;
+ 
++		if (arg)
++			set_bit(HCI_RAW, &hdev->flags);
++		else
++			clear_bit(HCI_RAW, &hdev->flags);
++
++		return 0;
++
++	case HCIGETCONNINFO:
++		return hci_get_conn_info(hdev, arg);
++
++	default:
++		if (hdev->ioctl)
++			return hdev->ioctl(hdev, cmd, arg);
++		return -EINVAL;
++	}
++}
++
++static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct sock *sk = sock->sk;
++	int err;
++
++	BT_DBG("cmd %x arg %lx", cmd, arg);
++
++	switch (cmd) {
+ 	case HCIGETDEVLIST:
+-		return hci_dev_list(arg);
++		return hci_get_dev_list(arg);
++
++	case HCIGETDEVINFO:
++		return hci_get_dev_info(arg);
++
++	case HCIGETCONNLIST:
++		return hci_get_conn_list(arg);
+ 
+ 	case HCIDEVUP:
+ 		if (!capable(CAP_NET_ADMIN))
+@@ -183,48 +227,31 @@
+ 			return -EACCES;
+ 		return hci_dev_reset(arg);
+ 
+-	case HCIRESETSTAT:
++	case HCIDEVRESTAT:
+ 		if (!capable(CAP_NET_ADMIN))
+ 			return -EACCES;
+ 		return hci_dev_reset_stat(arg);
+ 
+ 	case HCISETSCAN:
+-		if (!capable(CAP_NET_ADMIN))
+-			return -EACCES;
+-		return hci_dev_setscan(arg);
+-
+ 	case HCISETAUTH:
+-		if (!capable(CAP_NET_ADMIN))
+-			return -EACCES;
+-		return hci_dev_setauth(arg);
+-
+-	case HCISETRAW:
+-		if (!capable(CAP_NET_ADMIN))
+-			return -EACCES;
+-
+-		if (!hdev)
+-			return -EBADFD;
+-
+-		if (arg)
+-			mode = HCI_RAW;
+-		else
+-			mode = HCI_NORMAL;
+-
+-		return hci_dev_setmode(hdev, mode);
+-
++	case HCISETENCRYPT:
+ 	case HCISETPTYPE:
++	case HCISETLINKPOL:
++	case HCISETLINKMODE:
++	case HCISETACLMTU:
++	case HCISETSCOMTU:
+ 		if (!capable(CAP_NET_ADMIN))
+ 			return -EACCES;
+-		return hci_dev_setptype(arg);
++		return hci_dev_cmd(cmd, arg);
+ 
+ 	case HCIINQUIRY:
+ 		return hci_inquiry(arg);
+ 
+-	case HCIGETCONNLIST:
+-		return hci_conn_list(arg);
+-
+ 	default:
+-		return -EINVAL;
++		lock_sock(sk);
++		err = hci_sock_bound_ioctl(sk, cmd, arg);
++		release_sock(sk);
++		return err;
+ 	};
+ }
+ 
+@@ -233,28 +260,35 @@
+ 	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
+ 	struct sock *sk = sock->sk;
+ 	struct hci_dev *hdev = NULL;
++	int err = 0;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p sk %p", sock, sk);
+ 
+ 	if (!haddr || haddr->hci_family != AF_BLUETOOTH)
+ 		return -EINVAL;
+ 
++	lock_sock(sk);
++
+ 	if (hci_pi(sk)->hdev) {
+-		/* Already bound */
+-		return 0;
++		err = -EALREADY;
++		goto done;
+ 	}
+ 
+ 	if (haddr->hci_dev != HCI_DEV_NONE) {
+-		if (!(hdev = hci_dev_get(haddr->hci_dev)))
+-			return -ENODEV;
++		if (!(hdev = hci_dev_get(haddr->hci_dev))) {
++			err = -ENODEV;
++			goto done;
++		}
+ 
+-		hdev->flags |= HCI_SOCK;
++		atomic_inc(&hdev->promisc);
+ 	}
+ 
+ 	hci_pi(sk)->hdev = hdev;
+ 	sk->state = BT_BOUND;
+ 
+-	return 0;
++done:
++	release_sock(sk);
++	return err;
+ }
+ 
+ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
+@@ -262,73 +296,44 @@
+ 	struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
+ 	struct sock *sk = sock->sk;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	lock_sock(sk);
+ 
+ 	*addr_len = sizeof(*haddr);
+ 	haddr->hci_family = AF_BLUETOOTH;
+ 	haddr->hci_dev    = hci_pi(sk)->hdev->id;
+ 
++	release_sock(sk);
+ 	return 0;
+ }
+ 
+-static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
+-                            struct scm_cookie *scm)
+-{
+-	struct sock *sk = sock->sk;
+-	struct hci_dev *hdev = hci_pi(sk)->hdev;
+-	struct sk_buff *skb;
+-	int err;
+-
+-	DBG("sock %p sk %p", sock, sk);
+-
+-	if (msg->msg_flags & MSG_OOB)
+-		return -EOPNOTSUPP;
+-
+-	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
+-		return -EINVAL;
+-
+-	if (!hdev)
+-		return -EBADFD;
+-
+-	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
+-		return err;
+-
+-	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
+-		kfree_skb(skb);
+-		return -EFAULT;
+-	}
+-
+-	skb->dev = (void *) hdev;
+-	skb->pkt_type = *((unsigned char *) skb->data);
+-	skb_pull(skb, 1);
+-
+-	/* Send frame to HCI core */
+-	hci_send_raw(skb);
+-
+-	return len;
+-}
+-
+ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
+ {
+ 	__u32 mask = hci_pi(sk)->cmsg_mask;
+ 
+ 	if (mask & HCI_CMSG_DIR)
+         	put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(int), &bluez_cb(skb)->incomming);
++
++	if (mask & HCI_CMSG_TSTAMP)
++        	put_cmsg(msg, SOL_HCI, HCI_CMSG_TSTAMP, sizeof(skb->stamp), &skb->stamp);
+ }
+  
+-static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len,
+-                            int flags, struct scm_cookie *scm)
++static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+ {
+ 	int noblock = flags & MSG_DONTWAIT;
+ 	struct sock *sk = sock->sk;
+ 	struct sk_buff *skb;
+ 	int copied, err;
+ 
+-	DBG("sock %p sk %p", sock, sk);
++	BT_DBG("sock %p, sk %p", sock, sk);
+ 
+-	if (flags & (MSG_OOB | MSG_PEEK))
++	if (flags & (MSG_OOB))
+ 		return -EOPNOTSUPP;
+ 
++	if (sk->state == BT_CLOSED)
++		return 0;
++
+ 	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
+ 		return err;
+ 
+@@ -343,28 +348,107 @@
+ 	skb->h.raw = skb->data;
+ 	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+ 
+-	if (hci_pi(sk)->cmsg_mask)
+-		hci_sock_cmsg(sk, msg, skb);
+-
++	hci_sock_cmsg(sk, msg, skb);
++	
+ 	skb_free_datagram(sk, skb);
+ 
+ 	return err ? : copied;
+ }
+ 
++static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
++                            struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	struct hci_dev *hdev;
++	struct sk_buff *skb;
++	int err;
++
++	BT_DBG("sock %p sk %p", sock, sk);
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_NOSIGNAL|MSG_ERRQUEUE))
++		return -EINVAL;
++
++	if (len < 4)
++		return -EINVAL;
++	
++	lock_sock(sk);
++
++	if (!(hdev = hci_pi(sk)->hdev)) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	if (!(skb = bluez_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
++		goto done;
++
++	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
++		err = -EFAULT;
++		goto drop;
++	}
++
++	skb->pkt_type = *((unsigned char *) skb->data);
++	skb_pull(skb, 1);
++	skb->dev = (void *) hdev;
++
++	if (skb->pkt_type == HCI_COMMAND_PKT) {
++		u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data));
++		u16 ogf = cmd_opcode_ogf(opcode);
++		u16 ocf = cmd_opcode_ocf(opcode);
++
++		if (((ogf > HCI_SFLT_MAX_OGF) || 
++				!hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
++		    			!capable(CAP_NET_RAW)) {
++			err = -EPERM;
++			goto drop;
++		}
++
++		if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) {
++			skb_queue_tail(&hdev->raw_q, skb);
++			hci_sched_tx(hdev);
++		} else {
++			skb_queue_tail(&hdev->cmd_q, skb);
++			hci_sched_cmd(hdev);
++		}
++	} else {
++		if (!capable(CAP_NET_RAW)) {
++			err = -EPERM;
++			goto drop;
++		}
++
++		skb_queue_tail(&hdev->raw_q, skb);
++		hci_sched_tx(hdev);
++	}
++
++	err = len;
++
++done:
++	release_sock(sk);
++	return err;
++
++drop:
++	kfree_skb(skb);
++	goto done;
++}
++
+ int hci_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int len)
+ {
+ 	struct sock *sk = sock->sk;
+-	struct hci_filter flt;
++	struct hci_filter flt = { opcode: 0 };
+ 	int err = 0, opt = 0;
+ 
+-	DBG("sk %p, opt %d", sk, optname);
++	BT_DBG("sk %p, opt %d", sk, optname);
+ 
+ 	lock_sock(sk);
+ 
+ 	switch (optname) {
+ 	case HCI_DATA_DIR:
+-		if (get_user(opt, (int *)optval))
+-			return -EFAULT;
++		if (get_user(opt, (int *)optval)) {
++			err = -EFAULT;
++			break;
++		}
+ 
+ 		if (opt)
+ 			hci_pi(sk)->cmsg_mask |= HCI_CMSG_DIR;
+@@ -372,12 +456,31 @@
+ 			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_DIR;
+ 		break;
+ 
++	case HCI_TIME_STAMP:
++		if (get_user(opt, (int *)optval)) {
++			err = -EFAULT;
++			break;
++		}
++
++		if (opt)
++			hci_pi(sk)->cmsg_mask |= HCI_CMSG_TSTAMP;
++		else
++			hci_pi(sk)->cmsg_mask &= ~HCI_CMSG_TSTAMP;
++		break;
++
+ 	case HCI_FILTER:
+ 		len = MIN(len, sizeof(struct hci_filter));
+ 		if (copy_from_user(&flt, optval, len)) {
+ 			err = -EFAULT;
+ 			break;
+ 		}
++
++		if (!capable(CAP_NET_RAW)) {
++			flt.type_mask     &= hci_sec_filter.type_mask;
++			flt.event_mask[0] &= hci_sec_filter.event_mask[0];
++			flt.event_mask[1] &= hci_sec_filter.event_mask[1];
++		}
++		
+ 		memcpy(&hci_pi(sk)->filter, &flt, len);
+ 		break;
+ 
+@@ -409,6 +512,16 @@
+ 			return -EFAULT;
+ 		break;
+ 
++	case HCI_TIME_STAMP:
++		if (hci_pi(sk)->cmsg_mask & HCI_CMSG_TSTAMP)
++			opt = 1;
++		else 
++			opt = 0;
++
++		if (put_user(opt, optval))
++			return -EFAULT;
++		break;
++
+ 	case HCI_FILTER:
+ 		len = MIN(len, sizeof(struct hci_filter));
+ 		if (copy_to_user(optval, &hci_pi(sk)->filter, len))
+@@ -446,7 +559,7 @@
+ {
+ 	struct sock *sk;
+ 
+-	DBG("sock %p", sock);
++	BT_DBG("sock %p", sock);
+ 
+ 	if (sock->type != SOCK_RAW)
+ 		return -ESOCKTNOSUPPORT;
+@@ -464,44 +577,31 @@
+ 	sk->protocol = protocol;
+ 	sk->state    = BT_OPEN;
+ 
+-	/* Initialize filter */
+-	hci_pi(sk)->filter.type_mask  = (1<<HCI_EVENT_PKT);
+-	hci_pi(sk)->filter.event_mask[0] = ~0L;
+-	hci_pi(sk)->filter.event_mask[1] = ~0L;
+-
+ 	bluez_sock_link(&hci_sk_list, sk);
+ 
+ 	MOD_INC_USE_COUNT;
+-
+ 	return 0;
+ }
+ 
+ static int hci_sock_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+ {
+ 	struct hci_dev *hdev = (struct hci_dev *) ptr;
+-	struct sk_buff *skb;
+-
+-	DBG("hdev %s event %ld", hdev->name, event);
++	evt_si_device sd;
++	
++	BT_DBG("hdev %s event %ld", hdev->name, event);
+ 
+ 	/* Send event to sockets */
+-	if ((skb = bluez_skb_alloc(HCI_EVENT_HDR_SIZE + EVT_HCI_DEV_EVENT_SIZE, GFP_ATOMIC))) {
+-		hci_event_hdr eh = { EVT_HCI_DEV_EVENT, EVT_HCI_DEV_EVENT_SIZE };
+-		evt_hci_dev_event he = { event, hdev->id };
+-
+-		skb->pkt_type = HCI_EVENT_PKT;
+-		memcpy(skb_put(skb, HCI_EVENT_HDR_SIZE), &eh, HCI_EVENT_HDR_SIZE);
+-		memcpy(skb_put(skb, EVT_HCI_DEV_EVENT_SIZE), &he, EVT_HCI_DEV_EVENT_SIZE);
+-
+-		hci_send_to_sock(NULL, skb);
+-		kfree_skb(skb);
+-	}
+-
++	sd.event  = event;
++	sd.dev_id = hdev->id;
++	hci_si_event(NULL, EVT_SI_DEVICE, EVT_SI_DEVICE_SIZE, &sd);
++	
+ 	if (event == HCI_DEV_UNREG) {
+ 		struct sock *sk;
+ 
+ 		/* Detach sockets from device */
+ 		read_lock(&hci_sk_list.lock);
+ 		for (sk = hci_sk_list.head; sk; sk = sk->next) {
++			bh_lock_sock(sk);
+ 			if (hci_pi(sk)->hdev == hdev) {
+ 				hci_pi(sk)->hdev = NULL;
+ 				sk->err = EPIPE;
+@@ -510,6 +610,7 @@
+ 
+ 				hci_dev_put(hdev);
+ 			}
++			bh_unlock_sock(sk);
+ 		}
+ 		read_unlock(&hci_sk_list.lock);
+ 	}
+@@ -529,21 +630,19 @@
+ int hci_sock_init(void)
+ {
+ 	if (bluez_sock_register(BTPROTO_HCI, &hci_sock_family_ops)) {
+-		ERR("Can't register HCI socket");
++		BT_ERR("Can't register HCI socket");
+ 		return -EPROTO;
+ 	}
+ 
+ 	hci_register_notifier(&hci_sock_nblock);
+-
+ 	return 0;
+ }
+ 
+ int hci_sock_cleanup(void)
+ {
+ 	if (bluez_sock_unregister(BTPROTO_HCI))
+-		ERR("Can't unregister HCI socket");
++		BT_ERR("Can't unregister HCI socket");
+ 
+ 	hci_unregister_notifier(&hci_sock_nblock);
+-
+ 	return 0;
+ }
+diff -urN linux-2.4.18/net/bluetooth/l2cap.c linux-2.4.18-mh9/net/bluetooth/l2cap.c
+--- linux-2.4.18/net/bluetooth/l2cap.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/l2cap.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,2187 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ L2CAP core and sockets.
++ *
++ * $Id$
++ */
++#define VERSION "2.3"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/proc_fs.h>
++#include <linux/list.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include <net/bluetooth/l2cap.h>
++
++#ifndef L2CAP_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++static struct proto_ops l2cap_sock_ops;
++
++struct bluez_sock_list l2cap_sk_list = {
++	lock: RW_LOCK_UNLOCKED
++};
++
++static int l2cap_conn_del(struct hci_conn *conn, int err);
++
++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
++static void l2cap_chan_del(struct sock *sk, int err);
++static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
++
++static void __l2cap_sock_close(struct sock *sk, int reason);
++static void l2cap_sock_close(struct sock *sk);
++static void l2cap_sock_kill(struct sock *sk);
++
++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
++
++/* ----- L2CAP timers ------ */
++static void l2cap_sock_timeout(unsigned long arg)
++{
++	struct sock *sk = (struct sock *) arg;
++
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	bh_lock_sock(sk);
++	__l2cap_sock_close(sk, ETIMEDOUT);
++	bh_unlock_sock(sk);
++
++	l2cap_sock_kill(sk);
++	sock_put(sk);
++}
++
++static void l2cap_sock_set_timer(struct sock *sk, long timeout)
++{
++	BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout);
++
++	if (!mod_timer(&sk->timer, jiffies + timeout))
++		sock_hold(sk);
++}
++
++static void l2cap_sock_clear_timer(struct sock *sk)
++{
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
++		__sock_put(sk);
++}
++
++static void l2cap_sock_init_timer(struct sock *sk)
++{
++	init_timer(&sk->timer);
++	sk->timer.function = l2cap_sock_timeout;
++	sk->timer.data = (unsigned long)sk;
++}
++
++/* -------- L2CAP connections --------- */
++static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, __u8 status)
++{
++	struct l2cap_conn *conn;
++
++	if ((conn = hcon->l2cap_data))
++		return conn;
++
++	if (status)
++		return conn;
++
++	if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_ATOMIC)))
++		return NULL;
++	memset(conn, 0, sizeof(struct l2cap_conn));
++
++	hcon->l2cap_data = conn;
++	conn->hcon = hcon;
++	
++	conn->mtu = hcon->hdev->acl_mtu;
++	conn->src = &hcon->hdev->bdaddr;
++	conn->dst = &hcon->dst;
++	
++	spin_lock_init(&conn->lock);
++	conn->chan_list.lock = RW_LOCK_UNLOCKED;
++
++	BT_DBG("hcon %p conn %p", hcon, conn);
++
++	MOD_INC_USE_COUNT;
++	return conn;
++}
++
++static int l2cap_conn_del(struct hci_conn *hcon, int err)
++{
++	struct l2cap_conn *conn;
++	struct sock *sk;
++
++	if (!(conn = hcon->l2cap_data)) 
++		return 0;
++
++	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
++
++	if (conn->rx_skb)
++		kfree_skb(conn->rx_skb);
++
++	/* Kill channels */
++	while ((sk = conn->chan_list.head)) {
++		bh_lock_sock(sk);
++		l2cap_chan_del(sk, err);
++		bh_unlock_sock(sk);
++		l2cap_sock_kill(sk);
++	}
++
++	hcon->l2cap_data = NULL;
++	kfree(conn);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++/* -------- Socket interface ---------- */
++static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src)
++{
++	struct sock *sk;
++	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
++		if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src))
++			break;
++	}
++	return sk;
++}
++
++/* Find socket with psm and source bdaddr.
++ * Returns closest match.
++ */
++static struct sock *__l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
++{
++	struct sock *sk, *sk1 = NULL;
++
++	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
++		if (state && sk->state != state)
++			continue;
++
++		if (l2cap_pi(sk)->psm == psm) {
++			/* Exact match. */
++			if (!bacmp(&bluez_pi(sk)->src, src))
++				break;
++
++			/* Closest match */
++			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++				sk1 = sk;
++		}
++	}
++	return sk ? sk : sk1;
++}
++
++/* Find socket with given address (psm, src).
++ * Returns locked socket */
++static inline struct sock *l2cap_get_sock_by_psm(int state, __u16 psm, bdaddr_t *src)
++{
++	struct sock *s;
++	read_lock(&l2cap_sk_list.lock);
++	s = __l2cap_get_sock_by_psm(state, psm, src);
++	if (s) bh_lock_sock(s);
++	read_unlock(&l2cap_sk_list.lock);
++	return s;
++}
++
++static void l2cap_sock_destruct(struct sock *sk)
++{
++	BT_DBG("sk %p", sk);
++
++	skb_queue_purge(&sk->receive_queue);
++	skb_queue_purge(&sk->write_queue);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static void l2cap_sock_cleanup_listen(struct sock *parent)
++{
++	struct sock *sk;
++
++	BT_DBG("parent %p", parent);
++
++	/* Close not yet accepted channels */
++	while ((sk = bluez_accept_dequeue(parent, NULL)))
++		l2cap_sock_close(sk);
++
++	parent->state  = BT_CLOSED;
++	parent->zapped = 1;
++}
++
++/* Kill socket (only if zapped and orphan)
++ * Must be called on unlocked socket.
++ */
++static void l2cap_sock_kill(struct sock *sk)
++{
++	if (!sk->zapped || sk->socket)
++		return;
++
++	BT_DBG("sk %p state %d", sk, sk->state);
++
++	/* Kill poor orphan */
++	bluez_sock_unlink(&l2cap_sk_list, sk);
++	sk->dead = 1;
++	sock_put(sk);
++}
++
++/* Close socket.
++ */
++static void __l2cap_sock_close(struct sock *sk, int reason)
++{
++	BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
++
++	switch (sk->state) {
++	case BT_LISTEN:
++		l2cap_sock_cleanup_listen(sk);
++		break;
++
++	case BT_CONNECTED:
++	case BT_CONFIG:
++	case BT_CONNECT2:
++		if (sk->type == SOCK_SEQPACKET) {
++			struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++			l2cap_disconn_req req;
++
++			sk->state = BT_DISCONN;
++			l2cap_sock_set_timer(sk, sk->sndtimeo);
++
++			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
++		} else {
++			l2cap_chan_del(sk, reason);
++		}
++		break;
++
++	case BT_CONNECT:
++	case BT_DISCONN:
++		l2cap_chan_del(sk, reason);
++		break;
++
++	default:
++		sk->zapped = 1;
++		break;
++	};
++}
++
++/* Must be called on unlocked socket. */
++static void l2cap_sock_close(struct sock *sk)
++{
++	l2cap_sock_clear_timer(sk);
++	lock_sock(sk);
++	__l2cap_sock_close(sk, ECONNRESET);
++	release_sock(sk);
++	l2cap_sock_kill(sk);
++}
++
++static void l2cap_sock_init(struct sock *sk, struct sock *parent)
++{
++	struct l2cap_pinfo *pi = l2cap_pi(sk);
++
++	BT_DBG("sk %p", sk);
++
++	if (parent) {
++		sk->type = parent->type;
++		pi->imtu = l2cap_pi(parent)->imtu;
++		pi->omtu = l2cap_pi(parent)->omtu;
++		pi->link_mode = l2cap_pi(parent)->link_mode;
++	} else {
++		pi->imtu = L2CAP_DEFAULT_MTU;
++		pi->omtu = 0;
++		pi->link_mode = 0;
++	}
++
++	/* Default config options */
++	pi->conf_mtu = L2CAP_DEFAULT_MTU;
++	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
++}
++
++static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
++{
++	struct sock *sk;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
++		return NULL;
++
++	bluez_sock_init(sock, sk);
++	
++	sk->zapped   = 0;
++
++	sk->destruct = l2cap_sock_destruct;
++	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
++
++	sk->protocol = proto;
++	sk->state    = BT_OPEN;
++
++	l2cap_sock_init_timer(sk);
++
++	bluez_sock_link(&l2cap_sk_list, sk);
++
++	MOD_INC_USE_COUNT;
++	return sk;
++}
++
++static int l2cap_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	sock->state = SS_UNCONNECTED;
++
++	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW))
++		return -EPERM;
++	
++	sock->ops = &l2cap_sock_ops;
++
++	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
++		return -ENOMEM;
++
++	l2cap_sock_init(sk, NULL);
++	return 0;
++}
++
++static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
++{
++	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
++
++	if (!addr || addr->sa_family != AF_BLUETOOTH)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_OPEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	write_lock_bh(&l2cap_sk_list.lock);
++	if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
++		err = -EADDRINUSE;
++	} else {
++		/* Save source address */
++		bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr);
++		l2cap_pi(sk)->psm = la->l2_psm;
++		sk->sport = la->l2_psm;
++		sk->state = BT_BOUND;
++	}
++	write_unlock_bh(&l2cap_sk_list.lock);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_do_connect(struct sock *sk)
++{
++	bdaddr_t *src = &bluez_pi(sk)->src;
++	bdaddr_t *dst = &bluez_pi(sk)->dst;
++	struct l2cap_conn *conn;
++	struct hci_conn   *hcon;
++	struct hci_dev    *hdev;
++	int err = 0;
++
++	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
++
++	if (!(hdev = hci_get_route(dst, src)))
++		return -EHOSTUNREACH;
++
++	hci_dev_lock_bh(hdev);
++
++	err = -ENOMEM;
++
++	hcon = hci_connect(hdev, ACL_LINK, dst);
++	if (!hcon)
++		goto done;
++
++	conn = l2cap_conn_add(hcon, 0);
++	if (!conn) {
++		hci_conn_put(hcon);
++		goto done;
++	}
++
++	err = 0;
++
++	/* Update source addr of the socket */
++	bacpy(src, conn->src);
++
++	l2cap_chan_add(conn, sk, NULL);
++
++	sk->state = BT_CONNECT;
++	l2cap_sock_set_timer(sk, sk->sndtimeo);
++
++	if (hcon->state == BT_CONNECTED) {
++		if (sk->type == SOCK_SEQPACKET) {
++			l2cap_conn_req req;
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			req.psm  = l2cap_pi(sk)->psm;
++			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
++		} else {
++			l2cap_sock_clear_timer(sk);
++			sk->state = BT_CONNECTED;
++		}
++	}
++
++done:
++	hci_dev_unlock_bh(hdev);
++	hci_dev_put(hdev);
++	return err;
++}
++
++static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
++{
++	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	lock_sock(sk);
++
++	BT_DBG("sk %p", sk);
++
++	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
++		err = -EINVAL;
++		goto done;
++	}
++
++	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
++		err = -EINVAL;
++		goto done;
++	}
++
++	switch(sk->state) {
++	case BT_CONNECT:
++	case BT_CONNECT2:
++	case BT_CONFIG:
++		/* Already connecting */
++		goto wait;
++
++	case BT_CONNECTED:
++		/* Already connected */
++		goto done;
++
++	case BT_OPEN:
++	case BT_BOUND:
++		/* Can connect */
++		break;
++
++	default:
++		err = -EBADFD;
++		goto done;
++	}
++
++	/* Set destination address and psm */
++	bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr);
++	l2cap_pi(sk)->psm = la->l2_psm;
++
++	if ((err = l2cap_do_connect(sk)))
++		goto done;
++
++wait:
++	err = bluez_sock_wait_state(sk, BT_CONNECTED,
++			sock_sndtimeo(sk, flags & O_NONBLOCK));
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int l2cap_sock_listen(struct socket *sock, int backlog)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p backlog %d", sk, backlog);
++
++	lock_sock(sk);
++
++	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	if (!l2cap_pi(sk)->psm) {
++		err = -EINVAL;
++		goto done;
++	}
++
++	sk->max_ack_backlog = backlog;
++	sk->ack_backlog = 0;
++	sk->state = BT_LISTEN;
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct sock *sk = sock->sk, *nsk;
++	long timeo;
++	int err = 0;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_LISTEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
++
++	BT_DBG("sk %p timeo %ld", sk, timeo);
++
++	/* Wait for an incoming connection. (wake-one). */
++	add_wait_queue_exclusive(sk->sleep, &wait);
++	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->state != BT_LISTEN) {
++			err = -EBADFD;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	if (err)
++		goto done;
++
++	newsock->state = SS_CONNECTED;
++
++	BT_DBG("new socket %p", nsk);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
++{
++	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	addr->sa_family = AF_BLUETOOTH;
++	*len = sizeof(struct sockaddr_l2);
++
++	if (peer)
++		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->dst);
++	else
++		bacpy(&la->l2_bdaddr, &bluez_pi(sk)->src);
++
++	la->l2_psm = l2cap_pi(sk)->psm;
++	return 0;
++}
++
++static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (sk->err)
++		return sock_error(sk);
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	/* Check outgoing MTU */
++	if (len > l2cap_pi(sk)->omtu)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state == BT_CONNECTED)
++		err = l2cap_chan_send(sk, msg, len);
++	else
++		err = -ENOTCONN;
++
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
++{
++	struct sock *sk = sock->sk;
++	struct l2cap_options opts;
++	int err = 0, len;
++	__u32 opt;
++
++	BT_DBG("sk %p", sk);
++
++	lock_sock(sk);
++
++	switch (optname) {
++	case L2CAP_OPTIONS:
++		len = MIN(sizeof(opts), optlen);
++		if (copy_from_user((char *)&opts, optval, len)) {
++			err = -EFAULT;
++			break;
++		}
++		l2cap_pi(sk)->imtu  = opts.imtu;
++		l2cap_pi(sk)->omtu  = opts.omtu;
++		break;
++
++	case L2CAP_LM:
++		if (get_user(opt, (__u32 *)optval)) {
++			err = -EFAULT;
++			break;
++		}
++
++		l2cap_pi(sk)->link_mode = opt;
++		break;
++
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	}
++
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
++{
++	struct sock *sk = sock->sk;
++	struct l2cap_options opts;
++	struct l2cap_conninfo cinfo;
++	int len, err = 0; 
++
++	if (get_user(len, optlen))
++		return -EFAULT;
++
++	lock_sock(sk);
++
++	switch (optname) {
++	case L2CAP_OPTIONS:
++		opts.imtu     = l2cap_pi(sk)->imtu;
++		opts.omtu     = l2cap_pi(sk)->omtu;
++		opts.flush_to = l2cap_pi(sk)->flush_to;
++
++		len = MIN(len, sizeof(opts));
++		if (copy_to_user(optval, (char *)&opts, len))
++			err = -EFAULT;
++
++		break;
++
++	case L2CAP_LM:
++		if (put_user(l2cap_pi(sk)->link_mode, (__u32 *)optval))
++			err = -EFAULT;
++		break;
++
++	case L2CAP_CONNINFO:
++		if (sk->state != BT_CONNECTED) {
++			err = -ENOTCONN;
++			break;
++		}
++
++		cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle;
++
++		len = MIN(len, sizeof(cinfo));
++		if (copy_to_user(optval, (char *)&cinfo, len))
++			err = -EFAULT;
++
++		break;
++
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	}
++
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_shutdown(struct socket *sock, int how)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk) return 0;
++
++	lock_sock(sk);
++	if (!sk->shutdown) {
++		sk->shutdown = SHUTDOWN_MASK;
++		l2cap_sock_clear_timer(sk);
++		__l2cap_sock_close(sk, 0);
++
++		if (sk->linger)
++			err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
++	}
++	release_sock(sk);
++	return err;
++}
++
++static int l2cap_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++	int err;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk) return 0;
++
++	err = l2cap_sock_shutdown(sock, 2);
++
++	sock_orphan(sk);
++	l2cap_sock_kill(sk);
++	return err;
++}
++
++/* --------- L2CAP channels --------- */
++static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
++{
++	struct sock *s;
++	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
++		if (l2cap_pi(s)->dcid == cid)
++			break;
++	}
++	return s;
++}
++
++static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
++{
++	struct sock *s;
++	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
++		if (l2cap_pi(s)->scid == cid)
++			break;
++	}
++	return s;
++}
++
++/* Find channel with given SCID.
++ * Returns locked socket */
++static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
++{
++	struct sock *s;
++	read_lock(&l->lock);
++	s = __l2cap_get_chan_by_scid(l, cid);
++	if (s) bh_lock_sock(s);
++	read_unlock(&l->lock);
++	return s;
++}
++
++static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
++{
++	__u16 cid = 0x0040;
++
++	for (; cid < 0xffff; cid++) {
++		if(!__l2cap_get_chan_by_scid(l, cid))
++			return cid;
++	}
++
++	return 0;
++}
++
++static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
++{
++	sock_hold(sk);
++
++	if (l->head)
++		l2cap_pi(l->head)->prev_c = sk;
++
++	l2cap_pi(sk)->next_c = l->head;
++	l2cap_pi(sk)->prev_c = NULL;
++	l->head = sk;
++}
++
++static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
++{
++	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
++
++	write_lock(&l->lock);
++	if (sk == l->head)
++		l->head = next;
++
++	if (next)
++		l2cap_pi(next)->prev_c = prev;
++	if (prev)
++		l2cap_pi(prev)->next_c = next;
++	write_unlock(&l->lock);
++
++	__sock_put(sk);
++}
++
++static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++
++	BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
++
++	l2cap_pi(sk)->conn = conn;
++
++	if (sk->type == SOCK_SEQPACKET) {
++		/* Alloc CID for connection-oriented socket */
++		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
++	} else if (sk->type == SOCK_DGRAM) {
++		/* Connectionless socket */
++		l2cap_pi(sk)->scid = 0x0002;
++		l2cap_pi(sk)->dcid = 0x0002;
++		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
++	} else {
++		/* Raw socket can send/recv signalling messages only */
++		l2cap_pi(sk)->scid = 0x0001;
++		l2cap_pi(sk)->dcid = 0x0001;
++		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
++	}
++
++	__l2cap_chan_link(l, sk);
++
++	if (parent)
++		bluez_accept_enqueue(parent, sk);
++}
++
++static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	write_lock(&l->lock);
++	__l2cap_chan_add(conn, sk, parent);
++	write_unlock(&l->lock);
++}
++
++/* Delete channel. 
++ * Must be called on the locked socket. */
++static void l2cap_chan_del(struct sock *sk, int err)
++{
++	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++	struct sock *parent = bluez_pi(sk)->parent;
++
++	l2cap_sock_clear_timer(sk);
++
++	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
++
++	if (conn) { 
++		/* Unlink from channel list */
++		l2cap_chan_unlink(&conn->chan_list, sk);
++		l2cap_pi(sk)->conn = NULL;
++		hci_conn_put(conn->hcon);
++	}
++
++	sk->state  = BT_CLOSED;
++	sk->zapped = 1;
++
++	if (err)
++		sk->err = err;
++
++	if (parent)
++		parent->data_ready(parent, 0);
++	else
++		sk->state_change(sk);
++}
++
++static void l2cap_conn_ready(struct l2cap_conn *conn)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	struct sock *sk;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		bh_lock_sock(sk);
++
++		if (sk->type != SOCK_SEQPACKET) {
++			l2cap_sock_clear_timer(sk);
++			sk->state = BT_CONNECTED;
++			sk->state_change(sk);
++		} else if (sk->state == BT_CONNECT) {
++			l2cap_conn_req req;
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			req.psm  = l2cap_pi(sk)->psm;
++			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
++		}
++
++		bh_unlock_sock(sk);
++	}
++
++	read_unlock(&l->lock);
++}
++
++/* Notify sockets that we cannot guaranty reliability anymore */
++static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	struct sock *sk;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
++			sk->err = err;
++	}
++	read_unlock(&l->lock);
++}
++
++static void l2cap_chan_ready(struct sock *sk)
++{
++	struct sock *parent = bluez_pi(sk)->parent;
++
++	BT_DBG("sk %p, parent %p", sk, parent);
++
++	l2cap_pi(sk)->conf_state = 0;
++	l2cap_sock_clear_timer(sk);
++
++	if (!parent) {
++		/* Outgoing channel.
++		 * Wake up socket sleeping on connect.
++		 */
++		sk->state = BT_CONNECTED;
++		sk->state_change(sk);
++	} else {
++		/* Incomming channel.
++		 * Wake up socket sleeping on accept.
++		 */
++		parent->data_ready(parent, 0);
++	}
++}
++
++/* Copy frame to all raw sockets on that connection */
++void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
++{
++	struct l2cap_chan_list *l = &conn->chan_list;
++	struct sk_buff *nskb;
++	struct sock * sk;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		if (sk->type != SOCK_RAW)
++			continue;
++
++		/* Don't send frame to the socket it came from */
++		if (skb->sk == sk)
++			continue;
++
++		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
++			continue;
++
++		if (sock_queue_rcv_skb(sk, nskb))
++			kfree_skb(nskb);
++	}
++	read_unlock(&l->lock);
++}
++
++static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
++{
++	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
++	struct sk_buff *skb, **frag;
++	int err, hlen, count, sent=0;
++	l2cap_hdr *lh;
++
++	BT_DBG("sk %p len %d", sk, len);
++
++	/* First fragment (with L2CAP header) */
++	if (sk->type == SOCK_DGRAM)
++		hlen = L2CAP_HDR_SIZE + 2;
++	else
++		hlen = L2CAP_HDR_SIZE;
++
++	count = MIN(conn->mtu - hlen, len);
++
++	skb = bluez_skb_send_alloc(sk, hlen + count,
++			msg->msg_flags & MSG_DONTWAIT, &err);
++	if (!skb)
++		return err;
++
++	/* Create L2CAP header */
++	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
++	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++	lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
++
++	if (sk->type == SOCK_DGRAM)
++		put_unaligned(l2cap_pi(sk)->psm, (__u16 *) skb_put(skb, 2));
++
++	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
++		err = -EFAULT;
++		goto fail;
++	}
++
++	sent += count;
++	len  -= count;
++
++	/* Continuation fragments (no L2CAP header) */
++	frag = &skb_shinfo(skb)->frag_list;
++	while (len) {
++		count = MIN(conn->mtu, len);
++
++		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
++		if (!*frag)
++			goto fail;
++		
++		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
++			err = -EFAULT;
++			goto fail;
++		}
++
++		sent += count;
++		len  -= count;
++
++		frag = &(*frag)->next;
++	}
++
++	if ((err = hci_send_acl(conn->hcon, skb, 0)) < 0)
++		goto fail;
++
++	return sent;
++
++fail:
++	kfree_skb(skb);
++	return err;
++}
++
++/* --------- L2CAP signalling commands --------- */
++static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
++{
++	__u8 id;
++
++	/* Get next available identificator.
++	 *    1 - 199 are used by kernel.
++	 *  200 - 254 are used by utilities like l2ping, etc 
++	 */
++
++	spin_lock(&conn->lock);
++
++	if (++conn->tx_ident > 199)
++		conn->tx_ident = 1;
++
++	id = conn->tx_ident;
++
++	spin_unlock(&conn->lock);
++
++	return id;
++}
++
++static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
++				__u8 code, __u8 ident, __u16 dlen, void *data)
++{
++	struct sk_buff *skb, **frag;
++	l2cap_cmd_hdr *cmd;
++	l2cap_hdr *lh;
++	int len, count;
++
++	BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", conn, code, ident, dlen);
++
++	len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
++	count = MIN(conn->mtu, len);
++	
++	skb = bluez_skb_alloc(count, GFP_ATOMIC);
++	if (!skb)
++		return NULL;
++
++	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
++	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
++	lh->cid = __cpu_to_le16(0x0001);
++
++	cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
++	cmd->code  = code;
++	cmd->ident = ident;
++	cmd->len   = __cpu_to_le16(dlen);
++
++	if (dlen) {
++		count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
++		memcpy(skb_put(skb, count), data, count);
++		data += count;
++	}
++
++	len -= skb->len;
++	
++	/* Continuation fragments (no L2CAP header) */
++	frag = &skb_shinfo(skb)->frag_list;
++	while (len) {
++		count = MIN(conn->mtu, len);
++
++		*frag = bluez_skb_alloc(count, GFP_ATOMIC);
++		if (!*frag)
++			goto fail;
++		
++		memcpy(skb_put(*frag, count), data, count);
++
++		len  -= count;
++		data += count;
++		
++		frag = &(*frag)->next;
++	}
++
++	return skb;
++
++fail:
++	kfree_skb(skb);
++	return NULL;
++}
++
++static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
++{
++	__u8 ident = l2cap_get_ident(conn);
++	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
++
++	BT_DBG("code 0x%2.2x", code);
++
++	if (!skb)
++		return -ENOMEM;
++	return hci_send_acl(conn->hcon, skb, 0);
++}
++
++static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
++{
++	struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
++
++	BT_DBG("code 0x%2.2x", code);
++
++	if (!skb)
++		return -ENOMEM;
++	return hci_send_acl(conn->hcon, skb, 0);
++}
++
++static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
++{
++	l2cap_conf_opt *opt = *ptr;
++	int len;
++
++	len = L2CAP_CONF_OPT_SIZE + opt->len;
++	*ptr += len;
++
++	*type = opt->type;
++	*olen = opt->len;
++
++	switch (opt->len) {
++	case 1:
++		*val = *((__u8 *) opt->val);
++		break;
++
++	case 2:
++		*val = __le16_to_cpu(*((__u16 *)opt->val));
++		break;
++
++	case 4:
++		*val = __le32_to_cpu(*((__u32 *)opt->val));
++		break;
++
++	default:
++		*val = (unsigned long) opt->val;
++		break;
++	};
++
++	BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
++	return len;
++}
++
++static inline void l2cap_parse_conf_req(struct sock *sk, void *data, int len)
++{
++	int type, hint, olen; 
++	unsigned long val;
++	void *ptr = data;
++
++	BT_DBG("sk %p len %d", sk, len);
++
++	while (len >= L2CAP_CONF_OPT_SIZE) {
++		len -= l2cap_get_conf_opt(&ptr, &type, &olen, &val);
++
++		hint  = type & 0x80;
++		type &= 0x7f;
++
++		switch (type) {
++		case L2CAP_CONF_MTU:
++			l2cap_pi(sk)->conf_mtu = val;
++			break;
++
++		case L2CAP_CONF_FLUSH_TO:
++			l2cap_pi(sk)->flush_to = val;
++			break;
++
++		case L2CAP_CONF_QOS:
++			break;
++		
++		default:
++			if (hint)
++				break;
++
++			/* FIXME: Reject unknown option */
++			break;
++		};
++	}
++}
++
++static void l2cap_add_conf_opt(void **ptr, __u8 type, __u8 len, unsigned long val)
++{
++	register l2cap_conf_opt *opt = *ptr;
++
++	BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
++
++	opt->type = type;
++	opt->len  = len;
++
++	switch (len) {
++	case 1:
++		*((__u8 *) opt->val)  = val;
++		break;
++
++	case 2:
++		*((__u16 *) opt->val) = __cpu_to_le16(val);
++		break;
++
++	case 4:
++		*((__u32 *) opt->val) = __cpu_to_le32(val);
++		break;
++
++	default:
++		memcpy(opt->val, (void *) val, len);
++		break;
++	};
++
++	*ptr += L2CAP_CONF_OPT_SIZE + len;
++}
++
++static int l2cap_build_conf_req(struct sock *sk, void *data)
++{
++	struct l2cap_pinfo *pi = l2cap_pi(sk);
++	l2cap_conf_req *req = (l2cap_conf_req *) data;
++	void *ptr = req->data;
++
++	BT_DBG("sk %p", sk);
++
++	if (pi->imtu != L2CAP_DEFAULT_MTU)
++		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
++
++	/* FIXME. Need actual value of the flush timeout */
++	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
++	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
++
++	req->dcid  = __cpu_to_le16(pi->dcid);
++	req->flags = __cpu_to_le16(0);
++
++	return ptr - data;
++}
++
++static inline int l2cap_conf_output(struct sock *sk, void **ptr)
++{
++	struct l2cap_pinfo *pi = l2cap_pi(sk);
++	int result = 0;
++
++	/* Configure output options and let the other side know
++	 * which ones we don't like.
++	 */
++	if (pi->conf_mtu < pi->omtu) {
++		l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, pi->omtu);
++		result = L2CAP_CONF_UNACCEPT;
++	} else {
++		pi->omtu = pi->conf_mtu;
++	}
++
++	BT_DBG("sk %p result %d", sk, result);
++	return result;
++}
++
++static int l2cap_build_conf_rsp(struct sock *sk, void *data, int *result)
++{
++	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
++	void *ptr = rsp->data;
++	u16 flags = 0;
++
++	BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
++
++	if (result)
++		*result = l2cap_conf_output(sk, &ptr);
++	else	
++		flags |= 0x0001;
++
++	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
++	rsp->result = __cpu_to_le16(result ? *result : 0);
++	rsp->flags  = __cpu_to_le16(flags);
++
++	return ptr - data;
++}
++
++static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	struct l2cap_chan_list *list = &conn->chan_list;
++	l2cap_conn_req *req = (l2cap_conn_req *) data;
++	l2cap_conn_rsp rsp;
++	struct sock *sk, *parent;
++	int result = 0, status = 0;
++
++	__u16 dcid = 0, scid = __le16_to_cpu(req->scid);
++	__u16 psm  = req->psm;
++
++	BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
++
++	/* Check if we have socket listening on psm */
++	parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
++	if (!parent) {
++		result = L2CAP_CR_BAD_PSM;
++		goto sendresp;
++	}
++
++	result = L2CAP_CR_NO_MEM;
++
++	/* Check for backlog size */
++	if (parent->ack_backlog > parent->max_ack_backlog) {
++		BT_DBG("backlog full %d", parent->ack_backlog); 
++		goto response;
++	}
++
++	sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC);
++	if (!sk)
++		goto response;
++
++	write_lock(&list->lock);
++
++	/* Check if we already have channel with that dcid */
++	if (__l2cap_get_chan_by_dcid(list, scid)) {
++		write_unlock(&list->lock);
++		sk->zapped = 1;
++		l2cap_sock_kill(sk);
++		goto response;
++	}
++
++	hci_conn_hold(conn->hcon);
++
++	l2cap_sock_init(sk, parent);
++	bacpy(&bluez_pi(sk)->src, conn->src);
++	bacpy(&bluez_pi(sk)->dst, conn->dst);
++	l2cap_pi(sk)->psm  = psm;
++	l2cap_pi(sk)->dcid = scid;
++
++	__l2cap_chan_add(conn, sk, parent);
++	dcid = l2cap_pi(sk)->scid;
++
++	l2cap_sock_set_timer(sk, sk->sndtimeo);
++
++	/* Service level security */
++	result = L2CAP_CR_PEND;
++	status = L2CAP_CS_AUTHEN_PEND;
++	sk->state = BT_CONNECT2;
++	l2cap_pi(sk)->ident = cmd->ident;
++	
++	if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) {
++		if (!hci_conn_encrypt(conn->hcon))
++			goto done;
++	} else if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) {
++		if (!hci_conn_auth(conn->hcon))
++			goto done;
++	}
++
++	sk->state = BT_CONFIG;
++	result = status = 0;
++
++done:
++	write_unlock(&list->lock);
++
++response:
++	bh_unlock_sock(parent);
++
++sendresp:
++	rsp.scid   = __cpu_to_le16(scid);
++	rsp.dcid   = __cpu_to_le16(dcid);
++	rsp.result = __cpu_to_le16(result);
++	rsp.status = __cpu_to_le16(status);
++	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
++	return 0;
++}
++
++static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
++	__u16 scid, dcid, result, status;
++	struct sock *sk;
++	char req[128];
++
++	scid   = __le16_to_cpu(rsp->scid);
++	dcid   = __le16_to_cpu(rsp->dcid);
++	result = __le16_to_cpu(rsp->result);
++	status = __le16_to_cpu(rsp->status);
++
++	BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
++		return -ENOENT;
++
++	switch (result) {
++	case L2CAP_CR_SUCCESS:
++		sk->state = BT_CONFIG;
++		l2cap_pi(sk)->dcid = dcid;
++		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
++
++		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
++		break;
++
++	case L2CAP_CR_PEND:
++		break;
++
++	default:
++		l2cap_chan_del(sk, ECONNREFUSED);
++		break;
++	}
++
++	bh_unlock_sock(sk);
++	return 0;
++}
++
++static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_conf_req * req = (l2cap_conf_req *) data;
++	__u16 dcid, flags;
++	__u8 rsp[64];
++	struct sock *sk;
++	int result;
++
++	dcid  = __le16_to_cpu(req->dcid);
++	flags = __le16_to_cpu(req->flags);
++
++	BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
++		return -ENOENT;
++
++	l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
++
++	if (flags & 0x0001) {
++		/* Incomplete config. Send empty response. */
++		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
++		goto unlock;
++	}
++
++	/* Complete config. */
++	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
++
++	if (result)
++		goto unlock;
++
++	/* Output config done */
++	l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
++
++	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
++		sk->state = BT_CONNECTED;
++		l2cap_chan_ready(sk);
++	} else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
++		char req[64];
++		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
++	}
++
++unlock:
++	bh_unlock_sock(sk);
++	return 0;
++}
++
++static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
++	__u16 scid, flags, result;
++	struct sock *sk;
++	int err = 0;
++
++	scid   = __le16_to_cpu(rsp->scid);
++	flags  = __le16_to_cpu(rsp->flags);
++	result = __le16_to_cpu(rsp->result);
++
++	BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
++		return -ENOENT;
++
++	switch (result) {
++	case L2CAP_CONF_SUCCESS:
++		break;
++
++	case L2CAP_CONF_UNACCEPT:
++		if (++l2cap_pi(sk)->conf_retry < L2CAP_CONF_MAX_RETRIES) {
++			char req[128];
++			/* 
++			   It does not make sense to adjust L2CAP parameters 
++			   that are currently defined in the spec. We simply 
++			   resend config request that we sent earlier. It is
++			   stupid :) but it helps qualification testing
++			   which expects at least some response from us.
++			*/
++			l2cap_send_req(conn, L2CAP_CONF_REQ,
++				l2cap_build_conf_req(sk, req), req);
++			goto done;
++		}
++	default: 
++		sk->state = BT_DISCONN;
++		sk->err   = ECONNRESET;
++		l2cap_sock_set_timer(sk, HZ * 5);
++		{
++			l2cap_disconn_req req;
++			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
++			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
++		}
++		goto done;
++	}
++
++	if (flags & 0x01)
++		goto done;
++
++	/* Input config done */
++	l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
++
++	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
++		sk->state = BT_CONNECTED;
++		l2cap_chan_ready(sk);
++	}
++
++done:
++	bh_unlock_sock(sk);
++	return err;
++}
++
++static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_disconn_req *req = (l2cap_disconn_req *) data;
++	l2cap_disconn_rsp rsp;
++	__u16 dcid, scid;
++	struct sock *sk;
++
++	scid = __le16_to_cpu(req->scid);
++	dcid = __le16_to_cpu(req->dcid);
++
++	BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
++		return 0;
++
++	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
++	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
++	l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
++
++	sk->shutdown = SHUTDOWN_MASK;
++	
++	l2cap_chan_del(sk, ECONNRESET);
++	bh_unlock_sock(sk);
++
++	l2cap_sock_kill(sk);
++	return 0;
++}
++
++static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
++{
++	l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
++	__u16 dcid, scid;
++	struct sock *sk;
++
++	scid = __le16_to_cpu(rsp->scid);
++	dcid = __le16_to_cpu(rsp->dcid);
++
++	BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
++
++	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
++		return 0;
++	l2cap_chan_del(sk, 0);
++	bh_unlock_sock(sk);
++
++	l2cap_sock_kill(sk);
++	return 0;
++}
++
++static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
++{
++	__u8 *data = skb->data;
++	int len = skb->len;
++	l2cap_cmd_hdr cmd;
++	int err = 0;
++
++	while (len >= L2CAP_CMD_HDR_SIZE) {
++		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
++		data += L2CAP_CMD_HDR_SIZE;
++		len  -= L2CAP_CMD_HDR_SIZE;
++
++		cmd.len = __le16_to_cpu(cmd.len);
++
++		BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
++
++		if (cmd.len > len || !cmd.ident) {
++			BT_DBG("corrupted command");
++			break;
++		}
++
++		switch (cmd.code) {
++		case L2CAP_CONN_REQ:
++			err = l2cap_connect_req(conn, &cmd, data);
++			break;
++
++		case L2CAP_CONN_RSP:
++			err = l2cap_connect_rsp(conn, &cmd, data);
++			break;
++
++		case L2CAP_CONF_REQ:
++			err = l2cap_config_req(conn, &cmd, data);
++			break;
++
++		case L2CAP_CONF_RSP:
++			err = l2cap_config_rsp(conn, &cmd, data);
++			break;
++
++		case L2CAP_DISCONN_REQ:
++			err = l2cap_disconnect_req(conn, &cmd, data);
++			break;
++
++		case L2CAP_DISCONN_RSP:
++			err = l2cap_disconnect_rsp(conn, &cmd, data);
++			break;
++
++		case L2CAP_COMMAND_REJ:
++			/* FIXME: We should process this */
++			l2cap_raw_recv(conn, skb);
++			break;
++
++		case L2CAP_ECHO_REQ:
++			l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
++			break;
++
++		case L2CAP_ECHO_RSP:
++		case L2CAP_INFO_REQ:
++		case L2CAP_INFO_RSP:
++			l2cap_raw_recv(conn, skb);
++			break;
++
++		default:
++			BT_ERR("Uknown signaling command 0x%2.2x", cmd.code);
++			err = -EINVAL;
++			break;
++		};
++
++		if (err) {
++			l2cap_cmd_rej rej;
++			BT_DBG("error %d", err);
++
++			/* FIXME: Map err to a valid reason. */
++			rej.reason = __cpu_to_le16(0);
++			l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
++		}
++
++		data += cmd.len;
++		len  -= cmd.len;
++	}
++
++	kfree_skb(skb);
++}
++
++static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
++{
++	struct sock *sk;
++
++	sk = l2cap_get_chan_by_scid(&conn->chan_list, cid);
++	if (!sk) {
++		BT_DBG("unknown cid 0x%4.4x", cid);
++		goto drop;
++	}
++
++	BT_DBG("sk %p, len %d", sk, skb->len);
++
++	if (sk->state != BT_CONNECTED)
++		goto drop;
++
++	if (l2cap_pi(sk)->imtu < skb->len)
++		goto drop;
++
++	/* If socket recv buffers overflows we drop data here 
++	 * which is *bad* because L2CAP has to be reliable. 
++	 * But we don't have any other choice. L2CAP doesn't 
++	 * provide flow control mechanism */ 
++	
++	if (!sock_queue_rcv_skb(sk, skb))
++		goto done;
++
++drop:
++	kfree_skb(skb);
++
++done:
++	if (sk) bh_unlock_sock(sk);
++	return 0;
++}
++
++static inline int l2cap_conless_channel(struct l2cap_conn *conn, __u16 psm, struct sk_buff *skb)
++{
++	struct sock *sk;
++
++	sk = l2cap_get_sock_by_psm(0, psm, conn->src);
++	if (!sk)
++		goto drop;
++
++	BT_DBG("sk %p, len %d", sk, skb->len);
++
++	if (sk->state != BT_BOUND && sk->state != BT_CONNECTED)
++		goto drop;
++
++	if (l2cap_pi(sk)->imtu < skb->len)
++		goto drop;
++
++	if (!sock_queue_rcv_skb(sk, skb))
++		goto done;
++
++drop:
++	kfree_skb(skb);
++
++done:
++	if (sk) bh_unlock_sock(sk);
++	return 0;
++}
++
++static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
++{
++	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
++	__u16 cid, psm, len;
++
++	skb_pull(skb, L2CAP_HDR_SIZE);
++	cid = __le16_to_cpu(lh->cid);
++	len = __le16_to_cpu(lh->len);
++
++	BT_DBG("len %d, cid 0x%4.4x", len, cid);
++
++	switch (cid) {
++	case 0x0001:
++		l2cap_sig_channel(conn, skb);
++		break;
++
++	case 0x0002:
++		psm = get_unaligned((__u16 *) skb->data);
++		skb_pull(skb, 2);
++		l2cap_conless_channel(conn, psm, skb);
++		break;
++		
++	default:
++		l2cap_data_channel(conn, cid, skb);
++		break;
++	}
++}
++
++/* ------------ L2CAP interface with lower layer (HCI) ------------- */
++
++static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
++{
++	int exact = 0, lm1 = 0, lm2 = 0;
++	register struct sock *sk;
++
++	if (type != ACL_LINK)
++		return 0;
++
++	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
++
++	/* Find listening sockets and check their link_mode */
++	read_lock(&l2cap_sk_list.lock);
++	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
++		if (sk->state != BT_LISTEN)
++			continue;
++
++		if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) {
++			lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
++			exact++;
++		} else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++			lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
++	}
++	read_unlock(&l2cap_sk_list.lock);
++
++	return exact ? lm1 : lm2;
++}
++
++static int l2cap_connect_cfm(struct hci_conn *hcon, __u8 status)
++{
++	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
++
++	if (hcon->type != ACL_LINK)
++		return 0;
++
++	if (!status) {
++		struct l2cap_conn *conn;
++
++		conn = l2cap_conn_add(hcon, status);
++		if (conn)
++			l2cap_conn_ready(conn);
++	} else 
++		l2cap_conn_del(hcon, bterr(status));
++	
++	return 0;
++}
++
++static int l2cap_disconn_ind(struct hci_conn *hcon, __u8 reason)
++{
++	BT_DBG("hcon %p reason %d", hcon, reason);
++
++	if (hcon->type != ACL_LINK)
++		return 0;
++
++	l2cap_conn_del(hcon, bterr(reason));
++	return 0;
++}
++
++static int l2cap_auth_cfm(struct hci_conn *hcon, __u8 status)
++{
++	struct l2cap_chan_list *l;
++	struct l2cap_conn *conn;
++	l2cap_conn_rsp rsp;
++	struct sock *sk;
++	int result;
++	
++	if (!(conn = hcon->l2cap_data))
++		return 0;
++	l = &conn->chan_list;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		bh_lock_sock(sk);
++
++		if (sk->state != BT_CONNECT2 ||
++				(l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) {
++			bh_unlock_sock(sk);
++			continue;
++		}
++
++		if (!status) {
++			sk->state = BT_CONFIG;
++			result = 0;
++		} else {
++			sk->state = BT_DISCONN;
++			l2cap_sock_set_timer(sk, HZ/10);
++			result = L2CAP_CR_SEC_BLOCK;
++		}
++
++		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
++		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
++		rsp.result = __cpu_to_le16(result);
++		rsp.status = __cpu_to_le16(0);
++		l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP,
++			L2CAP_CONN_RSP_SIZE, &rsp);
++
++		bh_unlock_sock(sk);
++	}
++
++	read_unlock(&l->lock);
++	return 0;
++}
++
++static int l2cap_encrypt_cfm(struct hci_conn *hcon, __u8 status)
++{
++	struct l2cap_chan_list *l;
++	struct l2cap_conn *conn;
++	l2cap_conn_rsp rsp;
++	struct sock *sk;
++	int result;
++	
++	if (!(conn = hcon->l2cap_data))
++		return 0;
++	l = &conn->chan_list;
++
++	BT_DBG("conn %p", conn);
++
++	read_lock(&l->lock);
++
++	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
++		bh_lock_sock(sk);
++
++		if (sk->state != BT_CONNECT2) {
++			bh_unlock_sock(sk);
++			continue;
++		}
++
++		if (!status) {
++			sk->state = BT_CONFIG;
++			result = 0;
++		} else {
++			sk->state = BT_DISCONN;
++			l2cap_sock_set_timer(sk, HZ/10);
++			result = L2CAP_CR_SEC_BLOCK;
++		}
++
++		rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
++		rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
++		rsp.result = __cpu_to_le16(result);
++		rsp.status = __cpu_to_le16(0);
++		l2cap_send_rsp(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, 
++			L2CAP_CONN_RSP_SIZE, &rsp);
++
++		bh_unlock_sock(sk);
++	}
++
++	read_unlock(&l->lock);
++	return 0;
++}
++
++static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, __u16 flags)
++{
++	struct l2cap_conn *conn = hcon->l2cap_data;
++
++	if (!conn && !(conn = l2cap_conn_add(hcon, 0)))
++		goto drop;
++
++	BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
++
++	if (flags & ACL_START) {
++		l2cap_hdr *hdr;
++		int len;
++
++		if (conn->rx_len) {
++			BT_ERR("Unexpected start frame (len %d)", skb->len);
++			kfree_skb(conn->rx_skb);
++			conn->rx_skb = NULL;
++			conn->rx_len = 0;
++			l2cap_conn_unreliable(conn, ECOMM);
++		}
++
++		if (skb->len < 2) {
++			BT_ERR("Frame is too short (len %d)", skb->len);
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		hdr = (l2cap_hdr *) skb->data;
++		len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
++
++		if (len == skb->len) {
++			/* Complete frame received */
++			l2cap_recv_frame(conn, skb);
++			return 0;
++		}
++
++		BT_DBG("Start: total len %d, frag len %d", len, skb->len);
++
++		if (skb->len > len) {
++			BT_ERR("Frame is too long (len %d, expected len %d)",
++				skb->len, len);
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		/* Allocate skb for the complete frame including header */
++		conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC);
++		if (!conn->rx_skb)
++			goto drop;
++
++		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
++		conn->rx_len = len - skb->len;
++	} else {
++		BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
++
++		if (!conn->rx_len) {
++			BT_ERR("Unexpected continuation frame (len %d)", skb->len);
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		if (skb->len > conn->rx_len) {
++			BT_ERR("Fragment is too long (len %d, expected %d)",
++					skb->len, conn->rx_len);
++			kfree_skb(conn->rx_skb);
++			conn->rx_skb = NULL;
++			conn->rx_len = 0;
++			l2cap_conn_unreliable(conn, ECOMM);
++			goto drop;
++		}
++
++		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
++		conn->rx_len -= skb->len;
++
++		if (!conn->rx_len) {
++			/* Complete frame received */
++			l2cap_recv_frame(conn, conn->rx_skb);
++			conn->rx_skb = NULL;
++		}
++	}
++
++drop:
++	kfree_skb(skb);
++	return 0;
++}
++
++/* ----- Proc fs support ------ */
++static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
++{
++	struct l2cap_pinfo *pi;
++	struct sock *sk;
++	char *ptr = buf;
++
++	read_lock_bh(&list->lock);
++
++	for (sk = list->head; sk; sk = sk->next) {
++		pi = l2cap_pi(sk);
++		ptr += sprintf(ptr, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), 
++				sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu,
++				pi->link_mode);
++	}
++
++	read_unlock_bh(&list->lock);
++
++	ptr += sprintf(ptr, "\n");
++	return ptr - buf;
++}
++
++static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
++{
++	char *ptr = buf;
++	int len;
++
++	BT_DBG("count %d, offset %ld", count, offset);
++
++	ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
++	len  = ptr - buf;
++
++	if (len <= count + offset)
++		*eof = 1;
++
++	*start = buf + offset;
++	len -= offset;
++
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++
++static struct proto_ops l2cap_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	l2cap_sock_release,
++	bind:		l2cap_sock_bind,
++	connect:	l2cap_sock_connect,
++	listen:		l2cap_sock_listen,
++	accept:		l2cap_sock_accept,
++	getname:	l2cap_sock_getname,
++	sendmsg:	l2cap_sock_sendmsg,
++	recvmsg:	bluez_sock_recvmsg,
++	poll:		bluez_sock_poll,
++	socketpair:	sock_no_socketpair,
++	ioctl:		sock_no_ioctl,
++	shutdown:	l2cap_sock_shutdown,
++	setsockopt:	l2cap_sock_setsockopt,
++	getsockopt:	l2cap_sock_getsockopt,
++	mmap:		sock_no_mmap
++};
++
++static struct net_proto_family l2cap_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		l2cap_sock_create
++};
++
++static struct hci_proto l2cap_hci_proto = {
++	name:		"L2CAP",
++	id:		HCI_PROTO_L2CAP,
++	connect_ind:	l2cap_connect_ind,
++	connect_cfm:	l2cap_connect_cfm,
++	disconn_ind:	l2cap_disconn_ind,
++	recv_acldata:	l2cap_recv_acldata,
++	auth_cfm:	l2cap_auth_cfm,
++	encrypt_cfm:	l2cap_encrypt_cfm
++};
++
++int __init l2cap_init(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops))) {
++		BT_ERR("Can't register L2CAP socket");
++		return err;
++	}
++
++	if ((err = hci_register_proto(&l2cap_hci_proto))) {
++		BT_ERR("Can't register L2CAP protocol");
++		return err;
++	}
++
++	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
++
++	BT_INFO("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	return 0;
++}
++
++void l2cap_cleanup(void)
++{
++	remove_proc_entry("bluetooth/l2cap", NULL);
++
++	/* Unregister socket and protocol */
++	if (bluez_sock_unregister(BTPROTO_L2CAP))
++		BT_ERR("Can't unregister L2CAP socket");
++
++	if (hci_unregister_proto(&l2cap_hci_proto))
++		BT_ERR("Can't unregister L2CAP protocol");
++}
++
++void l2cap_load(void)
++{
++	/* Dummy function to trigger automatic L2CAP module loading by 
++	   other modules that use L2CAP sockets but do not use any other
++	   symbols from it. */
++	return;
++}
++
++EXPORT_SYMBOL(l2cap_load);
++
++module_init(l2cap_init);
++module_exit(l2cap_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
++MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/net/bluetooth/l2cap_core.c linux-2.4.18-mh9/net/bluetooth/l2cap_core.c
+--- linux-2.4.18/net/bluetooth/l2cap_core.c	Sun Sep 30 21:26:08 2001
++++ linux-2.4.18-mh9/net/bluetooth/l2cap_core.c	Thu Jan  1 01:00:00 1970
+@@ -1,2316 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * BlueZ L2CAP core and sockets.
+- *
+- * $Id$
+- */
+-#define VERSION "1.1"
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/kernel.h>
+-#include <linux/major.h>
+-#include <linux/sched.h>
+-#include <linux/slab.h>
+-#include <linux/poll.h>
+-#include <linux/fcntl.h>
+-#include <linux/init.h>
+-#include <linux/skbuff.h>
+-#include <linux/interrupt.h>
+-#include <linux/socket.h>
+-#include <linux/skbuff.h>
+-#include <linux/proc_fs.h>
+-#include <linux/list.h>
+-#include <net/sock.h>
+-
+-#include <asm/system.h>
+-#include <asm/uaccess.h>
+-
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/l2cap.h>
+-#include <net/bluetooth/l2cap_core.h>
+-
+-#ifndef L2CAP_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#endif
+-
+-struct proto_ops l2cap_sock_ops;
+-
+-struct bluez_sock_list l2cap_sk_list = {
+-	lock: RW_LOCK_UNLOCKED
+-};
+-
+-struct list_head l2cap_iff_list = LIST_HEAD_INIT(l2cap_iff_list);
+-rwlock_t l2cap_rt_lock = RW_LOCK_UNLOCKED;
+-
+-static int  l2cap_conn_del(struct l2cap_conn *conn, int err);
+-
+-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent);
+-static void l2cap_chan_del(struct sock *sk, int err);
+-static int  l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len);
+-
+-static void l2cap_sock_close(struct sock *sk);
+-static void l2cap_sock_kill(struct sock *sk);
+-
+-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data);
+-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data);
+-
+-/* -------- L2CAP interfaces & routing --------- */
+-/* Add/delete L2CAP interface.
+- * Must be called with locked rt_lock
+- */ 
+-
+-static void l2cap_iff_add(struct hci_dev *hdev)
+-{
+-	struct l2cap_iff *iff;
+-
+-	DBG("%s", hdev->name);
+-
+-	DBG("iff_list %p next %p prev %p", &l2cap_iff_list, l2cap_iff_list.next, l2cap_iff_list.prev);
+-
+-	/* Allocate new interface and lock HCI device */
+-	if (!(iff = kmalloc(sizeof(struct l2cap_iff), GFP_KERNEL))) {
+-		ERR("Can't allocate new interface %s", hdev->name);
+-		return;
+-	}
+-	memset(iff, 0, sizeof(struct l2cap_iff));
+-
+-	hci_dev_hold(hdev);
+-	hdev->l2cap_data = iff;
+-	iff->hdev   = hdev;
+-	iff->mtu    = hdev->acl_mtu - HCI_ACL_HDR_SIZE;
+-	iff->bdaddr = &hdev->bdaddr;
+-
+-	spin_lock_init(&iff->lock);
+-	INIT_LIST_HEAD(&iff->conn_list);
+-
+-	list_add(&iff->list, &l2cap_iff_list);
+-}
+-
+-static void l2cap_iff_del(struct hci_dev *hdev)
+-{
+-	struct l2cap_iff *iff;
+-
+-	if (!(iff = hdev->l2cap_data))
+-		return;
+-
+-	DBG("%s iff %p", hdev->name, iff);
+-
+-	list_del(&iff->list);
+-
+-	l2cap_iff_lock(iff);
+-
+-	/* Drop connections */
+-	while (!list_empty(&iff->conn_list)) {
+-		struct l2cap_conn *c;
+-
+-		c = list_entry(iff->conn_list.next, struct l2cap_conn, list);
+-		l2cap_conn_del(c, ENODEV);
+-	}
+-
+-	l2cap_iff_unlock(iff);
+-
+-	/* Unlock HCI device */
+-	hdev->l2cap_data = NULL;
+-	hci_dev_put(hdev);
+-
+-	kfree(iff);
+-}
+-
+-/* Get route. Returns L2CAP interface.
+- * Must be called with locked rt_lock
+- */
+-static struct l2cap_iff *l2cap_get_route(bdaddr_t *src, bdaddr_t *dst)
+-{
+-	struct list_head *p;
+-	int use_src;
+-
+-	DBG("%s -> %s", batostr(src), batostr(dst));
+-
+-	use_src = bacmp(src, BDADDR_ANY) ? 0 : 1;
+-	
+-	/* Simple routing: 
+-	 * 	No source address - find interface with bdaddr != dst 
+-	 *	Source address 	  - find interface with bdaddr == src 
+-	 */
+-
+-	list_for_each(p, &l2cap_iff_list) {
+-		struct l2cap_iff *iff;
+-
+-		iff = list_entry(p, struct l2cap_iff, list);
+-
+-		if (use_src && !bacmp(iff->bdaddr, src))
+-			return iff;
+-		else if (bacmp(iff->bdaddr, dst))
+-			return iff;
+-	}
+-	return NULL;
+-}
+-
+-/* ----- L2CAP timers ------ */
+-static void l2cap_sock_timeout(unsigned long arg)
+-{
+-	struct sock *sk = (struct sock *) arg;
+-
+-	DBG("sock %p state %d", sk, sk->state);
+-
+-	bh_lock_sock(sk);
+-	switch (sk->state) {
+-	case BT_DISCONN:
+-		l2cap_chan_del(sk, ETIMEDOUT);
+-		break;
+-
+-	default:
+-		sk->err = ETIMEDOUT;
+-		sk->state_change(sk);
+-		break;
+-	};
+-	bh_unlock_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-	sock_put(sk);
+-}
+-
+-static void l2cap_sock_set_timer(struct sock *sk, long timeout)
+-{
+-	DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
+-
+-	if (!mod_timer(&sk->timer, jiffies + timeout))
+-		sock_hold(sk);
+-}
+-
+-static void l2cap_sock_clear_timer(struct sock *sk)
+-{
+-	DBG("sock %p state %d", sk, sk->state);
+-
+-	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
+-		__sock_put(sk);
+-}
+-
+-static void l2cap_sock_init_timer(struct sock *sk)
+-{
+-	init_timer(&sk->timer);
+-	sk->timer.function = l2cap_sock_timeout;
+-	sk->timer.data = (unsigned long)sk;
+-}
+-
+-static void l2cap_conn_timeout(unsigned long arg)
+-{
+-	struct l2cap_conn *conn = (void *)arg;
+-	
+-	DBG("conn %p state %d", conn, conn->state);
+-
+-	if (conn->state == BT_CONNECTED) {
+-		hci_disconnect(conn->hconn, 0x13);
+-	}
+-		
+-	return;
+-}
+-
+-static void l2cap_conn_set_timer(struct l2cap_conn *conn, long timeout)
+-{
+-	DBG("conn %p state %d timeout %ld", conn, conn->state, timeout);
+-
+-	mod_timer(&conn->timer, jiffies + timeout);
+-}
+-
+-static void l2cap_conn_clear_timer(struct l2cap_conn *conn)
+-{
+-	DBG("conn %p state %d", conn, conn->state);
+-
+-	del_timer(&conn->timer);
+-}
+-
+-static void l2cap_conn_init_timer(struct l2cap_conn *conn)
+-{
+-	init_timer(&conn->timer);
+-	conn->timer.function = l2cap_conn_timeout;
+-	conn->timer.data = (unsigned long)conn;
+-}
+-
+-/* -------- L2CAP connections --------- */
+-/* Add new connection to the interface.
+- * Interface must be locked
+- */
+-static struct l2cap_conn *l2cap_conn_add(struct l2cap_iff *iff, bdaddr_t *dst)
+-{
+-	struct l2cap_conn *conn;
+-	bdaddr_t *src = iff->bdaddr;
+-
+-	if (!(conn = kmalloc(sizeof(struct l2cap_conn), GFP_KERNEL)))
+-		return NULL;
+-
+-	memset(conn, 0, sizeof(struct l2cap_conn));
+-
+-	conn->state = BT_OPEN;
+-	conn->iff   = iff;
+-	bacpy(&conn->src, src);
+-	bacpy(&conn->dst, dst);
+-
+-	spin_lock_init(&conn->lock);
+-	conn->chan_list.lock = RW_LOCK_UNLOCKED;
+-
+-	l2cap_conn_init_timer(conn);
+-	
+-	__l2cap_conn_link(iff, conn);
+-
+-	DBG("%s -> %s, %p", batostr(src), batostr(dst), conn);
+-
+-	MOD_INC_USE_COUNT;
+-
+-	return conn;
+-}
+-
+-/* Delete connection on the interface.
+- * Interface must be locked
+- */
+-static int l2cap_conn_del(struct l2cap_conn *conn, int err)
+-{
+-	struct sock *sk;
+-
+-	DBG("conn %p, state %d, err %d", conn, conn->state, err);
+-
+-	l2cap_conn_clear_timer(conn);
+-	__l2cap_conn_unlink(conn->iff, conn);
+-
+-	conn->state = BT_CLOSED;
+-
+-	if (conn->rx_skb)
+-		kfree_skb(conn->rx_skb);
+-
+-	/* Kill channels */
+-	while ((sk = conn->chan_list.head)) {
+-		bh_lock_sock(sk);
+-		l2cap_sock_clear_timer(sk);
+-		l2cap_chan_del(sk, err);
+-		bh_unlock_sock(sk);
+-
+-		l2cap_sock_kill(sk);
+-	}
+-
+-	kfree(conn);
+-
+-	MOD_DEC_USE_COUNT;
+-	return 0;
+-}
+-
+-static inline struct l2cap_conn *l2cap_get_conn_by_addr(struct l2cap_iff *iff, bdaddr_t *dst)
+-{
+-	struct list_head *p;
+-
+-	list_for_each(p, &iff->conn_list) {
+-		struct l2cap_conn *c;
+-
+-		c = list_entry(p, struct l2cap_conn, list);
+-		if (!bacmp(&c->dst, dst))
+-			return c;
+-	}
+-	return NULL;
+-}
+-
+-int l2cap_connect(struct sock *sk)
+-{
+-	bdaddr_t *src = &l2cap_pi(sk)->src;
+-	bdaddr_t *dst = &l2cap_pi(sk)->dst;
+-	struct l2cap_conn *conn;
+-	struct l2cap_iff *iff;
+-	int err = 0;
+-
+-	DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+-
+-	read_lock_bh(&l2cap_rt_lock);
+-
+-	/* Get route to remote BD address */
+-	if (!(iff = l2cap_get_route(src, dst))) {
+-		err = -EHOSTUNREACH;
+-		goto done;
+-	}
+-
+-	/* Update source addr of the socket */
+-	bacpy(src, iff->bdaddr);
+-
+-	l2cap_iff_lock(iff);
+-
+-	if (!(conn = l2cap_get_conn_by_addr(iff, dst))) {
+-		/* Connection doesn't exist */
+-		if (!(conn = l2cap_conn_add(iff, dst))) {
+-			l2cap_iff_unlock(iff);
+-			err = -ENOMEM;
+-			goto done;
+-		}
+-		conn->out = 1;
+-	}
+-
+-	l2cap_iff_unlock(iff);
+-
+-	l2cap_chan_add(conn, sk, NULL);
+-
+-	sk->state = BT_CONNECT;
+-	l2cap_sock_set_timer(sk, sk->sndtimeo);
+-
+-	switch (conn->state) {
+-	case BT_CONNECTED:
+-		if (sk->type == SOCK_SEQPACKET) {
+-			l2cap_conn_req req;
+-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-			req.psm  = l2cap_pi(sk)->psm;
+-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+-		} else {
+-			l2cap_sock_clear_timer(sk);
+-			sk->state = BT_CONNECTED;
+-		}
+-		break;
+-
+-	case BT_CONNECT:
+-		break;
+-
+-	default:
+-		/* Create ACL connection */
+-		conn->state = BT_CONNECT;
+-		hci_connect(iff->hdev, dst);
+-		break;
+-	};
+-
+-done:
+-	read_unlock_bh(&l2cap_rt_lock);
+-	return err;
+-}
+-
+-/* ------ Channel queues for listening sockets ------ */
+-void l2cap_accept_queue(struct sock *parent, struct sock *sk)
+-{
+-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+-
+-	DBG("parent %p, sk %p", parent, sk);
+-
+-	sock_hold(sk);
+-	l2cap_pi(sk)->parent = parent;
+-	l2cap_pi(sk)->next_q = NULL;
+-
+-	if (!q->head) {
+-		q->head = q->tail = sk;
+-	} else {
+-		struct sock *tail = q->tail;
+-
+-		l2cap_pi(sk)->prev_q = tail;
+-		l2cap_pi(tail)->next_q = sk;
+-		q->tail = sk;
+-	}
+-
+-	parent->ack_backlog++;
+-}
+-
+-void l2cap_accept_unlink(struct sock *sk)
+-{
+-	struct sock *parent = l2cap_pi(sk)->parent;
+-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+-	struct sock *next, *prev;
+-
+-	DBG("sk %p", sk);
+-
+-	next = l2cap_pi(sk)->next_q;
+-	prev = l2cap_pi(sk)->prev_q;
+-
+-	if (sk == q->head)
+-		q->head = next;
+-	if (sk == q->tail)
+-		q->tail = prev;
+-
+-	if (next)
+-		l2cap_pi(next)->prev_q = prev;
+-	if (prev)
+-		l2cap_pi(prev)->next_q = next;
+-
+-	l2cap_pi(sk)->parent = NULL;
+-
+-	parent->ack_backlog--;
+-	__sock_put(sk);
+-}
+-
+-/* Get next connected channel in queue. */
+-struct sock *l2cap_accept_dequeue(struct sock *parent, int state)
+-{
+-	struct l2cap_accept_q *q = &l2cap_pi(parent)->accept_q;
+-	struct sock *sk;
+-
+-	for (sk = q->head; sk; sk = l2cap_pi(sk)->next_q) {
+-		if (!state || sk->state == state) {
+-			l2cap_accept_unlink(sk);
+-			break;
+-		}
+-	}
+-
+-	DBG("parent %p, sk %p", parent, sk);
+-
+-	return sk;
+-}
+-
+-/* -------- Socket interface ---------- */
+-static struct sock *__l2cap_get_sock_by_addr(struct sockaddr_l2 *addr)
+-{
+-	bdaddr_t *src = &addr->l2_bdaddr;
+-	__u16 psm = addr->l2_psm;
+-	struct sock *sk;
+-
+-	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+-		if (l2cap_pi(sk)->psm == psm &&
+-		    !bacmp(&l2cap_pi(sk)->src, src))
+-			break;
+-	}
+-
+-	return sk;
+-}
+-
+-/* Find socket listening on psm and source bdaddr.
+- * Returns closest match.
+- */
+-static struct sock *l2cap_get_sock_listen(bdaddr_t *src, __u16 psm)
+-{
+-	struct sock *sk, *sk1 = NULL;
+-
+-	read_lock(&l2cap_sk_list.lock);
+-
+-	for (sk = l2cap_sk_list.head; sk; sk = sk->next) {
+-		struct l2cap_pinfo *pi;
+-
+-		if (sk->state != BT_LISTEN)
+-			continue;
+-
+-		pi = l2cap_pi(sk);
+-
+-		if (pi->psm == psm) {
+-			/* Exact match. */
+-			if (!bacmp(&pi->src, src))
+-				break;
+-
+-			/* Closest match */
+-			if (!bacmp(&pi->src, BDADDR_ANY))
+-				sk1 = sk;
+-		}
+-	}
+-
+-	read_unlock(&l2cap_sk_list.lock);
+-
+-	return sk ? sk : sk1;
+-}
+-
+-static void l2cap_sock_destruct(struct sock *sk)
+-{
+-	DBG("sk %p", sk);
+-
+-	skb_queue_purge(&sk->receive_queue);
+-	skb_queue_purge(&sk->write_queue);
+-
+-	MOD_DEC_USE_COUNT;
+-}
+-
+-static void l2cap_sock_cleanup_listen(struct sock *parent)
+-{
+-	struct sock *sk;
+-
+-	DBG("parent %p", parent);
+-
+-	/* Close not yet accepted channels */
+-	while ((sk = l2cap_accept_dequeue(parent, 0)))
+-		l2cap_sock_close(sk);
+-
+-	parent->state  = BT_CLOSED;
+-	parent->zapped = 1;
+-}
+-
+-/* Kill socket (only if zapped and orphan)
+- * Must be called on unlocked socket.
+- */
+-static void l2cap_sock_kill(struct sock *sk)
+-{
+-	if (!sk->zapped || sk->socket)
+-		return;
+-
+-	DBG("sk %p state %d", sk, sk->state);
+-
+-	/* Kill poor orphan */
+-	bluez_sock_unlink(&l2cap_sk_list, sk);
+-	sk->dead = 1;
+-	sock_put(sk);
+-}
+-
+-/* Close socket.
+- * Must be called on unlocked socket.
+- */
+-static void l2cap_sock_close(struct sock *sk)
+-{
+-	struct l2cap_conn *conn;
+-
+-	l2cap_sock_clear_timer(sk);
+-
+-	lock_sock(sk);
+-
+-	conn = l2cap_pi(sk)->conn;
+-
+-	DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
+-
+-	switch (sk->state) {
+-	case BT_LISTEN:
+-		l2cap_sock_cleanup_listen(sk);
+-		break;
+-
+-	case BT_CONNECTED:
+-	case BT_CONFIG:
+-		if (sk->type == SOCK_SEQPACKET) {
+-			l2cap_disconn_req req;
+-
+-			sk->state = BT_DISCONN;
+-
+-			req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-			l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+-
+-			l2cap_sock_set_timer(sk, sk->sndtimeo);
+-		} else {
+-			l2cap_chan_del(sk, ECONNRESET);
+-		}
+-		break;
+-
+-	case BT_CONNECT:
+-	case BT_DISCONN:
+-		l2cap_chan_del(sk, ECONNRESET);
+-		break;
+-
+-	default:
+-		sk->zapped = 1;
+-		break;
+-	};
+-
+-	release_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-}
+-
+-static void l2cap_sock_init(struct sock *sk, struct sock *parent)
+-{
+-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+-
+-	DBG("sk %p", sk);
+-
+-	if (parent) {
+-		sk->type = parent->type;
+-
+-		pi->imtu = l2cap_pi(parent)->imtu;
+-		pi->omtu = l2cap_pi(parent)->omtu;
+-	} else {
+-		pi->imtu = L2CAP_DEFAULT_MTU;
+-		pi->omtu = 0;
+-	}
+-
+-	/* Default config options */
+-	pi->conf_mtu = L2CAP_DEFAULT_MTU;
+-	pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+-}
+-
+-static struct sock *l2cap_sock_alloc(struct socket *sock, int proto, int prio)
+-{
+-	struct sock *sk;
+-
+-	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
+-		return NULL;
+-
+-	sock_init_data(sock, sk);
+-
+-	sk->zapped   = 0;
+-
+-	sk->destruct = l2cap_sock_destruct;
+-	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
+-
+-	sk->protocol = proto;
+-	sk->state    = BT_OPEN;
+-
+-	l2cap_sock_init_timer(sk);
+-
+-	bluez_sock_link(&l2cap_sk_list, sk);
+-
+-	MOD_INC_USE_COUNT;
+-
+-	return sk;
+-}
+-
+-static int l2cap_sock_create(struct socket *sock, int protocol)
+-{
+-	struct sock *sk;
+-
+-	DBG("sock %p", sock);
+-
+-	sock->state = SS_UNCONNECTED;
+-
+-	if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_RAW)
+-		return -ESOCKTNOSUPPORT;
+-
+-	sock->ops = &l2cap_sock_ops;
+-
+-	if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL)))
+-		return -ENOMEM;
+-
+-	l2cap_sock_init(sk, NULL);
+-
+-	return 0;
+-}
+-
+-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+-{
+-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
+-
+-	if (!addr || addr->sa_family != AF_BLUETOOTH)
+-		return -EINVAL;
+-
+-	lock_sock(sk);
+-
+-	if (sk->state != BT_OPEN) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	write_lock(&l2cap_sk_list.lock);
+-
+-	if (la->l2_psm && __l2cap_get_sock_by_addr(la)) {
+-		err = -EADDRINUSE;
+-		goto unlock;
+-	}
+-
+-	/* Save source address */
+-	bacpy(&l2cap_pi(sk)->src, &la->l2_bdaddr);
+-	l2cap_pi(sk)->psm = la->l2_psm;
+-	sk->state = BT_BOUND;
+-
+-unlock:
+-	write_unlock(&l2cap_sk_list.lock);
+-
+-done:
+-	release_sock(sk);
+-
+-	return err;
+-}
+-
+-static int l2cap_sock_w4_connect(struct sock *sk, int flags)
+-{
+-	DECLARE_WAITQUEUE(wait, current);
+-	long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
+-	int err = 0;
+-
+-	DBG("sk %p", sk);
+-
+-	add_wait_queue(sk->sleep, &wait);
+-	current->state = TASK_INTERRUPTIBLE;
+-
+-	while (sk->state != BT_CONNECTED) {
+-		if (!timeo) {
+-			err = -EAGAIN;
+-			break;
+-		}
+-
+-		release_sock(sk);
+-		timeo = schedule_timeout(timeo);
+-		lock_sock(sk);
+-
+-		err = 0;
+-		if (sk->state == BT_CONNECTED)
+-			break;
+-
+-		if (sk->err) {
+-			err = sock_error(sk);
+-			break;
+-		}
+-
+-		if (signal_pending(current)) {
+-			err = sock_intr_errno(timeo);
+-			break;
+-		}
+-	}
+-	current->state = TASK_RUNNING;
+-	remove_wait_queue(sk->sleep, &wait);
+-
+-	return err;
+-}
+-
+-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+-{
+-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	lock_sock(sk);
+-
+-	DBG("sk %p", sk);
+-
+-	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
+-		err = -EINVAL;
+-		goto done;
+-	}
+-
+-	if (sk->state != BT_OPEN && sk->state != BT_BOUND) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	if (sk->type == SOCK_SEQPACKET && !la->l2_psm) {
+-		err = -EINVAL;
+-		goto done;
+-	}
+-
+-	/* Set destination address and psm */
+-	bacpy(&l2cap_pi(sk)->dst, &la->l2_bdaddr);
+-	l2cap_pi(sk)->psm = la->l2_psm;
+-
+-	if ((err = l2cap_connect(sk)))
+-		goto done;
+-
+-	err = l2cap_sock_w4_connect(sk, flags);
+-
+-done:
+-	release_sock(sk);
+-	return err;
+-}
+-
+-int l2cap_sock_listen(struct socket *sock, int backlog)
+-{
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	DBG("sk %p backlog %d", sk, backlog);
+-
+-	lock_sock(sk);
+-
+-	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	if (!l2cap_pi(sk)->psm) {
+-		err = -EINVAL;
+-		goto done;
+-	}
+-
+-	sk->max_ack_backlog = backlog;
+-	sk->ack_backlog = 0;
+-	sk->state = BT_LISTEN;
+-
+-done:
+-	release_sock(sk);
+-	return err;
+-}
+-
+-int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+-{
+-	DECLARE_WAITQUEUE(wait, current);
+-	struct sock *sk = sock->sk, *ch;
+-	long timeo;
+-	int err = 0;
+-
+-	lock_sock(sk);
+-
+-	if (sk->state != BT_LISTEN) {
+-		err = -EBADFD;
+-		goto done;
+-	}
+-
+-	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
+-
+-	DBG("sk %p timeo %ld", sk, timeo);
+-
+-	/* Wait for an incoming connection. (wake-one). */
+-	add_wait_queue_exclusive(sk->sleep, &wait);
+-	current->state = TASK_INTERRUPTIBLE;
+-	while (!(ch = l2cap_accept_dequeue(sk, BT_CONNECTED))) {
+-		if (!timeo) {
+-			err = -EAGAIN;
+-			break;
+-		}
+-
+-		release_sock(sk);
+-		timeo = schedule_timeout(timeo);
+-		lock_sock(sk);
+-
+-		if (sk->state != BT_LISTEN) {
+-			err = -EBADFD;
+-			break;
+-		}
+-
+-		if (signal_pending(current)) {
+-			err = sock_intr_errno(timeo);
+-			break;
+-		}
+-	}
+-	current->state = TASK_RUNNING;
+-	remove_wait_queue(sk->sleep, &wait);
+-
+-	if (err)
+-		goto done;
+-
+-	sock_graft(ch, newsock);
+-	newsock->state = SS_CONNECTED;
+-
+-	DBG("new socket %p", ch);
+-
+-done:
+-	release_sock(sk);
+-
+-	return err;
+-}
+-
+-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+-{
+-	struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
+-	struct sock *sk = sock->sk;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	addr->sa_family = AF_BLUETOOTH;
+-	*len = sizeof(struct sockaddr_l2);
+-
+-	if (peer)
+-		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->dst);
+-	else
+-		bacpy(&la->l2_bdaddr, &l2cap_pi(sk)->src);
+-
+-	la->l2_psm = l2cap_pi(sk)->psm;
+-
+-	return 0;
+-}
+-
+-static int l2cap_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
+-{
+-	struct sock *sk = sock->sk;
+-	int err = 0;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	if (sk->err)
+-		return sock_error(sk);
+-
+-	if (msg->msg_flags & MSG_OOB)
+-		return -EOPNOTSUPP;
+-
+-	lock_sock(sk);
+-
+-	if (sk->state == BT_CONNECTED)
+-		err = l2cap_chan_send(sk, msg, len);
+-	else
+-		err = -ENOTCONN;
+-
+-	release_sock(sk);
+-	return err;
+-}
+-
+-static int l2cap_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm)
+-{
+-	struct sock *sk = sock->sk;
+-	int noblock = flags & MSG_DONTWAIT;
+-	int copied, err;
+-	struct sk_buff *skb;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	if (flags & (MSG_OOB))
+-		return -EOPNOTSUPP;
+-
+-	if (sk->state == BT_CLOSED)
+-		return 0;
+-
+-	if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
+-		return err;
+-
+-	msg->msg_namelen = 0;
+-
+-	copied = skb->len;
+-	if (len < copied) {
+-		msg->msg_flags |= MSG_TRUNC;
+-		copied = len;
+-	}
+-
+-	skb->h.raw = skb->data;
+-	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+-
+-	skb_free_datagram(sk, skb);
+-
+-	return err ? : copied;
+-}
+-
+-int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
+-{
+-	struct sock *sk = sock->sk;
+-	struct l2cap_options opts;
+-	int err = 0;
+-
+-	DBG("sk %p", sk);
+-
+-	lock_sock(sk);
+-
+-	switch (optname) {
+-	case L2CAP_OPTIONS:
+-		if (copy_from_user((char *)&opts, optval, optlen)) {
+-			err = -EFAULT;
+-			break;
+-		}
+-		l2cap_pi(sk)->imtu = opts.imtu;
+-		l2cap_pi(sk)->omtu = opts.omtu;
+-		break;
+-
+-	default:
+-		err = -ENOPROTOOPT;
+-		break;
+-	};
+-
+-	release_sock(sk);
+-	return err;
+-}
+-
+-int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
+-{
+-	struct sock *sk = sock->sk;
+-	struct l2cap_options opts;
+-	struct l2cap_conninfo cinfo;
+-	int len, err = 0; 
+-
+-	if (get_user(len, optlen))
+-		return -EFAULT;
+-
+-	lock_sock(sk);
+-
+-	switch (optname) {
+-	case L2CAP_OPTIONS:
+-		opts.imtu     = l2cap_pi(sk)->imtu;
+-		opts.omtu     = l2cap_pi(sk)->omtu;
+-		opts.flush_to = l2cap_pi(sk)->flush_to;
+-
+-		len = MIN(len, sizeof(opts));
+-		if (copy_to_user(optval, (char *)&opts, len))
+-			err = -EFAULT;
+-
+-		break;
+-
+-	case L2CAP_CONNINFO:
+-		if (sk->state != BT_CONNECTED) {
+-			err = -ENOTCONN;
+-			break;
+-		}
+-
+-		cinfo.hci_handle = l2cap_pi(sk)->conn->hconn->handle;
+-
+-		len = MIN(len, sizeof(cinfo));
+-		if (copy_to_user(optval, (char *)&cinfo, len))
+-			err = -EFAULT;
+-
+-		break;
+-
+-	default:
+-		err = -ENOPROTOOPT;
+-		break;
+-	};
+-
+-	release_sock(sk);
+-	return err;
+-}
+-
+-static unsigned int l2cap_sock_poll(struct file * file, struct socket *sock, poll_table *wait)
+-{
+-	struct sock *sk = sock->sk;
+-	struct l2cap_accept_q *aq;
+-	unsigned int mask;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	poll_wait(file, sk->sleep, wait);
+-	mask = 0;
+-
+-	if (sk->err || !skb_queue_empty(&sk->error_queue))
+-		mask |= POLLERR;
+-
+-	if (sk->shutdown == SHUTDOWN_MASK)
+-		mask |= POLLHUP;
+-
+-	aq = &l2cap_pi(sk)->accept_q;
+-	if (!skb_queue_empty(&sk->receive_queue) || aq->head || (sk->shutdown & RCV_SHUTDOWN))
+-		mask |= POLLIN | POLLRDNORM;
+-
+-	if (sk->state == BT_CLOSED)
+-		mask |= POLLHUP;
+-
+-	if (sock_writeable(sk))
+-		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
+-	else
+-		set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags);
+-
+-	return mask;
+-}
+-
+-static int l2cap_sock_release(struct socket *sock)
+-{
+-	struct sock *sk = sock->sk;
+-
+-	DBG("sock %p, sk %p", sock, sk);
+-
+-	if (!sk)
+-		return 0;
+-
+-	sock_orphan(sk);
+-
+-	l2cap_sock_close(sk);
+-
+-	return 0;
+-}
+-
+-/* --------- L2CAP channels --------- */
+-static struct sock * __l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+-		if (l2cap_pi(s)->dcid == cid)
+-			break;
+-	}
+-
+-	return s;
+-}
+-
+-static inline struct sock *l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	read_lock(&l->lock);
+-	s = __l2cap_get_chan_by_dcid(l, cid);
+-	read_unlock(&l->lock);
+-
+-	return s;
+-}
+-
+-static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+-		if (l2cap_pi(s)->scid == cid)
+-			break;
+-	}
+-
+-	return s;
+-}
+-static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, __u16 cid)
+-{
+-	struct sock *s;
+-
+-	read_lock(&l->lock);
+-	s = __l2cap_get_chan_by_scid(l, cid);
+-	read_unlock(&l->lock);
+-
+-	return s;
+-}
+-
+-static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
+-{
+-	struct sock *s;
+-
+-	for (s = l->head; s; s = l2cap_pi(s)->next_c) {
+-		if (l2cap_pi(s)->ident == ident)
+-			break;
+-	}
+-
+-	return s;
+-}
+-
+-static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, __u8 ident)
+-{
+-	struct sock *s;
+-
+-	read_lock(&l->lock);
+-	s = __l2cap_get_chan_by_ident(l, ident);
+-	read_unlock(&l->lock);
+-
+-	return s;
+-}
+-
+-static __u16 l2cap_alloc_cid(struct l2cap_chan_list *l)
+-{
+-	__u16 cid = 0x0040;
+-
+-	for (; cid < 0xffff; cid++) {
+-		if(!__l2cap_get_chan_by_scid(l, cid))
+-			return cid;
+-	}
+-
+-	return 0;
+-}
+-
+-static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk)
+-{
+-	sock_hold(sk);
+-
+-	if (l->head)
+-		l2cap_pi(l->head)->prev_c = sk;
+-
+-	l2cap_pi(sk)->next_c = l->head;
+-	l2cap_pi(sk)->prev_c = NULL;
+-	l->head = sk;
+-}
+-
+-static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk)
+-{
+-	struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c;
+-
+-	write_lock(&l->lock);
+-	if (sk == l->head)
+-		l->head = next;
+-
+-	if (next)
+-		l2cap_pi(next)->prev_c = prev;
+-	if (prev)
+-		l2cap_pi(prev)->next_c = next;
+-	write_unlock(&l->lock);
+-
+-	__sock_put(sk);
+-}
+-
+-static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-
+-	DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+-
+-	l2cap_conn_clear_timer(conn);
+-
+-	atomic_inc(&conn->refcnt);
+-	l2cap_pi(sk)->conn = conn;
+-
+-	if (sk->type == SOCK_SEQPACKET) {
+-		/* Alloc CID for normal socket */
+-		l2cap_pi(sk)->scid = l2cap_alloc_cid(l);
+-	} else {
+-		/* Raw socket can send only signalling messages */
+-		l2cap_pi(sk)->scid = 0x0001;
+-		l2cap_pi(sk)->dcid = 0x0001;
+-		l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+-	}
+-
+-	__l2cap_chan_link(l, sk);
+-
+-	if (parent)
+-		l2cap_accept_queue(parent, sk);
+-}
+-
+-static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-
+-	write_lock(&l->lock);
+-	__l2cap_chan_add(conn, sk, parent);
+-	write_unlock(&l->lock);
+-}
+-
+-/* Delete channel. 
+- * Must be called on the locked socket. */
+-static void l2cap_chan_del(struct sock *sk, int err)
+-{
+-	struct l2cap_conn *conn;
+-	struct sock *parent;
+-
+-	conn = l2cap_pi(sk)->conn;
+-	parent = l2cap_pi(sk)->parent;
+-
+-	DBG("sk %p, conn %p, err %d", sk, conn, err);
+-
+-	if (parent) {
+-		/* Unlink from parent accept queue */
+-		bh_lock_sock(parent);
+-		l2cap_accept_unlink(sk);
+-		bh_unlock_sock(parent);
+-	}
+-
+-	if (conn) { 
+-		long timeout;
+-
+-		/* Unlink from channel list */
+-		l2cap_chan_unlink(&conn->chan_list, sk);
+-		l2cap_pi(sk)->conn = NULL;
+-
+-		if (conn->out)
+-			timeout = L2CAP_DISCONN_TIMEOUT;
+-		else
+-			timeout = L2CAP_CONN_IDLE_TIMEOUT;
+-		
+-		if (atomic_dec_and_test(&conn->refcnt) && conn->state == BT_CONNECTED) {
+-			/* Schedule Baseband disconnect */
+-			l2cap_conn_set_timer(conn, timeout);
+-		}
+-	}
+-
+-	sk->state  = BT_CLOSED;
+-	sk->err    = err;
+-	sk->state_change(sk);
+-
+-	sk->zapped = 1;
+-}
+-
+-static void l2cap_conn_ready(struct l2cap_conn *conn)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-	struct sock *sk;
+-
+-	DBG("conn %p", conn);
+-
+-	read_lock(&l->lock);
+-
+-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+-		bh_lock_sock(sk);
+-
+-		if (sk->type != SOCK_SEQPACKET) {
+-			sk->state = BT_CONNECTED;
+-			sk->state_change(sk);
+-			l2cap_sock_clear_timer(sk);
+-		} else if (sk->state == BT_CONNECT) {
+-			l2cap_conn_req req;
+-			req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-			req.psm  = l2cap_pi(sk)->psm;
+-			l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req);
+-
+-			l2cap_sock_set_timer(sk, sk->sndtimeo);
+-		}
+-
+-		bh_unlock_sock(sk);
+-	}
+-
+-	read_unlock(&l->lock);
+-}
+-
+-static void l2cap_chan_ready(struct sock *sk)
+-{
+-	struct sock *parent = l2cap_pi(sk)->parent;
+-
+-	DBG("sk %p, parent %p", sk, parent);
+-
+-	l2cap_pi(sk)->conf_state = 0;
+-	l2cap_sock_clear_timer(sk);
+-
+-	if (!parent) {
+-		/* Outgoing channel.
+-		 * Wake up socket sleeping on connect.
+-		 */
+-		sk->state = BT_CONNECTED;
+-		sk->state_change(sk);
+-	} else {
+-		/* Incomming channel.
+-		 * Wake up socket sleeping on accept.
+-		 */
+-		parent->data_ready(parent, 1);
+-	}
+-}
+-
+-/* Copy frame to all raw sockets on that connection */
+-void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+-{
+-	struct l2cap_chan_list *l = &conn->chan_list;
+-	struct sk_buff *nskb;
+-	struct sock * sk;
+-
+-	DBG("conn %p", conn);
+-
+-	read_lock(&l->lock);
+-	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
+-		if (sk->type != SOCK_RAW)
+-			continue;
+-
+-		/* Don't send frame to the socket it came from */
+-		if (skb->sk == sk)
+-			continue;
+-
+-		if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
+-			continue;
+-
+-		skb_queue_tail(&sk->receive_queue, nskb);
+-		sk->data_ready(sk, nskb->len);
+-	}
+-	read_unlock(&l->lock);
+-}
+-
+-static int l2cap_chan_send(struct sock *sk, struct msghdr *msg, int len)
+-{
+-	struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+-	struct sk_buff *skb, **frag;
+-	int err, size, count, sent=0;
+-	l2cap_hdr *lh;
+-
+-	/* Check outgoing MTU */
+-	if (len > l2cap_pi(sk)->omtu)
+-		return -EINVAL;
+-
+-	DBG("sk %p len %d", sk, len);
+-
+-	/* First fragment (with L2CAP header) */
+-	count = MIN(conn->iff->mtu - L2CAP_HDR_SIZE, len);
+-	size  = L2CAP_HDR_SIZE + count;
+-	if (!(skb = bluez_skb_send_alloc(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)))
+-		return err;
+-
+-	/* Create L2CAP header */
+-	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+-	lh->len = __cpu_to_le16(len);
+-	lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-
+-	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
+-		err = -EFAULT;
+-		goto fail;
+-	}
+-
+-	sent += count;
+-	len  -= count;
+-
+-	/* Continuation fragments (no L2CAP header) */
+-	frag = &skb_shinfo(skb)->frag_list;
+-	while (len) {
+-		count = MIN(conn->iff->mtu, len);
+-
+-		*frag = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
+-		if (!*frag)
+-			goto fail;
+-		
+-		if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) {
+-			err = -EFAULT;
+-			goto fail;
+-		}
+-
+-		sent += count;
+-		len  -= count;
+-
+-		frag = &(*frag)->next;
+-	}
+-
+-	if ((err = hci_send_acl(conn->hconn, skb, 0)) < 0)
+-		goto fail;
+-
+-	return sent;
+-
+-fail:
+-	kfree_skb(skb);
+-	return err;
+-}
+-
+-/* --------- L2CAP signalling commands --------- */
+-static inline __u8 l2cap_get_ident(struct l2cap_conn *conn)
+-{
+-	__u8 id;
+-
+-	/* Get next available identificator.
+-	 *    1 - 199 are used by kernel.
+-	 *  200 - 254 are used by utilities like l2ping, etc 
+-	 */
+-
+-	spin_lock(&conn->lock);
+-
+-	if (++conn->tx_ident > 199)
+-		conn->tx_ident = 1;
+-
+-	id = conn->tx_ident;
+-
+-	spin_unlock(&conn->lock);
+-
+-	return id;
+-}
+-
+-static inline struct sk_buff *l2cap_build_cmd(__u8 code, __u8 ident, __u16 len, void *data)
+-{
+-	struct sk_buff *skb;
+-	l2cap_cmd_hdr *cmd;
+-	l2cap_hdr *lh;
+-	int size;
+-
+-	DBG("code 0x%2.2x, ident 0x%2.2x, len %d", code, ident, len);
+-
+-	size = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + len;
+-	if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+-		return NULL;
+-
+-	lh = (l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+-	lh->len = __cpu_to_le16(L2CAP_CMD_HDR_SIZE + len);
+-	lh->cid = __cpu_to_le16(0x0001);
+-
+-	cmd = (l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
+-	cmd->code  = code;
+-	cmd->ident = ident;
+-	cmd->len   = __cpu_to_le16(len);
+-
+-	if (len)
+-		memcpy(skb_put(skb, len), data, len);
+-
+-	return skb;
+-}
+-
+-static int l2cap_send_req(struct l2cap_conn *conn, __u8 code, __u16 len, void *data)
+-{
+-	struct sk_buff *skb;
+-	__u8 ident;
+-
+-	DBG("code 0x%2.2x", code);
+-
+-	ident = l2cap_get_ident(conn);
+-	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
+-		return -ENOMEM;
+-	return hci_send_acl(conn->hconn, skb, 0);
+-}
+-
+-static int l2cap_send_rsp(struct l2cap_conn *conn, __u8 ident, __u8 code, __u16 len, void *data)
+-{
+-	struct sk_buff *skb;
+-
+-	DBG("code 0x%2.2x", code);
+-
+-	if (!(skb = l2cap_build_cmd(code, ident, len, data)))
+-		return -ENOMEM;
+-	return hci_send_acl(conn->hconn, skb, 0);
+-}
+-
+-static inline int l2cap_get_conf_opt(__u8 **ptr, __u8 *type, __u32 *val)
+-{
+-	l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
+-	int len;
+-
+-	*type = opt->type;
+-	switch (opt->len) {
+-	case 1:
+-		*val = *((__u8 *) opt->val);
+-		break;
+-
+-	case 2:
+-		*val = __le16_to_cpu(*((__u16 *)opt->val));
+-		break;
+-
+-	case 4:
+-		*val = __le32_to_cpu(*((__u32 *)opt->val));
+-		break;
+-
+-	default:
+-		*val = 0L;
+-		break;
+-	};
+-
+-	DBG("type 0x%2.2x len %d val 0x%8.8x", *type, opt->len, *val);
+-
+-	len = L2CAP_CONF_OPT_SIZE + opt->len;
+-
+-	*ptr += len;
+-
+-	return len;
+-}
+-
+-static inline void l2cap_parse_conf_req(struct sock *sk, char *data, int len)
+-{
+-	__u8 type, hint; __u32 val;
+-	__u8 *ptr = data;
+-
+-	DBG("sk %p len %d", sk, len);
+-
+-	while (len >= L2CAP_CONF_OPT_SIZE) {
+-		len -= l2cap_get_conf_opt(&ptr, &type, &val);
+-
+-		hint  = type & 0x80;
+-		type &= 0x7f;
+-
+-		switch (type) {
+-		case L2CAP_CONF_MTU:
+-			l2cap_pi(sk)->conf_mtu = val;
+-			break;
+-
+-		case L2CAP_CONF_FLUSH_TO:
+-			l2cap_pi(sk)->flush_to = val;
+-			break;
+-
+-		case L2CAP_CONF_QOS:
+-			break;
+-		
+-		default:
+-			if (hint)
+-				break;
+-
+-			/* FIXME: Reject unknon option */
+-			break;
+-		};
+-	}
+-}
+-
+-static inline void l2cap_add_conf_opt(__u8 **ptr, __u8 type, __u8 len, __u32 val)
+-{
+-	register l2cap_conf_opt *opt = (l2cap_conf_opt *) (*ptr);
+-
+-	DBG("type 0x%2.2x len %d val 0x%8.8x", type, len, val);
+-
+-	opt->type = type;
+-	opt->len  = len;
+-	switch (len) {
+-	case 1:
+-		*((__u8 *) opt->val)  = val;
+-		break;
+-
+-	case 2:
+-		*((__u16 *) opt->val) = __cpu_to_le16(val);
+-		break;
+-
+-	case 4:
+-		*((__u32 *) opt->val) = __cpu_to_le32(val);
+-		break;
+-	};
+-
+-	*ptr += L2CAP_CONF_OPT_SIZE + len;
+-}
+-
+-static int l2cap_build_conf_req(struct sock *sk, __u8 *data)
+-{
+-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+-	l2cap_conf_req *req = (l2cap_conf_req *) data;
+-	__u8 *ptr = req->data;
+-
+-	DBG("sk %p", sk);
+-
+-	if (pi->imtu != L2CAP_DEFAULT_MTU)
+-		l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+-
+-	/* FIXME. Need actual value of the flush timeout */
+-	//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
+-	//   l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
+-
+-	req->dcid  = __cpu_to_le16(pi->dcid);
+-	req->flags = __cpu_to_le16(0);
+-
+-	return ptr - data;
+-}
+-
+-static int l2cap_conf_output(struct sock *sk, __u8 **ptr)
+-{
+-	struct l2cap_pinfo *pi = l2cap_pi(sk);
+-	int result = 0;
+-
+-	/* Configure output options and let other side know
+-	 * which ones we don't like.
+-	 */
+-	if (pi->conf_mtu < pi->omtu) {
+-		l2cap_add_conf_opt(ptr, L2CAP_CONF_MTU, 2, l2cap_pi(sk)->omtu);
+-		result = L2CAP_CONF_UNACCEPT;
+-	} else {
+-		pi->omtu = pi->conf_mtu;
+-	}
+-
+-	DBG("sk %p result %d", sk, result);
+-	return result;
+-}
+-
+-static int l2cap_build_conf_rsp(struct sock *sk, __u8 *data, int *result)
+-{
+-	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data;
+-	__u8 *ptr = rsp->data;
+-
+-	DBG("sk %p complete %d", sk, result ? 1 : 0);
+-
+-	if (result)
+-		*result = l2cap_conf_output(sk, &ptr);
+-
+-	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-	rsp->result = __cpu_to_le16(result ? *result : 0);
+-	rsp->flags  = __cpu_to_le16(0);
+-
+-	return ptr - data;
+-}
+-
+-static inline int l2cap_connect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	struct l2cap_chan_list *list = &conn->chan_list;
+-	l2cap_conn_req *req = (l2cap_conn_req *) data;
+-	l2cap_conn_rsp rsp;
+-	struct sock *sk, *parent;
+-
+-	__u16 scid = __le16_to_cpu(req->scid);
+-	__u16 psm  = req->psm;
+-
+-	DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
+-
+-	/* Check if we have socket listening on psm */
+-	if (!(parent = l2cap_get_sock_listen(&conn->src, psm)))
+-		goto reject;
+-
+-	bh_lock_sock(parent);
+-	write_lock(&list->lock);
+-
+-	/* Check if we already have channel with that dcid */
+-	if (__l2cap_get_chan_by_dcid(list, scid))
+-		goto unlock;
+-
+-	/* Check for backlog size */
+-	if (parent->ack_backlog > parent->max_ack_backlog)
+-		goto unlock;
+-
+-	if (!(sk = l2cap_sock_alloc(NULL, BTPROTO_L2CAP, GFP_ATOMIC)))
+-		goto unlock;
+-
+-	l2cap_sock_init(sk, parent);
+-
+-	bacpy(&l2cap_pi(sk)->src, &conn->src);
+-	bacpy(&l2cap_pi(sk)->dst, &conn->dst);
+-	l2cap_pi(sk)->psm  = psm;
+-	l2cap_pi(sk)->dcid = scid;
+-
+-	__l2cap_chan_add(conn, sk, parent);
+-	sk->state = BT_CONFIG;
+-
+-	write_unlock(&list->lock);
+-	bh_unlock_sock(parent);
+-
+-	rsp.dcid   = __cpu_to_le16(l2cap_pi(sk)->scid);
+-	rsp.scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-	rsp.result = __cpu_to_le16(0);
+-	rsp.status = __cpu_to_le16(0);
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
+-
+-	return 0;
+-
+-unlock:
+-	write_unlock(&list->lock);
+-	bh_unlock_sock(parent);
+-
+-reject:
+-	rsp.scid   = __cpu_to_le16(scid);
+-	rsp.dcid   = __cpu_to_le16(0);
+-	rsp.status = __cpu_to_le16(0);
+-	rsp.result = __cpu_to_le16(L2CAP_CONN_NO_MEM);
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONN_RSP, L2CAP_CONN_RSP_SIZE, &rsp);
+-
+-	return 0;
+-}
+-
+-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_conn_rsp *rsp = (l2cap_conn_rsp *) data;
+-	__u16 scid, dcid, result, status;
+-	struct sock *sk;
+-
+-	scid   = __le16_to_cpu(rsp->scid);
+-	dcid   = __le16_to_cpu(rsp->dcid);
+-	result = __le16_to_cpu(rsp->result);
+-	status = __le16_to_cpu(rsp->status);
+-
+-	DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-
+-	if (!result) {
+-		char req[64];
+-
+-		sk->state = BT_CONFIG;
+-		l2cap_pi(sk)->dcid = dcid;
+-		l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
+-
+-		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+-	} else {
+-		l2cap_chan_del(sk, ECONNREFUSED);
+-	}
+-
+-	bh_unlock_sock(sk);
+-	return 0;
+-}
+-
+-static inline int l2cap_config_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_conf_req * req = (l2cap_conf_req *) data;
+-	__u16 dcid, flags;
+-	__u8 rsp[64];
+-	struct sock *sk;
+-	int result;
+-
+-	dcid  = __le16_to_cpu(req->dcid);
+-	flags = __le16_to_cpu(req->flags);
+-
+-	DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-
+-	l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE);
+-
+-	if (flags & 0x01) {
+-		/* Incomplete config. Send empty response. */
+-		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
+-		goto unlock;
+-	}
+-
+-	/* Complete config. */
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, &result), rsp);
+-
+-	if (result)
+-		goto unlock;
+-
+-	/* Output config done */
+-	l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
+-
+-	if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
+-		sk->state = BT_CONNECTED;
+-		l2cap_chan_ready(sk);
+-	} else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
+-		char req[64];
+-		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
+-	}
+-
+-unlock:
+-	bh_unlock_sock(sk);
+-
+-	return 0;
+-}
+-
+-static inline int l2cap_config_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_conf_rsp *rsp = (l2cap_conf_rsp *)data;
+-	__u16 scid, flags, result;
+-	struct sock *sk;
+-	int err = 0;
+-
+-	scid   = __le16_to_cpu(rsp->scid);
+-	flags  = __le16_to_cpu(rsp->flags);
+-	result = __le16_to_cpu(rsp->result);
+-
+-	DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-
+-	if (result) {
+-		l2cap_disconn_req req;
+-
+-		/* They didn't like our options. Well... we do not negotiate.
+-		 * Close channel.
+-		 */
+-		sk->state = BT_DISCONN;
+-
+-		req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-		req.scid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-		l2cap_send_req(conn, L2CAP_DISCONN_REQ, L2CAP_DISCONN_REQ_SIZE, &req);
+-
+-		l2cap_sock_set_timer(sk, sk->sndtimeo);
+-		goto done;
+-	}
+-
+-	if (flags & 0x01)
+-		goto done;
+-
+-	/* Input config done */
+-	l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
+-
+-	if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
+-		sk->state = BT_CONNECTED;
+-		l2cap_chan_ready(sk);
+-	}
+-
+-done:
+-	bh_unlock_sock(sk);
+-
+-	return err;
+-}
+-
+-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_disconn_req *req = (l2cap_disconn_req *) data;
+-	l2cap_disconn_rsp rsp;
+-	__u16 dcid, scid;
+-	struct sock *sk;
+-
+-	scid = __le16_to_cpu(req->scid);
+-	dcid = __le16_to_cpu(req->dcid);
+-
+-	DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid)))
+-		return 0;
+-
+-	bh_lock_sock(sk);
+-
+-	rsp.dcid = __cpu_to_le16(l2cap_pi(sk)->scid);
+-	rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid);
+-	l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, L2CAP_DISCONN_RSP_SIZE, &rsp);
+-
+-	l2cap_chan_del(sk, ECONNRESET);
+-
+-	bh_unlock_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-
+-	return 0;
+-}
+-
+-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, l2cap_cmd_hdr *cmd, __u8 *data)
+-{
+-	l2cap_disconn_rsp *rsp = (l2cap_disconn_rsp *) data;
+-	__u16 dcid, scid;
+-	struct sock *sk;
+-
+-	scid = __le16_to_cpu(rsp->scid);
+-	dcid = __le16_to_cpu(rsp->dcid);
+-
+-	DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid)))
+-		return -ENOENT;
+-
+-	bh_lock_sock(sk);
+-	l2cap_sock_clear_timer(sk);
+-	l2cap_chan_del(sk, ECONNABORTED);
+-	bh_unlock_sock(sk);
+-
+-	l2cap_sock_kill(sk);
+-
+-	return 0;
+-}
+-
+-static inline void l2cap_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
+-{
+-	__u8 *data = skb->data;
+-	int len = skb->len;
+-	l2cap_cmd_hdr cmd;
+-	int err = 0;
+-
+-	while (len >= L2CAP_CMD_HDR_SIZE) {
+-		memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
+-		data += L2CAP_CMD_HDR_SIZE;
+-		len  -= L2CAP_CMD_HDR_SIZE;
+-
+-		cmd.len = __le16_to_cpu(cmd.len);
+-
+-		DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd.len, cmd.ident);
+-
+-		if (cmd.len > len || !cmd.ident) {
+-			DBG("corrupted command");
+-			break;
+-		}
+-
+-		switch (cmd.code) {
+-		case L2CAP_CONN_REQ:
+-			err = l2cap_connect_req(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_CONN_RSP:
+-			err = l2cap_connect_rsp(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_CONF_REQ:
+-			err = l2cap_config_req(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_CONF_RSP:
+-			err = l2cap_config_rsp(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_DISCONN_REQ:
+-			err = l2cap_disconnect_req(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_DISCONN_RSP:
+-			err = l2cap_disconnect_rsp(conn, &cmd, data);
+-			break;
+-
+-		case L2CAP_COMMAND_REJ:
+-			/* FIXME: We should process this */
+-			l2cap_raw_recv(conn, skb);
+-			break;
+-
+-		case L2CAP_ECHO_REQ:
+-			l2cap_send_rsp(conn, cmd.ident, L2CAP_ECHO_RSP, cmd.len, data);
+-			break;
+-
+-		case L2CAP_ECHO_RSP:
+-		case L2CAP_INFO_REQ:
+-		case L2CAP_INFO_RSP:
+-			l2cap_raw_recv(conn, skb);
+-			break;
+-
+-		default:
+-			ERR("Uknown signaling command 0x%2.2x", cmd.code);
+-			err = -EINVAL;
+-			break;
+-		};
+-
+-		if (err) {
+-			l2cap_cmd_rej rej;
+-			DBG("error %d", err);
+-
+-			/* FIXME: Map err to a valid reason. */
+-			rej.reason = __cpu_to_le16(0);
+-			l2cap_send_rsp(conn, cmd.ident, L2CAP_COMMAND_REJ, L2CAP_CMD_REJ_SIZE, &rej);
+-		}
+-
+-		data += cmd.len;
+-		len  -= cmd.len;
+-	}
+-
+-	kfree_skb(skb);
+-}
+-
+-static inline int l2cap_data_channel(struct l2cap_conn *conn, __u16 cid, struct sk_buff *skb)
+-{
+-	struct sock *sk;
+-
+-	if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, cid))) {
+-		DBG("unknown cid 0x%4.4x", cid);
+-		goto drop;
+-	}
+-
+-	DBG("sk %p, len %d", sk, skb->len);
+-
+-	if (sk->state != BT_CONNECTED)
+-		goto drop;
+-
+-	if (l2cap_pi(sk)->imtu < skb->len)
+-		goto drop;
+-
+-	skb_queue_tail(&sk->receive_queue, skb);
+-	sk->data_ready(sk, skb->len);
+-
+-	return 0;
+-
+-drop:
+-	kfree_skb(skb);
+-
+-	return 0;
+-}
+-
+-static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
+-{
+-	l2cap_hdr *lh = (l2cap_hdr *) skb->data;
+-	__u16 cid, len;
+-
+-	skb_pull(skb, L2CAP_HDR_SIZE);
+-	cid = __le16_to_cpu(lh->cid);
+-	len = __le16_to_cpu(lh->len);
+-
+-	DBG("len %d, cid 0x%4.4x", len, cid);
+-
+-	if (cid == 0x0001)
+-		l2cap_sig_channel(conn, skb);
+-	else	
+-		l2cap_data_channel(conn, cid, skb);
+-}
+-
+-/* ------------ L2CAP interface with lower layer (HCI) ------------- */
+-static int l2cap_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
+-{
+-	struct hci_dev *hdev = (struct hci_dev *) ptr;
+-
+-	DBG("hdev %s, event %ld", hdev->name, event);
+-
+-	write_lock(&l2cap_rt_lock);
+-
+-	switch (event) {
+-	case HCI_DEV_UP:
+-		l2cap_iff_add(hdev);
+-		break;
+-
+-	case HCI_DEV_DOWN:
+-		l2cap_iff_del(hdev);
+-		break;
+-	};
+-
+-	write_unlock(&l2cap_rt_lock);
+-
+-	return NOTIFY_DONE;
+-}
+-
+-int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
+-{
+-	struct l2cap_iff *iff;
+-
+-	DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+-
+-	if (!(iff = hdev->l2cap_data)) {
+-		ERR("unknown interface");
+-		return 0;
+-	}
+-
+-	/* Always accept connection */
+-	return 1;
+-}
+-
+-int l2cap_connect_cfm(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 status, struct hci_conn *hconn)
+-{
+-	struct l2cap_conn *conn;
+-	struct l2cap_iff *iff;
+-	int err = 0;
+-
+-	DBG("hdev %s bdaddr %s hconn %p", hdev->name, batostr(bdaddr), hconn);
+-
+-	if (!(iff = hdev->l2cap_data)) {
+-		ERR("unknown interface");
+-		return 0;
+-	}
+-
+-	l2cap_iff_lock(iff);
+-
+-	conn = l2cap_get_conn_by_addr(iff, bdaddr);
+-
+-	if (conn) {
+-		/* Outgoing connection */
+-		DBG("Outgoing connection: %s -> %s, %p, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), conn, status);
+-
+-		if (!status && hconn) {
+-			conn->state = BT_CONNECTED;
+-			conn->hconn = hconn;
+-
+-			hconn->l2cap_data = (void *)conn;
+-
+-			/* Establish channels */
+-			l2cap_conn_ready(conn);
+-		} else {
+-			l2cap_conn_del(conn, bterr(status));
+-		}
+-	} else {
+-		/* Incomming connection */
+-		DBG("Incomming connection: %s -> %s, %2.2x", batostr(iff->bdaddr), batostr(bdaddr), status);
+-	
+-		if (status || !hconn)
+-			goto done;
+-
+-		if (!(conn = l2cap_conn_add(iff, bdaddr))) {
+-			err = -ENOMEM;
+-			goto done;
+-		}
+-
+-		conn->hconn = hconn;
+-		hconn->l2cap_data = (void *)conn;
+-
+-		conn->state = BT_CONNECTED;
+-	}
+-
+-done:
+-	l2cap_iff_unlock(iff);
+-
+-	return err;
+-}
+-
+-int l2cap_disconn_ind(struct hci_conn *hconn, __u8 reason)
+-{
+-	struct l2cap_conn *conn = hconn->l2cap_data;
+-
+-	DBG("hconn %p reason %d", hconn, reason);
+-
+-	if (!conn) {
+-		ERR("unknown connection");
+-		return 0;
+-	}
+-	conn->hconn = NULL;
+-
+-	l2cap_iff_lock(conn->iff);
+-	l2cap_conn_del(conn, bterr(reason));
+-	l2cap_iff_unlock(conn->iff);
+-
+-	return 0;
+-}
+-
+-int l2cap_recv_acldata(struct hci_conn *hconn, struct sk_buff *skb, __u16 flags)
+-{
+-	struct l2cap_conn *conn = hconn->l2cap_data;
+-
+-	if (!conn) {
+-		ERR("unknown connection %p", hconn);
+-		goto drop;
+-	}
+-
+-	DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
+-
+-	if (flags & ACL_START) {
+-		int flen, tlen, size;
+-		l2cap_hdr *lh;
+-
+-		if (conn->rx_len) {
+-			ERR("Unexpected start frame (len %d)", skb->len);
+-			kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
+-			conn->rx_len = 0;
+-		}
+-
+-		if (skb->len < L2CAP_HDR_SIZE) {
+-			ERR("Frame is too small (len %d)", skb->len);
+-			goto drop;
+-		}
+-
+-		lh = (l2cap_hdr *)skb->data;
+-		tlen = __le16_to_cpu(lh->len);
+-		flen = skb->len - L2CAP_HDR_SIZE;
+-
+-		DBG("Start: total len %d, frag len %d", tlen, flen);
+-
+-		if (flen == tlen) {
+-			/* Complete frame received */
+-			l2cap_recv_frame(conn, skb);
+-			return 0;
+-		}
+-
+-		/* Allocate skb for the complete frame (with header) */
+-		size = L2CAP_HDR_SIZE + tlen;
+-		if (!(conn->rx_skb = bluez_skb_alloc(size, GFP_ATOMIC)))
+-			goto drop;
+-
+-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+-
+-		conn->rx_len = tlen - flen;
+-	} else {
+-		DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
+-
+-		if (!conn->rx_len) {
+-			ERR("Unexpected continuation frame (len %d)", skb->len);
+-			goto drop;
+-		}
+-
+-		if (skb->len > conn->rx_len) {
+-			ERR("Fragment is too large (len %d)", skb->len);
+-			kfree_skb(conn->rx_skb); conn->rx_skb = NULL;
+-			goto drop;
+-		}
+-
+-		memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len);
+-		conn->rx_len -= skb->len;
+-
+-		if (!conn->rx_len) {
+-			/* Complete frame received */
+-			l2cap_recv_frame(conn, conn->rx_skb);
+-			conn->rx_skb = NULL;
+-		}
+-	}
+-
+-drop:
+-	kfree_skb(skb);
+-	return 0;
+-}
+-
+-struct proto_ops l2cap_sock_ops = {
+-	family:		PF_BLUETOOTH,
+-	release:	l2cap_sock_release,
+-	bind:		l2cap_sock_bind,
+-	connect:	l2cap_sock_connect,
+-	listen:		l2cap_sock_listen,
+-	accept:		l2cap_sock_accept,
+-	getname:	l2cap_sock_getname,
+-	sendmsg:	l2cap_sock_sendmsg,
+-	recvmsg:	l2cap_sock_recvmsg,
+-	poll:		l2cap_sock_poll,
+-	socketpair:	sock_no_socketpair,
+-	ioctl:		sock_no_ioctl,
+-	shutdown:	sock_no_shutdown,
+-	setsockopt:	l2cap_sock_setsockopt,
+-	getsockopt:	l2cap_sock_getsockopt,
+-	mmap:		sock_no_mmap
+-};
+-
+-struct net_proto_family l2cap_sock_family_ops = {
+-	family:		PF_BLUETOOTH,
+-	create:		l2cap_sock_create
+-};
+-
+-struct hci_proto l2cap_hci_proto = {
+-	name:		"L2CAP",
+-	id:		HCI_PROTO_L2CAP,
+-	connect_ind:	l2cap_connect_ind,
+-	connect_cfm:	l2cap_connect_cfm,
+-	disconn_ind:	l2cap_disconn_ind,
+-	recv_acldata:	l2cap_recv_acldata,
+-};
+-
+-struct notifier_block l2cap_nblock = {
+-	notifier_call: l2cap_dev_event
+-};
+-
+-int __init l2cap_init(void)
+-{
+-	INF("BlueZ L2CAP ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+-		VERSION);
+-	INF("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
+-
+-	if (bluez_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops)) {
+-		ERR("Can't register L2CAP socket");
+-		return -EPROTO;
+-	}
+-
+-	if (hci_register_proto(&l2cap_hci_proto) < 0) {
+-		ERR("Can't register L2CAP protocol");
+-		return -EPROTO;
+-	}
+-
+-	hci_register_notifier(&l2cap_nblock);
+-
+-	l2cap_register_proc();
+-
+-	return 0;
+-}
+-
+-void l2cap_cleanup(void)
+-{
+-	l2cap_unregister_proc();
+-
+-	/* Unregister socket, protocol and notifier */
+-	if (bluez_sock_unregister(BTPROTO_L2CAP))
+-		ERR("Can't unregister L2CAP socket");
+-
+-	if (hci_unregister_proto(&l2cap_hci_proto) < 0)
+-		ERR("Can't unregister L2CAP protocol");
+-
+-	hci_unregister_notifier(&l2cap_nblock);
+-
+-	/* We _must_ not have any sockets and/or connections
+-	 * at this stage.
+-	 */
+-
+-	/* Free interface list and unlock HCI devices */
+-	{
+-		struct list_head *list = &l2cap_iff_list;
+-
+-		while (!list_empty(list)) {
+-			struct l2cap_iff *iff;
+-
+-			iff = list_entry(list->next, struct l2cap_iff, list);
+-			l2cap_iff_del(iff->hdev);
+-		}
+-	}
+-}
+-
+-module_init(l2cap_init);
+-module_exit(l2cap_cleanup);
+-
+-MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
+-MODULE_DESCRIPTION("BlueZ L2CAP ver " VERSION);
+-MODULE_LICENSE("GPL");
+-
+diff -urN linux-2.4.18/net/bluetooth/l2cap_proc.c linux-2.4.18-mh9/net/bluetooth/l2cap_proc.c
+--- linux-2.4.18/net/bluetooth/l2cap_proc.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/net/bluetooth/l2cap_proc.c	Thu Jan  1 01:00:00 1970
+@@ -1,165 +0,0 @@
+-/* 
+-   BlueZ - Bluetooth protocol stack for Linux
+-   Copyright (C) 2000-2001 Qualcomm Incorporated
+-
+-   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
+-
+-   This program is free software; you can redistribute it and/or modify
+-   it under the terms of the GNU General Public License version 2 as
+-   published by the Free Software Foundation;
+-
+-   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+-   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+-   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
+-   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
+-   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
+-   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
+-   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+-
+-   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
+-   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
+-   SOFTWARE IS DISCLAIMED.
+-*/
+-
+-/*
+- * BlueZ L2CAP proc fs support.
+- *
+- * $Id$
+- */
+-
+-#include <linux/config.h>
+-#include <linux/module.h>
+-
+-#include <linux/types.h>
+-#include <linux/errno.h>
+-#include <linux/kernel.h>
+-#include <linux/major.h>
+-#include <linux/sched.h>
+-#include <linux/slab.h>
+-#include <linux/poll.h>
+-#include <linux/fcntl.h>
+-#include <linux/init.h>
+-#include <linux/skbuff.h>
+-#include <linux/interrupt.h>
+-#include <linux/socket.h>
+-#include <linux/skbuff.h>
+-#include <linux/proc_fs.h>
+-#include <linux/list.h>
+-#include <net/sock.h>
+-
+-#include <asm/system.h>
+-#include <asm/uaccess.h>
+-
+-#include <net/bluetooth/bluez.h>
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/l2cap_core.h>
+-
+-#ifndef L2CAP_DEBUG
+-#undef  DBG
+-#define DBG( A... )
+-#endif
+-
+-/* ----- PROC fs support ----- */
+-static int l2cap_conn_dump(char *buf, struct l2cap_iff *iff)
+-{
+-	struct list_head *p;
+-	char *ptr = buf;
+-
+-	list_for_each(p, &iff->conn_list) {
+-		struct l2cap_conn *c;
+-
+-		c = list_entry(p, struct l2cap_conn, list);
+-		ptr += sprintf(ptr, "    %p %d %p %p %s %s\n", 
+-				c, c->state, c->iff, c->hconn, batostr(&c->src), batostr(&c->dst));
+-	}
+-
+-	return ptr - buf;
+-}
+-
+-static int l2cap_iff_dump(char *buf)
+-{
+-	struct list_head *p;
+-	char *ptr = buf;
+-
+-	ptr += sprintf(ptr, "Interfaces:\n");
+-
+-	write_lock(&l2cap_rt_lock);
+-
+-	list_for_each(p, &l2cap_iff_list) {
+-		struct l2cap_iff *iff;
+-
+-		iff = list_entry(p, struct l2cap_iff, list);
+-
+-		ptr += sprintf(ptr, "  %s %p %p\n", iff->hdev->name, iff, iff->hdev);
+-		
+-		l2cap_iff_lock(iff);
+-		ptr += l2cap_conn_dump(ptr, iff);
+-		l2cap_iff_unlock(iff);
+-	}
+-
+-	write_unlock(&l2cap_rt_lock);
+-
+-	ptr += sprintf(ptr, "\n");
+-
+-	return ptr - buf;
+-}
+-
+-static int l2cap_sock_dump(char *buf, struct bluez_sock_list *list)
+-{
+-	struct l2cap_pinfo *pi;
+-	struct sock *sk;
+-	char *ptr = buf;
+-
+-	ptr += sprintf(ptr, "Sockets:\n");
+-
+-	write_lock(&list->lock);
+-
+-	for (sk = list->head; sk; sk = sk->next) {
+-		pi = l2cap_pi(sk);
+-		ptr += sprintf(ptr, "  %p %d %p %d %s %s 0x%4.4x 0x%4.4x %d %d\n", sk, sk->state, pi->conn, pi->psm,
+-		               batostr(&pi->src), batostr(&pi->dst), pi->scid, pi->dcid, pi->imtu, pi->omtu );
+-	}
+-
+-	write_unlock(&list->lock);
+-
+-	ptr += sprintf(ptr, "\n");
+-
+-	return ptr - buf;
+-}
+-
+-static int l2cap_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
+-{
+-	char *ptr = buf;
+-	int len;
+-
+-	DBG("count %d, offset %ld", count, offset);
+-
+-	ptr += l2cap_iff_dump(ptr);
+-	ptr += l2cap_sock_dump(ptr, &l2cap_sk_list);
+-	len  = ptr - buf;
+-
+-	if (len <= count + offset)
+-		*eof = 1;
+-
+-	*start = buf + offset;
+-	len -= offset;
+-
+-	if (len > count)
+-		len = count;
+-	if (len < 0)
+-		len = 0;
+-
+-	return len;
+-}
+-
+-void l2cap_register_proc(void)
+-{
+-	create_proc_read_entry("bluetooth/l2cap", 0, 0, l2cap_read_proc, NULL);
+-}
+-
+-void l2cap_unregister_proc(void)
+-{
+-	remove_proc_entry("bluetooth/l2cap", NULL);
+-}
+diff -urN linux-2.4.18/net/bluetooth/lib.c linux-2.4.18-mh9/net/bluetooth/lib.c
+--- linux-2.4.18/net/bluetooth/lib.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/net/bluetooth/lib.c	Mon Aug 25 18:38:12 2003
+@@ -25,7 +25,7 @@
+ /*
+  * BlueZ kernel library.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/kernel.h>
+@@ -105,7 +105,7 @@
+ 		return EACCES;
+ 
+ 	case 0x06:
+-		return EINVAL;
++		return EBADE;
+ 
+ 	case 0x07:
+ 		return ENOMEM;
+diff -urN linux-2.4.18/net/bluetooth/rfcomm/Config.in linux-2.4.18-mh9/net/bluetooth/rfcomm/Config.in
+--- linux-2.4.18/net/bluetooth/rfcomm/Config.in	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/Config.in	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,10 @@
++#
++# Bluetooth RFCOMM layer configuration
++#
++
++dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP
++
++if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then
++   bool '  RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY
++fi
++
+diff -urN linux-2.4.18/net/bluetooth/rfcomm/Makefile linux-2.4.18-mh9/net/bluetooth/rfcomm/Makefile
+--- linux-2.4.18/net/bluetooth/rfcomm/Makefile	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/Makefile	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,11 @@
++#
++# Makefile for the Linux Bluetooth RFCOMM layer
++#
++
++O_TARGET := rfcomm.o
++
++obj-y				:= core.o sock.o crc.o
++obj-$(CONFIG_BLUEZ_RFCOMM_TTY)	+= tty.o
++obj-m				+= $(O_TARGET)
++
++include $(TOPDIR)/Rules.make
+diff -urN linux-2.4.18/net/bluetooth/rfcomm/core.c linux-2.4.18-mh9/net/bluetooth/rfcomm/core.c
+--- linux-2.4.18/net/bluetooth/rfcomm/core.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/core.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,1951 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/* 
++   RPN support    -    Dirk Husemann <hud@zurich.ibm.com>
++*/
++
++/*
++ * RFCOMM core.
++ *
++ * $Id$
++ */
++
++#define __KERNEL_SYSCALLS__
++
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/signal.h>
++#include <linux/init.h>
++#include <linux/wait.h>
++#include <linux/net.h>
++#include <linux/proc_fs.h>
++#include <net/sock.h>
++#include <asm/uaccess.h>
++#include <asm/unaligned.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/l2cap.h>
++#include <net/bluetooth/rfcomm.h>
++
++#define VERSION "1.0"
++
++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++struct task_struct *rfcomm_thread;
++DECLARE_MUTEX(rfcomm_sem);
++unsigned long rfcomm_event;
++
++static LIST_HEAD(session_list);
++static atomic_t terminate, running;
++
++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
++static int rfcomm_queue_disc(struct rfcomm_dlc *d);
++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type);
++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d);
++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig);
++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len);
++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits);
++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr);
++
++static void rfcomm_process_connect(struct rfcomm_session *s);
++
++/* ---- RFCOMM frame parsing macros ---- */
++#define __get_dlci(b)     ((b & 0xfc) >> 2)
++#define __get_channel(b)  ((b & 0xf8) >> 3)
++#define __get_dir(b)      ((b & 0x04) >> 2)
++#define __get_type(b)     ((b & 0xef))
++
++#define __test_ea(b)      ((b & 0x01))
++#define __test_cr(b)      ((b & 0x02))
++#define __test_pf(b)      ((b & 0x10))
++
++#define __addr(cr, dlci)       (((dlci & 0x3f) << 2) | (cr << 1) | 0x01)
++#define __ctrl(type, pf)       (((type & 0xef) | (pf << 4)))
++#define __dlci(dir, chn)       (((chn & 0x1f) << 1) | dir)
++#define __srv_channel(dlci)    (dlci >> 1)
++#define __dir(dlci)            (dlci & 0x01)
++
++#define __len8(len)       (((len) << 1) | 1)
++#define __len16(len)      ((len) << 1)
++
++/* MCC macros */
++#define __mcc_type(cr, type)   (((type << 2) | (cr << 1) | 0x01))
++#define __get_mcc_type(b) ((b & 0xfc) >> 2)
++#define __get_mcc_len(b)  ((b & 0xfe) >> 1)
++
++/* RPN macros */
++#define __rpn_line_settings(data, stop, parity)  ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3))
++#define __get_rpn_data_bits(line) ((line) & 0x3)
++#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
++#define __get_rpn_parity(line)    (((line) >> 3) & 0x3)
++
++/* ---- RFCOMM FCS computation ---- */
++
++/* CRC on 2 bytes */
++#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]])
++
++/* FCS on 2 bytes */ 
++static inline u8 __fcs(u8 *data)
++{
++	return (0xff - __crc(data));
++}
++
++/* FCS on 3 bytes */ 
++static inline u8 __fcs2(u8 *data)
++{
++	return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]);
++}
++
++/* Check FCS */
++static inline int __check_fcs(u8 *data, int type, u8 fcs)
++{
++	u8 f = __crc(data);
++
++	if (type != RFCOMM_UIH)
++		f = rfcomm_crc_table[f ^ data[2]];
++
++	return rfcomm_crc_table[f ^ fcs] != 0xcf;
++}
++
++/* ---- L2CAP callbacks ---- */
++static void rfcomm_l2state_change(struct sock *sk)
++{
++	BT_DBG("%p state %d", sk, sk->state);
++	rfcomm_schedule(RFCOMM_SCHED_STATE);
++}
++
++static void rfcomm_l2data_ready(struct sock *sk, int bytes)
++{
++	BT_DBG("%p bytes %d", sk, bytes);
++	rfcomm_schedule(RFCOMM_SCHED_RX);
++}
++
++static int rfcomm_l2sock_create(struct socket **sock)
++{
++	int err;
++
++	BT_DBG("");
++
++	err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock);
++	if (!err) {
++		struct sock *sk = (*sock)->sk;
++		sk->data_ready   = rfcomm_l2data_ready;
++		sk->state_change = rfcomm_l2state_change;
++	}
++	return err;
++}
++
++/* ---- RFCOMM DLCs ---- */
++static void rfcomm_dlc_timeout(unsigned long arg)
++{
++	struct rfcomm_dlc *d = (void *) arg;
++
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	set_bit(RFCOMM_TIMED_OUT, &d->flags);
++	rfcomm_dlc_put(d);
++	rfcomm_schedule(RFCOMM_SCHED_TIMEO);
++}
++
++static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout)
++{
++	BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout);
++
++	if (!mod_timer(&d->timer, jiffies + timeout))
++		rfcomm_dlc_hold(d);
++}
++
++static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	if (timer_pending(&d->timer) && del_timer(&d->timer))
++		rfcomm_dlc_put(d);
++}
++
++static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d)
++{
++	BT_DBG("%p", d);
++
++	d->state      = BT_OPEN;
++	d->flags      = 0;
++	d->mscex      = 0;
++	d->mtu        = RFCOMM_DEFAULT_MTU;
++	d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
++
++	d->credits    = 0;
++	d->rx_credits = RFCOMM_DEFAULT_CREDITS;
++}
++
++struct rfcomm_dlc *rfcomm_dlc_alloc(int prio)
++{
++	struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio);
++	if (!d)
++		return NULL;
++	memset(d, 0, sizeof(*d));
++
++	init_timer(&d->timer);
++	d->timer.function = rfcomm_dlc_timeout;
++	d->timer.data = (unsigned long) d;
++
++	skb_queue_head_init(&d->tx_queue);
++	spin_lock_init(&d->lock);
++	atomic_set(&d->refcnt, 1);
++
++	rfcomm_dlc_clear_state(d);
++	
++	BT_DBG("%p", d);
++	return d;
++}
++
++void rfcomm_dlc_free(struct rfcomm_dlc *d)
++{
++	BT_DBG("%p", d);
++
++	skb_queue_purge(&d->tx_queue);
++	kfree(d);
++}
++
++static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p session %p", d, s);
++
++	rfcomm_session_hold(s);
++
++	rfcomm_dlc_hold(d);
++	list_add(&d->list, &s->dlcs);
++	d->session = s;
++}
++
++static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
++{
++	struct rfcomm_session *s = d->session;
++
++	BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s);
++
++	list_del(&d->list);
++	d->session = NULL;
++	rfcomm_dlc_put(d);
++
++	rfcomm_session_put(s);
++}
++
++static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p;
++
++	list_for_each(p, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		if (d->dlci == dlci)
++			return d;
++	}
++	return NULL;
++}
++
++static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
++{
++	struct rfcomm_session *s;
++	int err = 0;
++	u8 dlci;
++
++	BT_DBG("dlc %p state %ld %s %s channel %d", 
++			d, d->state, batostr(src), batostr(dst), channel);
++
++	if (channel < 1 || channel > 30)
++		return -EINVAL;
++
++	if (d->state != BT_OPEN && d->state != BT_CLOSED)
++		return 0;
++
++	s = rfcomm_session_get(src, dst);
++	if (!s) {
++		s = rfcomm_session_create(src, dst, &err);
++		if (!s)
++			return err;
++	}
++
++	dlci = __dlci(!s->initiator, channel);
++
++	/* Check if DLCI already exists */
++	if (rfcomm_dlc_get(s, dlci))
++		return -EBUSY;
++
++	rfcomm_dlc_clear_state(d);
++
++	d->dlci     = dlci;
++	d->addr     = __addr(s->initiator, dlci);
++	d->priority = 7;
++
++	d->state    = BT_CONFIG;
++	rfcomm_dlc_link(s, d);
++
++	d->mtu     = s->mtu;
++	d->credits = s->credits;
++
++	if (s->state == BT_CONNECTED)
++		rfcomm_send_pn(s, 1, d);
++	rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
++	return 0;
++}
++
++int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel)
++{
++	mm_segment_t fs;
++	int r;
++
++	rfcomm_lock();
++
++	fs = get_fs(); set_fs(KERNEL_DS);
++	r = __rfcomm_dlc_open(d, src, dst, channel);
++	set_fs(fs);
++
++	rfcomm_unlock();
++	return r;
++}
++
++static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
++{
++	struct rfcomm_session *s = d->session;
++	if (!s)
++		return 0;
++
++	BT_DBG("dlc %p state %ld dlci %d err %d session %p",
++			d, d->state, d->dlci, err, s);
++
++	switch (d->state) {
++	case BT_CONNECTED:
++	case BT_CONFIG:
++	case BT_CONNECT:
++		d->state = BT_DISCONN;
++		if (skb_queue_empty(&d->tx_queue)) {
++			rfcomm_send_disc(s, d->dlci);
++			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT);
++		} else {
++			rfcomm_queue_disc(d);
++			rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2);
++		}
++		break;
++
++	default:
++		rfcomm_dlc_clear_timer(d);
++
++		rfcomm_dlc_lock(d);
++		d->state = BT_CLOSED;
++		d->state_change(d, err);
++		rfcomm_dlc_unlock(d);
++
++		skb_queue_purge(&d->tx_queue);
++		rfcomm_dlc_unlink(d);
++	}
++
++	return 0;
++}
++
++int rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
++{
++	mm_segment_t fs;
++	int r;
++
++	rfcomm_lock();
++
++	fs = get_fs(); set_fs(KERNEL_DS);
++	r = __rfcomm_dlc_close(d, err);
++	set_fs(fs);
++
++	rfcomm_unlock();
++	return r;
++}
++
++int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb)
++{
++	int len = skb->len;
++
++	if (d->state != BT_CONNECTED)
++		return -ENOTCONN;
++
++	BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len);
++
++	if (len > d->mtu)
++		return -EINVAL;
++
++	rfcomm_make_uih(skb, d->addr);
++	skb_queue_tail(&d->tx_queue, skb);
++
++	if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags))
++		rfcomm_schedule(RFCOMM_SCHED_TX);
++	return len;
++}
++
++void __rfcomm_dlc_throttle(struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	if (!d->credits) {
++		d->v24_sig |= RFCOMM_V24_FC;
++		set_bit(RFCOMM_MSC_PENDING, &d->flags);
++	}
++	rfcomm_schedule(RFCOMM_SCHED_TX);
++}
++
++void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)
++{
++	BT_DBG("dlc %p state %ld", d, d->state);
++
++	if (!d->credits) {
++		d->v24_sig &= ~RFCOMM_V24_FC;
++		set_bit(RFCOMM_MSC_PENDING, &d->flags);
++	}
++	rfcomm_schedule(RFCOMM_SCHED_TX);
++}
++
++/* 
++   Set/get modem status functions use _local_ status i.e. what we report
++   to the other side.
++   Remote status is provided by dlc->modem_status() callback.
++ */
++int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig)
++{
++	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
++			d, d->state, v24_sig);
++
++	if (test_bit(RFCOMM_RX_THROTTLED, &d->flags))
++		v24_sig |= RFCOMM_V24_FC;
++	else
++		v24_sig &= ~RFCOMM_V24_FC;
++	
++	d->v24_sig = v24_sig;
++
++	if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags))
++		rfcomm_schedule(RFCOMM_SCHED_TX);
++
++	return 0;
++}
++
++int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig)
++{
++	BT_DBG("dlc %p state %ld v24_sig 0x%x", 
++			d, d->state, d->v24_sig);
++
++	*v24_sig = d->v24_sig;
++	return 0;
++}
++
++/* ---- RFCOMM sessions ---- */
++struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
++{
++	struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL);
++	if (!s)
++		return NULL;
++	memset(s, 0, sizeof(*s));
++	
++	BT_DBG("session %p sock %p", s, sock);
++
++	INIT_LIST_HEAD(&s->dlcs);
++	s->state = state;
++	s->sock  = sock;
++
++	s->mtu     = RFCOMM_DEFAULT_MTU;
++	s->credits = 0;
++	
++	list_add(&s->list, &session_list);
++
++	/* Do not increment module usage count for listeting sessions.
++	 * Otherwise we won't be able to unload the module. */
++	if (state != BT_LISTEN)
++		MOD_INC_USE_COUNT;
++	return s;
++}
++
++void rfcomm_session_del(struct rfcomm_session *s)
++{
++	int state = s->state;
++	
++	BT_DBG("session %p state %ld", s, s->state);
++
++	list_del(&s->list);
++
++	if (state == BT_CONNECTED)
++		rfcomm_send_disc(s, 0);
++
++	sock_release(s->sock);
++	kfree(s);
++
++	if (state != BT_LISTEN)
++		MOD_DEC_USE_COUNT;
++}
++
++struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
++{
++	struct rfcomm_session *s;
++	struct list_head *p, *n;
++	struct bluez_pinfo *pi;
++	list_for_each_safe(p, n, &session_list) {
++		s = list_entry(p, struct rfcomm_session, list);
++		pi = bluez_pi(s->sock->sk); 
++
++		if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) &&
++				!bacmp(&pi->dst, dst))
++			return s;
++	}
++	return NULL;
++}
++
++void rfcomm_session_close(struct rfcomm_session *s, int err)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p, *n;
++
++	BT_DBG("session %p state %ld err %d", s, s->state, err);
++
++	rfcomm_session_hold(s);
++
++	s->state = BT_CLOSED;
++
++	/* Close all dlcs */
++	list_for_each_safe(p, n, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		d->state = BT_CLOSED;
++		__rfcomm_dlc_close(d, err);
++	}
++
++	rfcomm_session_put(s);
++}
++
++struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err)
++{
++	struct rfcomm_session *s = NULL;
++	struct sockaddr_l2 addr;
++	struct l2cap_options opts;
++	struct socket *sock;
++	int    size;
++
++	BT_DBG("%s %s", batostr(src), batostr(dst));
++
++	*err = rfcomm_l2sock_create(&sock);
++	if (*err < 0)
++		return NULL;
++
++	bacpy(&addr.l2_bdaddr, src);
++	addr.l2_family = AF_BLUETOOTH;
++	addr.l2_psm    = 0;
++	*err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
++	if (*err < 0)
++		goto failed;
++
++	/* Set L2CAP options */
++	size = sizeof(opts);
++	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
++	
++	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
++	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
++
++	s = rfcomm_session_add(sock, BT_BOUND);
++	if (!s) {
++		*err = -ENOMEM;
++		goto failed;
++	}
++
++	s->initiator = 1;
++
++	bacpy(&addr.l2_bdaddr, dst);
++	addr.l2_family = AF_BLUETOOTH;
++	addr.l2_psm    = htobs(RFCOMM_PSM);
++	*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
++	if (*err == 0 || *err == -EAGAIN)
++		return s;
++
++	rfcomm_session_del(s);
++	return NULL;
++
++failed:
++	sock_release(sock);
++	return NULL;
++}
++
++void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst)
++{
++	struct sock *sk = s->sock->sk;
++	if (src)
++		bacpy(src, &bluez_pi(sk)->src);
++	if (dst)
++		bacpy(dst, &bluez_pi(sk)->dst);
++}
++
++/* ---- RFCOMM frame sending ---- */
++static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
++{
++	struct socket *sock = s->sock;
++	struct iovec iv = { data, len };
++	struct msghdr msg;
++	int err;
++
++	BT_DBG("session %p len %d", s, len);
++
++	memset(&msg, 0, sizeof(msg));
++	msg.msg_iovlen = 1;
++	msg.msg_iov = &iv;
++
++	err = sock->ops->sendmsg(sock, &msg, len, 0);
++	return err;
++}
++
++static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_SABM, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(!s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_UA, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_DISC, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_queue_disc(struct rfcomm_dlc *d)
++{
++	struct rfcomm_cmd *cmd;
++	struct sk_buff *skb;
++
++	BT_DBG("dlc %p dlci %d", d, d->dlci);
++
++	skb = alloc_skb(sizeof(*cmd), GFP_KERNEL);
++	if (!skb)
++		return -ENOMEM;
++
++	cmd = (void *) __skb_put(skb, sizeof(*cmd));
++	cmd->addr = d->addr;
++	cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
++	cmd->len  = __len8(0);
++	cmd->fcs  = __fcs2((u8 *) cmd);
++
++	skb_queue_tail(&d->tx_queue, skb);
++	rfcomm_schedule(RFCOMM_SCHED_TX);
++	return 0;
++}
++
++static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_cmd cmd;
++
++	BT_DBG("%p dlci %d", s, dlci);
++
++	cmd.addr = __addr(!s->initiator, dlci);
++	cmd.ctrl = __ctrl(RFCOMM_DM, 1);
++	cmd.len  = __len8(0);
++	cmd.fcs  = __fcs2((u8 *) &cmd);
++
++	return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
++}
++
++static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d type %d", s, cr, type);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + 1);
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_NSC);
++	mcc->len  = __len8(1);
++
++	/* Type that we didn't like */
++	*ptr = __mcc_type(cr, type); ptr++;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_pn  *pn;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*pn));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_PN);
++	mcc->len  = __len8(sizeof(*pn));
++
++	pn = (void *) ptr; ptr += sizeof(*pn);
++	pn->dlci        = d->dlci;
++	pn->priority    = d->priority;
++	pn->ack_timer   = 0;
++	pn->max_retrans = 0;
++
++	if (cr || d->credits) {
++		pn->flow_ctrl = cr ? 0xf0 : 0xe0;
++		pn->credits = RFCOMM_DEFAULT_CREDITS;
++	} else {
++		pn->flow_ctrl = 0;
++		pn->credits   = 0;
++	}
++
++	pn->mtu = htobs(d->mtu);
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
++			   u8 bit_rate, u8 data_bits, u8 stop_bits,
++			   u8 parity, u8 flow_ctrl_settings, 
++			   u8 xon_char, u8 xoff_char, u16 param_mask)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_rpn *rpn;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x"
++	       "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", 
++			s, cr, dlci, bit_rate, data_bits, stop_bits, parity, 
++			flow_ctrl_settings, xon_char, xoff_char, param_mask);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*rpn));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_RPN);
++	mcc->len  = __len8(sizeof(*rpn));
++
++	rpn = (void *) ptr; ptr += sizeof(*rpn);
++	rpn->dlci          = __addr(1, dlci);
++	rpn->bit_rate      = bit_rate;
++	rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity);
++	rpn->flow_ctrl     = flow_ctrl_settings;
++	rpn->xon_char      = xon_char;
++	rpn->xoff_char     = xoff_char;
++	rpn->param_mask    = param_mask;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_rls *rls;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d status 0x%x", s, cr, status);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*rls));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_RLS);
++	mcc->len  = __len8(sizeof(*rls));
++
++	rls = (void *) ptr; ptr += sizeof(*rls);
++	rls->dlci   = __addr(1, dlci);
++	rls->status = status;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	struct rfcomm_msc *msc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc) + sizeof(*msc));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_MSC);
++	mcc->len  = __len8(sizeof(*msc));
++
++	msc = (void *) ptr; ptr += sizeof(*msc);
++	msc->dlci    = __addr(1, dlci);
++	msc->v24_sig = v24_sig | 0x01;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d", s, cr);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_FCOFF);
++	mcc->len  = __len8(0);
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
++{
++	struct rfcomm_hdr *hdr;
++	struct rfcomm_mcc *mcc;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p cr %d", s, cr);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = __addr(s->initiator, 0);
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++	hdr->len  = __len8(sizeof(*mcc));
++
++	mcc = (void *) ptr; ptr += sizeof(*mcc);
++	mcc->type = __mcc_type(cr, RFCOMM_FCON);
++	mcc->len  = __len8(0);
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
++{
++	struct socket *sock = s->sock;
++	struct iovec iv[3];
++	struct msghdr msg;
++	unsigned char hdr[5], crc[1];
++
++	if (len > 125)
++		return -EINVAL;
++
++	BT_DBG("%p cr %d", s, cr);
++
++	hdr[0] = __addr(s->initiator, 0);
++	hdr[1] = __ctrl(RFCOMM_UIH, 0);
++	hdr[2] = 0x01 | ((len + 2) << 1);
++	hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2);
++	hdr[4] = 0x01 | (len << 1);
++
++	crc[0] = __fcs(hdr);
++
++	iv[0].iov_base = hdr;
++	iv[0].iov_len  = 5;
++	iv[1].iov_base = pattern;
++	iv[1].iov_len  = len;
++	iv[2].iov_base = crc;
++	iv[2].iov_len  = 1;
++
++	memset(&msg, 0, sizeof(msg));
++	msg.msg_iovlen = 3;
++	msg.msg_iov = iv;
++	return sock->ops->sendmsg(sock, &msg, 6 + len, 0);
++}
++
++static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
++{
++	struct rfcomm_hdr *hdr;
++	u8 buf[16], *ptr = buf;
++
++	BT_DBG("%p addr %d credits %d", s, addr, credits);
++
++	hdr = (void *) ptr; ptr += sizeof(*hdr);
++	hdr->addr = addr;
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 1);
++	hdr->len  = __len8(0);
++
++	*ptr = credits; ptr++;
++
++	*ptr = __fcs(buf); ptr++;
++
++	return rfcomm_send_frame(s, buf, ptr - buf);
++}
++
++static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
++{
++	struct rfcomm_hdr *hdr;
++	int len = skb->len;
++	u8 *crc;
++
++	if (len > 127) {
++		hdr = (void *) skb_push(skb, 4);
++		put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len);
++	} else {
++		hdr = (void *) skb_push(skb, 3);
++		hdr->len = __len8(len);
++	}
++	hdr->addr = addr;
++	hdr->ctrl = __ctrl(RFCOMM_UIH, 0);
++
++	crc = skb_put(skb, 1);
++	*crc = __fcs((void *) hdr);
++}
++
++/* ---- RFCOMM frame reception ---- */
++static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
++{
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (dlci) {
++		/* Data channel */
++		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
++		if (!d) {
++			rfcomm_send_dm(s, dlci);
++			return 0;
++		}
++
++		switch (d->state) {
++		case BT_CONNECT:
++			rfcomm_dlc_clear_timer(d);
++
++			rfcomm_dlc_lock(d);
++			d->state = BT_CONNECTED;
++			d->state_change(d, 0);
++			rfcomm_dlc_unlock(d);
++
++			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
++			break;
++
++		case BT_DISCONN:
++			d->state = BT_CLOSED;
++			__rfcomm_dlc_close(d, 0);
++			break;
++		}
++	} else {
++		/* Control channel */
++		switch (s->state) {
++		case BT_CONNECT:
++			s->state = BT_CONNECTED;
++			rfcomm_process_connect(s);
++			break;
++		}
++	}
++	return 0;
++}
++
++static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci)
++{
++	int err = 0;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (dlci) {
++		/* Data DLC */
++		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
++		if (d) {
++			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
++				err = ECONNREFUSED;
++			else
++				err = ECONNRESET;
++
++			d->state = BT_CLOSED;
++			__rfcomm_dlc_close(d, err);
++		}
++	} else {
++		if (s->state == BT_CONNECT)
++			err = ECONNREFUSED;
++		else
++			err = ECONNRESET;
++
++		s->state = BT_CLOSED;
++		rfcomm_session_close(s, err);
++	}
++	return 0;
++}
++
++static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
++{
++	int err = 0;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (dlci) {
++		struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci);
++		if (d) {
++			rfcomm_send_ua(s, dlci);
++
++			if (d->state == BT_CONNECT || d->state == BT_CONFIG)
++				err = ECONNREFUSED;
++			else
++				err = ECONNRESET;
++
++			d->state = BT_CLOSED;
++			__rfcomm_dlc_close(d, err);
++		} else 
++			rfcomm_send_dm(s, dlci);
++			
++	} else {
++		rfcomm_send_ua(s, 0);
++
++		if (s->state == BT_CONNECT)
++			err = ECONNREFUSED;
++		else
++			err = ECONNRESET;
++
++		s->state = BT_CLOSED;
++		rfcomm_session_close(s, err);
++	}
++
++	return 0;
++}
++
++static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
++{
++	struct rfcomm_dlc *d;
++	u8 channel;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (!dlci) {
++		rfcomm_send_ua(s, 0);
++
++		if (s->state == BT_OPEN) {
++			s->state = BT_CONNECTED;
++			rfcomm_process_connect(s);
++		}
++		return 0;
++	}
++
++	/* Check if DLC exists */
++	d = rfcomm_dlc_get(s, dlci);
++	if (d) {
++		if (d->state == BT_OPEN) {
++			/* DLC was previously opened by PN request */
++			rfcomm_send_ua(s, dlci);
++
++			rfcomm_dlc_lock(d);
++			d->state = BT_CONNECTED;
++			d->state_change(d, 0);
++			rfcomm_dlc_unlock(d);
++
++			rfcomm_send_msc(s, 1, dlci, d->v24_sig);
++		}
++		return 0;
++	}
++
++	/* Notify socket layer about incomming connection */
++	channel = __srv_channel(dlci);
++	if (rfcomm_connect_ind(s, channel, &d)) {
++		d->dlci = dlci;
++		d->addr = __addr(s->initiator, dlci);
++		rfcomm_dlc_link(s, d);
++
++		rfcomm_send_ua(s, dlci);
++
++		rfcomm_dlc_lock(d);
++		d->state = BT_CONNECTED;
++		d->state_change(d, 0);
++		rfcomm_dlc_unlock(d);
++
++		rfcomm_send_msc(s, 1, dlci, d->v24_sig);
++	} else {
++		rfcomm_send_dm(s, dlci);
++	}
++
++	return 0;
++}
++
++static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn)
++{
++	struct rfcomm_session *s = d->session;
++
++	BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", 
++			d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits);
++
++	if (cr) {
++		if (pn->flow_ctrl == 0xf0) {
++			s->credits = RFCOMM_MAX_CREDITS;
++			d->credits = s->credits;
++			d->tx_credits = pn->credits;
++		} else {
++			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
++			d->credits = 0;
++		}
++	} else {
++		if (pn->flow_ctrl == 0xe0) {
++			s->credits = RFCOMM_MAX_CREDITS;
++			d->credits = s->credits;
++			d->tx_credits = pn->credits;
++		} else {
++			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
++			d->credits = 0;
++		}
++	}
++
++	d->priority = pn->priority;
++
++	d->mtu = btohs(pn->mtu);
++
++	return 0;
++}
++
++static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb)
++{
++	struct rfcomm_pn *pn = (void *) skb->data;
++	struct rfcomm_dlc *d;
++	u8 dlci = pn->dlci;
++
++	BT_DBG("session %p state %ld dlci %d", s, s->state, dlci);
++
++	if (!dlci)
++		return 0;
++
++	d = rfcomm_dlc_get(s, dlci);
++	if (d) {
++		if (cr) {
++			/* PN request */
++			rfcomm_apply_pn(d, cr, pn);
++			rfcomm_send_pn(s, 0, d);
++		} else {
++			/* PN response */
++			switch (d->state) {
++			case BT_CONFIG:
++				rfcomm_apply_pn(d, cr, pn);
++
++				d->state = BT_CONNECT;
++				rfcomm_send_sabm(s, d->dlci);
++				break;
++			}
++		}
++	} else {
++		u8 channel = __srv_channel(dlci);
++
++		if (!cr)
++			return 0;
++
++		/* PN request for non existing DLC.
++		 * Assume incomming connection. */
++		if (rfcomm_connect_ind(s, channel, &d)) {
++			d->dlci = dlci;
++			d->addr = __addr(s->initiator, dlci);
++			rfcomm_dlc_link(s, d);
++
++			rfcomm_apply_pn(d, cr, pn);
++
++			d->state = BT_OPEN;
++			rfcomm_send_pn(s, 0, d);
++		} else {
++			rfcomm_send_dm(s, dlci);
++		}
++	}
++	return 0;
++}
++
++static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb)
++{
++	struct rfcomm_rpn *rpn = (void *) skb->data;
++	u8 dlci = __get_dlci(rpn->dlci);
++
++	u8 bit_rate  = 0;
++	u8 data_bits = 0;
++	u8 stop_bits = 0;
++	u8 parity    = 0;
++	u8 flow_ctrl = 0;
++	u8 xon_char  = 0;
++	u8 xoff_char = 0;
++	u16 rpn_mask = RFCOMM_RPN_PM_ALL;
++	
++	BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", 
++	       dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl,
++	       rpn->xon_char, rpn->xoff_char, rpn->param_mask);
++	
++	if (!cr) 
++		return 0;
++	
++	if (len == 1) {
++		/* request: return default setting */
++		bit_rate  = RFCOMM_RPN_BR_115200;
++		data_bits = RFCOMM_RPN_DATA_8;
++		stop_bits = RFCOMM_RPN_STOP_1;
++		parity    = RFCOMM_RPN_PARITY_NONE;
++		flow_ctrl = RFCOMM_RPN_FLOW_NONE;
++		xon_char  = RFCOMM_RPN_XON_CHAR;
++		xoff_char = RFCOMM_RPN_XOFF_CHAR;
++
++		goto rpn_out;
++	}
++	/* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity,
++	                          no flow control lines, normal XON/XOFF chars */
++	if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) {
++		bit_rate = rpn->bit_rate;
++		if (bit_rate != RFCOMM_RPN_BR_115200) {
++			BT_DBG("RPN bit rate mismatch 0x%x", bit_rate);
++			bit_rate = RFCOMM_RPN_BR_115200;
++			rpn_mask ^= RFCOMM_RPN_PM_BITRATE;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_DATA) {
++		data_bits = __get_rpn_data_bits(rpn->line_settings);
++		if (data_bits != RFCOMM_RPN_DATA_8) {
++			BT_DBG("RPN data bits mismatch 0x%x", data_bits);
++			data_bits = RFCOMM_RPN_DATA_8;
++			rpn_mask ^= RFCOMM_RPN_PM_DATA;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_STOP) {
++		stop_bits = __get_rpn_stop_bits(rpn->line_settings);
++		if (stop_bits != RFCOMM_RPN_STOP_1) {
++			BT_DBG("RPN stop bits mismatch 0x%x", stop_bits);
++			stop_bits = RFCOMM_RPN_STOP_1;
++			rpn_mask ^= RFCOMM_RPN_PM_STOP;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) {
++		parity = __get_rpn_parity(rpn->line_settings);
++		if (parity != RFCOMM_RPN_PARITY_NONE) {
++			BT_DBG("RPN parity mismatch 0x%x", parity);
++			parity = RFCOMM_RPN_PARITY_NONE;
++			rpn_mask ^= RFCOMM_RPN_PM_PARITY;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
++		flow_ctrl = rpn->flow_ctrl;
++		if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
++			BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl);
++			flow_ctrl = RFCOMM_RPN_FLOW_NONE;
++			rpn_mask ^= RFCOMM_RPN_PM_FLOW;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
++		xon_char = rpn->xon_char;
++		if (xon_char != RFCOMM_RPN_XON_CHAR) {
++			BT_DBG("RPN XON char mismatch 0x%x", xon_char);
++			xon_char = RFCOMM_RPN_XON_CHAR;
++			rpn_mask ^= RFCOMM_RPN_PM_XON;
++		}
++	}
++	if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
++		xoff_char = rpn->xoff_char;
++		if (xoff_char != RFCOMM_RPN_XOFF_CHAR) {
++			BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char);
++			xoff_char = RFCOMM_RPN_XOFF_CHAR;
++			rpn_mask ^= RFCOMM_RPN_PM_XOFF;
++		}
++	}
++
++rpn_out:
++	rfcomm_send_rpn(s, 0, dlci, 
++			bit_rate, data_bits, stop_bits, parity, flow_ctrl,
++			xon_char, xoff_char, rpn_mask);
++
++	return 0;
++}
++
++static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb)
++{
++	struct rfcomm_rls *rls = (void *) skb->data;
++	u8 dlci = __get_dlci(rls->dlci);
++
++	BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status);
++	
++	if (!cr)
++		return 0;
++
++	/* FIXME: We should probably do something with this
++	   information here. But for now it's sufficient just
++	   to reply -- Bluetooth 1.1 says it's mandatory to 
++	   recognise and respond to RLS */
++
++	rfcomm_send_rls(s, 0, dlci, rls->status);
++
++	return 0;
++}
++
++static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb)
++{
++	struct rfcomm_msc *msc = (void *) skb->data;
++	struct rfcomm_dlc *d;
++	u8 dlci = __get_dlci(msc->dlci);
++
++	BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
++
++	d = rfcomm_dlc_get(s, dlci);
++	if (!d)
++		return 0;
++
++	if (cr) {
++		if (msc->v24_sig & RFCOMM_V24_FC && !d->credits)
++			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
++		else
++			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
++		
++		rfcomm_dlc_lock(d);
++		if (d->modem_status)
++			d->modem_status(d, msc->v24_sig);
++		rfcomm_dlc_unlock(d);
++		
++		rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
++
++		d->mscex |= RFCOMM_MSCEX_RX;
++	} else 
++		d->mscex |= RFCOMM_MSCEX_TX;
++
++	return 0;
++}
++
++static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
++{
++	struct rfcomm_mcc *mcc = (void *) skb->data;
++	u8 type, cr, len;
++
++	cr   = __test_cr(mcc->type);
++	type = __get_mcc_type(mcc->type);
++	len  = __get_mcc_len(mcc->len);
++
++	BT_DBG("%p type 0x%x cr %d", s, type, cr);
++
++	skb_pull(skb, 2);
++
++	switch (type) {
++	case RFCOMM_PN:
++		rfcomm_recv_pn(s, cr, skb);
++		break;
++
++	case RFCOMM_RPN:
++		rfcomm_recv_rpn(s, cr, len, skb);
++		break;
++
++	case RFCOMM_RLS:
++		rfcomm_recv_rls(s, cr, skb);
++		break;
++
++	case RFCOMM_MSC:
++		rfcomm_recv_msc(s, cr, skb);
++		break;
++
++	case RFCOMM_FCOFF:
++		if (cr) {
++			set_bit(RFCOMM_TX_THROTTLED, &s->flags);
++			rfcomm_send_fcoff(s, 0);
++		}
++		break;
++
++	case RFCOMM_FCON:
++		if (cr) {
++			clear_bit(RFCOMM_TX_THROTTLED, &s->flags);
++			rfcomm_send_fcon(s, 0);
++		}
++		break;
++
++	case RFCOMM_TEST:
++		if (cr)
++			rfcomm_send_test(s, 0, skb->data, skb->len);
++		break;
++
++	case RFCOMM_NSC:
++		break;
++
++	default:
++		BT_ERR("Unknown control type 0x%02x", type);
++		rfcomm_send_nsc(s, cr, type);
++		break;
++	}
++	return 0;
++}
++
++static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb)
++{
++	struct rfcomm_dlc *d;
++
++	BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf);
++
++	d = rfcomm_dlc_get(s, dlci);
++	if (!d) {
++		rfcomm_send_dm(s, dlci);
++		goto drop;
++	}
++
++	if (pf && d->credits) {
++		u8 credits = *(u8 *) skb->data; skb_pull(skb, 1);
++
++		d->tx_credits += credits;
++		if (d->tx_credits)
++			clear_bit(RFCOMM_TX_THROTTLED, &d->flags);
++	}
++
++	if (skb->len && d->state == BT_CONNECTED) {
++		rfcomm_dlc_lock(d);
++		d->rx_credits--;
++		d->data_ready(d, skb);
++		rfcomm_dlc_unlock(d);
++		return 0;
++	}
++
++drop:
++	kfree_skb(skb);
++	return 0;
++}
++
++static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb)
++{
++	struct rfcomm_hdr *hdr = (void *) skb->data;
++	u8 type, dlci, fcs;
++
++	dlci = __get_dlci(hdr->addr);
++	type = __get_type(hdr->ctrl);
++
++	/* Trim FCS */
++	skb->len--; skb->tail--;
++	fcs = *(u8 *) skb->tail;
++	
++	if (__check_fcs(skb->data, type, fcs)) {
++		BT_ERR("bad checksum in packet");
++		kfree_skb(skb);
++		return -EILSEQ;
++	}
++
++	if (__test_ea(hdr->len))
++		skb_pull(skb, 3);
++	else
++		skb_pull(skb, 4);
++	
++	switch (type) {
++	case RFCOMM_SABM:
++		if (__test_pf(hdr->ctrl))
++			rfcomm_recv_sabm(s, dlci);
++		break;
++
++	case RFCOMM_DISC:
++		if (__test_pf(hdr->ctrl))
++			rfcomm_recv_disc(s, dlci);
++		break;
++
++	case RFCOMM_UA:
++		if (__test_pf(hdr->ctrl))
++			rfcomm_recv_ua(s, dlci);
++		break;
++
++	case RFCOMM_DM:
++		rfcomm_recv_dm(s, dlci);
++		break;
++
++	case RFCOMM_UIH:
++		if (dlci)
++			return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb);
++
++		rfcomm_recv_mcc(s, skb);
++		break;
++
++	default:
++		BT_ERR("Unknown packet type 0x%02x\n", type);
++		break;
++	}
++	kfree_skb(skb);
++	return 0;
++}
++
++/* ---- Connection and data processing ---- */
++
++static void rfcomm_process_connect(struct rfcomm_session *s)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p, *n;
++
++	BT_DBG("session %p state %ld", s, s->state);
++
++	list_for_each_safe(p, n, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		if (d->state == BT_CONFIG) {
++			d->mtu = s->mtu;
++			rfcomm_send_pn(s, 1, d);
++		}
++	}
++}
++
++/* Send data queued for the DLC.
++ * Return number of frames left in the queue.
++ */
++static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
++{
++	struct sk_buff *skb;
++	int err;
++
++	BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", 
++			d, d->state, d->credits, d->rx_credits, d->tx_credits);
++
++	/* Send pending MSC */
++	if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags))
++		rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
++	
++	if (d->credits) {
++		/* CFC enabled. 
++		 * Give them some credits */
++		if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) &&
++			       	d->rx_credits <= (d->credits >> 2)) {
++			rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits);
++			d->rx_credits = d->credits;
++		}
++	} else {
++		/* CFC disabled. 
++		 * Give ourselves some credits */
++		d->tx_credits = 5;
++	}
++
++	if (test_bit(RFCOMM_TX_THROTTLED, &d->flags))
++		return skb_queue_len(&d->tx_queue);
++
++	while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
++		err = rfcomm_send_frame(d->session, skb->data, skb->len);
++		if (err < 0) {
++			skb_queue_head(&d->tx_queue, skb);
++			break;
++		}
++		kfree_skb(skb);
++		d->tx_credits--;
++	}
++
++	if (d->credits && !d->tx_credits) {
++		/* We're out of TX credits.
++		 * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */
++		set_bit(RFCOMM_TX_THROTTLED, &d->flags);
++	}
++
++	return skb_queue_len(&d->tx_queue);
++}
++
++static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
++{
++	struct rfcomm_dlc *d;
++	struct list_head *p, *n;
++
++	BT_DBG("session %p state %ld", s, s->state);
++
++	list_for_each_safe(p, n, &s->dlcs) {
++		d = list_entry(p, struct rfcomm_dlc, list);
++		if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) {
++			__rfcomm_dlc_close(d, ETIMEDOUT);
++			continue;
++		}
++
++		if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
++			continue;
++
++		if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
++				d->mscex == RFCOMM_MSCEX_OK)
++			rfcomm_process_tx(d);
++	}
++}
++
++static inline void rfcomm_process_rx(struct rfcomm_session *s)
++{
++	struct socket *sock = s->sock;
++	struct sock *sk = sock->sk;
++	struct sk_buff *skb;
++
++	BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue));
++
++	/* Get data directly from socket receive queue without copying it. */
++	while ((skb = skb_dequeue(&sk->receive_queue))) {
++		skb_orphan(skb);
++		rfcomm_recv_frame(s, skb);
++	}
++
++	if (sk->state == BT_CLOSED) {
++		if (!s->initiator)
++			rfcomm_session_put(s);
++
++		rfcomm_session_close(s, sk->err);
++	}
++}
++
++static inline void rfcomm_accept_connection(struct rfcomm_session *s)
++{
++	struct socket *sock = s->sock, *nsock;
++	int err;
++
++	/* Fast check for a new connection.
++	 * Avoids unnesesary socket allocations. */
++	if (list_empty(&bluez_pi(sock->sk)->accept_q))
++		return;
++
++	BT_DBG("session %p", s);
++
++	nsock = sock_alloc();
++	if (!nsock)
++		return;
++
++	nsock->type = sock->type;
++	nsock->ops  = sock->ops;
++	
++	err = sock->ops->accept(sock, nsock, O_NONBLOCK);
++	if (err < 0) {
++		sock_release(nsock);
++		return;
++	}
++
++	/* Set our callbacks */
++	nsock->sk->data_ready   = rfcomm_l2data_ready;
++	nsock->sk->state_change = rfcomm_l2state_change;
++
++	s = rfcomm_session_add(nsock, BT_OPEN);
++	if (s)
++		rfcomm_session_hold(s);
++	else
++		sock_release(nsock);
++}
++
++static inline void rfcomm_check_connection(struct rfcomm_session *s)
++{
++	struct sock *sk = s->sock->sk;
++
++	BT_DBG("%p state %ld", s, s->state);
++
++	switch(sk->state) {
++	case BT_CONNECTED:
++		s->state = BT_CONNECT;
++
++		/* We can adjust MTU on outgoing sessions.
++		 * L2CAP MTU minus UIH header and FCS. */
++		s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5;
++
++		rfcomm_send_sabm(s, 0);
++		break;
++
++	case BT_CLOSED:
++		s->state = BT_CLOSED;
++		rfcomm_session_close(s, sk->err);
++		break;
++	}
++}
++
++static inline void rfcomm_process_sessions(void)
++{
++	struct list_head *p, *n;
++
++	rfcomm_lock();
++
++	list_for_each_safe(p, n, &session_list) {
++		struct rfcomm_session *s;
++		s = list_entry(p, struct rfcomm_session, list);
++
++		if (s->state == BT_LISTEN) {
++			rfcomm_accept_connection(s);
++			continue;
++		}
++
++		rfcomm_session_hold(s);
++
++		switch (s->state) {
++		case BT_BOUND:
++			rfcomm_check_connection(s);
++			break;
++
++		default:
++			rfcomm_process_rx(s);
++			break;
++		}
++
++		rfcomm_process_dlcs(s);
++
++		rfcomm_session_put(s);
++	}
++	
++	rfcomm_unlock();
++}
++
++static void rfcomm_worker(void)
++{
++	BT_DBG("");
++
++	daemonize(); reparent_to_init();
++	set_fs(KERNEL_DS);
++
++	while (!atomic_read(&terminate)) {
++		BT_DBG("worker loop event 0x%lx", rfcomm_event);
++
++		if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
++			/* No pending events. Let's sleep.
++			 * Incomming connections and data will wake us up. */
++			set_current_state(TASK_INTERRUPTIBLE);
++			schedule();
++		}
++
++		/* Process stuff */
++		clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
++		rfcomm_process_sessions();
++	}
++	set_current_state(TASK_RUNNING);
++	return;
++}
++
++static int rfcomm_add_listener(bdaddr_t *ba)
++{
++	struct sockaddr_l2 addr;
++	struct l2cap_options opts;
++	struct socket *sock;
++	struct rfcomm_session *s;
++	int    size, err = 0;
++
++	/* Create socket */
++	err = rfcomm_l2sock_create(&sock);
++	if (err < 0) { 
++		BT_ERR("Create socket failed %d", err);
++		return err;
++	}
++
++	/* Bind socket */
++	bacpy(&addr.l2_bdaddr, ba);
++	addr.l2_family = AF_BLUETOOTH;
++	addr.l2_psm    = htobs(RFCOMM_PSM);
++	err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr));
++	if (err < 0) {
++		BT_ERR("Bind failed %d", err);
++		goto failed;
++	}
++
++	/* Set L2CAP options */
++	size = sizeof(opts);
++	sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size);
++
++	opts.imtu = RFCOMM_MAX_L2CAP_MTU;
++	sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size);
++
++	/* Start listening on the socket */
++	err = sock->ops->listen(sock, 10);
++	if (err) {
++		BT_ERR("Listen failed %d", err);
++		goto failed;
++	}
++
++	/* Add listening session */
++	s = rfcomm_session_add(sock, BT_LISTEN);
++	if (!s)
++		goto failed;
++
++	rfcomm_session_hold(s);
++	return 0;
++failed:
++	sock_release(sock);
++	return err;
++}
++
++static void rfcomm_kill_listener(void)
++{
++	struct rfcomm_session *s;
++	struct list_head *p, *n;
++
++	BT_DBG("");
++
++	list_for_each_safe(p, n, &session_list) {
++		s = list_entry(p, struct rfcomm_session, list);
++		rfcomm_session_del(s);
++	}
++}
++
++static int rfcomm_run(void *unused)
++{
++	rfcomm_thread = current;
++
++	atomic_inc(&running);
++
++	daemonize(); reparent_to_init();
++
++	sigfillset(&current->blocked);
++	set_fs(KERNEL_DS);
++
++	sprintf(current->comm, "krfcommd");
++
++	BT_DBG("");
++
++	rfcomm_add_listener(BDADDR_ANY);
++
++	rfcomm_worker();
++
++	rfcomm_kill_listener();
++
++	atomic_dec(&running);
++	return 0;
++}
++
++/* ---- Proc fs support ---- */
++static int rfcomm_dlc_dump(char *buf)
++{
++	struct rfcomm_session *s;
++	struct sock *sk;
++	struct list_head *p, *pp;
++	char *ptr = buf;
++
++	rfcomm_lock();
++
++	list_for_each(p, &session_list) {
++		s = list_entry(p, struct rfcomm_session, list);
++		sk = s->sock->sk;
++
++		list_for_each(pp, &s->dlcs) {
++		struct rfcomm_dlc *d;
++			d = list_entry(pp, struct rfcomm_dlc, list);
++
++			ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
++				d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
++		}
++	}
++	
++	rfcomm_unlock();
++
++	return ptr - buf;
++}
++
++extern int rfcomm_sock_dump(char *buf);
++
++static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
++{
++	char *ptr = buf;
++	int len;
++
++	BT_DBG("count %d, offset %ld", count, offset);
++
++	ptr += rfcomm_dlc_dump(ptr);
++	ptr += rfcomm_sock_dump(ptr);
++	len  = ptr - buf;
++
++	if (len <= count + offset)
++		*eof = 1;
++
++	*start = buf + offset;
++	len -= offset;
++
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++
++/* ---- Initialization ---- */
++int __init rfcomm_init(void)
++{
++	l2cap_load();
++
++	kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
++
++	rfcomm_init_sockets();
++
++#ifdef CONFIG_BLUEZ_RFCOMM_TTY
++	rfcomm_init_ttys();
++#endif
++
++	create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL);
++
++	BT_INFO("BlueZ RFCOMM ver %s", VERSION);
++	BT_INFO("Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>");
++	BT_INFO("Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>");
++	return 0;
++}
++
++void rfcomm_cleanup(void)
++{
++	/* Terminate working thread.
++	 * ie. Set terminate flag and wake it up */
++	atomic_inc(&terminate);
++	rfcomm_schedule(RFCOMM_SCHED_STATE);
++
++	/* Wait until thread is running */
++	while (atomic_read(&running))
++		schedule();
++
++	remove_proc_entry("bluetooth/rfcomm", NULL);
++
++#ifdef CONFIG_BLUEZ_RFCOMM_TTY
++	rfcomm_cleanup_ttys();
++#endif
++
++	rfcomm_cleanup_sockets();
++	return;
++}
++
++module_init(rfcomm_init);
++module_exit(rfcomm_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>, Marcel Holtmann <marcel@holtmann.org>");
++MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION);
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/net/bluetooth/rfcomm/crc.c linux-2.4.18-mh9/net/bluetooth/rfcomm/crc.c
+--- linux-2.4.18/net/bluetooth/rfcomm/crc.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/crc.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,71 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * RFCOMM FCS calculation.
++ *
++ * $Id$
++ */
++
++/* reversed, 8-bit, poly=0x07 */
++unsigned char rfcomm_crc_table[256] = { 
++	0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
++	0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
++	0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
++	0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
++
++	0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
++	0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
++	0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
++	0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
++
++	0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
++	0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
++	0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
++	0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
++
++	0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
++	0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
++	0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
++	0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
++
++	0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
++	0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
++	0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
++	0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
++
++	0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
++	0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
++	0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
++	0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
++
++	0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
++	0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
++	0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
++	0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
++
++	0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
++	0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
++	0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
++	0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
++};
+diff -urN linux-2.4.18/net/bluetooth/rfcomm/sock.c linux-2.4.18-mh9/net/bluetooth/rfcomm/sock.c
+--- linux-2.4.18/net/bluetooth/rfcomm/sock.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/sock.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,847 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * RFCOMM sockets.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/rfcomm.h>
++
++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++static struct proto_ops rfcomm_sock_ops;
++
++static struct bluez_sock_list rfcomm_sk_list = {
++	lock: RW_LOCK_UNLOCKED
++};
++
++static void rfcomm_sock_close(struct sock *sk);
++static void rfcomm_sock_kill(struct sock *sk);
++
++/* ---- DLC callbacks ----
++ *
++ * called under rfcomm_dlc_lock()
++ */
++static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
++{
++	struct sock *sk = d->owner;
++	if (!sk)
++		return;
++
++	atomic_add(skb->len, &sk->rmem_alloc);
++	skb_queue_tail(&sk->receive_queue, skb);
++	sk->data_ready(sk, skb->len);
++
++	if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf)
++		rfcomm_dlc_throttle(d);
++}
++
++static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
++{
++	struct sock *sk = d->owner, *parent;
++	if (!sk)
++		return;
++
++	BT_DBG("dlc %p state %ld err %d", d, d->state, err);
++
++	bh_lock_sock(sk);
++
++	if (err)
++		sk->err = err;
++	sk->state = d->state;
++
++	parent = bluez_pi(sk)->parent;
++	if (!parent) {
++		if (d->state == BT_CONNECTED)
++			rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL);
++		sk->state_change(sk);
++	} else
++		parent->data_ready(parent, 0);
++
++	bh_unlock_sock(sk);
++}
++
++/* ---- Socket functions ---- */
++static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
++{
++	struct sock *sk;
++
++	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
++		if (rfcomm_pi(sk)->channel == channel && 
++				!bacmp(&bluez_pi(sk)->src, src))
++			break;
++	}
++
++	return sk;
++}
++
++/* Find socket with channel and source bdaddr.
++ * Returns closest match.
++ */
++static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
++{
++	struct sock *sk, *sk1 = NULL;
++
++	for (sk = rfcomm_sk_list.head; sk; sk = sk->next) {
++		if (state && sk->state != state)
++			continue;
++
++		if (rfcomm_pi(sk)->channel == channel) {
++			/* Exact match. */
++			if (!bacmp(&bluez_pi(sk)->src, src))
++				break;
++
++			/* Closest match */
++			if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++				sk1 = sk;
++		}
++	}
++	return sk ? sk : sk1;
++}
++
++/* Find socket with given address (channel, src).
++ * Returns locked socket */
++static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
++{
++	struct sock *s;
++	read_lock(&rfcomm_sk_list.lock);
++	s = __rfcomm_get_sock_by_channel(state, channel, src);
++	if (s) bh_lock_sock(s);
++	read_unlock(&rfcomm_sk_list.lock);
++	return s;
++}
++
++static void rfcomm_sock_destruct(struct sock *sk)
++{
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++
++	BT_DBG("sk %p dlc %p", sk, d);
++
++	skb_queue_purge(&sk->receive_queue);
++	skb_queue_purge(&sk->write_queue);
++
++	rfcomm_dlc_lock(d);
++	rfcomm_pi(sk)->dlc = NULL;
++	
++	/* Detach DLC if it's owned by this socket */
++	if (d->owner == sk)
++		d->owner = NULL;
++	rfcomm_dlc_unlock(d);
++
++	rfcomm_dlc_put(d);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static void rfcomm_sock_cleanup_listen(struct sock *parent)
++{
++	struct sock *sk;
++
++	BT_DBG("parent %p", parent);
++
++	/* Close not yet accepted dlcs */
++	while ((sk = bluez_accept_dequeue(parent, NULL))) {
++		rfcomm_sock_close(sk);
++		rfcomm_sock_kill(sk);
++	}
++
++	parent->state  = BT_CLOSED;
++	parent->zapped = 1;
++}
++
++/* Kill socket (only if zapped and orphan)
++ * Must be called on unlocked socket.
++ */
++static void rfcomm_sock_kill(struct sock *sk)
++{
++	if (!sk->zapped || sk->socket)
++		return;
++
++	BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt));
++
++	/* Kill poor orphan */
++	bluez_sock_unlink(&rfcomm_sk_list, sk);
++	sk->dead = 1;
++	sock_put(sk);
++}
++
++static void __rfcomm_sock_close(struct sock *sk)
++{
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++
++	BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket);
++
++	switch (sk->state) {
++	case BT_LISTEN:
++		rfcomm_sock_cleanup_listen(sk);
++		break;
++
++	case BT_CONNECT:
++	case BT_CONNECT2:
++	case BT_CONFIG:
++	case BT_CONNECTED:
++		rfcomm_dlc_close(d, 0);
++
++	default:
++		sk->zapped = 1;
++		break;
++	}
++}
++
++/* Close socket.
++ * Must be called on unlocked socket.
++ */
++static void rfcomm_sock_close(struct sock *sk)
++{
++	lock_sock(sk);
++	__rfcomm_sock_close(sk);
++	release_sock(sk);
++}
++
++static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
++{
++	BT_DBG("sk %p", sk);
++
++	if (parent) 
++		sk->type = parent->type;
++}
++
++static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio)
++{
++	struct rfcomm_dlc *d;
++	struct sock *sk;
++
++	sk = sk_alloc(PF_BLUETOOTH, prio, 1);
++	if (!sk)
++		return NULL;
++
++	d = rfcomm_dlc_alloc(prio);
++	if (!d) {
++		sk_free(sk);
++		return NULL;
++	}
++	d->data_ready   = rfcomm_sk_data_ready;
++	d->state_change = rfcomm_sk_state_change;
++
++	rfcomm_pi(sk)->dlc = d;
++	d->owner = sk;
++
++	bluez_sock_init(sock, sk);
++
++	sk->zapped   = 0;
++
++	sk->destruct = rfcomm_sock_destruct;
++	sk->sndtimeo = RFCOMM_CONN_TIMEOUT;
++
++	sk->sndbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
++	sk->rcvbuf   = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
++
++	sk->protocol = proto;
++	sk->state    = BT_OPEN;
++
++	bluez_sock_link(&rfcomm_sk_list, sk);
++
++	BT_DBG("sk %p", sk);
++
++	MOD_INC_USE_COUNT;
++	return sk;
++}
++
++static int rfcomm_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	sock->state = SS_UNCONNECTED;
++
++	if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &rfcomm_sock_ops;
++
++	if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
++		return -ENOMEM;
++
++	rfcomm_sock_init(sk, NULL);
++	return 0;
++}
++
++static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
++{
++	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
++
++	if (!addr || addr->sa_family != AF_BLUETOOTH)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_OPEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	write_lock_bh(&rfcomm_sk_list.lock);
++
++	if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
++		err = -EADDRINUSE;
++	} else {
++		/* Save source address */
++		bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr);
++		rfcomm_pi(sk)->channel = sa->rc_channel;
++		sk->state = BT_BOUND;
++	}
++
++	write_unlock_bh(&rfcomm_sk_list.lock);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
++{
++	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
++	struct sock *sk = sock->sk;
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc))
++		return -EINVAL;
++
++	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
++		return -EBADFD;
++
++	if (sk->type != SOCK_STREAM)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	sk->state = BT_CONNECT;
++	bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr);
++	rfcomm_pi(sk)->channel = sa->rc_channel;
++	
++	err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
++	if (!err)
++		err = bluez_sock_wait_state(sk, BT_CONNECTED,
++				sock_sndtimeo(sk, flags & O_NONBLOCK));
++
++	release_sock(sk);
++	return err;
++}
++
++int rfcomm_sock_listen(struct socket *sock, int backlog)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p backlog %d", sk, backlog);
++
++	lock_sock(sk);
++
++	if (sk->state != BT_BOUND) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	sk->max_ack_backlog = backlog;
++	sk->ack_backlog = 0;
++	sk->state = BT_LISTEN;
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct sock *sk = sock->sk, *nsk;
++	long timeo;
++	int err = 0;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_LISTEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
++
++	BT_DBG("sk %p timeo %ld", sk, timeo);
++
++	/* Wait for an incoming connection. (wake-one). */
++	add_wait_queue_exclusive(sk->sleep, &wait);
++	while (!(nsk = bluez_accept_dequeue(sk, newsock))) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->state != BT_LISTEN) {
++			err = -EBADFD;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	if (err)
++		goto done;
++
++	newsock->state = SS_CONNECTED;
++
++	BT_DBG("new socket %p", nsk);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
++{
++	struct sockaddr_rc *sa = (struct sockaddr_rc *) addr;
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	sa->rc_family  = AF_BLUETOOTH;
++	sa->rc_channel = rfcomm_pi(sk)->channel;
++	if (peer)
++		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst);
++	else
++		bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src);
++
++	*len = sizeof(struct sockaddr_rc);
++	return 0;
++}
++
++static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len,
++			       struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
++	struct sk_buff *skb;
++	int err, size;
++	int sent = 0;
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	if (sk->shutdown & SEND_SHUTDOWN)
++		return -EPIPE;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	lock_sock(sk);
++
++	while (len) {
++		size = min_t(uint, len, d->mtu);
++		
++		skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
++				msg->msg_flags & MSG_DONTWAIT, &err);
++		if (!skb)
++			break;
++		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
++
++		err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
++		if (err) {
++			kfree_skb(skb);
++			sent = err;
++			break;
++		}
++
++		err = rfcomm_dlc_send(d, skb);
++		if (err < 0) {
++			kfree_skb(skb);
++			break;
++		}
++
++		sent += size;
++		len  -= size;
++	}
++
++	release_sock(sk);
++
++	return sent ? sent : err;
++}
++
++static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
++{
++	DECLARE_WAITQUEUE(wait, current);
++
++	add_wait_queue(sk->sleep, &wait);
++	for (;;) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) ||
++				signal_pending(current) || !timeo)
++			break;
++
++		set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++		clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
++	}
++
++	__set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++	return timeo;
++}
++
++static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size,
++			       int flags, struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	int target, err = 0, copied = 0;
++	long timeo;
++
++	if (flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	msg->msg_namelen = 0;
++
++	BT_DBG("sk %p size %d", sk, size);
++
++	lock_sock(sk);
++
++	target = sock_rcvlowat(sk, flags & MSG_WAITALL, size);
++	timeo  = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
++
++	do {
++		struct sk_buff *skb;
++		int chunk;
++
++		skb = skb_dequeue(&sk->receive_queue);
++		if (!skb) {
++			if (copied >= target)
++				break;
++
++			if ((err = sock_error(sk)) != 0)
++				break;
++			if (sk->shutdown & RCV_SHUTDOWN)
++				break;
++
++			err = -EAGAIN;
++			if (!timeo)
++				break;
++
++			timeo = rfcomm_sock_data_wait(sk, timeo);
++
++			if (signal_pending(current)) {
++				err = sock_intr_errno(timeo);
++				goto out;
++			}
++			continue;
++		}
++
++		chunk = min_t(unsigned int, skb->len, size);
++		if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
++			skb_queue_head(&sk->receive_queue, skb);
++			if (!copied)
++				copied = -EFAULT;
++			break;
++		}
++		copied += chunk;
++		size   -= chunk;
++
++		if (!(flags & MSG_PEEK)) {
++			atomic_sub(chunk, &sk->rmem_alloc);
++
++			skb_pull(skb, chunk);
++			if (skb->len) {
++				skb_queue_head(&sk->receive_queue, skb);
++				break;
++			}
++			kfree_skb(skb);
++
++		} else {
++			/* put message back and return */
++			skb_queue_head(&sk->receive_queue, skb);
++			break;
++		}
++	} while (size);
++
++out:
++	if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2))
++		rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc);
++
++	release_sock(sk);
++	return copied ? : err;
++}
++
++static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	lock_sock(sk);
++
++	switch (optname) {
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
++{
++	struct sock *sk = sock->sk;
++	int len, err = 0; 
++
++	BT_DBG("sk %p", sk);
++
++	if (get_user(len, optlen))
++		return -EFAULT;
++
++	lock_sock(sk);
++
++	switch (optname) {
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
++{
++	struct sock *sk = sock->sk;
++	int err;
++
++	lock_sock(sk);
++
++#ifdef CONFIG_BLUEZ_RFCOMM_TTY
++	err = rfcomm_dev_ioctl(sk, cmd, arg);
++#else
++	err = -EOPNOTSUPP;
++#endif
++
++	release_sock(sk);
++
++	return err;
++}
++
++static int rfcomm_sock_shutdown(struct socket *sock, int how)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk) return 0;
++
++	lock_sock(sk);
++	if (!sk->shutdown) {
++		sk->shutdown = SHUTDOWN_MASK;
++		__rfcomm_sock_close(sk);
++
++		if (sk->linger)
++			err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
++	}
++	release_sock(sk);
++	return err;
++}
++
++static int rfcomm_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	err = rfcomm_sock_shutdown(sock, 2);
++
++	sock_orphan(sk);
++	rfcomm_sock_kill(sk);
++	return err;
++}
++
++/* ---- RFCOMM core layer callbacks ---- 
++ *
++ * called under rfcomm_lock()
++ */
++int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d)
++{
++	struct sock *sk, *parent;
++	bdaddr_t src, dst;
++	int result = 0;
++
++	BT_DBG("session %p channel %d", s, channel);
++
++	rfcomm_session_getaddr(s, &src, &dst);
++
++	/* Check if we have socket listening on this channel */
++	parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src);
++	if (!parent)
++		return 0;
++
++	/* Check for backlog size */
++	if (parent->ack_backlog > parent->max_ack_backlog) {
++		BT_DBG("backlog full %d", parent->ack_backlog); 
++		goto done;
++	}
++
++	sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC);
++	if (!sk)
++		goto done;
++
++	rfcomm_sock_init(sk, parent);
++	bacpy(&bluez_pi(sk)->src, &src);
++	bacpy(&bluez_pi(sk)->dst, &dst);
++	rfcomm_pi(sk)->channel = channel;
++
++	sk->state = BT_CONFIG;
++	bluez_accept_enqueue(parent, sk);
++
++	/* Accept connection and return socket DLC */
++	*d = rfcomm_pi(sk)->dlc;
++	result = 1;
++
++done:
++	bh_unlock_sock(parent);
++	return result;
++}
++
++/* ---- Proc fs support ---- */
++int rfcomm_sock_dump(char *buf)
++{
++	struct bluez_sock_list *list = &rfcomm_sk_list;
++	struct rfcomm_pinfo *pi;
++	struct sock *sk;
++	char *ptr = buf;
++
++	write_lock_bh(&list->lock);
++
++	for (sk = list->head; sk; sk = sk->next) {
++		pi = rfcomm_pi(sk);
++		ptr += sprintf(ptr, "sk  %s %s %d %d\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
++				sk->state, rfcomm_pi(sk)->channel);
++	}
++
++	write_unlock_bh(&list->lock);
++
++	return ptr - buf;
++}
++
++static struct proto_ops rfcomm_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	rfcomm_sock_release,
++	bind:		rfcomm_sock_bind,
++	connect:	rfcomm_sock_connect,
++	listen:		rfcomm_sock_listen,
++	accept:		rfcomm_sock_accept,
++	getname:	rfcomm_sock_getname,
++	sendmsg:	rfcomm_sock_sendmsg,
++	recvmsg:	rfcomm_sock_recvmsg,
++	shutdown:	rfcomm_sock_shutdown,
++	setsockopt:	rfcomm_sock_setsockopt,
++	getsockopt:	rfcomm_sock_getsockopt,
++	ioctl:		rfcomm_sock_ioctl,
++	poll:		bluez_sock_poll,
++	socketpair:	sock_no_socketpair,
++	mmap:		sock_no_mmap
++};
++
++static struct net_proto_family rfcomm_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		rfcomm_sock_create
++};
++
++int rfcomm_init_sockets(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) {
++		BT_ERR("Can't register RFCOMM socket layer");
++		return err;
++	}
++
++	return 0;
++}
++
++void rfcomm_cleanup_sockets(void)
++{
++	int err;
++
++	/* Unregister socket, protocol and notifier */
++	if ((err = bluez_sock_unregister(BTPROTO_RFCOMM)))
++		BT_ERR("Can't unregister RFCOMM socket layer %d", err);
++}
+diff -urN linux-2.4.18/net/bluetooth/rfcomm/tty.c linux-2.4.18-mh9/net/bluetooth/rfcomm/tty.c
+--- linux-2.4.18/net/bluetooth/rfcomm/tty.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/rfcomm/tty.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,945 @@
++/* 
++   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
++   Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
++   Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * RFCOMM TTY.
++ *
++ * $Id$
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++
++#include <linux/slab.h>
++#include <linux/skbuff.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/rfcomm.h>
++
++#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG
++#undef  BT_DBG
++#define BT_DBG(D...)
++#endif
++
++#define RFCOMM_TTY_MAGIC 0x6d02		/* magic number for rfcomm struct */
++#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV	/* whole lotta rfcomm devices */
++#define RFCOMM_TTY_MAJOR 216		/* device node major id of the usb/bluetooth.c driver */
++#define RFCOMM_TTY_MINOR 0
++
++struct rfcomm_dev {
++	struct list_head	list;
++	atomic_t		refcnt;
++
++	char			name[12];
++	int			id;
++	unsigned long		flags;
++	int			opened;
++	int			err;
++
++	bdaddr_t		src;
++	bdaddr_t		dst;
++	u8 			channel;
++
++	uint 			modem_status;
++
++	struct rfcomm_dlc	*dlc;
++	struct tty_struct	*tty;
++	wait_queue_head_t       wait;
++	struct tasklet_struct   wakeup_task;
++
++	atomic_t 		wmem_alloc;
++};
++
++static LIST_HEAD(rfcomm_dev_list);
++static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED;
++
++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
++
++static void rfcomm_tty_wakeup(unsigned long arg);
++
++/* ---- Device functions ---- */
++static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
++{
++	struct rfcomm_dlc *dlc = dev->dlc;
++
++	BT_DBG("dev %p dlc %p", dev, dlc);
++
++	rfcomm_dlc_lock(dlc);
++	/* Detach DLC if it's owned by this dev */
++	if (dlc->owner == dev)
++		dlc->owner = NULL;
++	rfcomm_dlc_unlock(dlc);
++
++	rfcomm_dlc_put(dlc);
++	kfree(dev);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
++{
++	atomic_inc(&dev->refcnt);
++}
++
++static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
++{
++	if (atomic_dec_and_test(&dev->refcnt))
++		rfcomm_dev_destruct(dev);
++}
++
++static struct rfcomm_dev *__rfcomm_dev_get(int id)
++{
++	struct rfcomm_dev *dev;
++	struct list_head  *p;
++
++	list_for_each(p, &rfcomm_dev_list) {
++		dev = list_entry(p, struct rfcomm_dev, list);
++		if (dev->id == id)
++			return dev;
++	}
++
++	return NULL;
++}
++
++static inline struct rfcomm_dev *rfcomm_dev_get(int id)
++{
++	struct rfcomm_dev *dev;
++
++	read_lock(&rfcomm_dev_lock);
++	dev = __rfcomm_dev_get(id);
++	read_unlock(&rfcomm_dev_lock);
++
++	if (dev) rfcomm_dev_hold(dev);
++	return dev;
++}
++
++static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
++{
++	struct rfcomm_dev *dev;
++	struct list_head *head = &rfcomm_dev_list, *p;
++	int err = 0;
++
++	BT_DBG("id %d channel %d", req->dev_id, req->channel);
++	
++	dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL);
++	if (!dev)
++		return -ENOMEM;
++	memset(dev, 0, sizeof(struct rfcomm_dev));
++
++	write_lock_bh(&rfcomm_dev_lock);
++
++	if (req->dev_id < 0) {
++		dev->id = 0;
++
++		list_for_each(p, &rfcomm_dev_list) {
++			if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
++				break;
++
++			dev->id++;
++			head = p;
++		}
++	} else {
++		dev->id = req->dev_id;
++
++		list_for_each(p, &rfcomm_dev_list) {
++			struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
++
++			if (entry->id == dev->id) {
++				err = -EADDRINUSE;
++				goto out;
++			}
++
++			if (entry->id > dev->id - 1)
++				break;
++
++			head = p;
++		}
++	}
++
++	if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) {
++		err = -ENFILE;
++		goto out;
++	}
++
++	sprintf(dev->name, "rfcomm%d", dev->id);
++
++	list_add(&dev->list, head);
++	atomic_set(&dev->refcnt, 1);
++
++	bacpy(&dev->src, &req->src);
++	bacpy(&dev->dst, &req->dst);
++	dev->channel = req->channel;
++
++	dev->flags = req->flags & 
++		((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC));
++
++	init_waitqueue_head(&dev->wait);
++	tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
++
++	rfcomm_dlc_lock(dlc);
++	dlc->data_ready   = rfcomm_dev_data_ready;
++	dlc->state_change = rfcomm_dev_state_change;
++	dlc->modem_status = rfcomm_dev_modem_status;
++
++	dlc->owner = dev;
++	dev->dlc   = dlc;
++	rfcomm_dlc_unlock(dlc);
++
++	MOD_INC_USE_COUNT;
++	
++out:
++	write_unlock_bh(&rfcomm_dev_lock);
++
++	if (err) {
++		kfree(dev);
++		return err;
++	} else
++		return dev->id;
++}
++
++static void rfcomm_dev_del(struct rfcomm_dev *dev)
++{
++	BT_DBG("dev %p", dev);
++
++	write_lock_bh(&rfcomm_dev_lock);
++	list_del_init(&dev->list);
++	write_unlock_bh(&rfcomm_dev_lock);
++
++	rfcomm_dev_put(dev);
++}
++
++/* ---- Send buffer ---- */
++
++static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc)
++{
++	/* We can't let it be zero, because we don't get a callback 
++	   when tx_credits becomes nonzero, hence we'd never wake up */
++	return dlc->mtu * (dlc->tx_credits?:1);
++}
++
++static void rfcomm_wfree(struct sk_buff *skb)
++{
++	struct rfcomm_dev *dev = (void *) skb->sk;
++	atomic_sub(skb->truesize, &dev->wmem_alloc);
++	if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
++		tasklet_schedule(&dev->wakeup_task);
++	rfcomm_dev_put(dev);
++}
++
++static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
++{
++	rfcomm_dev_hold(dev);
++	atomic_add(skb->truesize, &dev->wmem_alloc);
++	skb->sk = (void *) dev;
++	skb->destructor = rfcomm_wfree;
++}
++
++static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority)
++{
++	if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) {
++		struct sk_buff *skb = alloc_skb(size, priority);
++		if (skb) {
++			rfcomm_set_owner_w(skb, dev);
++			return skb;
++		}
++	}
++	return NULL;
++}
++
++/* ---- Device IOCTLs ---- */
++
++#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP))
++
++static int rfcomm_create_dev(struct sock *sk, unsigned long arg)
++{
++	struct rfcomm_dev_req req;
++	struct rfcomm_dlc *dlc;
++	int id;
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags);
++
++	if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN))
++		return -EPERM;
++
++	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
++		/* Socket must be connected */
++		if (sk->state != BT_CONNECTED)
++			return -EBADFD;
++
++		dlc = rfcomm_pi(sk)->dlc;
++		rfcomm_dlc_hold(dlc);
++	} else {
++		dlc = rfcomm_dlc_alloc(GFP_KERNEL);
++		if (!dlc)
++			return -ENOMEM;
++	}
++
++	id = rfcomm_dev_add(&req, dlc);
++	if (id < 0) {
++		rfcomm_dlc_put(dlc);
++		return id;
++	}
++
++	if (req.flags & (1 << RFCOMM_REUSE_DLC)) {
++		/* DLC is now used by device.
++		 * Socket must be disconnected */
++		sk->state = BT_CLOSED;
++	}
++
++	return id;
++}
++
++static int rfcomm_release_dev(unsigned long arg)
++{
++	struct rfcomm_dev_req req;
++	struct rfcomm_dev *dev;
++
++	if (copy_from_user(&req, (void *) arg, sizeof(req)))
++		return -EFAULT;
++
++	BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags);
++
++	if (!capable(CAP_NET_ADMIN))
++		return -EPERM;
++
++	if (!(dev = rfcomm_dev_get(req.dev_id)))
++		return -ENODEV;
++
++	if (req.flags & (1 << RFCOMM_HANGUP_NOW))
++		rfcomm_dlc_close(dev->dlc, 0);
++
++	rfcomm_dev_del(dev);
++	rfcomm_dev_put(dev);
++	return 0;
++}
++
++static int rfcomm_get_dev_list(unsigned long arg)
++{
++	struct rfcomm_dev_list_req *dl;
++	struct rfcomm_dev_info *di;
++	struct list_head *p;
++	int n = 0, size;
++	u16 dev_num;
++
++	BT_DBG("");
++
++	if (get_user(dev_num, (u16 *) arg))
++		return -EFAULT;
++
++	if (!dev_num)
++		return -EINVAL;
++
++	size = sizeof(*dl) + dev_num * sizeof(*di);
++
++	if (verify_area(VERIFY_WRITE, (void *)arg, size))
++		return -EFAULT;
++
++	if (!(dl = kmalloc(size, GFP_KERNEL)))
++		return -ENOMEM;
++
++	di = dl->dev_info;
++
++	read_lock_bh(&rfcomm_dev_lock);
++
++	list_for_each(p, &rfcomm_dev_list) {
++		struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
++		(di + n)->id      = dev->id;
++		(di + n)->flags   = dev->flags;
++		(di + n)->state   = dev->dlc->state;
++		(di + n)->channel = dev->channel;
++		bacpy(&(di + n)->src, &dev->src);
++		bacpy(&(di + n)->dst, &dev->dst);
++		if (++n >= dev_num)
++			break;
++	}
++
++	read_unlock_bh(&rfcomm_dev_lock);
++
++	dl->dev_num = n;
++	size = sizeof(*dl) + n * sizeof(*di);
++
++	copy_to_user((void *) arg, dl, size);
++	kfree(dl);
++	return 0;
++}
++
++static int rfcomm_get_dev_info(unsigned long arg)
++{
++	struct rfcomm_dev *dev;
++	struct rfcomm_dev_info di;
++	int err = 0;
++
++	BT_DBG("");
++
++	if (copy_from_user(&di, (void *)arg, sizeof(di)))
++		return -EFAULT;
++
++	if (!(dev = rfcomm_dev_get(di.id)))
++		return -ENODEV;
++
++	di.flags   = dev->flags;
++	di.channel = dev->channel;
++	di.state   = dev->dlc->state;
++	bacpy(&di.src, &dev->src);
++	bacpy(&di.dst, &dev->dst);
++
++	if (copy_to_user((void *)arg, &di, sizeof(di)))
++		err = -EFAULT;
++
++	rfcomm_dev_put(dev);
++	return err;
++}
++
++int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
++{
++	BT_DBG("cmd %d arg %ld", cmd, arg);
++
++	switch (cmd) {
++	case RFCOMMCREATEDEV:
++		return rfcomm_create_dev(sk, arg);
++
++	case RFCOMMRELEASEDEV:
++		return rfcomm_release_dev(arg);
++
++	case RFCOMMGETDEVLIST:
++		return rfcomm_get_dev_list(arg);
++
++	case RFCOMMGETDEVINFO:
++		return rfcomm_get_dev_info(arg);
++	}
++
++	return -EINVAL;
++}
++
++/* ---- DLC callbacks ---- */
++static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
++{
++	struct rfcomm_dev *dev = dlc->owner;
++	struct tty_struct *tty;
++       
++	if (!dev || !(tty = dev->tty)) {
++		kfree_skb(skb);
++		return;
++	}
++
++	BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len);
++
++	if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
++		register int i;
++		for (i = 0; i < skb->len; i++) {
++			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
++				tty_flip_buffer_push(tty);
++
++			tty_insert_flip_char(tty, skb->data[i], 0);
++		}
++		tty_flip_buffer_push(tty);
++	} else
++		tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len);
++
++	kfree_skb(skb);
++}
++
++static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
++{
++	struct rfcomm_dev *dev = dlc->owner;
++	if (!dev)
++		return;
++	
++	BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
++
++	dev->err = err;
++	wake_up_interruptible(&dev->wait);
++
++	if (dlc->state == BT_CLOSED) {
++		if (!dev->tty) {
++			if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) {
++				rfcomm_dev_hold(dev);
++				rfcomm_dev_del(dev);
++
++				/* We have to drop DLC lock here, otherwise
++				 * rfcomm_dev_put() will dead lock if it's the last refference */
++				rfcomm_dlc_unlock(dlc);
++				rfcomm_dev_put(dev);
++				rfcomm_dlc_lock(dlc);
++			}
++		} else 
++			tty_hangup(dev->tty);
++	}
++}
++
++static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
++{
++	struct rfcomm_dev *dev = dlc->owner;
++	if (!dev)
++		return;
++	
++	BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig);
++
++	dev->modem_status = 
++		((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) |
++		((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) |
++		((v24_sig & RFCOMM_V24_IC)  ? TIOCM_RI : 0) |
++		((v24_sig & RFCOMM_V24_DV)  ? TIOCM_CD : 0);
++}
++
++/* ---- TTY functions ---- */
++static void rfcomm_tty_wakeup(unsigned long arg)
++{
++	struct rfcomm_dev *dev = (void *) arg;
++	struct tty_struct *tty = dev->tty;
++	if (!tty)
++		return;
++
++	BT_DBG("dev %p tty %p", dev, tty);
++
++	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
++                (tty->ldisc.write_wakeup)(tty);
++
++	wake_up_interruptible(&tty->write_wait);
++#ifdef SERIAL_HAVE_POLL_WAIT
++	wake_up_interruptible(&tty->poll_wait);
++#endif
++}
++
++static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct rfcomm_dev *dev;
++	struct rfcomm_dlc *dlc;
++	int err, id;
++
++	id = MINOR(tty->device) - tty->driver.minor_start;
++
++	BT_DBG("tty %p id %d", tty, id);
++
++	dev = rfcomm_dev_get(id);
++	if (!dev)
++		return -ENODEV;
++
++	BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened);
++
++	if (dev->opened++ != 0)
++		return 0;
++
++	dlc = dev->dlc;
++
++	/* Attach TTY and open DLC */
++
++	rfcomm_dlc_lock(dlc);
++	tty->driver_data = dev;
++	dev->tty = tty;
++	rfcomm_dlc_unlock(dlc);
++	set_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
++
++	err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel);
++	if (err < 0)
++		return err;
++
++	/* Wait for DLC to connect */
++	add_wait_queue(&dev->wait, &wait);
++	while (1) {
++		set_current_state(TASK_INTERRUPTIBLE);
++
++		if (dlc->state == BT_CLOSED) {
++			err = -dev->err;
++			break;
++		}
++
++		if (dlc->state == BT_CONNECTED)
++			break;
++
++		if (signal_pending(current)) {
++			err = -EINTR;
++			break;
++		}
++
++		schedule();
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(&dev->wait, &wait);
++
++	return err;
++}
++
++static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	if (!dev)
++		return;
++
++	BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened);
++
++	if (--dev->opened == 0) {
++		/* Close DLC and dettach TTY */
++		rfcomm_dlc_close(dev->dlc, 0);
++
++		clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
++		tasklet_kill(&dev->wakeup_task);
++
++		rfcomm_dlc_lock(dev->dlc);
++		tty->driver_data = NULL;
++		dev->tty = NULL;
++		rfcomm_dlc_unlock(dev->dlc);
++	}
++
++	rfcomm_dev_put(dev);
++}
++
++static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++	struct sk_buff *skb;
++	int err = 0, sent = 0, size;
++
++	BT_DBG("tty %p from_user %d count %d", tty, from_user, count);
++
++	while (count) {
++		size = min_t(uint, count, dlc->mtu);
++
++		if (from_user)
++			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL);
++		else
++			skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC);
++		
++		if (!skb)
++			break;
++
++		skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
++
++		if (from_user)
++			copy_from_user(skb_put(skb, size), buf + sent, size);
++		else
++			memcpy(skb_put(skb, size), buf + sent, size);
++
++		if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
++			kfree_skb(skb);
++			break;
++		}
++
++		sent  += size;
++		count -= size;
++	}
++
++	return sent ? sent : err;
++}
++
++static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++	struct sk_buff *skb;
++
++	BT_DBG("tty %p char %x", tty, ch);
++
++	skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC);
++
++	if (!skb)
++		return;
++
++	skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
++
++	*(char *)skb_put(skb, 1) = ch;
++
++	if ((rfcomm_dlc_send(dlc, skb)) < 0)
++		kfree_skb(skb);	
++}
++
++static int rfcomm_tty_write_room(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	int room;
++	
++	BT_DBG("tty %p", tty);
++
++	room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc);
++	if (room < 0)
++		room = 0;
++
++	return room;
++}
++
++static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status)
++{
++	u8 v24_sig, mask;
++
++	BT_DBG("dlc %p cmd 0x%02x", dlc, cmd);
++
++	if (cmd == TIOCMSET)
++		v24_sig = 0;
++	else
++		rfcomm_dlc_get_modem_status(dlc, &v24_sig);
++
++	mask =  ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) |
++		((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) |
++		((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) |
++		((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) |
++		((status & TIOCM_RI)  ? RFCOMM_V24_IC  : 0) |
++		((status & TIOCM_CD)  ? RFCOMM_V24_DV  : 0);
++
++	if (cmd == TIOCMBIC)
++		v24_sig &= ~mask;
++	else
++		v24_sig |= mask;
++
++	rfcomm_dlc_set_modem_status(dlc, v24_sig);
++	return 0;
++}
++
++static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++	uint status;
++	int err;
++
++	BT_DBG("tty %p cmd 0x%02x", tty, cmd);
++
++	switch (cmd) {
++	case TCGETS:
++		BT_DBG("TCGETS is not supported");
++		return -ENOIOCTLCMD;
++
++	case TCSETS:
++		BT_DBG("TCSETS is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCMGET:
++		BT_DBG("TIOCMGET");
++
++		return put_user(dev->modem_status, (unsigned int *)arg);
++
++	case TIOCMSET: /* Turns on and off the lines as specified by the mask */
++	case TIOCMBIS: /* Turns on the lines as specified by the mask */
++	case TIOCMBIC: /* Turns off the lines as specified by the mask */
++		if ((err = get_user(status, (unsigned int *)arg)))
++			return err;
++		return rfcomm_tty_set_modem_status(cmd, dlc, status);
++
++	case TIOCMIWAIT:
++		BT_DBG("TIOCMIWAIT");
++		break;
++
++	case TIOCGICOUNT:
++		BT_DBG("TIOCGICOUNT");
++		break;
++
++	case TIOCGSERIAL:
++		BT_ERR("TIOCGSERIAL is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSSERIAL:
++		BT_ERR("TIOCSSERIAL is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSERGSTRUCT:
++		BT_ERR("TIOCSERGSTRUCT is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSERGETLSR:
++		BT_ERR("TIOCSERGETLSR is not supported");
++		return -ENOIOCTLCMD;
++
++	case TIOCSERCONFIG:
++		BT_ERR("TIOCSERCONFIG is not supported");
++		return -ENOIOCTLCMD;
++
++	default:
++		return -ENOIOCTLCMD;	/* ioctls which we must ignore */
++
++	}
++
++	return -ENOIOCTLCMD;
++}
++
++#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
++
++static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
++{
++	BT_DBG("tty %p", tty);
++
++	if ((tty->termios->c_cflag == old->c_cflag) &&
++		(RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag)))
++		return;
++
++	/* handle turning off CRTSCTS */
++	if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
++		BT_DBG("turning off CRTSCTS");
++	}
++}
++
++static void rfcomm_tty_throttle(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++	
++	rfcomm_dlc_throttle(dev->dlc);
++}
++
++static void rfcomm_tty_unthrottle(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++	
++	rfcomm_dlc_unthrottle(dev->dlc);
++}
++
++static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	struct rfcomm_dlc *dlc = dev->dlc;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++
++	if (skb_queue_len(&dlc->tx_queue))
++		return dlc->mtu;
++
++	return 0;
++}
++
++static void rfcomm_tty_flush_buffer(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	if (!dev)
++		return;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++
++	skb_queue_purge(&dev->dlc->tx_queue);
++
++	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup)
++		tty->ldisc.write_wakeup(tty);
++}
++
++static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch)
++{
++	BT_DBG("tty %p ch %c", tty, ch);
++}
++
++static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++	BT_DBG("tty %p timeout %d", tty, timeout);
++}
++
++static void rfcomm_tty_hangup(struct tty_struct *tty)
++{
++	struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data;
++	if (!dev)
++		return;
++
++	BT_DBG("tty %p dev %p", tty, dev);
++
++	rfcomm_tty_flush_buffer(tty);
++
++	if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
++		rfcomm_dev_del(dev);
++}
++
++static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused)
++{
++	return 0;
++}
++
++/* ---- TTY structure ---- */
++static int    rfcomm_tty_refcount;       /* If we manage several devices */
++
++static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS];
++static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS];
++static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS];
++
++static struct tty_driver rfcomm_tty_driver = {
++	magic:			TTY_DRIVER_MAGIC,
++	driver_name:		"rfcomm",
++#ifdef CONFIG_DEVFS_FS
++	name:			"bluetooth/rfcomm/%d",
++#else
++	name:			"rfcomm",
++#endif
++	major:			RFCOMM_TTY_MAJOR,
++	minor_start:		RFCOMM_TTY_MINOR,
++	num:			RFCOMM_TTY_PORTS,
++	type:			TTY_DRIVER_TYPE_SERIAL,
++	subtype:		SERIAL_TYPE_NORMAL,
++	flags:			TTY_DRIVER_REAL_RAW,
++
++	refcount:		&rfcomm_tty_refcount,
++	table:			rfcomm_tty_table,
++	termios:		rfcomm_tty_termios,
++	termios_locked:		rfcomm_tty_termios_locked,
++
++	open:			rfcomm_tty_open,
++	close:			rfcomm_tty_close,
++	put_char:		rfcomm_tty_put_char,
++	write:			rfcomm_tty_write,
++	write_room:		rfcomm_tty_write_room,
++	chars_in_buffer:	rfcomm_tty_chars_in_buffer,
++	flush_buffer:		rfcomm_tty_flush_buffer,
++	ioctl:			rfcomm_tty_ioctl,
++	throttle:		rfcomm_tty_throttle,
++	unthrottle:		rfcomm_tty_unthrottle,
++	set_termios:		rfcomm_tty_set_termios,
++	send_xchar:		rfcomm_tty_send_xchar,
++	stop:			NULL,
++	start:			NULL,
++	hangup:			rfcomm_tty_hangup,
++	wait_until_sent:	rfcomm_tty_wait_until_sent,
++	read_proc:		rfcomm_tty_read_proc,
++};
++
++int rfcomm_init_ttys(void)
++{
++	int i;
++
++	/* Initalize our global data */
++	for (i = 0; i < RFCOMM_TTY_PORTS; i++)
++		rfcomm_tty_table[i] = NULL;
++
++	/* Register the TTY driver */
++	rfcomm_tty_driver.init_termios = tty_std_termios;
++	rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
++	rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW;
++
++	if (tty_register_driver(&rfcomm_tty_driver)) {
++		BT_ERR("Can't register RFCOMM TTY driver");
++		return -1;
++	}
++
++	return 0;
++}
++
++void rfcomm_cleanup_ttys(void)
++{
++	tty_unregister_driver(&rfcomm_tty_driver);
++	return;
++}
+diff -urN linux-2.4.18/net/bluetooth/sco.c linux-2.4.18-mh9/net/bluetooth/sco.c
+--- linux-2.4.18/net/bluetooth/sco.c	Thu Jan  1 01:00:00 1970
++++ linux-2.4.18-mh9/net/bluetooth/sco.c	Mon Aug 25 18:38:12 2003
+@@ -0,0 +1,1019 @@
++/* 
++   BlueZ - Bluetooth protocol stack for Linux
++   Copyright (C) 2000-2001 Qualcomm Incorporated
++
++   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
++
++   This program is free software; you can redistribute it and/or modify
++   it under the terms of the GNU General Public License version 2 as
++   published by the Free Software Foundation;
++
++   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
++   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
++   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES 
++   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 
++   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 
++   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
++
++   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, 
++   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS 
++   SOFTWARE IS DISCLAIMED.
++*/
++
++/*
++ * BlueZ SCO sockets.
++ *
++ * $Id$
++ */
++#define VERSION "0.3"
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/major.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/poll.h>
++#include <linux/fcntl.h>
++#include <linux/init.h>
++#include <linux/skbuff.h>
++#include <linux/interrupt.h>
++#include <linux/socket.h>
++#include <linux/skbuff.h>
++#include <linux/proc_fs.h>
++#include <linux/list.h>
++#include <net/sock.h>
++
++#include <asm/system.h>
++#include <asm/uaccess.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++#include <net/bluetooth/sco.h>
++
++#ifndef SCO_DEBUG
++#undef  BT_DBG
++#define BT_DBG( A... )
++#endif
++
++static struct proto_ops sco_sock_ops;
++
++static struct bluez_sock_list sco_sk_list = {
++	lock: RW_LOCK_UNLOCKED
++};
++
++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
++static void sco_chan_del(struct sock *sk, int err);
++static inline struct sock * sco_chan_get(struct sco_conn *conn);
++
++static int  sco_conn_del(struct hci_conn *conn, int err);
++
++static void sco_sock_close(struct sock *sk);
++static void sco_sock_kill(struct sock *sk);
++
++/* ----- SCO timers ------ */
++static void sco_sock_timeout(unsigned long arg)
++{
++	struct sock *sk = (struct sock *) arg;
++
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	bh_lock_sock(sk);
++	sk->err = ETIMEDOUT;
++	sk->state_change(sk);
++	bh_unlock_sock(sk);
++
++	sco_sock_kill(sk);
++	sock_put(sk);
++}
++
++static void sco_sock_set_timer(struct sock *sk, long timeout)
++{
++	BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout);
++
++	if (!mod_timer(&sk->timer, jiffies + timeout))
++		sock_hold(sk);
++}
++
++static void sco_sock_clear_timer(struct sock *sk)
++{
++	BT_DBG("sock %p state %d", sk, sk->state);
++
++	if (timer_pending(&sk->timer) && del_timer(&sk->timer))
++		__sock_put(sk);
++}
++
++static void sco_sock_init_timer(struct sock *sk)
++{
++	init_timer(&sk->timer);
++	sk->timer.function = sco_sock_timeout;
++	sk->timer.data = (unsigned long)sk;
++}
++
++/* -------- SCO connections --------- */
++static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)
++{
++	struct hci_dev *hdev = hcon->hdev;
++	struct sco_conn *conn;
++
++	if ((conn = hcon->sco_data))
++		return conn;
++
++	if (status)
++		return conn;
++
++	if (!(conn = kmalloc(sizeof(struct sco_conn), GFP_ATOMIC)))
++		return NULL;
++	memset(conn, 0, sizeof(struct sco_conn));
++
++	spin_lock_init(&conn->lock);
++
++	hcon->sco_data = conn;
++	conn->hcon = hcon;
++
++	conn->src = &hdev->bdaddr;
++	conn->dst = &hcon->dst;
++	
++	if (hdev->sco_mtu > 0)
++		conn->mtu = hdev->sco_mtu;
++	else
++		conn->mtu = 60;
++
++	BT_DBG("hcon %p conn %p", hcon, conn);
++
++	MOD_INC_USE_COUNT;
++	return conn;
++}
++
++static int sco_conn_del(struct hci_conn *hcon, int err)
++{
++	struct sco_conn *conn;
++	struct sock *sk;
++
++	if (!(conn = hcon->sco_data)) 
++		return 0;
++
++	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
++
++	/* Kill socket */
++	if ((sk = sco_chan_get(conn))) {
++		bh_lock_sock(sk);
++		sco_sock_clear_timer(sk);
++		sco_chan_del(sk, err);
++		bh_unlock_sock(sk);
++		sco_sock_kill(sk);
++	}
++
++	hcon->sco_data = NULL;
++	kfree(conn);
++
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++int sco_connect(struct sock *sk)
++{
++	bdaddr_t *src = &bluez_pi(sk)->src;
++	bdaddr_t *dst = &bluez_pi(sk)->dst;
++	struct sco_conn *conn;
++	struct hci_conn *hcon;
++	struct hci_dev  *hdev;
++	int err = 0;
++
++	BT_DBG("%s -> %s", batostr(src), batostr(dst));
++
++	if (!(hdev = hci_get_route(dst, src)))
++		return -EHOSTUNREACH;
++
++	hci_dev_lock_bh(hdev);
++
++	err = -ENOMEM;
++
++	hcon = hci_connect(hdev, SCO_LINK, dst);
++	if (!hcon)
++		goto done;
++
++	conn = sco_conn_add(hcon, 0);
++	if (!conn) {
++		hci_conn_put(hcon);
++		goto done;
++	}
++
++	/* Update source addr of the socket */
++	bacpy(src, conn->src);
++
++	err = sco_chan_add(conn, sk, NULL);
++	if (err)
++		goto done;
++
++	if (hcon->state == BT_CONNECTED) {
++		sco_sock_clear_timer(sk);
++		sk->state = BT_CONNECTED;
++	} else {
++		sk->state = BT_CONNECT;
++		sco_sock_set_timer(sk, sk->sndtimeo);
++	}
++done:
++	hci_dev_unlock_bh(hdev);
++	hci_dev_put(hdev);
++	return err;
++}
++
++static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
++{
++	struct sco_conn *conn = sco_pi(sk)->conn;
++	struct sk_buff *skb;
++	int err, count;
++
++	/* Check outgoing MTU */
++	if (len > conn->mtu)
++		return -EINVAL;
++
++	BT_DBG("sk %p len %d", sk, len);
++
++	count = MIN(conn->mtu, len);
++	if (!(skb = bluez_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err)))
++		return err;
++
++	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) {
++		err = -EFAULT;
++		goto fail;
++	}
++
++	if ((err = hci_send_sco(conn->hcon, skb)) < 0)
++		goto fail;
++
++	return count;
++
++fail:
++	kfree_skb(skb);
++	return err;
++}
++
++static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
++{
++	struct sock *sk = sco_chan_get(conn);
++
++	if (!sk)
++		goto drop;
++
++	BT_DBG("sk %p len %d", sk, skb->len);
++
++	if (sk->state != BT_CONNECTED)
++		goto drop;
++
++	if (!sock_queue_rcv_skb(sk, skb))
++		return;
++
++drop:
++	kfree_skb(skb);
++	return;
++}
++
++/* -------- Socket interface ---------- */
++static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba)
++{
++	struct sock *sk;
++
++	for (sk = sco_sk_list.head; sk; sk = sk->next) {
++		if (!bacmp(&bluez_pi(sk)->src, ba))
++			break;
++	}
++
++	return sk;
++}
++
++/* Find socket listening on source bdaddr.
++ * Returns closest match.
++ */
++static struct sock *sco_get_sock_listen(bdaddr_t *src)
++{
++	struct sock *sk, *sk1 = NULL;
++
++	read_lock(&sco_sk_list.lock);
++
++	for (sk = sco_sk_list.head; sk; sk = sk->next) {
++		if (sk->state != BT_LISTEN)
++			continue;
++
++		/* Exact match. */
++		if (!bacmp(&bluez_pi(sk)->src, src))
++			break;
++
++		/* Closest match */
++		if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY))
++			sk1 = sk;
++	}
++
++	read_unlock(&sco_sk_list.lock);
++
++	return sk ? sk : sk1;
++}
++
++static void sco_sock_destruct(struct sock *sk)
++{
++	BT_DBG("sk %p", sk);
++
++	skb_queue_purge(&sk->receive_queue);
++	skb_queue_purge(&sk->write_queue);
++
++	MOD_DEC_USE_COUNT;
++}
++
++static void sco_sock_cleanup_listen(struct sock *parent)
++{
++	struct sock *sk;
++
++	BT_DBG("parent %p", parent);
++
++	/* Close not yet accepted channels */
++	while ((sk = bluez_accept_dequeue(parent, NULL))) {
++		sco_sock_close(sk);
++		sco_sock_kill(sk);
++	}
++
++	parent->state  = BT_CLOSED;
++	parent->zapped = 1;
++}
++
++/* Kill socket (only if zapped and orphan)
++ * Must be called on unlocked socket.
++ */
++static void sco_sock_kill(struct sock *sk)
++{
++	if (!sk->zapped || sk->socket)
++		return;
++
++	BT_DBG("sk %p state %d", sk, sk->state);
++
++	/* Kill poor orphan */
++	bluez_sock_unlink(&sco_sk_list, sk);
++	sk->dead = 1;
++	sock_put(sk);
++}
++
++/* Close socket.
++ * Must be called on unlocked socket.
++ */
++static void sco_sock_close(struct sock *sk)
++{
++	struct sco_conn *conn;
++
++	sco_sock_clear_timer(sk);
++
++	lock_sock(sk);
++
++	conn = sco_pi(sk)->conn;
++
++	BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket);
++
++	switch (sk->state) {
++	case BT_LISTEN:
++		sco_sock_cleanup_listen(sk);
++		break;
++
++	case BT_CONNECTED:
++	case BT_CONFIG:
++	case BT_CONNECT:
++	case BT_DISCONN:
++		sco_chan_del(sk, ECONNRESET);
++		break;
++
++	default:
++		sk->zapped = 1;
++		break;
++	};
++
++	release_sock(sk);
++}
++
++static void sco_sock_init(struct sock *sk, struct sock *parent)
++{
++	BT_DBG("sk %p", sk);
++
++	if (parent) 
++		sk->type = parent->type;
++}
++
++static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio)
++{
++	struct sock *sk;
++
++	if (!(sk = sk_alloc(PF_BLUETOOTH, prio, 1)))
++		return NULL;
++
++	bluez_sock_init(sock, sk);
++
++	sk->zapped   = 0;
++
++	sk->destruct = sco_sock_destruct;
++	sk->sndtimeo = SCO_CONN_TIMEOUT;
++
++	sk->protocol = proto;
++	sk->state    = BT_OPEN;
++
++	sco_sock_init_timer(sk);
++
++	bluez_sock_link(&sco_sk_list, sk);
++
++	MOD_INC_USE_COUNT;
++	return sk;
++}
++
++static int sco_sock_create(struct socket *sock, int protocol)
++{
++	struct sock *sk;
++
++	BT_DBG("sock %p", sock);
++
++	sock->state = SS_UNCONNECTED;
++
++	if (sock->type != SOCK_SEQPACKET)
++		return -ESOCKTNOSUPPORT;
++
++	sock->ops = &sco_sock_ops;
++
++	if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
++		return -ENOMEM;
++
++	sco_sock_init(sk, NULL);
++	return 0;
++}
++
++static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
++{
++	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
++	struct sock *sk = sock->sk;
++	bdaddr_t *src = &sa->sco_bdaddr;
++	int err = 0;
++
++	BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
++
++	if (!addr || addr->sa_family != AF_BLUETOOTH)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_OPEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	write_lock_bh(&sco_sk_list.lock);
++
++	if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) {
++		err = -EADDRINUSE;
++	} else {
++		/* Save source address */
++		bacpy(&bluez_pi(sk)->src, &sa->sco_bdaddr);
++		sk->state = BT_BOUND;
++	}
++
++	write_unlock_bh(&sco_sk_list.lock);
++
++done:
++	release_sock(sk);
++
++	return err;
++}
++
++static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
++{
++	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++
++	BT_DBG("sk %p", sk);
++
++	if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco))
++		return -EINVAL;
++
++	if (sk->state != BT_OPEN && sk->state != BT_BOUND)
++		return -EBADFD;
++
++	if (sk->type != SOCK_SEQPACKET)
++		return -EINVAL;
++
++	lock_sock(sk);
++
++	/* Set destination address and psm */
++	bacpy(&bluez_pi(sk)->dst, &sa->sco_bdaddr);
++
++	if ((err = sco_connect(sk)))
++		goto done;
++
++	err = bluez_sock_wait_state(sk, BT_CONNECTED,
++			sock_sndtimeo(sk, flags & O_NONBLOCK));
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_listen(struct socket *sock, int backlog)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p backlog %d", sk, backlog);
++
++	lock_sock(sk);
++
++	if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	sk->max_ack_backlog = backlog;
++	sk->ack_backlog = 0;
++	sk->state = BT_LISTEN;
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
++{
++	DECLARE_WAITQUEUE(wait, current);
++	struct sock *sk = sock->sk, *ch;
++	long timeo;
++	int err = 0;
++
++	lock_sock(sk);
++
++	if (sk->state != BT_LISTEN) {
++		err = -EBADFD;
++		goto done;
++	}
++
++	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
++
++	BT_DBG("sk %p timeo %ld", sk, timeo);
++
++	/* Wait for an incoming connection. (wake-one). */
++	add_wait_queue_exclusive(sk->sleep, &wait);
++	while (!(ch = bluez_accept_dequeue(sk, newsock))) {
++		set_current_state(TASK_INTERRUPTIBLE);
++		if (!timeo) {
++			err = -EAGAIN;
++			break;
++		}
++
++		release_sock(sk);
++		timeo = schedule_timeout(timeo);
++		lock_sock(sk);
++
++		if (sk->state != BT_LISTEN) {
++			err = -EBADFD;
++			break;
++		}
++
++		if (signal_pending(current)) {
++			err = sock_intr_errno(timeo);
++			break;
++		}
++	}
++	set_current_state(TASK_RUNNING);
++	remove_wait_queue(sk->sleep, &wait);
++
++	if (err)
++		goto done;
++
++	newsock->state = SS_CONNECTED;
++
++	BT_DBG("new socket %p", ch);
++
++done:
++	release_sock(sk);
++	return err;
++}
++
++static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
++{
++	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
++	struct sock *sk = sock->sk;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	addr->sa_family = AF_BLUETOOTH;
++	*len = sizeof(struct sockaddr_sco);
++
++	if (peer)
++		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->dst);
++	else
++		bacpy(&sa->sco_bdaddr, &bluez_pi(sk)->src);
++
++	return 0;
++}
++
++static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (sk->err)
++		return sock_error(sk);
++
++	if (msg->msg_flags & MSG_OOB)
++		return -EOPNOTSUPP;
++
++	lock_sock(sk);
++
++	if (sk->state == BT_CONNECTED)
++		err = sco_send_frame(sk, msg, len);
++	else
++		err = -ENOTCONN;
++
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sk %p", sk);
++
++	lock_sock(sk);
++
++	switch (optname) {
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++int sco_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen)
++{
++	struct sock *sk = sock->sk;
++	struct sco_options opts;
++	struct sco_conninfo cinfo;
++	int len, err = 0; 
++
++	BT_DBG("sk %p", sk);
++
++	if (get_user(len, optlen))
++		return -EFAULT;
++
++	lock_sock(sk);
++
++	switch (optname) {
++	case SCO_OPTIONS:
++		if (sk->state != BT_CONNECTED) {
++			err = -ENOTCONN;
++			break;
++		}
++		
++		opts.mtu = sco_pi(sk)->conn->mtu;
++
++		BT_DBG("mtu %d", opts.mtu);
++
++		len = MIN(len, sizeof(opts));
++		if (copy_to_user(optval, (char *)&opts, len))
++			err = -EFAULT;
++
++		break;
++
++	case SCO_CONNINFO:
++		if (sk->state != BT_CONNECTED) {
++			err = -ENOTCONN;
++			break;
++		}
++
++		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
++
++		len = MIN(len, sizeof(cinfo));
++		if (copy_to_user(optval, (char *)&cinfo, len))
++			err = -EFAULT;
++
++		break;
++
++	default:
++		err = -ENOPROTOOPT;
++		break;
++	};
++
++	release_sock(sk);
++	return err;
++}
++
++static int sco_sock_release(struct socket *sock)
++{
++	struct sock *sk = sock->sk;
++	int err = 0;
++
++	BT_DBG("sock %p, sk %p", sock, sk);
++
++	if (!sk)
++		return 0;
++
++	sco_sock_close(sk);
++	if (sk->linger) {
++		lock_sock(sk);
++		err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime);
++		release_sock(sk);
++	}
++
++	sock_orphan(sk);
++	sco_sock_kill(sk);
++	return err;
++}
++
++static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
++{
++	BT_DBG("conn %p", conn);
++
++	sco_pi(sk)->conn = conn;
++	conn->sk = sk;
++
++	if (parent)
++		bluez_accept_enqueue(parent, sk);
++}
++
++static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
++{
++	int err = 0;
++
++	sco_conn_lock(conn);
++	if (conn->sk) {
++		err = -EBUSY;
++	} else {
++		__sco_chan_add(conn, sk, parent);
++	}
++	sco_conn_unlock(conn);
++	return err;
++}
++
++static inline struct sock * sco_chan_get(struct sco_conn *conn)
++{
++	struct sock *sk = NULL;
++	sco_conn_lock(conn);
++	sk = conn->sk;
++	sco_conn_unlock(conn);
++	return sk;
++}
++
++/* Delete channel. 
++ * Must be called on the locked socket. */
++static void sco_chan_del(struct sock *sk, int err)
++{
++	struct sco_conn *conn;
++
++	conn = sco_pi(sk)->conn;
++
++	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
++
++	if (conn) { 
++		sco_conn_lock(conn);
++		conn->sk = NULL;
++		sco_pi(sk)->conn = NULL;
++		sco_conn_unlock(conn);
++		hci_conn_put(conn->hcon);
++	}
++
++	sk->state = BT_CLOSED;
++	sk->err   = err;
++	sk->state_change(sk);
++
++	sk->zapped = 1;
++}
++
++static void sco_conn_ready(struct sco_conn *conn)
++{
++	struct sock *parent, *sk;
++
++	BT_DBG("conn %p", conn);
++
++	sco_conn_lock(conn);
++
++	if ((sk = conn->sk)) {
++		sco_sock_clear_timer(sk);
++		bh_lock_sock(sk);
++		sk->state = BT_CONNECTED;
++		sk->state_change(sk);
++		bh_unlock_sock(sk);
++	} else {
++		parent = sco_get_sock_listen(conn->src);
++		if (!parent)
++			goto done;
++
++		bh_lock_sock(parent);
++
++		sk = sco_sock_alloc(NULL, BTPROTO_SCO, GFP_ATOMIC);
++		if (!sk) {
++			bh_unlock_sock(parent);
++                	goto done;
++		}
++
++		sco_sock_init(sk, parent);
++
++		bacpy(&bluez_pi(sk)->src, conn->src);
++		bacpy(&bluez_pi(sk)->dst, conn->dst);
++
++		hci_conn_hold(conn->hcon);
++        	__sco_chan_add(conn, sk, parent);
++
++        	sk->state = BT_CONNECTED;
++
++		/* Wake up parent */
++		parent->data_ready(parent, 1);
++	
++        	bh_unlock_sock(parent);
++	}
++
++done:
++	sco_conn_unlock(conn);
++}
++
++/* ----- SCO interface with lower layer (HCI) ----- */
++int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
++{
++	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
++
++	/* Always accept connection */
++	return HCI_LM_ACCEPT;
++}
++
++int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
++{
++	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
++
++	if (hcon->type != SCO_LINK)
++		return 0;
++
++	if (!status) {
++		struct sco_conn *conn;
++
++		conn = sco_conn_add(hcon, status);
++		if (conn)
++			sco_conn_ready(conn);
++	} else 
++		sco_conn_del(hcon, bterr(status));
++	
++	return 0;
++}
++
++int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
++{
++	BT_DBG("hcon %p reason %d", hcon, reason);
++
++	if (hcon->type != SCO_LINK)
++		return 0;
++
++	sco_conn_del(hcon, bterr(reason));
++	return 0;
++}
++
++int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
++{
++	struct sco_conn *conn = hcon->sco_data;
++
++	if (!conn)
++		goto drop;
++
++	BT_DBG("conn %p len %d", conn, skb->len);
++
++	if (skb->len) {
++		sco_recv_frame(conn, skb);
++		return 0;
++	}
++
++drop:
++	kfree_skb(skb);	
++	return 0;
++}
++
++/* ----- Proc fs support ------ */
++static int sco_sock_dump(char *buf, struct bluez_sock_list *list)
++{
++	struct sco_pinfo *pi;
++	struct sock *sk;
++	char *ptr = buf;
++
++	write_lock_bh(&list->lock);
++
++	for (sk = list->head; sk; sk = sk->next) {
++		pi = sco_pi(sk);
++		ptr += sprintf(ptr, "%s %s %d\n",
++				batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst),
++				sk->state); 
++	}
++
++	write_unlock_bh(&list->lock);
++
++	ptr += sprintf(ptr, "\n");
++
++	return ptr - buf;
++}
++
++static int sco_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv)
++{
++	char *ptr = buf;
++	int len;
++
++	BT_DBG("count %d, offset %ld", count, offset);
++
++	ptr += sco_sock_dump(ptr, &sco_sk_list);
++	len  = ptr - buf;
++
++	if (len <= count + offset)
++		*eof = 1;
++
++	*start = buf + offset;
++	len -= offset;
++
++	if (len > count)
++		len = count;
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++
++static struct proto_ops sco_sock_ops = {
++	family:		PF_BLUETOOTH,
++	release:	sco_sock_release,
++	bind:		sco_sock_bind,
++	connect:	sco_sock_connect,
++	listen:		sco_sock_listen,
++	accept:		sco_sock_accept,
++	getname:	sco_sock_getname,
++	sendmsg:	sco_sock_sendmsg,
++	recvmsg:	bluez_sock_recvmsg,
++	poll:		bluez_sock_poll,
++	socketpair:	sock_no_socketpair,
++	ioctl:		sock_no_ioctl,
++	shutdown:	sock_no_shutdown,
++	setsockopt:	sco_sock_setsockopt,
++	getsockopt:	sco_sock_getsockopt,
++	mmap:		sock_no_mmap
++};
++
++static struct net_proto_family sco_sock_family_ops = {
++	family:		PF_BLUETOOTH,
++	create:		sco_sock_create
++};
++
++static struct hci_proto sco_hci_proto = {
++	name:		"SCO",
++	id:		HCI_PROTO_SCO,
++	connect_ind:	sco_connect_ind,
++	connect_cfm:	sco_connect_cfm,
++	disconn_ind:	sco_disconn_ind,
++	recv_scodata:	sco_recv_scodata,
++};
++
++int __init sco_init(void)
++{
++	int err;
++
++	if ((err = bluez_sock_register(BTPROTO_SCO, &sco_sock_family_ops))) {
++		BT_ERR("Can't register SCO socket layer");
++		return err;
++	}
++
++	if ((err = hci_register_proto(&sco_hci_proto))) {
++		BT_ERR("Can't register SCO protocol");
++		return err;
++	}
++
++	create_proc_read_entry("bluetooth/sco", 0, 0, sco_read_proc, NULL);
++
++	BT_INFO("BlueZ SCO ver %s Copyright (C) 2000,2001 Qualcomm Inc", VERSION);
++	BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
++	return 0;
++}
++
++void sco_cleanup(void)
++{
++	int err;
++
++	remove_proc_entry("bluetooth/sco", NULL);
++
++	/* Unregister socket, protocol and notifier */
++	if ((err = bluez_sock_unregister(BTPROTO_SCO)))
++		BT_ERR("Can't unregister SCO socket layer %d", err);
++
++	if ((err = hci_unregister_proto(&sco_hci_proto)))
++		BT_ERR("Can't unregister SCO protocol %d", err);
++}
++
++module_init(sco_init);
++module_exit(sco_cleanup);
++
++MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
++MODULE_DESCRIPTION("BlueZ SCO ver " VERSION);
++MODULE_LICENSE("GPL");
+diff -urN linux-2.4.18/net/bluetooth/syms.c linux-2.4.18-mh9/net/bluetooth/syms.c
+--- linux-2.4.18/net/bluetooth/syms.c	Fri Sep  7 18:28:38 2001
++++ linux-2.4.18-mh9/net/bluetooth/syms.c	Mon Aug 25 18:38:12 2003
+@@ -25,7 +25,7 @@
+ /*
+  * BlueZ symbols.
+  *
+- * $Id$
++ * $Id$
+  */
+ 
+ #include <linux/config.h>
+@@ -39,25 +39,28 @@
+ #include <linux/socket.h>
+ 
+ #include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/bluez.h>
+ #include <net/bluetooth/hci_core.h>
+ 
+ /* HCI Core */
+ EXPORT_SYMBOL(hci_register_dev);
+ EXPORT_SYMBOL(hci_unregister_dev);
++EXPORT_SYMBOL(hci_suspend_dev);
++EXPORT_SYMBOL(hci_resume_dev);
++
+ EXPORT_SYMBOL(hci_register_proto);
+ EXPORT_SYMBOL(hci_unregister_proto);
+-EXPORT_SYMBOL(hci_register_notifier);
+-EXPORT_SYMBOL(hci_unregister_notifier);
+ 
++EXPORT_SYMBOL(hci_get_route);
+ EXPORT_SYMBOL(hci_connect);
+-EXPORT_SYMBOL(hci_disconnect);
+ EXPORT_SYMBOL(hci_dev_get);
++EXPORT_SYMBOL(hci_conn_auth);
++EXPORT_SYMBOL(hci_conn_encrypt);
+ 
+ EXPORT_SYMBOL(hci_recv_frame);
+ EXPORT_SYMBOL(hci_send_acl);
+ EXPORT_SYMBOL(hci_send_sco);
+-EXPORT_SYMBOL(hci_send_raw);
++EXPORT_SYMBOL(hci_send_cmd);
++EXPORT_SYMBOL(hci_si_event);
+ 
+ /* BlueZ lib */
+ EXPORT_SYMBOL(bluez_dump);
+@@ -68,5 +71,11 @@
+ /* BlueZ sockets */
+ EXPORT_SYMBOL(bluez_sock_register);
+ EXPORT_SYMBOL(bluez_sock_unregister);
++EXPORT_SYMBOL(bluez_sock_init);
+ EXPORT_SYMBOL(bluez_sock_link);
+ EXPORT_SYMBOL(bluez_sock_unlink);
++EXPORT_SYMBOL(bluez_sock_recvmsg);
++EXPORT_SYMBOL(bluez_sock_poll);
++EXPORT_SYMBOL(bluez_accept_enqueue);
++EXPORT_SYMBOL(bluez_accept_dequeue);
++EXPORT_SYMBOL(bluez_sock_wait_state);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch
index e69de29bb2..79ba036323 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/disable-pcmcia-probe.patch
@@ -0,0 +1,17 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/pcmcia/Config.in~disable-pcmcia-probe	2003-05-13 11:18:23.000000000 +0200
++++ linux/drivers/pcmcia/Config.in	2004-05-27 13:59:50.000000000 +0200
+@@ -15,9 +15,6 @@
+ tristate 'PCMCIA/CardBus support' CONFIG_PCMCIA
+ if [ "$CONFIG_PCMCIA" != "n" ]; then
+    # yes, I really mean the following...
+-   if [ "$CONFIG_ISA" = "y" -o "$CONFIG_ARCH_SA1100" = "y" ]; then
+-      define_bool CONFIG_PCMCIA_PROBE y
+-   fi
+    if [ "$CONFIG_PCI" != "n" ]; then
+       bool '  CardBus support' CONFIG_CARDBUS
+    fi
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch
index e69de29bb2..62038c34e2 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/idecs.patch
@@ -0,0 +1,77 @@
+--- linux/drivers/ide/ide-cs.c	2003-02-28 17:04:00.000000000 -0600
++++ linux.new/drivers/ide/ide-cs.c	2003-02-28 17:18:53.000000000 -0600
+@@ -2,7 +2,7 @@
+ 
+     A driver for PCMCIA IDE/ATA disk cards
+ 
+-    ide_cs.c 1.26 1999/11/16 02:10:49
++    ide-cs.c 1.26 1999/11/16 02:10:49
+ 
+     The contents of this file are subject to the Mozilla Public
+     License Version 1.1 (the "License"); you may not use this file
+@@ -66,7 +66,7 @@
+ MODULE_PARM(pc_debug, "i");
+ #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+ static char *version =
+-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
++"ide-cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
+ #else
+ #define DEBUG(n, args...)
+ #endif
+@@ -110,7 +110,7 @@
+ static int ide_event(event_t event, int priority,
+ 		     event_callback_args_t *args);
+ 
+-static dev_info_t dev_info = "ide_cs";
++static dev_info_t dev_info = "ide-cs";
+ 
+ static dev_link_t *ide_attach(void);
+ static void ide_detach(dev_link_t *);
+@@ -356,7 +356,7 @@
+     }
+     
+     if (hd < 0) {
+-	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
++	printk(KERN_NOTICE "ide-cs: ide_register() at 0x%03x & 0x%03x"
+ 	       ", irq %u failed\n", io_base, ctl_base,
+ 	       link->irq.AssignedIRQ);
+ 	goto failed;
+@@ -369,7 +369,7 @@
+     info->node.minor = 0;
+     info->hd = hd;
+     link->dev = &info->node;
+-    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
++    printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+ 	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+ 	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+ 
+@@ -409,9 +409,9 @@
+ 	MOD_DEC_USE_COUNT;
+     }
+ 
+-    request_region(link->io.BasePort1, link->io.NumPorts1,"ide_cs");
++    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
+     if (link->io.NumPorts2)
+-	request_region(link->io.BasePort2, link->io.NumPorts2,"ide_cs");
++	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
+     
+     info->ndev = 0;
+     link->dev = NULL;
+@@ -508,7 +508,7 @@
+     DEBUG(0, "%s\n", version);
+     CardServices(GetCardServicesInfo, &serv);
+     if (serv.Revision != CS_RELEASE_CODE) {
+-	printk(KERN_NOTICE "ide_cs: Card Services release "
++	printk(KERN_NOTICE "ide-cs: Card Services release "
+ 	       "does not match!\n");
+ 	return -1;
+     }
+@@ -518,7 +518,7 @@
+ 
+ static void __exit exit_ide_cs(void)
+ {
+-    DEBUG(0, "ide_cs: unloading\n");
++    DEBUG(0, "ide-cs: unloading\n");
+     unregister_pccard_driver(&dev_info);
+     while (dev_list != NULL)
+ 	ide_detach(dev_list);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch
index e69de29bb2..a672631194 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/initsh.patch
@@ -0,0 +1,14 @@
+--- linux/init/main.c	2002-02-25 13:38:13.000000000 -0600
++++ linux.new/init/main.c	2003-03-16 11:49:45.000000000 -0600
+@@ -830,8 +830,10 @@
+ 	 * trying to recover a really broken machine.
+ 	 */
+ 
+-	if (execute_command)
++	if (execute_command) {
++		argv_init[0] = execute_command; 
+ 		execve(execute_command,argv_init,envp_init);
++	}
+ 	execve("/sbin/init",argv_init,envp_init);
+ 	execve("/etc/init",argv_init,envp_init);
+ 	execve("/bin/init",argv_init,envp_init);
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff
index e69de29bb2..2ebfd8ec12 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw240_we15-6.diff
@@ -0,0 +1,399 @@
+diff -u -p linux/include/linux/wireless.14.h linux/include/linux/wireless.h
+--- linux/include/linux/wireless.14.h	Mon Dec  2 18:51:00 2002
++++ linux/include/linux/wireless.h	Mon Dec  2 18:53:35 2002
+@@ -1,7 +1,7 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	14	25.1.02
++ * Version :	15	12.7.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+@@ -80,7 +80,7 @@
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	14
++#define WIRELESS_EXT	15
+ 
+ /*
+  * Changes :
+@@ -153,17 +153,32 @@
+  *	- Define additional specific event numbers
+  *	- Add "addr" and "param" fields in union iwreq_data
+  *	- AP scanning stuff (SIOCSIWSCAN and friends)
++ *
++ * V14 to V15
++ * ----------
++ *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
++ *	- Make struct iw_freq signed (both m & e), add explicit padding
++ *	- Add IWEVCUSTOM for driver specific event/scanning token
++ *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
++ *	- Add IW_TXPOW_RANGE for range of Tx Powers
++ *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
++ *	- Add IW_MODE_MONITOR for passive monitor
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+ /* -------------------------- IOCTL LIST -------------------------- */
+ 
+-/* Basic operations */
++/* Wireless Identification */
+ #define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
+ #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
+-#define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
+-#define SIOCGIWNWID	0x8B03		/* get network id */
++/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
++ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
++ * Don't put the name of your driver there, it's useless. */
++
++/* Basic operations */
++#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
++#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
+ #define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
+ #define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
+ #define SIOCSIWMODE	0x8B06		/* set operation mode */
+@@ -178,16 +193,18 @@
+ #define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
+ #define SIOCSIWSTATS	0x8B0E		/* Unused */
+ #define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
++/* SIOCGIWSTATS is strictly used between user space and the kernel, and
++ * is never passed to the driver (i.e. the driver will never see it). */
+ 
+-/* Mobile IP support */
++/* Mobile IP support (statistics per MAC address) */
+ #define SIOCSIWSPY	0x8B10		/* set spy addresses */
+ #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
+ 
+ /* Access Point manipulation */
+ #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
+ #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
+-#define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
+-#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
++#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
++#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
+ #define SIOCGIWSCAN	0x8B19		/* get scanning results */
+ 
+ /* 802.11 specific support */
+@@ -197,9 +214,7 @@
+ #define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
+ /* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
+  * within the 'iwreq' structure, so we need to use the 'data' member to
+- * point to a string in user space, like it is done for RANGE...
+- * The "flags" member indicate if the ESSID is active or not (promiscuous).
+- */
++ * point to a string in user space, like it is done for RANGE... */
+ 
+ /* Other parameters useful in 802.11 and some other devices */
+ #define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
+@@ -257,7 +272,10 @@
+ /* Most events use the same identifier as ioctl requests */
+ 
+ #define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
+-#define IWEVQUAL	0x8C01		/* Quality part of statistics */
++#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
++#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
++#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
++#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
+ 
+ #define IWEVFIRST	0x8C00
+ 
+@@ -273,7 +291,8 @@
+ #define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
+ #define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
+ #define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
+-#define IW_PRIV_TYPE_FLOAT	0x5000
++#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
++#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
+ 
+ #define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed nuber of args */
+ 
+@@ -297,13 +316,16 @@
+ 
+ /* Maximum tx powers in the range struct */
+ #define IW_MAX_TXPOWER		8
++/* Note : if you more than 8 TXPowers, just set the max and min or
++ * a few of them in the struct iw_range. */
+ 
+ /* Maximum of address that you may set with SPY */
+-#define IW_MAX_SPY		8
++#define IW_MAX_SPY		8	/* set */
++#define IW_MAX_GET_SPY		64	/* get */
+ 
+ /* Maximum of address that you may get in the
+    list of access points in range */
+-#define IW_MAX_AP		8
++#define IW_MAX_AP		64
+ 
+ /* Maximum size of the ESSID and NICKN strings */
+ #define IW_ESSID_MAX_SIZE	32
+@@ -315,6 +337,7 @@
+ #define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
+ #define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
+ #define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
++#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
+ 
+ /* Maximum number of size of encoding token available
+  * they are listed in the range structure */
+@@ -350,8 +373,10 @@
+ #define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+ 
+ /* Transmit Power flags available */
++#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
+ #define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
+ #define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
++#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
+ 
+ /* Retry limits and lifetime flags available */
+ #define IW_RETRY_ON		0x0000	/* No details... */
+@@ -376,6 +401,9 @@
+ /* Maximum size of returned data */
+ #define IW_SCAN_MAX_DATA	4096	/* In bytes */
+ 
++/* Max number of char in custom event - use multiple of them if needed */
++#define IW_CUSTOM_MAX		256	/* In bytes */
++
+ /****************************** TYPES ******************************/
+ 
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -411,9 +439,10 @@ struct	iw_point
+  */
+ struct	iw_freq
+ {
+-	__u32		m;		/* Mantissa */
+-	__u16		e;		/* Exponent */
++	__s32		m;		/* Mantissa */
++	__s16		e;		/* Exponent */
+ 	__u8		i;		/* List index (when in range struct) */
++	__u8		pad;		/* Unused - just for alignement */
+ };
+ 
+ /*
+diff -u -p linux/include/net/iw_handler.14.h linux/include/net/iw_handler.h
+--- linux/include/net/iw_handler.14.h	Mon Dec  2 18:51:17 2002
++++ linux/include/net/iw_handler.h	Mon Dec  2 18:54:51 2002
+@@ -1,7 +1,7 @@
+ /*
+  * This file define the new driver API for Wireless Extensions
+  *
+- * Version :	3	17.1.02
++ * Version :	4	21.6.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+@@ -206,7 +206,7 @@
+  * will be needed...
+  * I just plan to increment with each new version.
+  */
+-#define IW_HANDLER_VERSION	3
++#define IW_HANDLER_VERSION	4
+ 
+ /*
+  * Changes :
+@@ -217,6 +217,9 @@
+  *	- Add Wireless Event support :
+  *		o wireless_send_event() prototype
+  *		o iwe_stream_add_event/point() inline functions
++ * V3 to V4
++ * --------
++ *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+@@ -233,10 +236,10 @@
+ #define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
+ #define IW_HEADER_TYPE_UINT	4	/* __u32 */
+ #define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
+-#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+-#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+-#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
+-#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
++#define IW_HEADER_TYPE_ADDR	6	/* struct sockaddr */
++#define IW_HEADER_TYPE_POINT	8	/* struct iw_point */
++#define IW_HEADER_TYPE_PARAM	9	/* struct iw_param */
++#define IW_HEADER_TYPE_QUAL	10	/* struct iw_quality */
+ 
+ /* Handling flags */
+ /* Most are not implemented. I just use them as a reminder of some
+diff -u -p linux/net/core/wireless.14.c linux/net/core/wireless.c
+--- linux/net/core/wireless.14.c	Mon Dec  2 18:51:35 2002
++++ linux/net/core/wireless.c	Mon Dec  2 18:53:10 2002
+@@ -33,8 +33,16 @@
+  *	o Propagate events as rtnetlink IFLA_WIRELESS option
+  *	o Generate event on selected SET requests
+  *
+- * v4 - 18.04.01 - Jean II
++ * v4 - 18.04.02 - Jean II
+  *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
++ *
++ * v5 - 21.06.02 - Jean II
++ *	o Add IW_PRIV_TYPE_ADDR in priv_type_size (+cleanup)
++ *	o Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
++ *	o Add IWEVCUSTOM for driver specific event/scanning token
++ *	o Turn on WE_STRICT_WRITE by default + kernel warning
++ *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
++ *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
+  */
+ 
+ /***************************** INCLUDES *****************************/
+@@ -50,8 +58,9 @@
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+-/* This will be turned on later on... */
+-#undef WE_STRICT_WRITE		/* Check write buffer size */
++/* Enough lenience, let's make sure things are proper... */
++#define WE_STRICT_WRITE		/* Check write buffer size */
++/* I'll probably drop both the define and kernel message in the next version */
+ 
+ /* Debuging stuff */
+ #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
+@@ -106,7 +115,7 @@ static const struct iw_ioctl_description
+ 	/* SIOCSIWSPY */
+ 	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
+ 	/* SIOCGIWSPY */
+-	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_GET_SPY, 0},
+ 	/* -- hole -- */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* -- hole -- */
+@@ -176,25 +185,41 @@ static const struct iw_ioctl_description
+ 	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ 	/* IWEVQUAL */
+ 	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
++	/* IWEVCUSTOM */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_CUSTOM_MAX, 0},
++	/* IWEVREGISTERED */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* IWEVEXPIRED */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
+ };
+ static const int standard_event_num = (sizeof(standard_event) /
+ 				       sizeof(struct iw_ioctl_description));
+ 
+ /* Size (in bytes) of the various private data types */
+-static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++static const char priv_type_size[] = {
++	0,				/* IW_PRIV_TYPE_NONE */
++	1,				/* IW_PRIV_TYPE_BYTE */
++	1,				/* IW_PRIV_TYPE_CHAR */
++	0,				/* Not defined */
++	sizeof(__u32),			/* IW_PRIV_TYPE_INT */
++	sizeof(struct iw_freq),		/* IW_PRIV_TYPE_FLOAT */
++	sizeof(struct sockaddr),	/* IW_PRIV_TYPE_ADDR */
++	0,				/* Not defined */
++};
+ 
+ /* Size (in bytes) of various events */
+ static const int event_type_size[] = {
+-	IW_EV_LCP_LEN,
++	IW_EV_LCP_LEN,			/* IW_HEADER_TYPE_NULL */
++	0,
++	IW_EV_CHAR_LEN,			/* IW_HEADER_TYPE_CHAR */
+ 	0,
+-	IW_EV_CHAR_LEN,
++	IW_EV_UINT_LEN,			/* IW_HEADER_TYPE_UINT */
++	IW_EV_FREQ_LEN,			/* IW_HEADER_TYPE_FREQ */
++	IW_EV_ADDR_LEN,			/* IW_HEADER_TYPE_ADDR */
+ 	0,
+-	IW_EV_UINT_LEN,
+-	IW_EV_FREQ_LEN,
+ 	IW_EV_POINT_LEN,		/* Without variable payload */
+-	IW_EV_PARAM_LEN,
+-	IW_EV_ADDR_LEN,
+-	IW_EV_QUAL_LEN,
++	IW_EV_PARAM_LEN,		/* IW_HEADER_TYPE_PARAM */
++	IW_EV_QUAL_LEN,			/* IW_HEADER_TYPE_QUAL */
+ };
+ 
+ /************************ COMMON SUBROUTINES ************************/
+@@ -440,8 +465,10 @@ static inline int ioctl_export_private(s
+ 		return -EFAULT;
+ #ifdef WE_STRICT_WRITE
+ 	/* Check if there is enough buffer up there */
+-	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
++	if(iwr->u.data.length < dev->wireless_handlers->num_private_args) {
++		printk(KERN_ERR "%s (WE) : Buffer for request SIOCGIWPRIV too small (%d<%d)\n", dev->name, iwr->u.data.length, dev->wireless_handlers->num_private_args);
+ 		return -E2BIG;
++	}
+ #endif	/* WE_STRICT_WRITE */
+ 
+ 	/* Set the number of available ioctls. */
+@@ -471,6 +498,7 @@ static inline int ioctl_standard_call(st
+ 	const struct iw_ioctl_description *	descr;
+ 	struct iw_request_info			info;
+ 	int					ret = -EINVAL;
++	int					user_size = 0;
+ 
+ 	/* Get the description of the IOCTL */
+ 	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
+@@ -518,11 +546,8 @@ static inline int ioctl_standard_call(st
+ 			/* Check NULL pointer */
+ 			if(iwr->u.data.pointer == NULL)
+ 				return -EFAULT;
+-#ifdef WE_STRICT_WRITE
+-			/* Check if there is enough buffer up there */
+-			if(iwr->u.data.length < descr->max_tokens)
+-				return -E2BIG;
+-#endif	/* WE_STRICT_WRITE */
++			/* Save user space buffer size for checking */
++			user_size = iwr->u.data.length;
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+@@ -559,6 +584,15 @@ static inline int ioctl_standard_call(st
+ 
+ 		/* If we have something to return to the user */
+ 		if (!ret && IW_IS_GET(cmd)) {
++#ifdef WE_STRICT_WRITE
++			/* Check if there is enough buffer up there */
++			if(user_size < iwr->u.data.length) {
++				printk(KERN_ERR "%s (WE) : Buffer for request %04X too small (%d<%d)\n", dev->name, cmd, user_size, iwr->u.data.length);
++				kfree(extra);
++				return -E2BIG;
++			}
++#endif	/* WE_STRICT_WRITE */
++
+ 			err = copy_to_user(iwr->u.data.pointer, extra,
+ 					   iwr->u.data.length *
+ 					   descr->token_size);
+@@ -646,12 +680,18 @@ static inline int ioctl_private_call(str
+ 	/* Compute the size of the set/get arguments */
+ 	if(descr != NULL) {
+ 		if(IW_IS_SET(cmd)) {
++			int	offset = 0;	/* For sub-ioctls */
++			/* Check for sub-ioctl handler */
++			if(descr->name[0] == '\0')
++				/* Reserve one int for sub-ioctl index */
++				offset = sizeof(__u32);
++
+ 			/* Size of set arguments */
+ 			extra_size = get_priv_size(descr->set_args);
+ 
+ 			/* Does it fits in iwr ? */
+ 			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
+-			   (extra_size < IFNAMSIZ))
++			   ((extra_size + offset) <= IFNAMSIZ))
+ 				extra_size = 0;
+ 		} else {
+ 			/* Size of set arguments */
+@@ -659,7 +699,7 @@ static inline int ioctl_private_call(str
+ 
+ 			/* Does it fits in iwr ? */
+ 			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
+-			   (extra_size < IFNAMSIZ))
++			   (extra_size <= IFNAMSIZ))
+ 				extra_size = 0;
+ 		}
+ 	}
+@@ -925,7 +965,7 @@ void wireless_send_event(struct net_devi
+ 		 * The best the driver could do is to log an error message.
+ 		 * We will do it ourselves instead...
+ 		 */
+-	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
++	  	printk(KERN_ERR "%s (WE) : Invalid/Unknown Wireless Event (0x%04X)\n",
+ 		       dev->name, cmd);
+ 		return;
+ 	}
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff
index e69de29bb2..a27a7654a9 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w13-5.diff
@@ -0,0 +1,1513 @@
+diff -u -p -r --new-file linux/include/linux-w12/netdevice.h linux/include/linux/netdevice.h
+--- linux/include/linux-w12/netdevice.h	Thu Nov 22 11:47:09 2001
++++ linux/include/linux/netdevice.h	Thu Jan 17 12:00:39 2002
+@@ -278,6 +278,10 @@ struct net_device
+ 	struct net_device_stats* (*get_stats)(struct net_device *dev);
+ 	struct iw_statistics*	(*get_wireless_stats)(struct net_device *dev);
+ 
++	/* List of functions to handle Wireless Extensions (instead of ioctl).
++	 * See <net/iw_handler.h> for details. Jean II */
++	struct iw_handler_def *	wireless_handlers;
++
+ 	/*
+ 	 * This marks the end of the "visible" part of the structure. All
+ 	 * fields hereafter are internal to the system, and may change at
+diff -u -p -r --new-file linux/include/linux-w12/wireless.h linux/include/linux/wireless.h
+--- linux/include/linux-w12/wireless.h	Thu Nov 22 11:47:12 2001
++++ linux/include/linux/wireless.h	Thu Jan 17 12:04:08 2002
+@@ -1,9 +1,10 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	12	5.10.01
++ * Version :	13	6.12.01
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _LINUX_WIRELESS_H
+@@ -11,6 +12,8 @@
+ 
+ /************************** DOCUMENTATION **************************/
+ /*
++ * Initial APIs (1996 -> onward) :
++ * -----------------------------
+  * Basically, the wireless extensions are for now a set of standard ioctl
+  * call + /proc/net/wireless
+  *
+@@ -27,16 +30,27 @@
+  * We have the list of command plus a structure descibing the
+  * data exchanged...
+  * Note that to add these ioctl, I was obliged to modify :
+- *	net/core/dev.c (two place + add include)
+- *	net/ipv4/af_inet.c (one place + add include)
++ *	# net/core/dev.c (two place + add include)
++ *	# net/ipv4/af_inet.c (one place + add include)
+  *
+  * /proc/net/wireless is a copy of /proc/net/dev.
+  * We have a structure for data passed from the driver to /proc/net/wireless
+  * Too add this, I've modified :
+- *	net/core/dev.c (two other places)
+- *	include/linux/netdevice.h (one place)
+- *	include/linux/proc_fs.h (one place)
++ *	# net/core/dev.c (two other places)
++ *	# include/linux/netdevice.h (one place)
++ *	# include/linux/proc_fs.h (one place)
++ *
++ * New driver API (2001 -> onward) :
++ * -------------------------------
++ * This file is only concerned with the user space API and common definitions.
++ * The new driver API is defined and documented in :
++ *	# include/net/iw_handler.h
+  *
++ * Note as well that /proc/net/wireless implementation has now moved in :
++ *	# include/linux/wireless.c
++ *
++ * Other comments :
++ * --------------
+  * Do not add here things that are redundant with other mechanisms
+  * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
+  * wireless specific.
+@@ -54,16 +68,14 @@
+ #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
+ #include <linux/if.h>			/* for IFNAMSIZ and co... */
+ 
+-/**************************** CONSTANTS ****************************/
+-
+-/* --------------------------- VERSION --------------------------- */
++/***************************** VERSION *****************************/
+ /*
+  * This constant is used to know the availability of the wireless
+  * extensions and to know which version of wireless extensions it is
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	12
++#define WIRELESS_EXT	13
+ 
+ /*
+  * Changes :
+@@ -123,12 +135,20 @@
+  *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
+  *	- Add new statistics (frag, retry, beacon)
+  *	- Add average quality (for user space calibration)
++ *
++ * V12 to V13
++ * ----------
++ *	- Document creation of new driver API.
++ *	- Extract union iwreq_data from struct iwreq (for new driver API).
++ *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
+  */
+ 
++/**************************** CONSTANTS ****************************/
++
+ /* -------------------------- IOCTL LIST -------------------------- */
+ 
+ /* Basic operations */
+-#define SIOCSIWNAME	0x8B00		/* Unused */
++#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
+ #define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
+ #define SIOCSIWNWID	0x8B02		/* set network id (the cell) */
+ #define SIOCGIWNWID	0x8B03		/* get network id */
+@@ -414,13 +434,49 @@ struct	iw_statistics
+ 
+ /* ------------------------ IOCTL REQUEST ------------------------ */
+ /*
++ * This structure defines the payload of an ioctl, and is used 
++ * below.
++ *
++ * Note that this structure should fit on the memory footprint
++ * of iwreq (which is the same as ifreq), which mean a max size of
++ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
++ * You should check this when increasing the structures defined
++ * above in this file...
++ */
++union	iwreq_data
++{
++	/* Config - generic */
++	char		name[IFNAMSIZ];
++	/* Name : used to verify the presence of  wireless extensions.
++	 * Name of the protocol/provider... */
++
++	struct iw_point	essid;		/* Extended network name */
++	struct iw_param	nwid;		/* network id (or domain - the cell) */
++	struct iw_freq	freq;		/* frequency or channel :
++					 * 0-1000 = channel
++					 * > 1000 = frequency in Hz */
++
++	struct iw_param	sens;		/* signal level threshold */
++	struct iw_param	bitrate;	/* default bit rate */
++	struct iw_param	txpower;	/* default transmit power */
++	struct iw_param	rts;		/* RTS threshold threshold */
++	struct iw_param	frag;		/* Fragmentation threshold */
++	__u32		mode;		/* Operation mode */
++	struct iw_param	retry;		/* Retry limits & lifetime */
++
++	struct iw_point	encoding;	/* Encoding stuff : tokens */
++	struct iw_param	power;		/* PM duration/timeout */
++
++	struct sockaddr	ap_addr;	/* Access point address */
++
++	struct iw_point	data;		/* Other large parameters */
++};
++
++/*
+  * The structure to exchange data for ioctl.
+  * This structure is the same as 'struct ifreq', but (re)defined for
+  * convenience...
+- *
+- * Note that it should fit on the same memory footprint !
+- * You should check this when increasing the above structures (16 octets)
+- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
++ * Do I need to remind you about structure size (32 octets) ?
+  */
+ struct	iwreq 
+ {
+@@ -429,35 +485,8 @@ struct	iwreq 
+ 		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
+ 	} ifr_ifrn;
+ 
+-	/* Data part */
+-	union
+-	{
+-		/* Config - generic */
+-		char		name[IFNAMSIZ];
+-		/* Name : used to verify the presence of  wireless extensions.
+-		 * Name of the protocol/provider... */
+-
+-		struct iw_point	essid;	/* Extended network name */
+-		struct iw_param	nwid;	/* network id (or domain - the cell) */
+-		struct iw_freq	freq;	/* frequency or channel :
+-					 * 0-1000 = channel
+-					 * > 1000 = frequency in Hz */
+-
+-		struct iw_param	sens;		/* signal level threshold */
+-		struct iw_param	bitrate;	/* default bit rate */
+-		struct iw_param	txpower;	/* default transmit power */
+-		struct iw_param	rts;		/* RTS threshold threshold */
+-		struct iw_param	frag;		/* Fragmentation threshold */
+-		__u32		mode;		/* Operation mode */
+-		struct iw_param	retry;		/* Retry limits & lifetime */
+-
+-		struct iw_point	encoding;	/* Encoding stuff : tokens */
+-		struct iw_param	power;		/* PM duration/timeout */
+-
+-		struct sockaddr	ap_addr;	/* Access point address */
+-
+-		struct iw_point	data;		/* Other large parameters */
+-	}	u;
++	/* Data part (defined just above) */
++	union	iwreq_data	u;
+ };
+ 
+ /* -------------------------- IOCTL DATA -------------------------- */
+diff -u -p -r --new-file linux/include/net-w12/iw_handler.h linux/include/net/iw_handler.h
+--- linux/include/net-w12/iw_handler.h	Wed Dec 31 16:00:00 1969
++++ linux/include/net/iw_handler.h	Thu Jan 17 12:16:46 2002
+@@ -0,0 +1,374 @@
++/*
++ * This file define the new driver API for Wireless Extensions
++ *
++ * Version :	2	6.12.01
++ *
++ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
++ */
++
++#ifndef _IW_HANDLER_H
++#define _IW_HANDLER_H
++
++/************************** DOCUMENTATION **************************/
++/*
++ * Initial driver API (1996 -> onward) :
++ * -----------------------------------
++ * The initial API just sends the IOCTL request received from user space
++ * to the driver (via the driver ioctl handler). The driver has to
++ * handle all the rest...
++ *
++ * The initial API also defines a specific handler in struct net_device
++ * to handle wireless statistics.
++ *
++ * The initial APIs served us well and has proven a reasonably good design.
++ * However, there is a few shortcommings :
++ *	o No events, everything is a request to the driver.
++ *	o Large ioctl function in driver with gigantic switch statement
++ *	  (i.e. spaghetti code).
++ *	o Driver has to mess up with copy_to/from_user, and in many cases
++ *	  does it unproperly. Common mistakes are :
++ *		* buffer overflows (no checks or off by one checks)
++ *		* call copy_to/from_user with irq disabled
++ *	o The user space interface is tied to ioctl because of the use
++ *	  copy_to/from_user.
++ *
++ * New driver API (2001 -> onward) :
++ * -------------------------------
++ * The new driver API is just a bunch of standard functions (handlers),
++ * each handling a specific Wireless Extension. The driver just export
++ * the list of handler it supports, and those will be called apropriately.
++ *
++ * I tried to keep the main advantage of the previous API (simplicity,
++ * efficiency and light weight), and also I provide a good dose of backward
++ * compatibility (most structures are the same, driver can use both API
++ * simultaneously, ...).
++ * Hopefully, I've also addressed the shortcomming of the initial API.
++ *
++ * The advantage of the new API are :
++ *	o Handling of Extensions in driver broken in small contained functions
++ *	o Tighter checks of ioctl before calling the driver
++ *	o Flexible commit strategy (at least, the start of it)
++ *	o Backward compatibility (can be mixed with old API)
++ *	o Driver doesn't have to worry about memory and user-space issues
++ * The last point is important for the following reasons :
++ *	o You are now able to call the new driver API from any API you
++ *		want (including from within other parts of the kernel).
++ *	o Common mistakes are avoided (buffer overflow, user space copy
++ *		with irq disabled and so on).
++ *
++ * The Drawback of the new API are :
++ *	o bloat (especially kernel)
++ *	o need to migrate existing drivers to new API
++ * My initial testing shows that the new API adds around 3kB to the kernel
++ * and save between 0 and 5kB from a typical driver.
++ * Also, as all structures and data types are unchanged, the migration is
++ * quite straightforward (but tedious).
++ *
++ * ---
++ *
++ * The new driver API is defined below in this file. User space should
++ * not be aware of what's happening down there...
++ *
++ * A new kernel wrapper is in charge of validating the IOCTLs and calling
++ * the appropriate driver handler. This is implemented in :
++ *	# net/core/wireless.c
++ *
++ * The driver export the list of handlers in :
++ *	# include/linux/netdevice.h (one place)
++ *
++ * The new driver API is available for WIRELESS_EXT >= 13.
++ * Good luck with migration to the new API ;-)
++ */
++
++/* ---------------------- THE IMPLEMENTATION ---------------------- */
++/*
++ * Some of the choice I've made are pretty controversials. Defining an
++ * API is very much weighting compromises. This goes into some of the
++ * details and the thinking behind the implementation.
++ *
++ * Implementation goals :
++ * --------------------
++ * The implementation goals were as follow :
++ *	o Obvious : you should not need a PhD to understand what's happening,
++ *		the benefit is easier maintainance.
++ *	o Flexible : it should accomodate a wide variety of driver
++ *		implementations and be as flexible as the old API.
++ *	o Lean : it should be efficient memory wise to minimise the impact
++ *		on kernel footprint.
++ *	o Transparent to user space : the large number of user space
++ *		applications that use Wireless Extensions should not need
++ *		any modifications.
++ *
++ * Array of functions versus Struct of functions
++ * ---------------------------------------------
++ * 1) Having an array of functions allow the kernel code to access the
++ * handler in a single lookup, which is much more efficient (think hash
++ * table here).
++ * 2) The only drawback is that driver writer may put their handler in
++ * the wrong slot. This is trivial to test (I set the frequency, the
++ * bitrate changes). Once the handler is in the proper slot, it will be
++ * there forever, because the array is only extended at the end.
++ * 3) Backward/forward compatibility : adding new handler just require
++ * extending the array, so you can put newer driver in older kernel
++ * without having to patch the kernel code (and vice versa).
++ *
++ * All handler are of the same generic type
++ * ----------------------------------------
++ * That's a feature !!!
++ * 1) Having a generic handler allow to have generic code, which is more
++ * efficient. If each of the handler was individually typed I would need
++ * to add a big switch in the kernel (== more bloat). This solution is
++ * more scalable, adding new Wireless Extensions doesn't add new code.
++ * 2) You can use the same handler in different slots of the array. For
++ * hardware, it may be more efficient or logical to handle multiple
++ * Wireless Extensions with a single function, and the API allow you to
++ * do that. (An example would be a single record on the card to control
++ * both bitrate and frequency, the handler would read the old record,
++ * modify it according to info->cmd and rewrite it).
++ *
++ * Functions prototype uses union iwreq_data
++ * -----------------------------------------
++ * Some would have prefered functions defined this way :
++ *	static int mydriver_ioctl_setrate(struct net_device *dev, 
++ *					  long rate, int auto)
++ * 1) The kernel code doesn't "validate" the content of iwreq_data, and
++ * can't do it (different hardware may have different notion of what a
++ * valid frequency is), so we don't pretend that we do it.
++ * 2) The above form is not extendable. If I want to add a flag (for
++ * example to distinguish setting max rate and basic rate), I would
++ * break the prototype. Using iwreq_data is more flexible.
++ * 3) Also, the above form is not generic (see above).
++ * 4) I don't expect driver developper using the wrong field of the
++ * union (Doh !), so static typechecking doesn't add much value.
++ * 5) Lastly, you can skip the union by doing :
++ *	static int mydriver_ioctl_setrate(struct net_device *dev,
++ *					  struct iw_request_info *info,
++ *					  struct iw_param *rrq,
++ *					  char *extra)
++ * And then adding the handler in the array like this :
++ *        (iw_handler) mydriver_ioctl_setrate,             // SIOCSIWRATE
++ *
++ * Using functions and not a registry
++ * ----------------------------------
++ * Another implementation option would have been for every instance to
++ * define a registry (a struct containing all the Wireless Extensions)
++ * and only have a function to commit the registry to the hardware.
++ * 1) This approach can be emulated by the current code, but not
++ * vice versa.
++ * 2) Some drivers don't keep any configuration in the driver, for them
++ * adding such a registry would be a significant bloat.
++ * 3) The code to translate from Wireless Extension to native format is
++ * needed anyway, so it would not reduce significantely the amount of code.
++ * 4) The current approach only selectively translate Wireless Extensions
++ * to native format and only selectively set, whereas the registry approach
++ * would require to translate all WE and set all parameters for any single
++ * change.
++ * 5) For many Wireless Extensions, the GET operation return the current
++ * dynamic value, not the value that was set.
++ *
++ * This header is <net/iw_handler.h>
++ * ---------------------------------
++ * 1) This header is kernel space only and should not be exported to
++ * user space. Headers in "include/linux/" are exported, headers in
++ * "include/net/" are not.
++ *
++ * Mixed 32/64 bit issues
++ * ----------------------
++ * The Wireless Extensions are designed to be 64 bit clean, by using only
++ * datatypes with explicit storage size.
++ * There are some issues related to kernel and user space using different
++ * memory model, and in particular 64bit kernel with 32bit user space.
++ * The problem is related to struct iw_point, that contains a pointer
++ * that *may* need to be translated.
++ * This is quite messy. The new API doesn't solve this problem (it can't),
++ * but is a step in the right direction :
++ * 1) Meta data about each ioctl is easily available, so we know what type
++ * of translation is needed.
++ * 2) The move of data between kernel and user space is only done in a single
++ * place in the kernel, so adding specific hooks in there is possible.
++ * 3) In the long term, it allows to move away from using ioctl as the
++ * user space API.
++ *
++ * So many comments and so few code
++ * --------------------------------
++ * That's a feature. Comments won't bloat the resulting kernel binary.
++ */
++
++/***************************** INCLUDES *****************************/
++
++#include <linux/wireless.h>		/* IOCTL user space API */
++
++/***************************** VERSION *****************************/
++/*
++ * This constant is used to know which version of the driver API is
++ * available. Hopefully, this will be pretty stable and no changes
++ * will be needed...
++ * I just plan to increment with each new version.
++ */
++#define IW_HANDLER_VERSION	2
++
++/**************************** CONSTANTS ****************************/
++
++/* Special error message for the driver to indicate that we
++ * should do a commit after return from the iw_handler */
++#define EIWCOMMIT	EINPROGRESS
++
++/* Flags available in struct iw_request_info */
++#define IW_REQUEST_FLAG_NONE	0x0000	/* No flag so far */
++
++/* Type of headers we know about (basically union iwreq_data) */
++#define IW_HEADER_TYPE_NULL	0	/* Not available */
++#define IW_HEADER_TYPE_CHAR	2	/* char [IFNAMSIZ] */
++#define IW_HEADER_TYPE_UINT	4	/* __u32 */
++#define IW_HEADER_TYPE_FREQ	5	/* struct iw_freq */
++#define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
++#define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
++#define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
++
++/* Handling flags */
++/* Most are not implemented. I just use them as a reminder of some
++ * cool features we might need one day ;-) */
++#define IW_DESCR_FLAG_NONE	0x0000	/* Obvious */
++/* Wrapper level flags */
++#define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
++#define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
++#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
++/* Driver level flags */
++#define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
++
++/****************************** TYPES ******************************/
++
++/* ----------------------- WIRELESS HANDLER ----------------------- */
++/*
++ * A wireless handler is just a standard function, that looks like the
++ * ioctl handler.
++ * We also define there how a handler list look like... As the Wireless
++ * Extension space is quite dense, we use a simple array, which is faster
++ * (that's the perfect hash table ;-).
++ */
++
++/*
++ * Meta data about the request passed to the iw_handler.
++ * Most handlers can safely ignore what's in there.
++ * The 'cmd' field might come handy if you want to use the same handler
++ * for multiple command...
++ * This struct is also my long term insurance. I can add new fields here
++ * without breaking the prototype of iw_handler...
++ */
++struct iw_request_info
++{
++	__u16		cmd;		/* Wireless Extension command */
++	__u16		flags;		/* More to come ;-) */
++};
++
++/*
++ * This is how a function handling a Wireless Extension should look
++ * like (both get and set, standard and private).
++ */
++typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info,
++			  union iwreq_data *wrqu, char *extra);
++
++/*
++ * This define all the handler that the driver export.
++ * As you need only one per driver type, please use a static const
++ * shared by all driver instances... Same for the members...
++ * This will be linked from net_device in <linux/netdevice.h>
++ */
++struct iw_handler_def
++{
++	/* Number of handlers defined (more precisely, index of the
++	 * last defined handler + 1) */
++	__u16			num_standard;
++	__u16			num_private;
++	/* Number of private arg description */
++	__u16			num_private_args;
++
++	/* Array of handlers for standard ioctls
++	 * We will call dev->wireless_handlers->standard[ioctl - SIOCSIWNAME]
++	 */
++	iw_handler *		standard;
++
++	/* Array of handlers for private ioctls
++	 * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV]
++	 */
++	iw_handler *		private;
++
++	/* Arguments of private handler. This one is just a list, so you
++	 * can put it in any order you want and should not leave holes...
++	 * We will automatically export that to user space... */
++	struct iw_priv_args *	private_args;
++
++	/* In the long term, get_wireless_stats will move from
++	 * 'struct net_device' to here, to minimise bloat. */
++};
++
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/*
++ * Currently we don't support events, so let's just plan for the
++ * future...
++ */
++
++/*
++ * A Wireless Event.
++ */
++// How do we define short header ? We don't want a flag on length.
++// Probably a flag on event ? Highest bit to zero...
++struct iw_event
++{
++	__u16		length;			/* Lenght of this stuff */
++	__u16		event;			/* Wireless IOCTL */
++	union	iwreq_data	header;		/* IOCTL fixed payload */
++	char		extra[0];		/* Optional IOCTL data */
++};
++
++/* ---------------------- IOCTL DESCRIPTION ---------------------- */
++/*
++ * One of the main goal of the new interface is to deal entirely with
++ * user space/kernel space memory move.
++ * For that, we need to know :
++ *	o if iwreq is a pointer or contain the full data
++ *	o what is the size of the data to copy
++ *
++ * For private IOCTLs, we use the same rules as used by iwpriv and
++ * defined in struct iw_priv_args.
++ *
++ * For standard IOCTLs, things are quite different and we need to
++ * use the stuctures below. Actually, this struct is also more
++ * efficient, but that's another story...
++ */
++
++/*
++ * Describe how a standard IOCTL looks like.
++ */
++struct iw_ioctl_description
++{
++	__u8	header_type;		/* NULL, iw_point or other */
++	__u8	token_type;		/* Future */
++	__u16	token_size;		/* Granularity of payload */
++	__u16	min_tokens;		/* Min acceptable token number */
++	__u16	max_tokens;		/* Max acceptable token number */
++	__u32	flags;			/* Special handling of the request */
++};
++
++/* Need to think of short header translation table. Later. */
++
++/**************************** PROTOTYPES ****************************/
++/*
++ * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
++ * Those may be called only within the kernel.
++ */
++
++/* First : function strictly used inside the kernel */
++
++/* Handle /proc/net/wireless, called in net/code/dev.c */
++extern int dev_get_wireless_info(char * buffer, char **start, off_t offset,
++				 int length);
++
++/* Handle IOCTLs, called in net/code/dev.c */
++extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
++
++/* Second : functions that may be called by driver modules */
++/* None yet */
++
++#endif	/* _LINUX_WIRELESS_H */
+diff -u -p -r --new-file linux/net/core-w12/Makefile linux/net/core/Makefile
+--- linux/net/core-w12/Makefile	Tue Oct 30 15:08:12 2001
++++ linux/net/core/Makefile	Thu Jan 17 11:06:07 2002
+@@ -26,5 +26,8 @@ obj-$(CONFIG_NET) += dev.o dev_mcast.o d
+ obj-$(CONFIG_NETFILTER) += netfilter.o
+ obj-$(CONFIG_NET_DIVERT) += dv.o
+ obj-$(CONFIG_NET_PROFILE) += profile.o
++obj-$(CONFIG_NET_RADIO) += wireless.o
++# Ugly. I wish all wireless drivers were moved in drivers/net/wireless
++obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
+ 
+ include $(TOPDIR)/Rules.make
+diff -u -p -r --new-file linux/net/core-w12/dev.c linux/net/core/dev.c
+--- linux/net/core-w12/dev.c	Wed Nov  7 14:39:36 2001
++++ linux/net/core/dev.c	Thu Jan 17 11:06:07 2002
+@@ -102,6 +102,7 @@
+ #include <linux/module.h>
+ #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
+ #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
++#include <net/iw_handler.h>
+ #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
+ #ifdef CONFIG_PLIP
+ extern int plip_init(void);
+@@ -1796,122 +1797,6 @@ static int dev_proc_stats(char *buffer, 
+ #endif	/* CONFIG_PROC_FS */
+ 
+ 
+-#ifdef WIRELESS_EXT
+-#ifdef CONFIG_PROC_FS
+-
+-/*
+- * Print one entry of /proc/net/wireless
+- * This is a clone of /proc/net/dev (just above)
+- */
+-static int sprintf_wireless_stats(char *buffer, struct net_device *dev)
+-{
+-	/* Get stats from the driver */
+-	struct iw_statistics *stats = (dev->get_wireless_stats ?
+-				       dev->get_wireless_stats(dev) :
+-				       (struct iw_statistics *) NULL);
+-	int size;
+-
+-	if (stats != (struct iw_statistics *) NULL) {
+-		size = sprintf(buffer,
+-			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
+-			       dev->name,
+-			       stats->status,
+-			       stats->qual.qual,
+-			       stats->qual.updated & 1 ? '.' : ' ',
+-			       stats->qual.level,
+-			       stats->qual.updated & 2 ? '.' : ' ',
+-			       stats->qual.noise,
+-			       stats->qual.updated & 4 ? '.' : ' ',
+-			       stats->discard.nwid,
+-			       stats->discard.code,
+-			       stats->discard.fragment,
+-			       stats->discard.retries,
+-			       stats->discard.misc,
+-			       stats->miss.beacon);
+-		stats->qual.updated = 0;
+-	}
+-	else
+-		size = 0;
+-
+-	return size;
+-}
+-
+-/*
+- * Print info for /proc/net/wireless (print all entries)
+- * This is a clone of /proc/net/dev (just above)
+- */
+-static int dev_get_wireless_info(char * buffer, char **start, off_t offset,
+-			  int length)
+-{
+-	int		len = 0;
+-	off_t		begin = 0;
+-	off_t		pos = 0;
+-	int		size;
+-	
+-	struct net_device *	dev;
+-
+-	size = sprintf(buffer,
+-		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
+-		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
+-			);
+-	
+-	pos += size;
+-	len += size;
+-
+-	read_lock(&dev_base_lock);
+-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+-		size = sprintf_wireless_stats(buffer + len, dev);
+-		len += size;
+-		pos = begin + len;
+-
+-		if (pos < offset) {
+-			len = 0;
+-			begin = pos;
+-		}
+-		if (pos > offset + length)
+-			break;
+-	}
+-	read_unlock(&dev_base_lock);
+-
+-	*start = buffer + (offset - begin);	/* Start of wanted data */
+-	len -= (offset - begin);		/* Start slop */
+-	if (len > length)
+-		len = length;			/* Ending slop */
+-	if (len < 0)
+-		len = 0;
+-
+-	return len;
+-}
+-#endif	/* CONFIG_PROC_FS */
+-
+-/*
+- *	Allow programatic access to /proc/net/wireless even if /proc
+- *	doesn't exist... Also more efficient...
+- */
+-static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
+-{
+-	/* Get stats from the driver */
+-	struct iw_statistics *stats = (dev->get_wireless_stats ?
+-				       dev->get_wireless_stats(dev) :
+-				       (struct iw_statistics *) NULL);
+-
+-	if (stats != (struct iw_statistics *) NULL) {
+-		struct iwreq *	wrq = (struct iwreq *)ifr;
+-
+-		/* Copy statistics to the user buffer */
+-		if(copy_to_user(wrq->u.data.pointer, stats,
+-				sizeof(struct iw_statistics)))
+-			return -EFAULT;
+-
+-		/* Check if we need to clear the update flag */
+-		if(wrq->u.data.flags != 0)
+-			stats->qual.updated = 0;
+-		return(0);
+-	} else
+-		return -EOPNOTSUPP;
+-}
+-#endif	/* WIRELESS_EXT */
+-
+ /**
+  *	netdev_set_master	-	set up master/slave pair
+  *	@slave: slave device
+@@ -2209,11 +2094,6 @@ static int dev_ifsioc(struct ifreq *ifr,
+ 			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+ 			return 0;
+ 
+-#ifdef WIRELESS_EXT
+-		case SIOCGIWSTATS:
+-			return dev_iwstats(dev, ifr);
+-#endif	/* WIRELESS_EXT */
+-
+ 		/*
+ 		 *	Unknown or private ioctl
+ 		 */
+@@ -2239,17 +2119,6 @@ static int dev_ifsioc(struct ifreq *ifr,
+ 				return -EOPNOTSUPP;
+ 			}
+ 
+-#ifdef WIRELESS_EXT
+-			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
+-				if (dev->do_ioctl) {
+-					if (!netif_device_present(dev))
+-						return -ENODEV;
+-					return dev->do_ioctl(dev, ifr, cmd);
+-				}
+-				return -EOPNOTSUPP;
+-			}
+-#endif	/* WIRELESS_EXT */
+-
+ 	}
+ 	return -EINVAL;
+ }
+@@ -2431,7 +2300,8 @@ int dev_ioctl(unsigned int cmd, void *ar
+ 				}
+ 				dev_load(ifr.ifr_name);
+ 				rtnl_lock();
+-				ret = dev_ifsioc(&ifr, cmd);
++				/* Follow me in net/core/wireless.c */
++				ret = wireless_process_ioctl(&ifr, cmd);
+ 				rtnl_unlock();
+ 				if (!ret && IW_IS_GET(cmd) &&
+ 				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+@@ -2856,6 +2726,7 @@ int __init net_dev_init(void)
+ 	proc_net_create("dev", 0, dev_get_info);
+ 	create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL);
+ #ifdef WIRELESS_EXT
++	/* Available in net/core/wireless.c */
+ 	proc_net_create("wireless", 0, dev_get_wireless_info);
+ #endif	/* WIRELESS_EXT */
+ #endif	/* CONFIG_PROC_FS */
+diff -u -p -r --new-file linux/net/core-w12/wireless.c linux/net/core/wireless.c
+--- linux/net/core-w12/wireless.c	Wed Dec 31 16:00:00 1969
++++ linux/net/core/wireless.c	Mon Jan 21 11:13:23 2002
+@@ -0,0 +1,733 @@
++/*
++ * This file implement the Wireless Extensions APIs.
++ *
++ * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
++ * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ *
++ * (As all part of the Linux kernel, this file is GPL)
++ */
++
++/************************** DOCUMENTATION **************************/
++/*
++ * API definition :
++ * --------------
++ * See <linux/wireless.h> for details of the APIs and the rest.
++ *
++ * History :
++ * -------
++ *
++ * v1 - 5.12.01 - Jean II
++ *	o Created this file.
++ *
++ * v2 - 13.12.01 - Jean II
++ *	o Move /proc/net/wireless stuff from net/core/dev.c to here
++ *	o Make Wireless Extension IOCTLs go through here
++ *	o Added iw_handler handling ;-)
++ *	o Added standard ioctl description
++ *	o Initial dumb commit strategy based on orinoco.c
++ */
++
++/***************************** INCLUDES *****************************/
++
++#include <asm/uaccess.h>		/* copy_to_user() */
++#include <linux/config.h>		/* Not needed ??? */
++#include <linux/types.h>		/* off_t */
++#include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
++
++#include <linux/wireless.h>		/* Pretty obvious */
++#include <net/iw_handler.h>		/* New driver API */
++
++/**************************** CONSTANTS ****************************/
++
++/* This will be turned on later on... */
++#undef WE_STRICT_WRITE		/* Check write buffer size */
++
++/* Debuging stuff */
++#undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
++
++/************************* GLOBAL VARIABLES *************************/
++/*
++ * You should not use global variables, because or re-entrancy.
++ * On our case, it's only const, so it's OK...
++ */
++static const struct iw_ioctl_description	standard_ioctl[] = {
++	/* SIOCSIWCOMMIT (internal) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWNAME */
++	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWNWID */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWNWID */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWFREQ */
++	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWFREQ */
++	{ IW_HEADER_TYPE_FREQ, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWMODE */
++	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWMODE */
++	{ IW_HEADER_TYPE_UINT, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWSENS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWSENS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRANGE */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWRANGE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, sizeof(struct iw_range), IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWPRIV */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWPRIV (handled directly by us) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWSTATS */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWSTATS (handled directly by us) */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWSPY */
++	{ IW_HEADER_TYPE_POINT, 0, sizeof(struct sockaddr), 0, IW_MAX_SPY, 0},
++	/* SIOCGIWSPY */
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_SPY, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWAP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* SIOCGIWAP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCGIWAPLIST */
++	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWESSID */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
++	/* SIOCGIWESSID */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
++	/* SIOCSIWNICKN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	/* SIOCGIWNICKN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* -- hole -- */
++	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWRATE */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRATE */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRTS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRTS */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWFRAG */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWFRAG */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWTXPOW */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWTXPOW */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWRETRY */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWRETRY */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCSIWENCODE */
++	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
++	/* SIOCGIWENCODE */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
++	/* SIOCSIWPOWER */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWPOWER */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++};
++
++/* Size (in bytes) of the various private data types */
++char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++
++/************************ COMMON SUBROUTINES ************************/
++/*
++ * Stuff that may be used in various place or doesn't fit in one
++ * of the section below.
++ */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Return the driver handler associated with a specific Wireless Extension.
++ * Called from various place, so make sure it remains efficient.
++ */
++static inline iw_handler get_handler(struct net_device *dev,
++				     unsigned int cmd)
++{
++	unsigned int	index;		/* MUST be unsigned */
++
++	/* Check if we have some wireless handlers defined */
++	if(dev->wireless_handlers == NULL)
++		return NULL;
++
++	/* Try as a standard command */
++	index = cmd - SIOCIWFIRST;
++	if(index < dev->wireless_handlers->num_standard)
++		return dev->wireless_handlers->standard[index];
++
++	/* Try as a private command */
++	index = cmd - SIOCIWFIRSTPRIV;
++	if(index < dev->wireless_handlers->num_private)
++		return dev->wireless_handlers->private[index];
++
++	/* Not found */
++	return NULL;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Get statistics out of the driver
++ */
++static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
++{
++	return (dev->get_wireless_stats ?
++		dev->get_wireless_stats(dev) :
++		(struct iw_statistics *) NULL);
++	/* In the future, get_wireless_stats may move from 'struct net_device'
++	 * to 'struct iw_handler_def', to de-bloat struct net_device.
++	 * Definitely worse a thought... */
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Call the commit handler in the driver
++ * (if exist and if conditions are right)
++ *
++ * Note : our current commit strategy is currently pretty dumb,
++ * but we will be able to improve on that...
++ * The goal is to try to agreagate as many changes as possible
++ * before doing the commit. Drivers that will define a commit handler
++ * are usually those that need a reset after changing parameters, so
++ * we want to minimise the number of reset.
++ * A cool idea is to use a timer : at each "set" command, we re-set the
++ * timer, when the timer eventually fires, we call the driver.
++ * Hopefully, more on that later.
++ *
++ * Also, I'm waiting to see how many people will complain about the
++ * netif_running(dev) test. I'm open on that one...
++ * Hopefully, the driver will remember to do a commit in "open()" ;-)
++ */
++static inline int call_commit_handler(struct net_device *	dev)
++{
++	if((netif_running(dev)) &&
++	   (dev->wireless_handlers->standard[0] != NULL)) {
++		/* Call the commit handler on the driver */
++		return dev->wireless_handlers->standard[0](dev, NULL,
++							   NULL, NULL);
++	} else
++		return 0;		/* Command completed successfully */
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Number of private arguments
++ */
++static inline int get_priv_size(__u16	args)
++{
++	int	num = args & IW_PRIV_SIZE_MASK;
++	int	type = (args & IW_PRIV_TYPE_MASK) >> 12;
++
++	return num * priv_type_size[type];
++}
++
++
++/******************** /proc/net/wireless SUPPORT ********************/
++/*
++ * The /proc/net/wireless file is a human readable user-space interface
++ * exporting various wireless specific statistics from the wireless devices.
++ * This is the most popular part of the Wireless Extensions ;-)
++ *
++ * This interface is a pure clone of /proc/net/dev (in net/core/dev.c).
++ * The content of the file is basically the content of "struct iw_statistics".
++ */
++
++#ifdef CONFIG_PROC_FS
++
++/* ---------------------------------------------------------------- */
++/*
++ * Print one entry (line) of /proc/net/wireless
++ */
++static inline int sprintf_wireless_stats(char *buffer, struct net_device *dev)
++{
++	/* Get stats from the driver */
++	struct iw_statistics *stats;
++	int size;
++
++	stats = get_wireless_stats(dev);
++	if (stats != (struct iw_statistics *) NULL) {
++		size = sprintf(buffer,
++			       "%6s: %04x  %3d%c  %3d%c  %3d%c  %6d %6d %6d %6d %6d   %6d\n",
++			       dev->name,
++			       stats->status,
++			       stats->qual.qual,
++			       stats->qual.updated & 1 ? '.' : ' ',
++			       stats->qual.level,
++			       stats->qual.updated & 2 ? '.' : ' ',
++			       stats->qual.noise,
++			       stats->qual.updated & 4 ? '.' : ' ',
++			       stats->discard.nwid,
++			       stats->discard.code,
++			       stats->discard.fragment,
++			       stats->discard.retries,
++			       stats->discard.misc,
++			       stats->miss.beacon);
++		stats->qual.updated = 0;
++	}
++	else
++		size = 0;
++
++	return size;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Print info for /proc/net/wireless (print all entries)
++ */
++int dev_get_wireless_info(char * buffer, char **start, off_t offset,
++			  int length)
++{
++	int		len = 0;
++	off_t		begin = 0;
++	off_t		pos = 0;
++	int		size;
++	
++	struct net_device *	dev;
++
++	size = sprintf(buffer,
++		       "Inter-| sta-|   Quality        |   Discarded packets               | Missed\n"
++		       " face | tus | link level noise |  nwid  crypt   frag  retry   misc | beacon\n"
++			);
++	
++	pos += size;
++	len += size;
++
++	read_lock(&dev_base_lock);
++	for (dev = dev_base; dev != NULL; dev = dev->next) {
++		size = sprintf_wireless_stats(buffer + len, dev);
++		len += size;
++		pos = begin + len;
++
++		if (pos < offset) {
++			len = 0;
++			begin = pos;
++		}
++		if (pos > offset + length)
++			break;
++	}
++	read_unlock(&dev_base_lock);
++
++	*start = buffer + (offset - begin);	/* Start of wanted data */
++	len -= (offset - begin);		/* Start slop */
++	if (len > length)
++		len = length;			/* Ending slop */
++	if (len < 0)
++		len = 0;
++
++	return len;
++}
++#endif	/* CONFIG_PROC_FS */
++
++/************************** IOCTL SUPPORT **************************/
++/*
++ * The original user space API to configure all those Wireless Extensions
++ * is through IOCTLs.
++ * In there, we check if we need to call the new driver API (iw_handler)
++ * or just call the driver ioctl handler.
++ */
++
++/* ---------------------------------------------------------------- */
++/*
++ *	Allow programatic access to /proc/net/wireless even if /proc
++ *	doesn't exist... Also more efficient...
++ */
++static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr)
++{
++	/* Get stats from the driver */
++	struct iw_statistics *stats;
++
++	stats = get_wireless_stats(dev);
++	if (stats != (struct iw_statistics *) NULL) {
++		struct iwreq *	wrq = (struct iwreq *)ifr;
++
++		/* Copy statistics to the user buffer */
++		if(copy_to_user(wrq->u.data.pointer, stats,
++				sizeof(struct iw_statistics)))
++			return -EFAULT;
++
++		/* Check if we need to clear the update flag */
++		if(wrq->u.data.flags != 0)
++			stats->qual.updated = 0;
++		return 0;
++	} else
++		return -EOPNOTSUPP;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Export the driver private handler definition
++ * They will be picked up by tools like iwpriv...
++ */
++static inline int ioctl_export_private(struct net_device *	dev,
++				       struct ifreq *		ifr)
++{
++	struct iwreq *				iwr = (struct iwreq *) ifr;
++
++	/* Check if the driver has something to export */
++	if((dev->wireless_handlers->num_private_args == 0) ||
++	   (dev->wireless_handlers->private_args == NULL))
++		return -EOPNOTSUPP;
++
++	/* Check NULL pointer */
++	if(iwr->u.data.pointer == NULL)
++		return -EFAULT;
++#ifdef WE_STRICT_WRITE
++	/* Check if there is enough buffer up there */
++	if(iwr->u.data.length < (SIOCIWLASTPRIV - SIOCIWFIRSTPRIV + 1))
++		return -E2BIG;
++#endif	/* WE_STRICT_WRITE */
++
++	/* Set the number of available ioctls. */
++	iwr->u.data.length = dev->wireless_handlers->num_private_args;
++
++	/* Copy structure to the user buffer. */
++	if (copy_to_user(iwr->u.data.pointer,
++			 dev->wireless_handlers->private_args,
++			 sizeof(struct iw_priv_args) * iwr->u.data.length))
++		return -EFAULT;
++
++	return 0;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Wrapper to call a standard Wireless Extension handler.
++ * We do various checks and also take care of moving data between
++ * user space and kernel space.
++ */
++static inline int ioctl_standard_call(struct net_device *	dev,
++				      struct ifreq *		ifr,
++				      unsigned int		cmd,
++				      iw_handler		handler)
++{
++	struct iwreq *				iwr = (struct iwreq *) ifr;
++	const struct iw_ioctl_description *	descr;
++	struct iw_request_info			info;
++	int					ret = -EINVAL;
++
++	/* Get the description of the IOCTL */
++	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
++
++#ifdef WE_IOCTL_DEBUG
++	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
++	       ifr->ifr_name, cmd);
++	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++#endif	/* WE_IOCTL_DEBUG */
++
++	/* Prepare the call */
++	info.cmd = cmd;
++	info.flags = 0;
++
++	/* Check if we have a pointer to user space data or not */
++	if(descr->header_type != IW_HEADER_TYPE_POINT) {
++		/* No extra arguments. Trivial to handle */
++		ret = handler(dev, &info, &(iwr->u), NULL);
++	} else {
++		char *	extra;
++		int	err;
++
++		/* Check what user space is giving us */
++		if(IW_IS_SET(cmd)) {
++			/* Check NULL pointer */
++			if((iwr->u.data.pointer == NULL) &&
++			   (iwr->u.data.length != 0))
++				return -EFAULT;
++			/* Check if number of token fits within bounds */
++			if(iwr->u.data.length > descr->max_tokens)
++				return -E2BIG;
++			if(iwr->u.data.length < descr->min_tokens)
++				return -EINVAL;
++		} else {
++			/* Check NULL pointer */
++			if(iwr->u.data.pointer == NULL)
++				return -EFAULT;
++#ifdef WE_STRICT_WRITE
++			/* Check if there is enough buffer up there */
++			if(iwr->u.data.length < descr->max_tokens)
++				return -E2BIG;
++#endif	/* WE_STRICT_WRITE */
++		}
++
++#ifdef WE_IOCTL_DEBUG
++		printk(KERN_DEBUG "Malloc %d bytes\n",
++		       descr->max_tokens * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++
++		/* Always allocate for max space. Easier, and won't last
++		 * long... */
++		extra = kmalloc(descr->max_tokens * descr->token_size,
++				GFP_KERNEL);
++		if (extra == NULL) {
++			return -ENOMEM;
++		}
++
++		/* If it is a SET, get all the extra data in here */
++		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
++			err = copy_from_user(extra, iwr->u.data.pointer,
++					     iwr->u.data.length *
++					     descr->token_size);
++			if (err) {
++				kfree(extra);
++				return -EFAULT;
++			}
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Got %d bytes\n",
++			       iwr->u.data.length * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Call the handler */
++		ret = handler(dev, &info, &(iwr->u), extra);
++
++		/* If we have something to return to the user */
++		if (!ret && IW_IS_GET(cmd)) {
++			err = copy_to_user(iwr->u.data.pointer, extra,
++					   iwr->u.data.length *
++					   descr->token_size);
++			if (err)
++				ret =  -EFAULT;				   
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Wrote %d bytes\n",
++			       iwr->u.data.length * descr->token_size);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Cleanup - I told you it wasn't that long ;-) */
++		kfree(extra);
++	}
++
++	/* Call commit handler if needed and defined */
++	if(ret == -EIWCOMMIT)
++		ret = call_commit_handler(dev);
++
++	/* Here, we will generate the appropriate event if needed */
++
++	return ret;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Wrapper to call a private Wireless Extension handler.
++ * We do various checks and also take care of moving data between
++ * user space and kernel space.
++ * It's not as nice and slimline as the standard wrapper. The cause
++ * is struct iw_priv_args, which was not really designed for the
++ * job we are going here.
++ *
++ * IMPORTANT : This function prevent to set and get data on the same
++ * IOCTL and enforce the SET/GET convention. Not doing it would be
++ * far too hairy...
++ * If you need to set and get data at the same time, please don't use
++ * a iw_handler but process it in your ioctl handler (i.e. use the
++ * old driver API).
++ */
++static inline int ioctl_private_call(struct net_device *	dev,
++				     struct ifreq *		ifr,
++				     unsigned int		cmd,
++				     iw_handler		handler)
++{
++	struct iwreq *			iwr = (struct iwreq *) ifr;
++	struct iw_priv_args *		descr = NULL;
++	struct iw_request_info		info;
++	int				extra_size = 0;
++	int				i;
++	int				ret = -EINVAL;
++
++	/* Get the description of the IOCTL */
++	for(i = 0; i < dev->wireless_handlers->num_private_args; i++)
++		if(cmd == dev->wireless_handlers->private_args[i].cmd) {
++			descr = &(dev->wireless_handlers->private_args[i]);
++			break;
++		}
++
++#ifdef WE_IOCTL_DEBUG
++	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
++	       ifr->ifr_name, cmd);
++	if(descr) {
++		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
++		       descr->name, descr->set_args, descr->get_args);
++	}
++#endif	/* WE_IOCTL_DEBUG */
++
++	/* Compute the size of the set/get arguments */
++	if(descr != NULL) {
++		if(IW_IS_SET(cmd)) {
++			/* Size of set arguments */
++			extra_size = get_priv_size(descr->set_args);
++
++			/* Does it fits in iwr ? */
++			if((descr->set_args & IW_PRIV_SIZE_FIXED) &&
++			   (extra_size < IFNAMSIZ))
++				extra_size = 0;
++		} else {
++			/* Size of set arguments */
++			extra_size = get_priv_size(descr->get_args);
++
++			/* Does it fits in iwr ? */
++			if((descr->get_args & IW_PRIV_SIZE_FIXED) &&
++			   (extra_size < IFNAMSIZ))
++				extra_size = 0;
++		}
++	}
++
++	/* Prepare the call */
++	info.cmd = cmd;
++	info.flags = 0;
++
++	/* Check if we have a pointer to user space data or not. */
++	if(extra_size == 0) {
++		/* No extra arguments. Trivial to handle */
++		ret = handler(dev, &info, &(iwr->u), (char *) &(iwr->u));
++	} else {
++		char *	extra;
++		int	err;
++
++		/* Check what user space is giving us */
++		if(IW_IS_SET(cmd)) {
++			/* Check NULL pointer */
++			if((iwr->u.data.pointer == NULL) &&
++			   (iwr->u.data.length != 0))
++				return -EFAULT;
++
++			/* Does it fits within bounds ? */
++			if(iwr->u.data.length > (descr->set_args &
++						 IW_PRIV_SIZE_MASK))
++				return -E2BIG;
++		} else {
++			/* Check NULL pointer */
++			if(iwr->u.data.pointer == NULL)
++				return -EFAULT;
++		}
++
++#ifdef WE_IOCTL_DEBUG
++		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
++#endif	/* WE_IOCTL_DEBUG */
++
++		/* Always allocate for max space. Easier, and won't last
++		 * long... */
++		extra = kmalloc(extra_size, GFP_KERNEL);
++		if (extra == NULL) {
++			return -ENOMEM;
++		}
++
++		/* If it is a SET, get all the extra data in here */
++		if(IW_IS_SET(cmd) && (iwr->u.data.length != 0)) {
++			err = copy_from_user(extra, iwr->u.data.pointer,
++					     extra_size);
++			if (err) {
++				kfree(extra);
++				return -EFAULT;
++			}
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Call the handler */
++		ret = handler(dev, &info, &(iwr->u), extra);
++
++		/* If we have something to return to the user */
++		if (!ret && IW_IS_GET(cmd)) {
++			err = copy_to_user(iwr->u.data.pointer, extra,
++					   extra_size);
++			if (err)
++				ret =  -EFAULT;				   
++#ifdef WE_IOCTL_DEBUG
++			printk(KERN_DEBUG "Wrote %d elem\n",
++			       iwr->u.data.length);
++#endif	/* WE_IOCTL_DEBUG */
++		}
++
++		/* Cleanup - I told you it wasn't that long ;-) */
++		kfree(extra);
++	}
++
++
++	/* Call commit handler if needed and defined */
++	if(ret == -EIWCOMMIT)
++		ret = call_commit_handler(dev);
++
++	return ret;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Main IOCTl dispatcher. Called from the main networking code
++ * (dev_ioctl() in net/core/dev.c).
++ * Check the type of IOCTL and call the appropriate wrapper...
++ */
++int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd)
++{
++	struct net_device *dev;
++	iw_handler	handler;
++
++	/* Permissions are already checked in dev_ioctl() before calling us.
++	 * The copy_to/from_user() of ifr is also dealt with in there */
++
++	/* Make sure the device exist */
++	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
++		return -ENODEV;
++
++	/* A bunch of special cases, then the generic case...
++	 * Note that 'cmd' is already filtered in dev_ioctl() with
++	 * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
++	switch(cmd) 
++	{
++		case SIOCGIWSTATS:
++			/* Get Wireless Stats */
++			return dev_iwstats(dev, ifr);
++
++		case SIOCGIWPRIV:
++			/* Check if we have some wireless handlers defined */
++			if(dev->wireless_handlers != NULL) {
++				/* We export to user space the definition of
++				 * the private handler ourselves */
++				return ioctl_export_private(dev, ifr);
++			}
++			// ## Fall-through for old API ##
++		default:
++			/* Generic IOCTL */
++			/* Basic check */
++			if (!netif_device_present(dev))
++				return -ENODEV;
++			/* New driver API : try to find the handler */
++			handler = get_handler(dev, cmd);
++			if(handler != NULL) {
++				/* Standard and private are not the same */
++				if(cmd < SIOCIWFIRSTPRIV)
++					return ioctl_standard_call(dev,
++								   ifr,
++								   cmd,
++								   handler);
++				else
++					return ioctl_private_call(dev,
++								  ifr,
++								  cmd,
++								  handler);
++			}
++			/* Old driver API : call driver ioctl handler */
++			if (dev->do_ioctl) {
++				return dev->do_ioctl(dev, ifr, cmd);
++			}
++			return -EOPNOTSUPP;
++	}
++	/* Not reached */
++	return -EINVAL;
++}
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff
index e69de29bb2..539b160068 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/iw_handlers.w14-5.diff
@@ -0,0 +1,838 @@
+diff -u -p -r --new-file linux/include/linux-w13/rtnetlink.h linux/include/linux/rtnetlink.h
+--- linux/include/linux-w13/rtnetlink.h	Thu Jun  6 14:44:08 2002
++++ linux/include/linux/rtnetlink.h	Thu Jun  6 15:47:44 2002
+@@ -440,12 +440,14 @@ enum
+ #define IFLA_COST IFLA_COST
+ 	IFLA_PRIORITY,
+ #define IFLA_PRIORITY IFLA_PRIORITY
+-	IFLA_MASTER
++	IFLA_MASTER,
+ #define IFLA_MASTER IFLA_MASTER
++	IFLA_WIRELESS,		/* Wireless Extension event - see wireless.h */
++#define IFLA_WIRELESS IFLA_WIRELESS
+ };
+ 
+ 
+-#define IFLA_MAX IFLA_MASTER
++#define IFLA_MAX IFLA_WIRELESS
+ 
+ #define IFLA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+ #define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+diff -u -p -r --new-file linux/include/linux-w13/wireless.h linux/include/linux/wireless.h
+--- linux/include/linux-w13/wireless.h	Thu Jun  6 15:00:28 2002
++++ linux/include/linux/wireless.h	Thu Jun  6 15:47:44 2002
+@@ -1,10 +1,10 @@
+ /*
+  * This file define a set of standard wireless extensions
+  *
+- * Version :	13	6.12.01
++ * Version :	14	25.1.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _LINUX_WIRELESS_H
+@@ -40,7 +40,7 @@
+  *	# include/linux/netdevice.h (one place)
+  *	# include/linux/proc_fs.h (one place)
+  *
+- * New driver API (2001 -> onward) :
++ * New driver API (2002 -> onward) :
+  * -------------------------------
+  * This file is only concerned with the user space API and common definitions.
+  * The new driver API is defined and documented in :
+@@ -49,6 +49,11 @@
+  * Note as well that /proc/net/wireless implementation has now moved in :
+  *	# include/linux/wireless.c
+  *
++ * Wireless Events (2002 -> onward) :
++ * --------------------------------
++ * Events are defined at the end of this file, and implemented in :
++ *	# include/linux/wireless.c
++ *
+  * Other comments :
+  * --------------
+  * Do not add here things that are redundant with other mechanisms
+@@ -75,7 +80,7 @@
+  * (there is some stuff that will be added in the future...)
+  * I just plan to increment with each new version.
+  */
+-#define WIRELESS_EXT	13
++#define WIRELESS_EXT	14
+ 
+ /*
+  * Changes :
+@@ -141,6 +146,13 @@
+  *	- Document creation of new driver API.
+  *	- Extract union iwreq_data from struct iwreq (for new driver API).
+  *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
++ *
++ * V13 to V14
++ * ----------
++ *	- Wireless Events support : define struct iw_event
++ *	- Define additional specific event numbers
++ *	- Add "addr" and "param" fields in union iwreq_data
++ *	- AP scanning stuff (SIOCSIWSCAN and friends)
+  */
+ 
+ /**************************** CONSTANTS ****************************/
+@@ -175,6 +187,8 @@
+ #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
+ #define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
+ #define SIOCGIWAPLIST	0x8B17		/* get list of access point in range */
++#define SIOCSIWSCAN	0x8B18		/* trigger scanning */
++#define SIOCGIWSCAN	0x8B19		/* get scanning results */
+ 
+ /* 802.11 specific support */
+ #define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
+@@ -238,6 +252,15 @@
+ #define IW_IS_SET(cmd)	(!((cmd) & 0x1))
+ #define IW_IS_GET(cmd)	((cmd) & 0x1)
+ 
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/* Those are *NOT* ioctls, do not issue request on them !!! */
++/* Most events use the same identifier as ioctl requests */
++
++#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
++#define IWEVQUAL	0x8C01		/* Quality part of statistics */
++
++#define IWEVFIRST	0x8C00
++
+ /* ------------------------- PRIVATE INFO ------------------------- */
+ /*
+  * The following is used with SIOCGIWPRIV. It allow a driver to define
+@@ -340,6 +363,19 @@
+ #define IW_RETRY_MAX		0x0002	/* Value is a maximum */
+ #define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
+ 
++/* Scanning request flags */
++#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
++#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
++#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
++#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
++#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
++#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
++#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
++#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
++#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
++/* Maximum size of returned data */
++#define IW_SCAN_MAX_DATA	4096	/* In bytes */
++
+ /****************************** TYPES ******************************/
+ 
+ /* --------------------------- SUBTYPES --------------------------- */
+@@ -466,9 +502,12 @@ union	iwreq_data
+ 
+ 	struct iw_point	encoding;	/* Encoding stuff : tokens */
+ 	struct iw_param	power;		/* PM duration/timeout */
++	struct iw_quality qual;		/* Quality part of statistics */
+ 
+ 	struct sockaddr	ap_addr;	/* Access point address */
++	struct sockaddr	addr;		/* Destination address (hw) */
+ 
++	struct iw_param	param;		/* Other small parameters */
+ 	struct iw_point	data;		/* Other large parameters */
+ };
+ 
+@@ -595,5 +634,36 @@ struct	iw_priv_args
+ 	__u16		get_args;	/* Type and number of args */
+ 	char		name[IFNAMSIZ];	/* Name of the extension */
+ };
++
++/* ----------------------- WIRELESS EVENTS ----------------------- */
++/*
++ * Wireless events are carried through the rtnetlink socket to user
++ * space. They are encapsulated in the IFLA_WIRELESS field of
++ * a RTM_NEWLINK message.
++ */
++
++/*
++ * A Wireless Event. Contains basically the same data as the ioctl...
++ */
++struct iw_event
++{
++	__u16		len;			/* Real lenght of this stuff */
++	__u16		cmd;			/* Wireless IOCTL */
++	union iwreq_data	u;		/* IOCTL fixed payload */
++};
++
++/* Size of the Event prefix (including padding and alignement junk) */
++#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
++/* Size of the various events */
++#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
++#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
++#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
++#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point))
++#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
++#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
++#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
++
++/* Note : in the case of iw_point, the extra data will come at the
++ * end of the event */
+ 
+ #endif	/* _LINUX_WIRELESS_H */
+diff -u -p -r --new-file linux/include/net-w13/iw_handler.h linux/include/net/iw_handler.h
+--- linux/include/net-w13/iw_handler.h	Thu Jun  6 15:06:16 2002
++++ linux/include/net/iw_handler.h	Thu Jun  6 15:48:06 2002
+@@ -1,10 +1,10 @@
+ /*
+  * This file define the new driver API for Wireless Extensions
+  *
+- * Version :	2	6.12.01
++ * Version :	3	17.1.02
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
+  */
+ 
+ #ifndef _IW_HANDLER_H
+@@ -33,7 +33,7 @@
+  *	o The user space interface is tied to ioctl because of the use
+  *	  copy_to/from_user.
+  *
+- * New driver API (2001 -> onward) :
++ * New driver API (2002 -> onward) :
+  * -------------------------------
+  * The new driver API is just a bunch of standard functions (handlers),
+  * each handling a specific Wireless Extension. The driver just export
+@@ -206,7 +206,18 @@
+  * will be needed...
+  * I just plan to increment with each new version.
+  */
+-#define IW_HANDLER_VERSION	2
++#define IW_HANDLER_VERSION	3
++
++/*
++ * Changes :
++ *
++ * V2 to V3
++ * --------
++ *	- Move event definition in <linux/wireless.h>
++ *	- Add Wireless Event support :
++ *		o wireless_send_event() prototype
++ *		o iwe_stream_add_event/point() inline functions
++ */
+ 
+ /**************************** CONSTANTS ****************************/
+ 
+@@ -225,6 +236,7 @@
+ #define IW_HEADER_TYPE_POINT	6	/* struct iw_point */
+ #define IW_HEADER_TYPE_PARAM	7	/* struct iw_param */
+ #define IW_HEADER_TYPE_ADDR	8	/* struct sockaddr */
++#define IW_HEADER_TYPE_QUAL	9	/* struct iw_quality */
+ 
+ /* Handling flags */
+ /* Most are not implemented. I just use them as a reminder of some
+@@ -233,7 +245,8 @@
+ /* Wrapper level flags */
+ #define IW_DESCR_FLAG_DUMP	0x0001	/* Not part of the dump command */
+ #define IW_DESCR_FLAG_EVENT	0x0002	/* Generate an event on SET */
+-#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET request is ROOT only */
++#define IW_DESCR_FLAG_RESTRICT	0x0004	/* GET : request is ROOT only */
++				/* SET : Omit payload from generated iwevent */
+ /* Driver level flags */
+ #define IW_DESCR_FLAG_WAIT	0x0100	/* Wait for driver event */
+ 
+@@ -303,25 +316,6 @@ struct iw_handler_def
+ 	 * 'struct net_device' to here, to minimise bloat. */
+ };
+ 
+-/* ----------------------- WIRELESS EVENTS ----------------------- */
+-/*
+- * Currently we don't support events, so let's just plan for the
+- * future...
+- */
+-
+-/*
+- * A Wireless Event.
+- */
+-// How do we define short header ? We don't want a flag on length.
+-// Probably a flag on event ? Highest bit to zero...
+-struct iw_event
+-{
+-	__u16		length;			/* Lenght of this stuff */
+-	__u16		event;			/* Wireless IOCTL */
+-	union	iwreq_data	header;		/* IOCTL fixed payload */
+-	char		extra[0];		/* Optional IOCTL data */
+-};
+-
+ /* ---------------------- IOCTL DESCRIPTION ---------------------- */
+ /*
+  * One of the main goal of the new interface is to deal entirely with
+@@ -369,6 +363,88 @@ extern int dev_get_wireless_info(char * 
+ extern int wireless_process_ioctl(struct ifreq *ifr, unsigned int cmd);
+ 
+ /* Second : functions that may be called by driver modules */
+-/* None yet */
+ 
+-#endif	/* _LINUX_WIRELESS_H */
++/* Send a single event to user space */
++extern void wireless_send_event(struct net_device *	dev,
++				unsigned int		cmd,
++				union iwreq_data *	wrqu,
++				char *			extra);
++
++/* We may need a function to send a stream of events to user space.
++ * More on that later... */
++
++/************************* INLINE FUNTIONS *************************/
++/*
++ * Function that are so simple that it's more efficient inlining them
++ */
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add an Wireless Event to a stream of events.
++ */
++static inline char *
++iwe_stream_add_event(char *	stream,		/* Stream of events */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     int	event_len)	/* Real size of payload */
++{
++	/* Check if it's possible */
++	if((stream + event_len) < ends) {
++		iwe->len = event_len;
++		memcpy(stream, (char *) iwe, event_len);
++		stream += event_len;
++	}
++	return stream;
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add an short Wireless Event containing a pointer to a
++ * stream of events.
++ */
++static inline char *
++iwe_stream_add_point(char *	stream,		/* Stream of events */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     char *	extra)
++{
++	int	event_len = IW_EV_POINT_LEN + iwe->u.data.length;
++	/* Check if it's possible */
++	if((stream + event_len) < ends) {
++		iwe->len = event_len;
++		memcpy(stream, (char *) iwe, IW_EV_POINT_LEN);
++		memcpy(stream + IW_EV_POINT_LEN, extra, iwe->u.data.length);
++		stream += event_len;
++	}
++	return stream;
++}
++
++/*------------------------------------------------------------------*/
++/*
++ * Wrapper to add a value to a Wireless Event in a stream of events.
++ * Be careful, this one is tricky to use properly :
++ * At the first run, you need to have (value = event + IW_EV_LCP_LEN).
++ */
++static inline char *
++iwe_stream_add_value(char *	event,		/* Event in the stream */
++		     char *	value,		/* Value in event */
++		     char *	ends,		/* End of stream */
++		     struct iw_event *iwe,	/* Payload */
++		     int	event_len)	/* Real size of payload */
++{
++	/* Don't duplicate LCP */
++	event_len -= IW_EV_LCP_LEN;
++
++	/* Check if it's possible */
++	if((value + event_len) < ends) {
++		/* Add new value */
++		memcpy(value, (char *) iwe + IW_EV_LCP_LEN, event_len);
++		value += event_len;
++		/* Patch LCP */
++		iwe->len = value - event;
++		memcpy(event, (char *) iwe, IW_EV_LCP_LEN);
++	}
++	return value;
++}
++
++#endif	/* _IW_HANDLER_H */
+diff -u -p -r --new-file linux/net/netsyms-w13.c linux/net/netsyms.c
+--- linux/net/netsyms-w13.c	Thu Jun  6 15:46:34 2002
++++ linux/net/netsyms.c	Thu Jun  6 15:47:44 2002
+@@ -588,4 +588,10 @@ EXPORT_SYMBOL(register_gifconf);
+ EXPORT_SYMBOL(net_call_rx_atomic);
+ EXPORT_SYMBOL(softnet_data);
+ 
++#if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO)
++/* Don't include the whole header mess for a single function */
++extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra);
++EXPORT_SYMBOL(wireless_send_event);
++#endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
++
+ #endif  /* CONFIG_NET */
+diff -u -p -r --new-file linux/net/core/wireless-w13.c linux/net/core/wireless.c
+--- linux/net/core/wireless-w13.c	Thu Jun  6 15:46:45 2002
++++ linux/net/core/wireless.c	Thu Jun  6 15:48:06 2002
+@@ -2,7 +2,7 @@
+  * This file implement the Wireless Extensions APIs.
+  *
+  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+- * Copyright (c) 1997-2001 Jean Tourrilhes, All Rights Reserved.
++ * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+  *
+  * (As all part of the Linux kernel, this file is GPL)
+  */
+@@ -25,6 +25,16 @@
+  *	o Added iw_handler handling ;-)
+  *	o Added standard ioctl description
+  *	o Initial dumb commit strategy based on orinoco.c
++ *
++ * v3 - 19.12.01 - Jean II
++ *	o Make sure we don't go out of standard_ioctl[] in ioctl_standard_call
++ *	o Add event dispatcher function
++ *	o Add event description
++ *	o Propagate events as rtnetlink IFLA_WIRELESS option
++ *	o Generate event on selected SET requests
++ *
++ * v4 - 18.04.01 - Jean II
++ *	o Fix stupid off by one in iw_ioctl_description : IW_ESSID_MAX_SIZE + 1
+  */
+ 
+ /***************************** INCLUDES *****************************/
+@@ -33,6 +43,7 @@
+ #include <linux/config.h>		/* Not needed ??? */
+ #include <linux/types.h>		/* off_t */
+ #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
++#include <linux/rtnetlink.h>		/* rtnetlink stuff */
+ 
+ #include <linux/wireless.h>		/* Pretty obvious */
+ #include <net/iw_handler.h>		/* New driver API */
+@@ -44,14 +55,23 @@
+ 
+ /* Debuging stuff */
+ #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
++#undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
++
++/* Options */
++#define WE_EVENT_NETLINK	/* Propagate events using rtnetlink */
++#define WE_SET_EVENT		/* Generate an event on some set commands */
+ 
+ /************************* GLOBAL VARIABLES *************************/
+ /*
+  * You should not use global variables, because or re-entrancy.
+  * On our case, it's only const, so it's OK...
+  */
++/*
++ * Meta-data about all the standard Wireless Extension request we
++ * know about.
++ */
+ static const struct iw_ioctl_description	standard_ioctl[] = {
+-	/* SIOCSIWCOMMIT (internal) */
++	/* SIOCSIWCOMMIT */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* SIOCGIWNAME */
+ 	{ IW_HEADER_TYPE_CHAR, 0, 0, 0, 0, IW_DESCR_FLAG_DUMP},
+@@ -99,18 +119,18 @@ static const struct iw_ioctl_description
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* SIOCGIWAPLIST */
+ 	{ IW_HEADER_TYPE_POINT, 0, (sizeof(struct sockaddr) + sizeof(struct iw_quality)), 0, IW_MAX_AP, 0},
+-	/* -- hole -- */
+-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+-	/* -- hole -- */
+-	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
++	/* SIOCSIWSCAN */
++	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
++	/* SIOCGIWSCAN */
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_SCAN_MAX_DATA, 0},
+ 	/* SIOCSIWESSID */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_EVENT},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_EVENT},
+ 	/* SIOCGIWESSID */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, IW_DESCR_FLAG_DUMP},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, IW_DESCR_FLAG_DUMP},
+ 	/* SIOCSIWNICKN */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+ 	/* SIOCGIWNICKN */
+-	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE, 0},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ESSID_MAX_SIZE + 1, 0},
+ 	/* -- hole -- */
+ 	{ IW_HEADER_TYPE_NULL, 0, 0, 0, 0, 0},
+ 	/* -- hole -- */
+@@ -136,7 +156,7 @@ static const struct iw_ioctl_description
+ 	/* SIOCGIWRETRY */
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ 	/* SIOCSIWENCODE */
+-	{ IW_HEADER_TYPE_POINT, 4, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
++	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_EVENT | IW_DESCR_FLAG_RESTRICT},
+ 	/* SIOCGIWENCODE */
+ 	{ IW_HEADER_TYPE_POINT, 0, 1, 0, IW_ENCODING_TOKEN_MAX, IW_DESCR_FLAG_DUMP | IW_DESCR_FLAG_RESTRICT},
+ 	/* SIOCSIWPOWER */
+@@ -144,9 +164,38 @@ static const struct iw_ioctl_description
+ 	/* SIOCGIWPOWER */
+ 	{ IW_HEADER_TYPE_PARAM, 0, 0, 0, 0, 0},
+ };
++static const int standard_ioctl_num = (sizeof(standard_ioctl) /
++				       sizeof(struct iw_ioctl_description));
++
++/*
++ * Meta-data about all the additional standard Wireless Extension events
++ * we know about.
++ */
++static const struct iw_ioctl_description	standard_event[] = {
++	/* IWEVTXDROP */
++	{ IW_HEADER_TYPE_ADDR, 0, 0, 0, 0, 0},
++	/* IWEVQUAL */
++	{ IW_HEADER_TYPE_QUAL, 0, 0, 0, 0, 0},
++};
++static const int standard_event_num = (sizeof(standard_event) /
++				       sizeof(struct iw_ioctl_description));
+ 
+ /* Size (in bytes) of the various private data types */
+-char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++static const char priv_type_size[] = { 0, 1, 1, 0, 4, 4, 0, 0 };
++
++/* Size (in bytes) of various events */
++static const int event_type_size[] = {
++	IW_EV_LCP_LEN,
++	0,
++	IW_EV_CHAR_LEN,
++	0,
++	IW_EV_UINT_LEN,
++	IW_EV_FREQ_LEN,
++	IW_EV_POINT_LEN,		/* Without variable payload */
++	IW_EV_PARAM_LEN,
++	IW_EV_ADDR_LEN,
++	IW_EV_QUAL_LEN,
++};
+ 
+ /************************ COMMON SUBROUTINES ************************/
+ /*
+@@ -162,7 +211,8 @@ char priv_type_size[] = { 0, 1, 1, 0, 4,
+ static inline iw_handler get_handler(struct net_device *dev,
+ 				     unsigned int cmd)
+ {
+-	unsigned int	index;		/* MUST be unsigned */
++	/* Don't "optimise" the following variable, it will crash */
++	unsigned int	index;		/* *MUST* be unsigned */
+ 
+ 	/* Check if we have some wireless handlers defined */
+ 	if(dev->wireless_handlers == NULL)
+@@ -269,9 +319,9 @@ static inline int sprintf_wireless_stats
+ 			       stats->status,
+ 			       stats->qual.qual,
+ 			       stats->qual.updated & 1 ? '.' : ' ',
+-			       stats->qual.level,
++			       ((__u8) stats->qual.level),
+ 			       stats->qual.updated & 2 ? '.' : ' ',
+-			       stats->qual.noise,
++			       ((__u8) stats->qual.noise),
+ 			       stats->qual.updated & 4 ? '.' : ' ',
+ 			       stats->discard.nwid,
+ 			       stats->discard.code,
+@@ -423,12 +473,14 @@ static inline int ioctl_standard_call(st
+ 	int					ret = -EINVAL;
+ 
+ 	/* Get the description of the IOCTL */
++	if((cmd - SIOCIWFIRST) >= standard_ioctl_num)
++		return -EOPNOTSUPP;
+ 	descr = &(standard_ioctl[cmd - SIOCIWFIRST]);
+ 
+ #ifdef WE_IOCTL_DEBUG
+-	printk(KERN_DEBUG "%s : Found standard handler for 0x%04X\n",
++	printk(KERN_DEBUG "%s (WE) : Found standard handler for 0x%04X\n",
+ 	       ifr->ifr_name, cmd);
+-	printk(KERN_DEBUG "Header type : %d, token type : %d, token_size : %d, max_token : %d\n", descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 	/* Prepare the call */
+@@ -437,8 +489,16 @@ static inline int ioctl_standard_call(st
+ 
+ 	/* Check if we have a pointer to user space data or not */
+ 	if(descr->header_type != IW_HEADER_TYPE_POINT) {
++
+ 		/* No extra arguments. Trivial to handle */
+ 		ret = handler(dev, &info, &(iwr->u), NULL);
++
++#ifdef WE_SET_EVENT
++		/* Generate an event to notify listeners of the change */
++		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
++		   ((ret == 0) || (ret == -EIWCOMMIT)))
++			wireless_send_event(dev, cmd, &(iwr->u), NULL);
++#endif	/* WE_SET_EVENT */
+ 	} else {
+ 		char *	extra;
+ 		int	err;
+@@ -466,8 +526,8 @@ static inline int ioctl_standard_call(st
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-		printk(KERN_DEBUG "Malloc %d bytes\n",
+-		       descr->max_tokens * descr->token_size);
++		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
++		       dev->name, descr->max_tokens * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 		/* Always allocate for max space. Easier, and won't last
+@@ -488,7 +548,8 @@ static inline int ioctl_standard_call(st
+ 				return -EFAULT;
+ 			}
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Got %d bytes\n",
++			printk(KERN_DEBUG "%s (WE) : Got %d bytes\n",
++			       dev->name,
+ 			       iwr->u.data.length * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+@@ -504,11 +565,26 @@ static inline int ioctl_standard_call(st
+ 			if (err)
+ 				ret =  -EFAULT;				   
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Wrote %d bytes\n",
++			printk(KERN_DEBUG "%s (WE) : Wrote %d bytes\n",
++			       dev->name,
+ 			       iwr->u.data.length * descr->token_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
++#ifdef WE_SET_EVENT
++		/* Generate an event to notify listeners of the change */
++		if((descr->flags & IW_DESCR_FLAG_EVENT) &&
++		   ((ret == 0) || (ret == -EIWCOMMIT))) {
++			if(descr->flags & IW_DESCR_FLAG_RESTRICT)
++				/* If the event is restricted, don't
++				 * export the payload */
++				wireless_send_event(dev, cmd, &(iwr->u), NULL);
++			else
++				wireless_send_event(dev, cmd, &(iwr->u),
++						    extra);
++		}
++#endif	/* WE_SET_EVENT */
++
+ 		/* Cleanup - I told you it wasn't that long ;-) */
+ 		kfree(extra);
+ 	}
+@@ -558,11 +634,12 @@ static inline int ioctl_private_call(str
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-	printk(KERN_DEBUG "%s : Found private handler for 0x%04X\n",
++	printk(KERN_DEBUG "%s (WE) : Found private handler for 0x%04X\n",
+ 	       ifr->ifr_name, cmd);
+ 	if(descr) {
+-		printk(KERN_DEBUG "Name %s, set %X, get %X\n",
+-		       descr->name, descr->set_args, descr->get_args);
++		printk(KERN_DEBUG "%s (WE) : Name %s, set %X, get %X\n",
++		       dev->name, descr->name,
++		       descr->set_args, descr->get_args);
+ 	}
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+@@ -617,7 +694,8 @@ static inline int ioctl_private_call(str
+ 		}
+ 
+ #ifdef WE_IOCTL_DEBUG
+-		printk(KERN_DEBUG "Malloc %d bytes\n", extra_size);
++		printk(KERN_DEBUG "%s (WE) : Malloc %d bytes\n",
++		       dev->name, extra_size);
+ #endif	/* WE_IOCTL_DEBUG */
+ 
+ 		/* Always allocate for max space. Easier, and won't last
+@@ -636,7 +714,8 @@ static inline int ioctl_private_call(str
+ 				return -EFAULT;
+ 			}
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Got %d elem\n", iwr->u.data.length);
++			printk(KERN_DEBUG "%s (WE) : Got %d elem\n",
++			       dev->name, iwr->u.data.length);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
+@@ -650,8 +729,8 @@ static inline int ioctl_private_call(str
+ 			if (err)
+ 				ret =  -EFAULT;				   
+ #ifdef WE_IOCTL_DEBUG
+-			printk(KERN_DEBUG "Wrote %d elem\n",
+-			       iwr->u.data.length);
++			printk(KERN_DEBUG "%s (WE) : Wrote %d elem\n",
++			       dev->name, iwr->u.data.length);
+ #endif	/* WE_IOCTL_DEBUG */
+ 		}
+ 
+@@ -730,4 +809,178 @@ int wireless_process_ioctl(struct ifreq 
+ 	}
+ 	/* Not reached */
+ 	return -EINVAL;
++}
++
++/************************* EVENT PROCESSING *************************/
++/*
++ * Process events generated by the wireless layer or the driver.
++ * Most often, the event will be propagated through rtnetlink
++ */
++
++#ifdef WE_EVENT_NETLINK
++/* "rtnl" is defined in net/core/rtnetlink.c, but we need it here.
++ * It is declared in <linux/rtnetlink.h> */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Fill a rtnetlink message with our event data.
++ * Note that we propage only the specified event and don't dump the
++ * current wireless config. Dumping the wireless config is far too
++ * expensive (for each parameter, the driver need to query the hardware).
++ */
++static inline int rtnetlink_fill_iwinfo(struct sk_buff *	skb,
++					struct net_device *	dev,
++					int			type,
++					char *			event,
++					int			event_len)
++{
++	struct ifinfomsg *r;
++	struct nlmsghdr  *nlh;
++	unsigned char	 *b = skb->tail;
++
++	nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
++	r = NLMSG_DATA(nlh);
++	r->ifi_family = AF_UNSPEC;
++	r->ifi_type = dev->type;
++	r->ifi_index = dev->ifindex;
++	r->ifi_flags = dev->flags;
++	r->ifi_change = 0;	/* Wireless changes don't affect those flags */
++
++	/* Add the wireless events in the netlink packet */
++	RTA_PUT(skb, IFLA_WIRELESS,
++		event_len, event);
++
++	nlh->nlmsg_len = skb->tail - b;
++	return skb->len;
++
++nlmsg_failure:
++rtattr_failure:
++	skb_trim(skb, b - skb->data);
++	return -1;
++}
++
++/* ---------------------------------------------------------------- */
++/*
++ * Create and broadcast and send it on the standard rtnetlink socket
++ * This is a pure clone rtmsg_ifinfo() in net/core/rtnetlink.c
++ * Andrzej Krzysztofowicz mandated that I used a IFLA_XXX field
++ * within a RTM_NEWLINK event.
++ */
++static inline void rtmsg_iwinfo(struct net_device *	dev,
++				char *			event,
++				int			event_len)
++{
++	struct sk_buff *skb;
++	int size = NLMSG_GOODSIZE;
++
++	skb = alloc_skb(size, GFP_ATOMIC);
++	if (!skb)
++		return;
++
++	if (rtnetlink_fill_iwinfo(skb, dev, RTM_NEWLINK,
++				  event, event_len) < 0) {
++		kfree_skb(skb);
++		return;
++	}
++	NETLINK_CB(skb).dst_groups = RTMGRP_LINK;
++	netlink_broadcast(rtnl, skb, 0, RTMGRP_LINK, GFP_ATOMIC);
++}
++#endif	/* WE_EVENT_NETLINK */
++
++/* ---------------------------------------------------------------- */
++/*
++ * Main event dispatcher. Called from other parts and drivers.
++ * Send the event on the apropriate channels.
++ * May be called from interrupt context.
++ */
++void wireless_send_event(struct net_device *	dev,
++			 unsigned int		cmd,
++			 union iwreq_data *	wrqu,
++			 char *			extra)
++{
++	const struct iw_ioctl_description *	descr = NULL;
++	int extra_len = 0;
++	struct iw_event  *event;		/* Mallocated whole event */
++	int event_len;				/* Its size */
++	int hdr_len;				/* Size of the event header */
++	/* Don't "optimise" the following variable, it will crash */
++	unsigned	cmd_index;		/* *MUST* be unsigned */
++
++	/* Get the description of the IOCTL */
++	if(cmd <= SIOCIWLAST) {
++		cmd_index = cmd - SIOCIWFIRST;
++		if(cmd_index < standard_ioctl_num)
++			descr = &(standard_ioctl[cmd_index]);
++	} else {
++		cmd_index = cmd - IWEVFIRST;
++		if(cmd_index < standard_event_num)
++			descr = &(standard_event[cmd_index]);
++	}
++	/* Don't accept unknown events */
++	if(descr == NULL) {
++		/* Note : we don't return an error to the driver, because
++		 * the driver would not know what to do about it. It can't
++		 * return an error to the user, because the event is not
++		 * initiated by a user request.
++		 * The best the driver could do is to log an error message.
++		 * We will do it ourselves instead...
++		 */
++	  	printk(KERN_ERR "%s (WE) : Invalid Wireless Event (0x%04X)\n",
++		       dev->name, cmd);
++		return;
++	}
++#ifdef WE_EVENT_DEBUG
++	printk(KERN_DEBUG "%s (WE) : Got event 0x%04X\n",
++	       dev->name, cmd);
++	printk(KERN_DEBUG "%s (WE) : Header type : %d, Token type : %d, size : %d, token : %d\n", dev->name, descr->header_type, descr->token_type, descr->token_size, descr->max_tokens);
++#endif	/* WE_EVENT_DEBUG */
++
++	/* Check extra parameters and set extra_len */
++	if(descr->header_type == IW_HEADER_TYPE_POINT) {
++		/* Check if number of token fits within bounds */
++		if(wrqu->data.length > descr->max_tokens) {
++		  	printk(KERN_ERR "%s (WE) : Wireless Event too big (%d)\n", dev->name, wrqu->data.length);
++			return;
++		}
++		if(wrqu->data.length < descr->min_tokens) {
++		  	printk(KERN_ERR "%s (WE) : Wireless Event too small (%d)\n", dev->name, wrqu->data.length);
++			return;
++		}
++		/* Calculate extra_len - extra is NULL for restricted events */
++		if(extra != NULL)
++			extra_len = wrqu->data.length * descr->token_size;
++#ifdef WE_EVENT_DEBUG
++		printk(KERN_DEBUG "%s (WE) : Event 0x%04X, tokens %d, extra_len %d\n", dev->name, cmd, wrqu->data.length, extra_len);
++#endif	/* WE_EVENT_DEBUG */
++	}
++
++	/* Total length of the event */
++	hdr_len = event_type_size[descr->header_type];
++	event_len = hdr_len + extra_len;
++
++#ifdef WE_EVENT_DEBUG
++	printk(KERN_DEBUG "%s (WE) : Event 0x%04X, hdr_len %d, event_len %d\n", dev->name, cmd, hdr_len, event_len);
++#endif	/* WE_EVENT_DEBUG */
++
++	/* Create temporary buffer to hold the event */
++	event = kmalloc(event_len, GFP_ATOMIC);
++	if(event == NULL)
++		return;
++
++	/* Fill event */
++	event->len = event_len;
++	event->cmd = cmd;
++	memcpy(&event->u, wrqu, hdr_len - IW_EV_LCP_LEN);
++	if(extra != NULL)
++		memcpy(((char *) event) + hdr_len, extra, extra_len);
++
++#ifdef WE_EVENT_NETLINK
++	/* rtnetlink event channel */
++	rtmsg_iwinfo(dev, (char *) event, event_len);
++#endif	/* WE_EVENT_NETLINK */
++
++	/* Cleanup */
++	kfree(event);
++
++	return;		/* Always success, I guess ;-) */
+ }
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch
index e69de29bb2..a7eefd1e16 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/keymap-more-sane.patch
@@ -0,0 +1,19 @@
+
+#
+# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/drivers/char/collie_keymap.map~keymap-more-sane	2003-05-13 11:18:18.000000000 +0200
++++ linux/drivers/char/collie_keymap.map	2004-06-23 00:03:19.000000000 +0200
+@@ -55,9 +55,11 @@
+ # (Cancel:34) F9 -> Escape
+ keycode 34 = Escape
+ keycode 35 = Left
++	control keycode 35 = Decr_Console
+ keycode 36 = Up
+ keycode 37 = Down
+ keycode 38 = Right
++	control keycode 38 = Incr_Console
+ # (OK:39) F4 -> Return 
+ keycode 39 = Return
+ keycode 40 = 
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch
index e69de29bb2..c006684f23 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/logo.patch
@@ -0,0 +1,2598 @@
+--- linux/drivers/video/fbcon.c	2003-02-27 21:47:36.000000000 -0600
++++ linux.new/drivers/video/fbcon.c	2003-02-27 18:39:39.000000000 -0600
+@@ -126,8 +126,8 @@
+ #define LOGO_H			(320-16)
+ #define LOGO_W			240
+ #else
+-#define LOGO_H			80
+-#define LOGO_W			80
++#define LOGO_H			52
++#define LOGO_W			240
+ #endif
+ #define LOGO_LINE	(LOGO_W/8)
+ #if defined(CONFIG_SHARP_LOGO_SCREEN)
+--- linux/include/linux/linux_logo.h	2001-06-11 21:15:27.000000000 -0500
++++ linux.new/include/linux/linux_logo.h	2003-02-27 15:58:15.000000000 -0600
+@@ -1,4 +1,4 @@
+-/* $Id$
++/* linux_logo.h created with fblogo, 2002/12/29 02:43:36
+  * include/linux/linux_logo.h: This is a linux logo
+  *                             to be displayed on boot.
+  *
+@@ -7,907 +7,1673 @@
+  *
+  * You can put anything here, but:
+  * LINUX_LOGO_COLORS has to be less than 224
+- * image size has to be 80x80
+- * values have to start from 0x20
+- * (i.e. RGB(linux_logo_red[0],
+- *           linux_logo_green[0],
+- *           linux_logo_blue[0]) is color 0x20)
+- * BW image has to be 80x80 as well, with MS bit
+- * on the left
+- * Serial_console ascii image can be any size,
+- * but should contain %s to display the version
++ * Generated by fblogo version 0.5.0
++ *
++ *
++ * Remember to modify drivers/video/fbcon.c:
++ * Change "#define LOGO_H 80" to "#define LOGO_H 52"
++ * Change "#define LOGO_W 80" to "#define LOGO_W 240"
+  */
+ 
+ #ifndef __HAVE_ARCH_LINUX_LOGO
+-#define LINUX_LOGO_COLORS	187
++#define LINUX_LOGO_COLORS 223
+ #endif
+-
+ #ifdef INCLUDE_LINUX_LOGO_DATA
+-
+ #ifndef __HAVE_ARCH_LINUX_LOGO
+-
+ unsigned char linux_logo_red[] __initdata = {
+-    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+-    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+-    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+-    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+-    0xc3, 0x65, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+-    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+-    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x76, 0x79,
+-    0x62, 0x36, 0x9a, 0xe2, 0xec, 0xe1, 0xb8, 0xd7,
+-    0xaf, 0x25, 0xbc, 0xc0, 0xef, 0xea, 0xe8, 0xe8,
+-    0xf5, 0xf1, 0xda, 0xd3, 0x79, 0xdb, 0xf4, 0xf6,
+-    0xf6, 0xf6, 0xe2, 0x3d, 0xb4, 0xce, 0xe6, 0xee,
+-    0xf6, 0x68, 0xd8, 0xec, 0xf5, 0xc6, 0xc8, 0x9c,
+-    0x89, 0xd2, 0xee, 0xcb, 0xb9, 0xd2, 0x66, 0x5e,
+-    0x8b, 0xbe, 0xa8, 0xd5, 0xca, 0xb6, 0xae, 0x9c,
+-    0xc5, 0xbe, 0xbe, 0xca, 0x90, 0xb2, 0x9a, 0xa8,
+-    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x12,
+-    0x4a, 0x8e, 0xf2, 0xf6, 0xf6, 0xee, 0xb5, 0xe4,
+-    0xf1, 0x26, 0x9a, 0xea, 0xf6, 0xe0, 0xd2, 0x16,
+-    0x9a, 0x2e, 0x70, 0xd6, 0x46, 0x7c, 0xb4, 0x62,
+-    0xd6, 0xa3, 0x74, 0xa7, 0xa2, 0xca, 0xe0, 0xae,
+-    0xbe, 0xce, 0xa3, 0x8e, 0x6d, 0x8e, 0x32, 0xaf,
+-    0x50, 0x9e, 0x5b, 0x8a, 0x98, 0x82, 0x7a, 0x82,
+-    0x56, 0x7c, 0x8a, 0x56, 0x5e, 0x86, 0x6a, 0x52,
+-    0x59, 0x64, 0x5e,
++  0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, 
++  0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, 
++  0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, 
++  0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, 
++  0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, 
++  0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, 
++  0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, 
++  0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x32, 0x7E, 
++  0x3A, 0x16, 0x02, 0x02, 0x06, 0x1F, 0x02, 0x02, 
++  0x06, 0x02, 0x22, 0x3A, 0x35, 0x16, 0x0A, 0x02, 
++  0x2A, 0x3E, 0x39, 0x32, 0x2A, 0x1E, 0x16, 0x06, 
++  0x22, 0x22, 0x1E, 0x16, 0x6E, 0x82, 0x6E, 0x2E, 
++  0x1E, 0x2E, 0x1E, 0x0A, 0x3A, 0xDA, 0xFE, 0xFA, 
++  0xFA, 0xE2, 0x6A, 0x3A, 0x1A, 0xFA, 0xF6, 0x9E, 
++  0x02, 0x6E, 0xFE, 0xF6, 0x3E, 0x66, 0x52, 0x1B, 
++  0xD6, 0x5A, 0xEE, 0xC6, 0x72, 0x36, 0x22, 0x1E, 
++  0x02, 0x96, 0xF6, 0xDE, 0xA2, 0xD6, 0x39, 0x0E, 
++  0xAA, 0x52, 0x5A, 0xD2, 0xDE, 0x61, 0x46, 0xDE, 
++  0x7A, 0x57, 0x9E, 0xBA, 0xB6, 0x4A, 0x5A, 0xA6, 
++  0x96, 0x23, 0x1E, 0x12, 0x9A, 0x4E, 0x76, 0xAE, 
++  0x2E, 0xBE, 0x86, 0x48, 0xA6, 0x52, 0x06, 0x2E, 
++  0x56, 0x13, 0x2A, 0x4A, 0x36, 0x56, 0x2E, 0x1E, 
++  0x46, 0x3A, 0x66, 0x02, 0x3D, 0x3E, 0x2E, 0x3E, 
++  0x4A, 0x32, 0x52, 0x72, 0x76, 0x67, 0x68, 0x5A, 
++  0x3A, 0x1A, 0x0E, 0x2E, 0x4E, 0x02, 0x3E, 0x0A, 
++  0x28, 0x42, 0x10, 0x26, 0x8E, 0x0A, 0x86, 0xC2, 
++  0x02, 0x6E, 0x92, 0x02, 0x42, 0x02, 0xBE, 0x4E, 
++  0x02, 0x22, 0x02, 0x3E, 0x3A, 0x32
+ };
+ 
+ unsigned char linux_logo_green[] __initdata = {
+-    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+-    0x12, 0x00, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+-    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x02, 0x65,
+-    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+-    0xc3, 0x62, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+-    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+-    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x62, 0x5c,
+-    0x4e, 0x26, 0x72, 0xaa, 0xba, 0xaf, 0x90, 0xae,
+-    0x92, 0x1a, 0xa4, 0x85, 0xb6, 0xbe, 0xc3, 0xc8,
+-    0xcf, 0xd0, 0xc2, 0xce, 0x57, 0xa2, 0xd6, 0xda,
+-    0xda, 0xd7, 0xb8, 0x2a, 0x7b, 0x91, 0xae, 0xca,
+-    0xda, 0x45, 0x9e, 0xb2, 0xd7, 0x9b, 0x90, 0x76,
+-    0x5c, 0xa2, 0xbe, 0xa6, 0x85, 0x96, 0x4e, 0x46,
+-    0x66, 0x92, 0x7a, 0x9a, 0x96, 0x9d, 0x9a, 0x6b,
+-    0x8a, 0x8e, 0xb2, 0xca, 0x90, 0xa6, 0x79, 0x7c,
+-    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x0e,
+-    0x36, 0x86, 0xba, 0xbe, 0xe6, 0xcc, 0x8e, 0xb8,
+-    0xc4, 0x1e, 0x8e, 0xae, 0xba, 0xb2, 0xa6, 0x12,
+-    0x7a, 0x20, 0x64, 0xaa, 0x2f, 0x70, 0x85, 0x46,
+-    0xa6, 0x6e, 0x51, 0x72, 0x92, 0xa2, 0xa6, 0x87,
+-    0x96, 0xa2, 0x85, 0x7a, 0x6a, 0x6e, 0x22, 0x76,
+-    0x36, 0x76, 0x3c, 0x6e, 0x63, 0x53, 0x66, 0x62,
+-    0x42, 0x50, 0x56, 0x42, 0x56, 0x56, 0x56, 0x3e,
+-    0x51, 0x52, 0x56,
++  0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, 
++  0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, 
++  0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, 
++  0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, 
++  0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, 
++  0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, 
++  0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, 
++  0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x2E, 0x7E, 
++  0x3A, 0x3E, 0x6A, 0xA2, 0x92, 0x30, 0x95, 0x76, 
++  0x4E, 0x86, 0x36, 0x7E, 0x9A, 0x6E, 0x42, 0x56, 
++  0x5A, 0xC2, 0xBE, 0xB2, 0xAA, 0x9A, 0x63, 0x1E, 
++  0xA2, 0x9E, 0x96, 0x5A, 0x3A, 0x42, 0x4A, 0x52, 
++  0x91, 0x46, 0x4E, 0x62, 0x22, 0x4A, 0x6E, 0x86, 
++  0x92, 0x9A, 0x52, 0x4A, 0x76, 0x7A, 0x9E, 0x76, 
++  0x62, 0x32, 0x5E, 0xAE, 0x3E, 0x66, 0x52, 0x81, 
++  0xA6, 0x5A, 0xEE, 0xC6, 0x72, 0x5C, 0x6A, 0x8A, 
++  0x36, 0x3E, 0xBA, 0xBA, 0xA2, 0xD6, 0xAA, 0x4E, 
++  0x8A, 0x4E, 0x5A, 0xD2, 0xDE, 0x64, 0x32, 0x9A, 
++  0x5E, 0x57, 0x9E, 0xBA, 0xB6, 0x52, 0x62, 0xA6, 
++  0x9A, 0x47, 0x3E, 0x56, 0x02, 0x1A, 0x76, 0xAE, 
++  0x4A, 0x02, 0x02, 0x38, 0x02, 0x4A, 0x46, 0x86, 
++  0x1E, 0x2E, 0x7A, 0xD2, 0x5E, 0x26, 0x92, 0x62, 
++  0xCA, 0x42, 0x66, 0x26, 0x67, 0xB6, 0x62, 0x92, 
++  0x9E, 0x72, 0xB2, 0xF2, 0xFE, 0xDE, 0xFE, 0xFE, 
++  0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0x8A, 0x2A, 
++  0x42, 0x52, 0x6A, 0x26, 0x8E, 0x26, 0x86, 0xC2, 
++  0xE2, 0x6E, 0x92, 0xBE, 0x42, 0xC6, 0xBE, 0x4E, 
++  0xEE, 0x5A, 0xEA, 0x3E, 0x4A, 0x32
+ };
+ 
+ unsigned char linux_logo_blue[] __initdata = {
+-    0x00, 0x06, 0x0a, 0x0e, 0x16, 0x1a, 0x1e, 0x22,
+-    0x12, 0x01, 0x2a, 0x36, 0x42, 0x4e, 0x4a, 0x56,
+-    0x26, 0x46, 0x2e, 0x32, 0x52, 0x3a, 0x06, 0x65,
+-    0x5e, 0x3e, 0x74, 0x8a, 0xa2, 0x9a, 0x86, 0xc6,
+-    0xc3, 0x59, 0xbb, 0xd2, 0xda, 0xd6, 0xe2, 0xf6,
+-    0xfd, 0xae, 0x7b, 0xdd, 0xea, 0x6a, 0xaa, 0xe7,
+-    0xbe, 0x5a, 0xee, 0x9e, 0x95, 0x80, 0x2e, 0x08,
+-    0x0a, 0x06, 0x0a, 0x0b, 0x0b, 0x0f, 0x0c, 0x0f,
+-    0x3d, 0x09, 0x73, 0x09, 0x0d, 0x0a, 0x10, 0x1e,
+-    0x2d, 0x13, 0x86, 0xba, 0x19, 0x0a, 0x36, 0x3c,
+-    0x26, 0x14, 0x0d, 0x06, 0x07, 0x0a, 0x0b, 0x0f,
+-    0x4a, 0x06, 0x0a, 0x0c, 0x2b, 0x0a, 0x0b, 0x0a,
+-    0x06, 0x0a, 0x0a, 0x11, 0x0b, 0x0a, 0x0a, 0x1e,
+-    0x0f, 0x0d, 0x0a, 0x0b, 0x22, 0x6a, 0x72, 0x0b,
+-    0x0b, 0x22, 0x90, 0xca, 0x90, 0x92, 0x3c, 0x2c,
+-    0xb6, 0xf2, 0xce, 0xfa, 0xb2, 0x6e, 0xa6, 0x06,
+-    0x0e, 0x6a, 0x0e, 0x0e, 0xbe, 0x5b, 0x2c, 0x3e,
+-    0x0e, 0x0a, 0x5a, 0x0d, 0x0e, 0x3e, 0x0a, 0x06,
+-    0x2e, 0x06, 0x4e, 0x36, 0x06, 0x58, 0x24, 0x06,
+-    0x3a, 0x08, 0x08, 0x07, 0x5e, 0x45, 0x0a, 0x32,
+-    0x2e, 0x2a, 0x43, 0x48, 0x5f, 0x2e, 0x06, 0x06,
+-    0x07, 0x24, 0x06, 0x32, 0x06, 0x06, 0x46, 0x2e,
+-    0x22, 0x06, 0x06, 0x1e, 0x4c, 0x06, 0x3a, 0x22,
+-    0x42, 0x34, 0x42,
++ 0x00, 0x02, 0x06, 0x0A, 0x56, 0xA6, 0xBE, 0xBA, 
++ 0xB6, 0x92, 0x3E, 0x1A, 0x8A, 0xF3, 0xFB, 0xEE, 
++ 0xC6, 0x62, 0x4A, 0x12, 0x26, 0x0E, 0x76, 0xDA, 
++ 0x6E, 0x32, 0x8E, 0x1E, 0x2A, 0xCE, 0xE2, 0x36, 
++ 0x66, 0xA2, 0x2E, 0x9E, 0xCA, 0x6A, 0x5A, 0x82, 
++ 0x7E, 0xE9, 0xD2, 0xDE, 0x22, 0x72, 0xAE, 0xD6, 
++ 0x86, 0x3A, 0x52, 0x9A, 0xAA, 0x16, 0x46, 0x4E, 
++ 0x42, 0xC2, 0x96, 0x7A, 0x5E, 0xB2, 0x1A, 0x06, 
++ 0x1A, 0x2A, 0x36, 0x52, 0x46, 0x23, 0x4D, 0x3E, 
++ 0x2A, 0x42, 0x2A, 0x5A, 0x69, 0x42, 0x26, 0x2E, 
++ 0x42, 0x7E, 0x7C, 0x72, 0x6A, 0x5E, 0x3B, 0x12, 
++ 0x62, 0x5E, 0x5A, 0x36, 0x26, 0x1E, 0x26, 0x42, 
++ 0x56, 0x3A, 0x36, 0x36, 0x1E, 0x2E, 0x2A, 0x22, 
++ 0x22, 0x1A, 0x16, 0x42, 0x46, 0x26, 0x1E, 0x12, 
++ 0x32, 0x2A, 0x2E, 0x16, 0x2A, 0x1A, 0x2E, 0x4E, 
++ 0x12, 0x22, 0x02, 0x02, 0x12, 0x4A, 0x46, 0x52, 
++ 0x1E, 0x1E, 0x16, 0x0E, 0x02, 0x02, 0x6F, 0x2E, 
++ 0x0E, 0x1A, 0x06, 0x02, 0x02, 0x04, 0x22, 0x16, 
++ 0x0E, 0x12, 0x02, 0x02, 0x02, 0x0A, 0x5A, 0x02, 
++ 0x02, 0x1B, 0x2E, 0x32, 0x02, 0x02, 0x02, 0x02, 
++ 0x16, 0x02, 0x02, 0x10, 0x02, 0x02, 0x26, 0x5A, 
++ 0x02, 0x1F, 0x52, 0x8E, 0x22, 0x02, 0x5E, 0x3E, 
++ 0x86, 0x0E, 0x16, 0x16, 0x52, 0x7A, 0x4A, 0x66, 
++ 0x72, 0x52, 0x82, 0xB2, 0xBA, 0xA4, 0xB2, 0xAA, 
++ 0x9E, 0x8E, 0x88, 0x96, 0xA6, 0x82, 0x62, 0x1A, 
++ 0x34, 0x4A, 0x31, 0x16, 0x02, 0x1A, 0x02, 0x02, 
++ 0x72, 0x02, 0x02, 0x5E, 0x1A, 0x62, 0x02, 0x0E, 
++ 0x76, 0x1E, 0x76, 0x1E, 0x0A, 0x02
+ };
+ 
+ unsigned char linux_logo[] __initdata = {
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22,
+-    0x22, 0x21, 0x21, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+-    0x26, 0x26, 0x25, 0x28, 0x23, 0x22, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x23, 0x25, 0x2a, 0x2b, 0x2c, 0x2d, 0x2d,
+-    0x2d, 0x2e, 0x2c, 0x2b, 0x2a, 0x25, 0x28, 0x22,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x24, 0x2a, 0x2c, 0x2f, 0x2c, 0x30, 0x30, 0x24,
+-    0x25, 0x27, 0x2b, 0x2c, 0x2f, 0x31, 0x32, 0x25,
+-    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+-    0x33, 0x34, 0x35, 0x21, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x21, 0x2b, 0x2f, 0x2c,
+-    0x30, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+-    0x2d, 0x27, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x31,
+-    0x2d, 0x32, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x28, 0x2a, 0x34,
+-    0x25, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x23, 0x32, 0x27, 0x21, 0x36,
+-    0x2a, 0x2d, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x22, 0x26, 0x2c, 0x35,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x25, 0x2f, 0x37, 0x32, 0x22,
+-    0x36, 0x35, 0x31, 0x27, 0x22, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x22,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x26, 0x38, 0x38, 0x35, 0x25,
+-    0x36, 0x21, 0x2d, 0x2b, 0x24, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x24, 0x39, 0x39, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x25, 0x2b, 0x30, 0x28, 0x22,
+-    0x36, 0x36, 0x27, 0x34, 0x30, 0x23, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x26, 0x2d, 0x26, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x22, 0x22, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x2d, 0x33, 0x28, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x2b, 0x2c, 0x25, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x36, 0x36,
+-    0x36, 0x21, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x21, 0x23, 0x22, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x28, 0x34, 0x27, 0x22, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+-    0x21, 0x21, 0x24, 0x27, 0x21, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x28, 0x27, 0x22, 0x33, 0x24, 0x36,
+-    0x36, 0x36, 0x36, 0x22, 0x2f, 0x2a, 0x23, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x36,
+-    0x30, 0x3a, 0x38, 0x24, 0x24, 0x36, 0x36, 0x36,
+-    0x23, 0x2f, 0x3b, 0x3c, 0x3d, 0x30, 0x25, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x2f, 0x32, 0x23, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x23,
+-    0x3e, 0x3f, 0x40, 0x3a, 0x22, 0x36, 0x36, 0x21,
+-    0x41, 0x42, 0x43, 0x44, 0x45, 0x3e, 0x23, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x2f, 0x33, 0x28, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x2f, 0x36, 0x2b,
+-    0x44, 0x40, 0x46, 0x47, 0x35, 0x36, 0x36, 0x26,
+-    0x43, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x2e, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x32, 0x34, 0x36, 0x4d,
+-    0x4e, 0x25, 0x2f, 0x46, 0x4a, 0x22, 0x23, 0x32,
+-    0x4f, 0x50, 0x21, 0x31, 0x51, 0x52, 0x53, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x31, 0x35, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x20, 0x29, 0x29, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x2f, 0x21, 0x3a,
+-    0x4d, 0x21, 0x31, 0x54, 0x55, 0x28, 0x30, 0x2b,
+-    0x4b, 0x4d, 0x36, 0x23, 0x32, 0x50, 0x3f, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x20, 0x29, 0x20, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x38, 0x23, 0x37,
+-    0x55, 0x36, 0x28, 0x3a, 0x56, 0x57, 0x57, 0x58,
+-    0x3c, 0x4d, 0x36, 0x36, 0x36, 0x40, 0x40, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x2e, 0x39, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x29, 0x29, 0x29, 0x20, 0x29, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x51, 0x23, 0x35,
+-    0x43, 0x25, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e,
+-    0x5f, 0x60, 0x61, 0x36, 0x31, 0x47, 0x3b, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x31, 0x2c, 0x25, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x23, 0x22,
+-    0x40, 0x62, 0x63, 0x5d, 0x64, 0x65, 0x66, 0x67,
+-    0x68, 0x69, 0x66, 0x5e, 0x6a, 0x6b, 0x2a, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x33, 0x2e, 0x26, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x27, 0x2f, 0x23, 0x36,
+-    0x6c, 0x63, 0x6d, 0x64, 0x5c, 0x66, 0x69, 0x6e,
+-    0x6f, 0x70, 0x71, 0x69, 0x69, 0x72, 0x6c, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x33, 0x34, 0x27, 0x22,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x27, 0x34, 0x26, 0x73,
+-    0x74, 0x75, 0x76, 0x64, 0x65, 0x77, 0x69, 0x78,
+-    0x70, 0x71, 0x71, 0x71, 0x72, 0x5f, 0x5e, 0x21,
+-    0x36, 0x36, 0x36, 0x36, 0x25, 0x38, 0x2a, 0x23,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x33, 0x79,
+-    0x63, 0x7a, 0x7b, 0x5c, 0x66, 0x69, 0x6e, 0x7c,
+-    0x71, 0x71, 0x69, 0x7d, 0x7e, 0x7a, 0x7f, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x21, 0x51, 0x2b, 0x28,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x26, 0x2d, 0x32, 0x24,
+-    0x80, 0x81, 0x64, 0x82, 0x77, 0x69, 0x71, 0x71,
+-    0x69, 0x83, 0x84, 0x85, 0x7a, 0x85, 0x86, 0x36,
+-    0x21, 0x2b, 0x23, 0x36, 0x36, 0x39, 0x2e, 0x26,
+-    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x27, 0x2d, 0x33, 0x21,
+-    0x87, 0x88, 0x89, 0x72, 0x67, 0x66, 0x5f, 0x89,
+-    0x8a, 0x63, 0x85, 0x8b, 0x8c, 0x8d, 0x41, 0x36,
+-    0x36, 0x2d, 0x3a, 0x35, 0x36, 0x24, 0x51, 0x32,
+-    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x30, 0x2f, 0x33, 0x21,
+-    0x55, 0x8e, 0x8f, 0x8a, 0x7d, 0x5e, 0x90, 0x7e,
+-    0x75, 0x75, 0x90, 0x62, 0x40, 0x3f, 0x49, 0x23,
+-    0x36, 0x24, 0x3a, 0x3a, 0x24, 0x36, 0x2e, 0x31,
+-    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x21, 0x28, 0x33, 0x37, 0x25, 0x22,
+-    0x3b, 0x50, 0x8e, 0x8f, 0x90, 0x7e, 0x90, 0x63,
+-    0x74, 0x91, 0x92, 0x42, 0x93, 0x4b, 0x45, 0x2c,
+-    0x36, 0x36, 0x33, 0x39, 0x21, 0x36, 0x22, 0x51,
+-    0x33, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x22, 0x27, 0x2e, 0x2e, 0x36, 0x21,
+-    0x94, 0x3f, 0x50, 0x95, 0x96, 0x8f, 0x8f, 0x97,
+-    0x8e, 0x42, 0x50, 0x43, 0x47, 0x48, 0x48, 0x98,
+-    0x21, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39,
+-    0x2e, 0x27, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x22, 0x24, 0x2b, 0x38, 0x28, 0x36, 0x32,
+-    0x4c, 0x4b, 0x50, 0x50, 0x50, 0x42, 0x42, 0x50,
+-    0x50, 0x40, 0x45, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x23,
+-    0x2f, 0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x28, 0x32, 0x51, 0x32, 0x28, 0x21, 0x98,
+-    0x48, 0x47, 0x9a, 0x50, 0x50, 0x50, 0x50, 0x50,
+-    0x9a, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x93, 0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x2a, 0x2f, 0x2a, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x23, 0x30, 0x2e, 0x2c, 0x36, 0x21, 0x51, 0x9b,
+-    0x48, 0x48, 0x52, 0x3f, 0x50, 0x50, 0x40, 0x4b,
+-    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x34, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2d, 0x31, 0x27, 0x23, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+-    0x27, 0x2c, 0x2d, 0x21, 0x36, 0x28, 0x44, 0x48,
+-    0x48, 0x48, 0x48, 0x47, 0x46, 0x4f, 0x47, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x9c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x28, 0x51, 0x39, 0x26, 0x22, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x25,
+-    0x35, 0x51, 0x28, 0x36, 0x36, 0x9d, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x4f, 0x28, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x28, 0x38, 0x2b, 0x25, 0x22, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24, 0x33,
+-    0x51, 0x25, 0x36, 0x36, 0x23, 0x40, 0x9b, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x9b, 0x99, 0x2b, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x30, 0x2f, 0x33, 0x24, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x23, 0x30, 0x34,
+-    0x27, 0x36, 0x36, 0x36, 0x2a, 0x40, 0x47, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x99, 0x99, 0x9b, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x47, 0x52,
+-    0x46, 0x4f, 0x37, 0x21, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x30, 0x34, 0x2a, 0x23,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x22, 0x25, 0x39, 0x2c,
+-    0x36, 0x36, 0x36, 0x21, 0x31, 0x4e, 0x9a, 0x4c,
+-    0x47, 0x9b, 0x9b, 0x52, 0x46, 0x4f, 0x52, 0x9b,
+-    0x9b, 0x9b, 0x47, 0x4f, 0x45, 0x9a, 0x93, 0x93,
+-    0x3f, 0x93, 0x98, 0x28, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c, 0x26,
+-    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x23, 0x2a, 0x34, 0x28,
+-    0x36, 0x36, 0x36, 0x22, 0x38, 0x98, 0x44, 0x99,
+-    0x9b, 0x48, 0x48, 0x9b, 0x4c, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x47, 0x52, 0x46, 0x43, 0x93,
+-    0x40, 0x40, 0x43, 0x53, 0x21, 0x23, 0x33, 0x23,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x2f, 0x32,
+-    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x24, 0x2b, 0x31, 0x36,
+-    0x36, 0x22, 0x36, 0x24, 0x9e, 0x4f, 0x9b, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x99, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x47,
+-    0x4f, 0x9a, 0x3f, 0x46, 0x38, 0x36, 0x21, 0x30,
+-    0x26, 0x36, 0x36, 0x36, 0x36, 0x36, 0x39, 0x2c,
+-    0x25, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x22, 0x26, 0x2e, 0x33, 0x36,
+-    0x25, 0x25, 0x36, 0x4d, 0x52, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x47, 0x44, 0x93, 0x43, 0x23, 0x36, 0x36,
+-    0x26, 0x24, 0x36, 0x36, 0x36, 0x36, 0x28, 0x2f,
+-    0x2a, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x23, 0x2a, 0x51, 0x24, 0x36,
+-    0x2a, 0x36, 0x28, 0x44, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x9b, 0x4b, 0x44, 0x37, 0x36, 0x23,
+-    0x28, 0x30, 0x22, 0x36, 0x36, 0x36, 0x36, 0x2d,
+-    0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x21, 0x28, 0x2b, 0x34, 0x36, 0x25,
+-    0x24, 0x36, 0x4a, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x52, 0x3f, 0x21, 0x30,
+-    0x35, 0x25, 0x30, 0x36, 0x36, 0x36, 0x36, 0x32,
+-    0x2d, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x22, 0x26, 0x2e, 0x35, 0x36, 0x2a,
+-    0x36, 0x24, 0x4f, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x9b, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x47, 0x32, 0x30,
+-    0x2a, 0x23, 0x30, 0x23, 0x36, 0x36, 0x36, 0x21,
+-    0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x23, 0x2a, 0x51, 0x28, 0x28, 0x25,
+-    0x36, 0x3a, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x9b, 0x52, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x38, 0x21,
+-    0x36, 0x36, 0x22, 0x27, 0x36, 0x36, 0x36, 0x36,
+-    0x2e, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x22, 0x25, 0x2c, 0x34, 0x36, 0x30, 0x21,
+-    0x23, 0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x47, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x94, 0x36,
+-    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+-    0x2a, 0x2e, 0x26, 0x22, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x23, 0x2a, 0x51, 0x25, 0x21, 0x2a, 0x36,
+-    0x2e, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x99, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x98, 0x36,
+-    0x36, 0x36, 0x36, 0x32, 0x36, 0x36, 0x36, 0x36,
+-    0x22, 0x2f, 0x30, 0x22, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x22, 0x25, 0x2c, 0x34, 0x36, 0x24, 0x28, 0x36,
+-    0x54, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+-    0x36, 0x36, 0x36, 0x30, 0x36, 0x36, 0x36, 0x36,
+-    0x21, 0x2f, 0x32, 0x23, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x28, 0x32, 0x2f, 0x28, 0x36, 0x27, 0x22, 0x21,
+-    0x43, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4b, 0x21,
+-    0x36, 0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x25, 0x2c, 0x39, 0x36, 0x36, 0x30, 0x22, 0x25,
+-    0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x52, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4f, 0x21,
+-    0x36, 0x36, 0x22, 0x26, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x30, 0x2d, 0x21, 0x36, 0x36, 0x32, 0x23, 0x2a,
+-    0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x22,
+-    0x36, 0x36, 0x24, 0x23, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x33, 0x2e, 0x36, 0x36, 0x23, 0x31, 0x27, 0x39,
+-    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x4c, 0x23,
+-    0x36, 0x36, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x39, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x2b, 0x39, 0x36, 0x36, 0x36, 0x26, 0x32, 0x31,
+-    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x46, 0x22,
+-    0x36, 0x21, 0x26, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x2c, 0x35, 0x24, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+-    0x35, 0x39, 0x36, 0x36, 0x36, 0x36, 0x26, 0x2d,
+-    0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x9a, 0x36,
+-    0x24, 0x27, 0x9f, 0x24, 0x25, 0x28, 0x21, 0x36,
+-    0x36, 0x34, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x25,
+-    0x39, 0x4d, 0xa0, 0x84, 0x81, 0x57, 0x21, 0x39,
+-    0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x47, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x53, 0x28,
+-    0x23, 0x36, 0x36, 0x36, 0x21, 0x28, 0x2c, 0x30,
+-    0x21, 0x38, 0x33, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x28, 0x30,
+-    0x2d, 0xa1, 0x7a, 0xa2, 0xa3, 0xa3, 0x7f, 0x22,
+-    0x51, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0xa4, 0xa5, 0xa5, 0xa6, 0x61,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x30, 0x32,
+-    0x25, 0x4d, 0x2b, 0x28, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x23, 0x24, 0x26, 0x30, 0x33, 0x31,
+-    0x4d, 0x91, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0x5a,
+-    0x21, 0x2e, 0x46, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4f, 0x9b, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0xa7, 0xa8, 0x69, 0x66, 0xa9,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x26, 0x25,
+-    0x83, 0xaa, 0x2c, 0x25, 0x21, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x28, 0x30, 0x35, 0x2d, 0x2f, 0x37, 0x4a,
+-    0x60, 0x85, 0xab, 0xac, 0xa3, 0xa3, 0xa3, 0x82,
+-    0x86, 0x36, 0x32, 0x3f, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x4c, 0x99, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0xad, 0xa2, 0xa8, 0xae, 0xaf,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x21, 0x57,
+-    0x77, 0x66, 0x34, 0x27, 0x22, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x23, 0x30, 0x31, 0xb0, 0x91, 0x7e, 0x90, 0x90,
+-    0x8b, 0x5b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0x5d, 0xb1, 0x36, 0x24, 0x53, 0x9b, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x9b, 0x99, 0xad, 0x64, 0x5c, 0x8b, 0xb1,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x73, 0x5d,
+-    0x82, 0x5c, 0xb2, 0x2a, 0x23, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x24, 0x2b, 0xb0, 0x8b, 0x5b, 0x76, 0x5b, 0x5b,
+-    0x7b, 0xa2, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa8, 0x5e, 0x22, 0x36, 0x21, 0x3a, 0x99, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x4f, 0x3f, 0xb3, 0x7b, 0x7b, 0x85, 0x80,
+-    0x9f, 0x36, 0x36, 0x36, 0x21, 0xb4, 0x7e, 0x7b,
+-    0x64, 0x64, 0xb5, 0x35, 0x24, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x31, 0xb6, 0x5b, 0x64, 0xa2, 0xa2, 0xac,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0x66, 0xb7, 0x36, 0x36, 0x36, 0x2c, 0x4b,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x9a, 0x3f, 0xb8, 0x76, 0x76, 0x7a, 0x63,
+-    0xb9, 0xba, 0x86, 0xba, 0xbb, 0x90, 0x5b, 0x64,
+-    0xa2, 0xa2, 0xbc, 0x2d, 0x27, 0x23, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x26, 0x2d, 0x91, 0x5b, 0x64, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa8, 0x83, 0xaf, 0x36, 0x36, 0x36, 0x30,
+-    0x44, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x9b, 0x9a, 0x3f, 0xbd, 0x5b, 0x7b, 0xbe, 0x85,
+-    0x7e, 0x90, 0x63, 0x90, 0x85, 0x5b, 0xa2, 0xa3,
+-    0xa3, 0xac, 0x5d, 0xb5, 0x39, 0x26, 0x23, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x2d, 0xbf, 0xbe, 0x64, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa8, 0x88, 0x36, 0x36, 0x36, 0x36,
+-    0x2d, 0x9b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x9b, 0x45, 0x3f, 0xc0, 0x6d, 0x7b, 0xab, 0xbe,
+-    0x7a, 0x8b, 0x8b, 0x7a, 0x5b, 0x64, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa2, 0xc1, 0x37, 0x35, 0x26, 0x23,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x2e, 0xbf, 0x7a, 0x7b, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa8, 0x72, 0x73, 0x36, 0x36, 0x36,
+-    0x24, 0x52, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x46, 0x42, 0xb6, 0x7a, 0x7b, 0x64, 0x7b,
+-    0x76, 0x5b, 0x5b, 0x76, 0x7b, 0xa2, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xac, 0x64, 0xc1, 0x4d, 0x2c, 0x27,
+-    0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x25, 0x31, 0xc2, 0x8b, 0x7b, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa8, 0x89, 0x9f, 0x36, 0x36,
+-    0x32, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x4b, 0x2f, 0x8f, 0x7a, 0x7b, 0xa2, 0xac,
+-    0xa2, 0x64, 0x64, 0xa2, 0xa2, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x5d, 0xc3, 0x2c,
+-    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x25, 0x31, 0xc2, 0x85, 0x7b, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x57, 0x27, 0x4d,
+-    0x4b, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x99, 0x34, 0x9f, 0xb9, 0x7a, 0x7b, 0xa2, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xc2,
+-    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x22,
+-    0x26, 0x2d, 0xc2, 0x85, 0x7b, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa8, 0x5f, 0x92, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x44,
+-    0x35, 0x36, 0xaf, 0xbb, 0x7a, 0x7b, 0xac, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0xa2, 0xc0,
+-    0x2b, 0x24, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+-    0x30, 0x2f, 0xb6, 0x8b, 0x7b, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x66, 0x89, 0x45,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x48, 0x9b, 0x4e, 0x25,
+-    0x36, 0x36, 0x61, 0xb9, 0x6d, 0x64, 0xac, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0xbe, 0xc3,
+-    0x32, 0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x33, 0xc4, 0x63, 0xbe, 0xa2, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x72, 0x81, 0xc5,
+-    0x46, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48,
+-    0x48, 0x48, 0x48, 0x48, 0x3f, 0x2c, 0x36, 0x36,
+-    0x36, 0x36, 0xc6, 0x8f, 0x6d, 0x64, 0xac, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa2, 0xab, 0x8b, 0xb0, 0x2c,
+-    0x26, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+-    0x35, 0x96, 0x75, 0xab, 0xa2, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x7b, 0x81, 0xb9,
+-    0x73, 0x3b, 0x44, 0x9b, 0x48, 0x48, 0x48, 0x9b,
+-    0x99, 0x43, 0x94, 0x2c, 0x21, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x73, 0xb9, 0x7a, 0x7b, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0x64, 0x76, 0x7a, 0x91, 0xb5, 0x31, 0x30,
+-    0x28, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x24,
+-    0x39, 0x97, 0x75, 0xbe, 0x7b, 0x64, 0xa2, 0xa2,
+-    0xac, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0x7b, 0x7a, 0xc7,
+-    0xc8, 0x36, 0x21, 0x26, 0x2b, 0x39, 0x33, 0x30,
+-    0x23, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x21, 0xc8, 0xbb, 0x8b, 0x7b, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0x64, 0x64,
+-    0x76, 0x85, 0xbf, 0xb5, 0x34, 0x2b, 0x27, 0x28,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x28,
+-    0x33, 0xc9, 0x63, 0x7e, 0x7a, 0x6d, 0xbe, 0x5b,
+-    0x76, 0x7b, 0x64, 0x64, 0xa2, 0xac, 0xa3, 0xa3,
+-    0xa3, 0xa3, 0xa3, 0xa3, 0xac, 0x76, 0x85, 0xb9,
+-    0x79, 0x22, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x21, 0xca, 0xbb, 0x75, 0x76, 0xa2, 0xa3,
+-    0xa3, 0xa3, 0xac, 0xa2, 0x64, 0x76, 0xbe, 0x8b,
+-    0xb6, 0xb5, 0x2f, 0x35, 0x30, 0x24, 0x22, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x23,
+-    0x27, 0x31, 0xcb, 0xc9, 0xbb, 0x74, 0x63, 0x90,
+-    0x7e, 0x75, 0x8b, 0x6d, 0xbe, 0x76, 0x64, 0xa2,
+-    0xac, 0xac, 0xac, 0xac, 0x64, 0x7a, 0x84, 0xcc,
+-    0x79, 0x9f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+-    0x36, 0x21, 0xc8, 0xcc, 0x63, 0x6d, 0x7b, 0x64,
+-    0xac, 0xa2, 0x64, 0x7b, 0xbe, 0x75, 0x63, 0x96,
+-    0x38, 0x39, 0x2a, 0x24, 0x23, 0x21, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x28, 0x27, 0x35, 0x2d, 0x41, 0xb5, 0xc5, 0x8f,
+-    0xb9, 0xbb, 0xc7, 0x74, 0x84, 0x90, 0x85, 0x6d,
+-    0x5b, 0x7b, 0x7b, 0xab, 0x6d, 0x90, 0xb9, 0xcd,
+-    0xca, 0x22, 0x36, 0x36, 0x28, 0x30, 0x30, 0x30,
+-    0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x25, 0x36,
+-    0x36, 0x21, 0xb4, 0x80, 0xc7, 0x7e, 0x6d, 0x76,
+-    0xab, 0x76, 0x6d, 0x85, 0x63, 0xb9, 0xb5, 0x34,
+-    0x33, 0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x23, 0x24, 0x27, 0x2a, 0x35, 0x2e, 0x2f,
+-    0x41, 0xce, 0xcf, 0x6c, 0x80, 0xcc, 0xb9, 0x74,
+-    0x84, 0x90, 0x75, 0x7e, 0x74, 0x8f, 0xcd, 0x79,
+-    0xc6, 0x2b, 0x9d, 0x41, 0x2f, 0x34, 0x2d, 0x2d,
+-    0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x34, 0x2f, 0x38,
+-    0x4d, 0x37, 0xd0, 0xd1, 0x8f, 0x74, 0x63, 0x7e,
+-    0x75, 0x7e, 0x63, 0xc7, 0x88, 0xc4, 0x31, 0x2a,
+-    0x24, 0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x30,
+-    0x33, 0x39, 0x2e, 0x51, 0x41, 0xb2, 0x6c, 0xd1,
+-    0x80, 0xcc, 0xcc, 0xcc, 0xd2, 0xd1, 0xb7, 0xd3,
+-    0x41, 0x34, 0x35, 0x32, 0x30, 0x27, 0x27, 0x27,
+-    0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x30, 0x2a,
+-    0x2b, 0x34, 0xd4, 0xca, 0xd5, 0x8f, 0xbb, 0xc7,
+-    0xc7, 0xbb, 0xcc, 0x6c, 0x41, 0x39, 0x27, 0x28,
+-    0x21, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
+-    0x28, 0x24, 0x26, 0x2a, 0x33, 0x2c, 0x2f, 0x41,
+-    0xd6, 0xb7, 0x79, 0x79, 0x79, 0xca, 0xd7, 0x51,
+-    0x39, 0x30, 0x24, 0x23, 0x22, 0x22, 0x22, 0x22,
+-    0x22, 0x22, 0x21, 0x22, 0x22, 0x22, 0x22, 0x23,
+-    0x24, 0x2a, 0x31, 0xd8, 0xc8, 0x79, 0xd1, 0x80,
+-    0xd5, 0xba, 0xd9, 0x2f, 0x35, 0x26, 0x23, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x22, 0x23, 0x28, 0x25, 0x30, 0x2b,
+-    0x31, 0x2f, 0xd4, 0xd8, 0xd8, 0x2f, 0x2e, 0x33,
+-    0x26, 0x23, 0x21, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x21, 0x28, 0x27, 0x35, 0x34, 0xd8, 0xd8, 0xd8,
+-    0xda, 0xd4, 0x2e, 0x33, 0x25, 0x23, 0x21, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x23, 0x28,
+-    0x26, 0x30, 0x32, 0x2b, 0x33, 0x2a, 0x26, 0x28,
+-    0x22, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x21, 0x23, 0x25, 0x30, 0x33, 0x35, 0x35,
+-    0x2b, 0x2a, 0x26, 0x28, 0x22, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x21,
+-    0x21, 0x22, 0x23, 0x28, 0x28, 0x23, 0x22, 0x21,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x21, 0x23, 0x28, 0x24, 0x24,
+-    0x28, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+-    0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x33, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x61, 0x62, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x35, 0x61, 0x63, 0x64, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x65, 0x66, 0x66, 0x67, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B,
++  0x3B, 0x68, 0x64, 0x69, 0x62, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x22, 0x23, 0x23, 0x55, 0x6A, 0x6B,
++  0x6C, 0x6D, 0x6E, 0x6F, 0x6F, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x22, 0x23, 0x35, 0x33, 0x3B, 0x70, 0x71, 0x72,
++  0x73, 0x74, 0x75, 0x76, 0x77, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x23, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x55,
++  0x2B, 0x34, 0x34, 0x42, 0x70, 0x71, 0x73, 0x78,
++  0x78, 0x78, 0x79, 0x7A, 0x7B, 0x34, 0x22, 0x21,
++  0x55, 0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x3B, 0x7C, 0x7D, 0x7E, 0x34, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x35, 0x3B, 0x4C, 0x3C,
++  0x42, 0x3F, 0x56, 0x7F, 0x71, 0x74, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x79, 0x80, 0x81, 0x3C, 0x82,
++  0x83, 0x62, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A,
++  0x3B, 0x21, 0x55, 0x55, 0x2B, 0x34, 0x39, 0x3F,
++  0x2A, 0x57, 0x8B, 0x72, 0x74, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x75, 0x8C, 0x6F, 0x63,
++  0x63, 0x66, 0x61, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x84, 0x85, 0x86, 0x8D, 0x88, 0x8E, 0x8F, 0x5E,
++  0x3C, 0x34, 0x3B, 0x34, 0x3F, 0x2A, 0x58, 0x57,
++  0x52, 0x46, 0x6C, 0x73, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x79, 0x7A, 0x6E, 0x69,
++  0x69, 0x90, 0x34, 0x33, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x91, 0x92, 0x8D, 0x87, 0x8E, 0x93, 0x8A, 0x35,
++  0x94, 0x95, 0x96, 0x56, 0x32, 0x32, 0x52, 0x5C,
++  0x4D, 0x82, 0x72, 0x78, 0x78, 0x78, 0x78, 0x79,
++  0x97, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D, 0x6F,
++  0x62, 0x65, 0x34, 0x4C, 0x33, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
++  0x91, 0x86, 0x87, 0x88, 0x93, 0x98, 0x60, 0x3F,
++  0x99, 0x9A, 0x9A, 0x9B, 0x9C, 0x57, 0x5C, 0x36,
++  0x9D, 0x9E, 0x6D, 0x78, 0x78, 0x78, 0x97, 0x6E,
++  0x9F, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80, 0xA0,
++  0x61, 0x51, 0x51, 0x3C, 0x4C, 0x55, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x3B, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C,
++  0xA1, 0x8D, 0x88, 0x8E, 0xA2, 0xA3, 0x94, 0x42,
++  0x51, 0xA4, 0x9A, 0x9A, 0x9A, 0xA5, 0x9C, 0x2A,
++  0xA6, 0x74, 0x8C, 0x75, 0x97, 0xA7, 0x76, 0x75,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6E,
++  0x46, 0x52, 0x56, 0x3F, 0x42, 0x34, 0x33, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x22,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x3A,
++  0x5A, 0x53, 0x53, 0x29, 0x43, 0x50, 0x53, 0x5A,
++  0x5A, 0x29, 0x5A, 0x43, 0x53, 0x5D, 0x44, 0x2A,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
++  0x7D, 0x87, 0x8E, 0x93, 0xA8, 0xA9, 0xAA, 0x2A,
++  0x57, 0x94, 0xA4, 0x9B, 0xAB, 0xAC, 0x9A, 0x9B,
++  0xAD, 0x76, 0x79, 0x78, 0x75, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x6D,
++  0x46, 0x5C, 0x57, 0x56, 0x51, 0x42, 0x4C, 0x55,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x27,
++  0x29, 0x2A, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x30,
++  0x59, 0x3D, 0x3D, 0x3D, 0x27, 0x27, 0x26, 0x5D,
++  0x27, 0x27, 0x54, 0x37, 0x2E, 0x4A, 0x36, 0x2B,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0xAE, 0x88, 0xAF, 0xB0, 0xAA, 0x2A, 0x39, 0x34,
++  0x4C, 0x5C, 0x58, 0xB1, 0xB2, 0xB3, 0xAB, 0xA5,
++  0x9A, 0xB4, 0xB5, 0x8C, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x80,
++  0xB6, 0x38, 0x5C, 0x57, 0x56, 0x3F, 0x42, 0x3B,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x32,
++  0x31, 0x2C, 0x26, 0x2C, 0x33, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34,
++  0x32, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x33,
++  0x33, 0x55, 0x55, 0x55, 0x23, 0x23, 0x35, 0x23,
++  0x23, 0x35, 0x2B, 0x4E, 0x4F, 0x2A, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x55, 0x38, 0x25,
++  0x2C, 0x52, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x55, 0x8A, 0x8F, 0x39, 0x34, 0x3C, 0x57, 0x32,
++  0x46, 0x42, 0x52, 0x4A, 0x51, 0xAA, 0xB7, 0xB3,
++  0xAB, 0xAC, 0xAC, 0xB8, 0xB9, 0x79, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79, 0x7A,
++  0xBA, 0x70, 0x7B, 0xBB, 0x82, 0x56, 0x3F, 0x34,
++  0x4C, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x36,
++  0x2D, 0x37, 0x38, 0x2A, 0x2B, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x39, 0x3A, 0x2C, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x24, 0x3D,
++  0x3E, 0x25, 0x3C, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x33, 0x29, 0x26, 0x2A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x54, 0x3E, 0x28,
++  0x28, 0x59, 0x59, 0x48, 0x51, 0x3F, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x2B, 0x56, 0x4D, 0x29, 0x5B, 0x34,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x55, 0x60, 0x3F, 0x42, 0x51, 0x32, 0x52,
++  0x40, 0x38, 0x40, 0x46, 0x42, 0xBC, 0xBD, 0xBE,
++  0xBF, 0x9B, 0xAB, 0x9B, 0xC0, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
++  0xA7, 0x63, 0x63, 0x66, 0x6F, 0x58, 0x56, 0x39,
++  0x34, 0x2B, 0x23, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x24, 0x2F,
++  0x3D, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x40, 0x41, 0x3B, 0x21,
++  0x21, 0x22, 0x42, 0x38, 0x43, 0x44, 0x3A, 0x45,
++  0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x46, 0x30, 0x47,
++  0x2A, 0x48, 0x48, 0x21, 0x21, 0x21, 0x21, 0x22,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x34, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x4D, 0x44, 0x2A, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x50, 0x4A, 0x57, 0x35,
++  0x35, 0x2B, 0x56, 0x27, 0x4B, 0x5D, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x3B, 0x52, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x38,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x3C, 0x42, 0x21, 0x33, 0x24, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x2B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x33, 0x38, 0x59, 0x37, 0x27, 0x27, 0x4A, 0x47,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x23, 0x4C, 0x4C, 0x2A, 0x56, 0x46, 0x31,
++  0x4D, 0x36, 0x50, 0x5A, 0x35, 0xC1, 0xC1, 0xC2,
++  0xC3, 0xB7, 0xB3, 0xBE, 0x76, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
++  0x6D, 0x62, 0x69, 0x6F, 0x58, 0x46, 0x32, 0x2A,
++  0x39, 0x34, 0x35, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x49,
++  0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x23, 0x29, 0x48, 0x22,
++  0x42, 0x3A, 0x4A, 0x49, 0x4B, 0x2E, 0x4B, 0x3E,
++  0x4A, 0x2C, 0x34, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x30, 0x40, 0x22,
++  0x21, 0x32, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x39,
++  0x36, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22,
++  0x31, 0x4F, 0x2A, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x31, 0x59, 0x2A, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x55, 0x27, 0x24, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4C, 0x44, 0x27, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x2A, 0x26, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3A,
++  0x40, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51, 0x49,
++  0x35, 0x21, 0x21, 0x21, 0x21, 0x22, 0x58, 0x25,
++  0x5A, 0x57, 0x21, 0x4C, 0x3D, 0x34, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x38,
++  0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x3A, 0x4B, 0x53, 0x56, 0x55, 0x33, 0x42, 0x56,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x55, 0x4C, 0x42, 0x2A, 0x57, 0x5C, 0x38,
++  0x36, 0x47, 0x5A, 0xB6, 0x77, 0xC4, 0xC1, 0xC1,
++  0xC4, 0xC5, 0xB7, 0xB9, 0x79, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x75,
++  0x97, 0xC6, 0x68, 0x57, 0x4D, 0x38, 0x46, 0x32,
++  0x51, 0x42, 0x2B, 0x35, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x2D, 0x38,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x3C,
++  0x47, 0x4F, 0x50, 0x51, 0x3F, 0x44, 0x42, 0x34,
++  0x52, 0x53, 0x28, 0x2A, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x48, 0x54, 0x33, 0x21,
++  0x23, 0x3A, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x2A,
++  0x26, 0x33, 0x21, 0x21, 0x21, 0x21, 0x23, 0x45,
++  0x37, 0x3D, 0x41, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x31,
++  0x59, 0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x28, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x27, 0x5B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x54, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B,
++  0x46, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3B, 0x49,
++  0x2B, 0x21, 0x21, 0x21, 0x23, 0x40, 0x43, 0x32,
++  0x35, 0x21, 0x21, 0x33, 0x28, 0x4C, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x4F,
++  0x5B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x50,
++  0x44, 0x39, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x3B, 0x34, 0x3F, 0x58, 0x46, 0x40, 0x36,
++  0x50, 0x41, 0x4D, 0xC7, 0x65, 0xC2, 0xC1, 0xC1,
++  0xC8, 0xBF, 0xB1, 0x97, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79,
++  0x80, 0xC9, 0x36, 0x50, 0x36, 0x38, 0x31, 0x32,
++  0x56, 0x39, 0x34, 0x33, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x2B, 0x3D, 0x28, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x4D,
++  0x55, 0x2B, 0x21, 0x21, 0x2B, 0x28, 0x3B, 0x21,
++  0x21, 0x22, 0x52, 0x27, 0x56, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x2A, 0x30, 0x3F, 0x21, 0x22,
++  0x57, 0x44, 0x58, 0x21, 0x21, 0x21, 0x21, 0x56,
++  0x37, 0x2B, 0x21, 0x21, 0x21, 0x21, 0x56, 0x3E,
++  0x36, 0x2A, 0x59, 0x23, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x50, 0x3D,
++  0x42, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x40, 0x5A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x56, 0x49, 0x24, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x42, 0x54, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4D, 0x59,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x4A,
++  0x51, 0x21, 0x21, 0x33, 0x47, 0x47, 0x33, 0x21,
++  0x21, 0x21, 0x21, 0x55, 0x27, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x4B,
++  0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x34, 0x44,
++  0x3F, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x33, 0x4C, 0x3C, 0x51, 0x57, 0x5C, 0x38, 0x38,
++  0x9D, 0xCA, 0x61, 0xCB, 0xCC, 0xCD, 0xC4, 0xC8,
++  0xA4, 0x9C, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x79,
++  0x7A, 0x7F, 0x41, 0x29, 0x47, 0x38, 0x40, 0x57,
++  0x32, 0x51, 0x42, 0x2B, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x57, 0x49, 0x32, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57, 0x27,
++  0x35, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x2A, 0x21,
++  0x21, 0x21, 0x21, 0x56, 0x54, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x4C, 0x2E, 0x5A, 0x23, 0x55, 0x5B,
++  0x49, 0x3A, 0x22, 0x21, 0x21, 0x21, 0x21, 0x32,
++  0x3E, 0x3B, 0x21, 0x21, 0x21, 0x35, 0x54, 0x53,
++  0x23, 0x55, 0x4F, 0x55, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x25, 0x44, 0x42,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x41, 0x46, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x23, 0x53, 0x2F, 0x2A, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x32, 0x28, 0x33, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x35, 0x59, 0x5B,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54,
++  0x57, 0x21, 0x35, 0x53, 0x47, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x44, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x41, 0x43,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3F, 0x29,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x55, 0x4C, 0x3F, 0x2A, 0x46, 0x31, 0x36, 0x46,
++  0x71, 0x97, 0xCE, 0xCB, 0xCF, 0xA4, 0x9C, 0xA4,
++  0xAD, 0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x8C,
++  0x7A, 0xA7, 0x36, 0x50, 0x3A, 0x36, 0x38, 0x52,
++  0x32, 0x2A, 0x3F, 0x2B, 0x22, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x22, 0x5A, 0x5A, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x28,
++  0x35, 0x21, 0x21, 0x21, 0x55, 0x30, 0x56, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x5B, 0x45, 0x21, 0x21,
++  0x21, 0x21, 0x2B, 0x2E, 0x25, 0x47, 0x3D, 0x2D,
++  0x25, 0x4C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39,
++  0x44, 0x55, 0x21, 0x21, 0x21, 0x46, 0x59, 0x3B,
++  0x21, 0x23, 0x30, 0x34, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x2A, 0x28, 0x4E, 0x42, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x3C, 0x3D, 0x42, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x51, 0x4B, 0x49, 0x39, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x5C, 0x25, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x38, 0x4B, 0x3B,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x54,
++  0x56, 0x21, 0x5B, 0x3A, 0x35, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x51, 0x59, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x32, 0x2D, 0x42,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x2B, 0x3C, 0x39, 0x56, 0x46, 0x40, 0x36, 0xB6,
++  0x73, 0x82, 0xCB, 0xD0, 0x75, 0xD1, 0xD2, 0xD1,
++  0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x74, 0xCE,
++  0x9E, 0x6E, 0xD3, 0xC6, 0x6F, 0x81, 0x38, 0x5C,
++  0x52, 0x58, 0x39, 0x4C, 0x35, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x4C, 0x4A, 0x40, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x36, 0x3A,
++  0x21, 0x21, 0x21, 0x21, 0x55, 0x27, 0x3F, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x3B, 0x21,
++  0x21, 0x21, 0x42, 0x2E, 0x2D, 0x2D, 0x26, 0x46,
++  0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51,
++  0x44, 0x55, 0x21, 0x21, 0x35, 0x25, 0x40, 0x21,
++  0x21, 0x22, 0x4E, 0x58, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x39, 0x59, 0x38, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x56, 0x59, 0x23, 0x21, 0x21, 0x21,
++  0x21, 0x4C, 0x54, 0x5B, 0x59, 0x4C, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x57, 0x3A, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x4D, 0x49, 0x26, 0x23,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x53,
++  0x32, 0x51, 0x27, 0x42, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x42, 0x25, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x24, 0x37, 0x3E, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x48,
++  0x48, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x3B, 0x39, 0x3F, 0x32, 0x5C, 0x38, 0x47, 0xD4,
++  0x7A, 0xC7, 0xCB, 0xD0, 0x74, 0x80, 0x8C, 0x9F,
++  0x80, 0x79, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x73, 0x72, 0xD5, 0xCA, 0x61, 0xD3, 0x40, 0x5C,
++  0x46, 0x58, 0x51, 0x42, 0x33, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x39, 0x4B, 0x58, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x2A, 0x3D, 0x51,
++  0x21, 0x21, 0x21, 0x21, 0x55, 0x28, 0x42, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x47, 0x52, 0x21,
++  0x21, 0x21, 0x58, 0x59, 0x42, 0x3C, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x57,
++  0x4E, 0x23, 0x21, 0x22, 0x4D, 0x54, 0x35, 0x21,
++  0x21, 0x21, 0x5A, 0x46, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x56, 0x59, 0x36, 0x35, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x36, 0x5B, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x53, 0x48, 0x3F, 0x27, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x24, 0x47, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x22, 0x40, 0x27, 0x29, 0x29, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47,
++  0x40, 0x41, 0x5C, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x39, 0x41, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x32, 0x26, 0x47, 0x28, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B,
++  0x53, 0x28, 0x36, 0x42, 0x23, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x4C, 0x39, 0x58, 0x32, 0x31, 0x38, 0x47, 0xD4,
++  0xCF, 0xD0, 0x6C, 0x9E, 0xD6, 0x6B, 0xD7, 0xD8,
++  0xD7, 0x6B, 0xCF, 0x7B, 0x80, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x74, 0x72, 0xD0, 0xA6, 0x70, 0x51,
++  0x46, 0x56, 0x51, 0x42, 0x55, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x5C, 0x27, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x32, 0x37, 0x54, 0x33,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x2A, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x2C, 0x21,
++  0x21, 0x21, 0x47, 0x36, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52,
++  0x54, 0x23, 0x21, 0x24, 0x4F, 0x46, 0x21, 0x21,
++  0x21, 0x21, 0x38, 0x2C, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x42, 0x55, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x45, 0x54, 0x56, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x53, 0x24, 0x21, 0x21, 0x21, 0x21,
++  0x46, 0x5D, 0x4C, 0x52, 0x4E, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x31, 0x48, 0x22, 0x21, 0x21,
++  0x21, 0x22, 0x46, 0x54, 0x3B, 0x45, 0x29, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x47,
++  0x28, 0x28, 0x55, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x51, 0x41, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x56, 0x54, 0x39, 0x56, 0x28, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x34, 0x50, 0x30, 0x4E, 0x40, 0x34, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x4C, 0x39, 0x58, 0x52, 0x5C, 0x38, 0x47, 0x9D,
++  0xC9, 0xD9, 0xDA, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC,
++  0xDC, 0xDC, 0xDC, 0xDD, 0x6B, 0x7B, 0x75, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x74, 0x71, 0xD0, 0x3F,
++  0x52, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x47, 0x3A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x35, 0x45, 0x4A, 0x2C, 0x3B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x30, 0x56, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x58, 0x29, 0x21,
++  0x21, 0x21, 0x53, 0x3F, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x31,
++  0x43, 0x22, 0x3B, 0x28, 0x48, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x56, 0x25, 0x35, 0x21, 0x21, 0x21,
++  0x39, 0x54, 0x34, 0x21, 0x21, 0x21, 0x35, 0x3A,
++  0x30, 0x57, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0x39, 0x21, 0x21,
++  0x21, 0x35, 0x25, 0x3F, 0x21, 0x21, 0x21, 0x56,
++  0x30, 0x58, 0x21, 0x24, 0x43, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4D, 0x29, 0x22, 0x21, 0x21,
++  0x22, 0x32, 0x26, 0x42, 0x21, 0x46, 0x2C, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x48,
++  0x2E, 0x36, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x56, 0x28, 0x35, 0x21, 0x21,
++  0x21, 0x3F, 0x27, 0x32, 0x21, 0x51, 0x25, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x22, 0x39, 0x38, 0x25, 0x54, 0x50,
++  0x58, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x4C, 0x3F, 0x56, 0x52, 0x31, 0x4D, 0x47, 0x39,
++  0xD8, 0xDC, 0xDC, 0xDC, 0xDE, 0xDF, 0xDF, 0xDF,
++  0xDF, 0xDF, 0xDE, 0xDE, 0xDC, 0xDD, 0xD6, 0x97,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x75, 0x97, 0x56,
++  0x46, 0x57, 0x2A, 0x42, 0x2B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x38, 0x29, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x35, 0x5B, 0x3D, 0x40, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x59, 0x3F, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x40, 0x5A, 0x21,
++  0x21, 0x22, 0x5D, 0x34, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x5B,
++  0x2C, 0x33, 0x29, 0x28, 0x3B, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x34, 0x59, 0x3C, 0x21, 0x21, 0x2B,
++  0x53, 0x36, 0x22, 0x21, 0x21, 0x34, 0x5A, 0x28,
++  0x3F, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x40, 0x41, 0x23, 0x21,
++  0x21, 0x3B, 0x28, 0x2B, 0x21, 0x21, 0x2A, 0x44,
++  0x38, 0x22, 0x21, 0x24, 0x50, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x50, 0x25, 0x23, 0x21, 0x23,
++  0x45, 0x5D, 0x52, 0x21, 0x21, 0x40, 0x50, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x50,
++  0x2D, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x46, 0x30, 0x33, 0x21, 0x22,
++  0x24, 0x4E, 0x45, 0x22, 0x21, 0x58, 0x25, 0x22,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x33, 0x3C, 0x48,
++  0x27, 0x39, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x34, 0x3F, 0x58, 0x57, 0x31, 0x4D, 0x47, 0x56,
++  0xDB, 0xDC, 0xDE, 0xE0, 0xE1, 0xE2, 0xE2, 0xE2,
++  0xE2, 0xE2, 0xE1, 0xE3, 0xE4, 0xDE, 0xDC, 0x6B,
++  0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0xA7, 0x38,
++  0x46, 0x56, 0x2A, 0x39, 0x3B, 0x23, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x32, 0x44, 0x34, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3F,
++  0x4D, 0x41, 0x29, 0x42, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x44, 0x46, 0x34,
++  0x2B, 0x55, 0x55, 0x2B, 0x56, 0x59, 0x36, 0x21,
++  0x21, 0x22, 0x59, 0x2B, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x55, 0x5C, 0x21, 0x21, 0x21, 0x40,
++  0x50, 0x4D, 0x4F, 0x32, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x55, 0x44, 0x31, 0x22, 0x3B, 0x5A,
++  0x41, 0x55, 0x21, 0x35, 0x57, 0x4A, 0x2E, 0x48,
++  0x57, 0x32, 0x3F, 0x55, 0x35, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x25, 0x47, 0x22, 0x21,
++  0x21, 0x4C, 0x28, 0x35, 0x21, 0x34, 0x30, 0x3A,
++  0x23, 0x21, 0x21, 0x58, 0x3A, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4D, 0x4E, 0x35, 0x33, 0x48,
++  0x44, 0x56, 0x21, 0x21, 0x21, 0x58, 0x41, 0x23,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x29,
++  0x4A, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x32, 0x44, 0x2B, 0x23, 0x45,
++  0x3D, 0x31, 0x22, 0x21, 0x21, 0x4C, 0x27, 0x35,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x53, 0x53, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x34, 0x3F, 0x58, 0x57, 0x40, 0x38, 0x47, 0xD4,
++  0xDC, 0xDE, 0xE0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE1, 0xDF, 0xDC,
++  0xE6, 0x8C, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x2A, 0x40,
++  0x46, 0x58, 0x2A, 0x42, 0x34, 0x34, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x2B, 0x54, 0x5A, 0x34, 0x23,
++  0x35, 0x23, 0x35, 0x33, 0x2B, 0x24, 0x54, 0x4B,
++  0x59, 0x5C, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x4B, 0x44, 0x59,
++  0x27, 0x26, 0x26, 0x4A, 0x3E, 0x41, 0x55, 0x21,
++  0x21, 0x22, 0x41, 0x39, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x34, 0x53, 0x4D, 0x21, 0x21, 0x21, 0x5C,
++  0x4B, 0x4F, 0x40, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x48, 0x30, 0x50, 0x26, 0x54,
++  0x34, 0x21, 0x55, 0x4E, 0x2D, 0x2F, 0x4F, 0x37,
++  0x3E, 0x4B, 0x4B, 0x30, 0x27, 0x53, 0x2C, 0x57,
++  0x42, 0x4C, 0x55, 0x22, 0x22, 0x22, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x39, 0x4A, 0x3F, 0x21, 0x21,
++  0x21, 0x55, 0x53, 0x55, 0x2A, 0x26, 0x54, 0x33,
++  0x21, 0x21, 0x21, 0x51, 0x54, 0x3B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x51, 0x3D, 0x46, 0x5A, 0x4F,
++  0x52, 0x21, 0x21, 0x21, 0x21, 0x22, 0x27, 0x31,
++  0x33, 0x23, 0x42, 0x4C, 0x21, 0x21, 0x21, 0x5B,
++  0x54, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3B, 0x44, 0x45, 0x48, 0x4B,
++  0x38, 0x22, 0x21, 0x21, 0x21, 0x21, 0x53, 0x48,
++  0x33, 0x23, 0x34, 0x3C, 0x22, 0x57, 0x4D, 0x33,
++  0x21, 0x21, 0x21, 0x21, 0x22, 0x23, 0x34, 0x40,
++  0x44, 0x31, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x3B, 0x42, 0x2A, 0x57, 0x31, 0x38, 0x5C, 0xD8,
++  0xDC, 0xE4, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE2, 0xE0,
++  0xDE, 0xCA, 0x9F, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x80, 0x76, 0x57, 0x5C,
++  0x31, 0x6E, 0x34, 0x3C, 0xC9, 0x3B, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x33, 0x5B, 0x30, 0x25,
++  0x5D, 0x5A, 0x53, 0x27, 0x26, 0x59, 0x36, 0x56,
++  0x55, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x3D, 0x2A, 0x55,
++  0x42, 0x51, 0x56, 0x24, 0x2A, 0x35, 0x21, 0x21,
++  0x21, 0x21, 0x45, 0x53, 0x3B, 0x22, 0x22, 0x35,
++  0x46, 0x59, 0x54, 0x55, 0x21, 0x21, 0x21, 0x31,
++  0x2D, 0x47, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x33, 0x50, 0x5D, 0x45, 0x55,
++  0x21, 0x21, 0x34, 0x4F, 0x29, 0x58, 0x33, 0x4C,
++  0x39, 0x3C, 0x2A, 0x40, 0x48, 0x54, 0x3D, 0x3D,
++  0x37, 0x4A, 0x59, 0x29, 0x5B, 0x36, 0x52, 0x2A,
++  0x42, 0x3C, 0x32, 0x30, 0x41, 0x35, 0x21, 0x21,
++  0x21, 0x33, 0x41, 0x26, 0x4B, 0x5A, 0x35, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x3E, 0x41, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x41, 0x49, 0x30, 0x32,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x52, 0x4F,
++  0x5D, 0x41, 0x27, 0x58, 0x21, 0x21, 0x21, 0x5B,
++  0x41, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x47, 0x49, 0x4F, 0x5C,
++  0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x39, 0x4A,
++  0x28, 0x43, 0x27, 0x5C, 0x35, 0x25, 0x49, 0x5B,
++  0x58, 0x52, 0x5C, 0x38, 0x48, 0x41, 0x4A, 0x4B,
++  0x50, 0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x35,
++  0x3B, 0x3C, 0x2A, 0x32, 0x5C, 0x40, 0x32, 0xDD,
++  0xDC, 0xE3, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE1, 0xE0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x80, 0xE7, 0x58, 0x52,
++  0x5C, 0x67, 0xE7, 0x6C, 0xE8, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x23, 0x39, 0x5C,
++  0x29, 0x5A, 0x4D, 0x5C, 0x2A, 0x2B, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x44, 0x42, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x33, 0x27, 0x30, 0x5A, 0x2C, 0x25,
++  0x4B, 0x50, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x33,
++  0x2C, 0x3B, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x4C, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x55, 0x2B,
++  0x39, 0x32, 0x4D, 0x29, 0x26, 0x3D, 0x2D, 0x2D,
++  0x4B, 0x4B, 0x2F, 0x30, 0x42, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x3B, 0x29, 0x2C, 0x55, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x23, 0x50, 0x4D, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2B, 0x32, 0x3B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x51,
++  0x48, 0x45, 0x34, 0x21, 0x21, 0x21, 0x21, 0x38,
++  0x44, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0x32, 0x34, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x3C,
++  0x5B, 0x4D, 0x42, 0x21, 0x21, 0x34, 0x4D, 0x47,
++  0x5A, 0x5D, 0x27, 0x4E, 0x25, 0x3A, 0x5C, 0x42,
++  0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0x2B, 0x34, 0x51, 0x56, 0x46, 0x40, 0xE9, 0xDA,
++  0xDD, 0xE1, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE2, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x76, 0xD3, 0x67, 0x39,
++  0x3C, 0xCF, 0xD5, 0x9F, 0x3B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x2B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3C, 0x53, 0x44, 0x3D, 0x43,
++  0x57, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x35, 0x55, 0x3F, 0x2A,
++  0x57, 0x24, 0x3F, 0x3B, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x22, 0x22, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
++  0x3C, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x55, 0x4C, 0x3F, 0x58, 0x46, 0x31, 0x8B, 0xAD,
++  0xCC, 0xE2, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xEA, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x97, 0x35, 0x6E, 0xC6, 0x82,
++  0xA6, 0x73, 0x75, 0xBA, 0x2B, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x34, 0x44, 0x3B, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x33, 0x34, 0xEB, 0x34, 0x57, 0x5C, 0x4C, 0xA4,
++  0xEC, 0x64, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0x83, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x80, 0xED, 0xCF, 0xCE, 0x78, 0x78,
++  0x78, 0x7A, 0x6D, 0x34, 0x22, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x55, 0x25, 0x55, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x23, 0x34, 0xEE, 0xEF, 0x5F, 0x96, 0x23, 0xB3,
++  0xBF, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x9F, 0x78, 0x78, 0x78, 0x78,
++  0x80, 0x9F, 0x65, 0x33, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x28, 0x55, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0x4C, 0xF1, 0xA5, 0xAC, 0xAB, 0x60, 0xB3,
++  0xB3, 0xF2, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xF3, 0x6D, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x80, 0x61, 0x34, 0x23, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x3B, 0x25, 0x22, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5E,
++  0x4C, 0x3B, 0xF4, 0xA5, 0x9B, 0x9B, 0xB4, 0xEF,
++  0xEF, 0xBF, 0xAD, 0xF5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0x67, 0x75, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80,
++  0xA7, 0x3F, 0x55, 0x22, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x4E, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x2B, 0x5F,
++  0x9B, 0xD2, 0x3C, 0xB7, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0xF0, 0xBB, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x80, 0x82,
++  0x34, 0x3B, 0x33, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x5D, 0x23, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x60,
++  0xAB, 0xA5, 0xB8, 0xB1, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xF6, 0xB7, 0xB5, 0xF0, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
++  0x67, 0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x78, 0x80, 0x9F, 0xBA, 0x42,
++  0x4C, 0x2B, 0x22, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x3A, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x55,
++  0xF2, 0x9B, 0x9B, 0xB4, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB4, 0x5F, 0x63, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF5,
++  0x76, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x78, 0x78, 0x80, 0x6D, 0x65, 0x3C, 0x34,
++  0x3B, 0x35, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23,
++  0xF7, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB3, 0xB8, 0xEA, 0xE5, 0xE5, 0xE5,
++  0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xF8, 0x68,
++  0x7A, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x78, 0x80, 0x97, 0x82, 0x39, 0x39, 0x34, 0x3B,
++  0x33, 0x23, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x2A, 0x29, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x3B, 0xB8, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xF6, 0xB2, 0xF9, 0xFA, 0xFA, 0xFA,
++  0xFA, 0xF8, 0xF8, 0xF8, 0xF0, 0xF0, 0x6F, 0x97,
++  0x80, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
++  0x8C, 0x61, 0x39, 0x2A, 0x3F, 0x3C, 0x4C, 0x55,
++  0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x4C, 0x31, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x22, 0xFB, 0xF6, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB3, 0xB2, 0xF9, 0xF3, 0xF3, 0xF3,
++  0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0x90, 0x6D, 0x97,
++  0x8C, 0x6D, 0x76, 0xBB, 0xC6, 0xB9, 0xC0, 0xFC,
++  0xAD, 0xFB, 0x2A, 0x58, 0x42, 0x4C, 0x55, 0x33,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x33, 0xD2, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
++  0xEF, 0xEF, 0xB4, 0xB8, 0xEB, 0xE8, 0x7F, 0xD6,
++  0xD6, 0xD6, 0xD6, 0x9D, 0x9D, 0x52, 0xEB, 0x5F,
++  0x5F, 0x5F, 0xF2, 0xA4, 0xBF, 0xBF, 0xB4, 0xBF,
++  0xEE, 0x56, 0x2A, 0x42, 0x4C, 0x2B, 0x33, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x4C, 0xBE, 0xF6, 0xEF, 0xEF, 0xEF,
++  0xF6, 0xB4, 0xB2, 0xF1, 0x3C, 0x56, 0x46, 0x5C,
++  0x31, 0x38, 0x40, 0x40, 0x4D, 0x4D, 0xB8, 0xAC,
++  0xBF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xB4,
++  0xB1, 0x39, 0x39, 0x3B, 0x2B, 0x23, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x3B, 0xAD, 0xA4, 0xBF, 0xBF,
++  0xB7, 0xB2, 0xEE, 0x5E, 0x39, 0x51, 0x2A, 0x32,
++  0x52, 0x46, 0x5C, 0x31, 0x31, 0x2A, 0xA5, 0xEF,
++  0xFD, 0xB4, 0xEF, 0xF6, 0xF6, 0xEF, 0xF6, 0xB2,
++  0x3F, 0x34, 0x2B, 0x55, 0x23, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x33, 0xEB, 0xF7, 0xAA,
++  0xAA, 0xF7, 0xEB, 0x55, 0x3B, 0x3C, 0x39, 0x51,
++  0x2A, 0x56, 0x32, 0x57, 0x57, 0x2A, 0x96, 0x3C,
++  0x2A, 0xEE, 0xEF, 0x5F, 0xD2, 0xEF, 0xB4, 0xAA,
++  0x42, 0x55, 0x35, 0x22, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x23, 0x3B,
++  0x3B, 0x35, 0x21, 0x23, 0x33, 0x3B, 0x4C, 0x3C,
++  0x39, 0x3F, 0x51, 0x2A, 0x51, 0x51, 0x58, 0x32,
++  0x56, 0xF4, 0xB1, 0x42, 0x3C, 0xF2, 0x9C, 0x3F,
++  0x33, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x33, 0x55,
++  0x3B, 0x4C, 0x4C, 0x3C, 0x42, 0x42, 0x3C, 0x34,
++  0x34, 0x3F, 0x4C, 0x3B, 0x4C, 0x3B, 0x3C, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x35, 0x33, 0x55, 0x33, 0x33, 0x33, 0x55, 0x2B,
++  0x2B, 0x35, 0x35, 0x35, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
++  0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
++  0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
+ };
+ 
+ #endif /* !__HAVE_ARCH_LINUX_LOGO */
+@@ -994,7 +1760,7 @@
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
++    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+ 
+ #endif /* !__HAVE_ARCH_LINUX_LOGOBW */
+@@ -1401,7 +2167,7 @@
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ 
+ #endif /* !__HAVE_ARCH_LINUX_LOGO16 */
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch
index e69de29bb2..4daeaa11be 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/mkdep.patch
@@ -0,0 +1,16 @@
+
+#
+# Made by http://www.mn-logistik.de/unsupported/pxa250/patcher
+#
+
+--- linux/Makefile~mkdep	2003-12-19 09:36:51.000000000 -0800
++++ linux/Makefile	2003-12-19 09:57:44.000000000 -0800
+@@ -458,7 +458,7 @@
+ 
+ dep-files: scripts/mkdep archdep include/linux/version.h
+ 	scripts/mkdep -- init/*.c > .depend
+-	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > .hdepend
++	$(foreach, dir, $(FINDHPATH), scripts/mkdep -- `find $(dir) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` >> .hdepend)
+ 	$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS)) _FASTDEP_ALL_SUB_DIRS="$(SUBDIRS)"
+ ifdef CONFIG_MODVERSIONS
+ 	$(MAKE) update-modverfile
diff --git a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch
index e69de29bb2..867774aab8 100644
--- a/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch
+++ b/linux/openzaurus-sa-2.4.18-rmk7-pxa3-embedix20030509/sound-2.4.18r2.patch
@@ -0,0 +1,5602 @@
+diff -Nuar linux-2.4.18/arch/arm/mach-sa1100/m62332.c linux-2.4.18p/arch/arm/mach-sa1100/m62332.c
+--- linux-2.4.18/arch/arm/mach-sa1100/m62332.c	2003-05-13 11:18:14.000000000 +0200
++++ linux-2.4.18p/arch/arm/mach-sa1100/m62332.c	2004-10-12 22:36:36.000000000 +0200
+@@ -131,3 +131,5 @@
+ 
+ 	return 0;
+ }
++EXPORT_SYMBOL(m62332_senddata);
++
+diff -Nuar linux-2.4.18/arch/arm/mach-sa1100/Makefile linux-2.4.18p/arch/arm/mach-sa1100/Makefile
+--- linux-2.4.18/arch/arm/mach-sa1100/Makefile	2003-05-13 11:18:14.000000000 +0200
++++ linux-2.4.18p/arch/arm/mach-sa1100/Makefile	2004-10-12 22:36:19.000000000 +0200
+@@ -18,7 +18,7 @@
+ export-objs :=	assabet.o consus.o badge4.o dma-sa1100.o dma-sa1111.o \
+ 		flexanet.o freebird.o generic.o h3600.o \
+ 		huw_webpanel.o irq.o pcipool.o sa1111.o sa1111-pcibuf.o \
+-		system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o
++		system3.o yopy.o usb_ctl.o usb_recv.o usb_send.o m62332.o
+ 
+ # These aren't present yet, and prevents a plain -ac kernel building.
+ # hwtimer.o
+@@ -36,7 +36,7 @@
+ obj-$(CONFIG_SA1100_LART) += cpu-sa1100.o
+ endif
+ 
+-obj-$(CONFIG_SA1100_COLLIE) += collie.o m62332.o collie_battery.o collie_led.o collie_buzzer.o
++obj-$(CONFIG_SA1100_COLLIE) += collie.o m62332.o collie_battery.o collie_led.o
+ 
+ # Next, the SA1111 stuff.
+ obj-$(CONFIG_SA1111) += sa1111.o dma-sa1111.o
+diff -Nuar linux-2.4.18/drivers/char/Makefile linux-2.4.18p/drivers/char/Makefile
+--- linux-2.4.18/drivers/char/Makefile	2003-05-13 11:18:18.000000000 +0200
++++ linux-2.4.18p/drivers/char/Makefile	2004-10-12 17:26:44.000000000 +0200
+@@ -228,7 +228,7 @@
+ obj-y += joystick/js.o
+ endif
+ 
+-obj-$(CONFIG_SA1100_COLLIE) += sharp_led.o sharp_kbdctl.o sharp_buzzer.o
++obj-$(CONFIG_SA1100_COLLIE) += sharp_led.o sharp_kbdctl.o
+ obj-$(CONFIG_DISCOVERY_LED) += sharp_led.o discovery_led.o
+ obj-$(CONFIG_ARCH_PXA_POODLE) += sharp_led.o sharp_kbdctl.o sharpsl_led.o sharp_buzzer.o
+ obj-$(CONFIG_ARCH_PXA_CORGI) += sharp_led.o sharpsl_led.o sharp_kbdctl.o corgi_rc.o sharp_buzzer.o
+diff -Nuar linux-2.4.18/drivers/sound/colliebuzzer.h linux-2.4.18p/drivers/sound/colliebuzzer.h
+--- linux-2.4.18/drivers/sound/colliebuzzer.h	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.18p/drivers/sound/colliebuzzer.h	2004-10-13 15:24:51.028208808 +0200
+@@ -0,0 +1,756 @@
++unsigned short tap_data[] = {
++	0x0000 , 0xff00 , 0xff00 , 0x0000 , 
++	0xff00 , 0x0000 , 0x0000 , 0x0100 , 
++	0x0000 , 0x0100 , 0x0000 , 0x0100 , 
++	0x0100 , 0x0000 , 0x0100 , 0x0100 , 
++	0x0100 , 0x0100 , 0x0100 , 0x0100 , 
++	0x0100 , 0x0100 , 0x0100 , 0x0100 , 
++	0x0100 , 0x0000 , 0x0100 , 0x0000 , 
++	0x0100 , 0xff00 , 0x0100 , 0x0000 , 
++	0x0100 , 0x0000 , 0x0000 , 0x0100 , 
++	0x0000 , 0x0100 , 0x0000 , 0x0100 , 
++	0x0000 , 0x0000 , 0x0000 , 0x0000 , 
++	0x0000 , 0x0100 , 0x0000 , 0x0100 , 
++	0x0000 , 0x0100 , 0x0700 , 0x1c00 , 
++	0xc800 , 0xd900 , 0x2b00 , 0x2700 , 
++	0xbf00 , 0xe000 , 0x0d00 , 0x1000 , 
++	0xf500 , 0xd700 , 0x0100 , 0x0a00 , 
++	0xfb00 , 0xfa00 , 0x2200 , 0x0100 , 
++	0xeb00 , 0x0300 , 0x0600 , 0x1600 , 
++	0xe500 , 0xf500 , 0x0d00 , 0x0a00 , 
++	0x0100 , 0xfb00 , 0x0000 , 0x0100 , 
++	0xf200 , 0x0400 , 0x0600 , 0x0000 , 
++	0xf100 , 0x0300 , 0x1200 , 0xfe00 , 
++	0xe900 , 0x0400 , 0x0100 , 0x0d00 , 
++	0xf500 , 0x0100 , 0x0100 , 0xfe00 , 
++	0x0100 , 0xfb00 , 0x0400 , 0xff00 , 
++	0xf700 , 0x0400 , 0x0000 , 0xfe00 , 
++	0x0200 , 0x0000 , 0x0100 , 0xfd00 , 
++	0x0000 , 0xff00 , 0x0200 , 0x0000 , 
++	0xff00 , 0x0000 , 0x0200 , 0xfc00 , 
++	0xfe00 , 0xff00 , 0x0100 , 0x0200 , 
++	0x0000 , 0xff00 , 0xfc00 , 0x0100 , 
++	0x0100 , 0x0100 , 0xff00 , 0x0000 , 
++	0x0300 , 0xfe00 , 0xfe00 , 0x0200 , 
++	0xff00 , 0x0000 , 0x0000 , 0xfe00 , 
++	0x0000 , 0xff00 , 0x0000 , 0x0000 , 
++	0x0000 , 0xff00 , 0x0000 , 0x0000 , 
++	0xff00 , 0xfe00 , 0xfd00 , 0x0100 , 
++	0x0000 , 0xfe00 , 0xff00 , 0xff00 , 
++	0x0000 , 0xff00 , 0x0100 , 0xfe00 , 
++	0xff00 , 0xff00 , 0x0000 , 0x0000 , 
++	0xfe00 , 0xff00 , 0x0100 , 0x0100 , 
++	0xff00 , 0x0100 , 0x0100 , 0xfe00 , 
++	0x0000 , 0x0000 , 0x0000 , 0x0100 , 
++	0x0000 , 0x0000 , 0xff00 , 0x0000 , 
++	0x0100 , 0x0000 , 0x0200 };
++
++
++unsigned short click_data[] = {
++	0x0100 , 0x0100 , 0x0100 , 0x0000 , 
++	0x0100 , 0xff00 , 0x0100 , 0x0000 , 
++	0xff00 , 0xff00 , 0xff00 , 0x0000 , 
++	0xff00 , 0xff00 , 0xff00 , 0xff00 , 
++	0xff00 , 0xff00 , 0x0000 , 0xff00 , 
++	0xff00 , 0xff00 , 0x0000 , 0xff00 , 
++	0xff00 , 0xff00 , 0xff00 , 0x0100 , 
++	0x0000 , 0xff00 , 0xfe00 , 0x0100 , 
++	0xff00 , 0x0100 , 0xff00 , 0x0100 , 
++	0x0100 , 0x0300 , 0xff00 , 0xff00 , 
++	0xff00 , 0x0100 , 0x0100 , 0x0000 , 
++	0xfe00 , 0xfe00 , 0xfe00 , 0xfc00 , 
++	0xfe00 , 0x0100 , 0xfd00 , 0xff00 , 
++	0xff00 , 0xfc00 , 0xfe00 , 0xfd00 , 
++	0x0100 , 0xfe00 , 0x0100 , 0xf800 , 
++	0xfe00 , 0xfe00 , 0xfc00 , 0xe600 , 
++	0xdb00 , 0x2500 , 0xdb00 , 0xee00 , 
++	0xdb00 , 0x0600 , 0xeb00 , 0x1f00 , 
++	0x1e00 , 0xeb00 , 0xfe00 , 0x0000 , 
++	0xff00 , 0x1900 , 0xef00 , 0xf700 , 
++	0x2100 , 0xe400 , 0x0100 , 0x0600 , 
++	0xff00 , 0x0300 , 0xf900 , 0x0f00 , 
++	0xf600 , 0x0100 , 0xfe00 , 0xf900 , 
++	0x0500 , 0xf500 , 0x0600 , 0xfb00 , 
++	0x0800 , 0x0100 , 0x0300 , 0x0100 , 
++	0xf700 , 0xfa00 , 0xfd00 , 0xfc00 , 
++	0x0800 , 0xfb00 , 0x0500 , 0xfe00 , 
++	0xfc00 , 0xfc00 , 0xfe00 , 0x0400 , 
++	0xff00 , 0xff00 , 0x0500 , 0x0100 , 
++	0xfc00 , 0xff00 , 0xfe00 , 0xfb00 , 
++	0x0200 , 0x0200 , 0xff00 , 0xfe00 , 
++	0xfe00 , 0x0600 , 0xfb00 , 0xff00 , 
++	0xfc00 , 0x0600 , 0xfb00 , 0xff00 , 
++	0xff00 , 0x0100 , 0xff00 , 0x0200 , 
++	0xff00 , 0xfb00 , 0xff00 , 0x0200 , 
++	0xff00 , 0x0200 , 0x0100 , 0xfe00 , 
++	0xfe00 , 0x0100 , 0xfd00 , 0x0200 , 
++	0xfc00 , 0x0800 , 0xfe00 , 0xfe00 , 
++	0x0400 , 0xfc00 , 0xff00 , 0xfc00 , 
++	0x0500 , 0x0200 , 0x0800 , 0x0200 , 
++	0x0100 , 0xfe00 , 0x0100 , 0xff00 , 
++	0x0700 , 0xfb00 , 0xfc00 , 0x0100 , 
++	0xfe00 , 0xfc00 , 0x0b00 , 0xfb00 , 
++	0xfb00 , 0x0700 , 0xfb00 , 0xfb00 , 
++	0x0100 , 0xff00 , 0xfb00 , 0xfd00 , 
++	0x0000 , 0xfe00 , 0xfe00 , 0xff00 , 
++	0xfc00 , 0x0400 , 0x0000 , 0xfe00 , 
++	0xff00 , 0x0200 , 0xff00 , 0x0000 , 
++	0x0500 , 0x0100 , 0x0100 , 0x0100 , 
++	0x0100 , 0x0000 , 0x0300 , 0xfe00 , 
++	0xff00 , 0x0100 , 0x0100 , 0xfe00 , 
++	0x0000 , 0xff00 , 0x0100 , 0xff00 , 
++	0x0200 , 0xff00 , 0xff00 , 0xff00 , 
++	0xff00 , 0xfe00 , 0x0000 , 0xff00 , 
++	0xfe00 , 0xff00 , 0xfd00 , 0x0000 , 
++	0xff00 , 0xfe00 , 0xff00 , 0xfc00 , 
++	0x0100 , 0xfd00 , 0xff00 , 0xff00 , 
++	0x0200 , 0xff00 , 0x0100 , 0xff00 , 
++	0xfc00 , 0x0300 , 0xff00 , 0x0200 , 
++	0xff00 , 0x0100 , 0xff00 , 0x0100 , 
++	0xff00 , 0xff00 , 0x0100 , 0xfe00 , 
++	0x0300 , 0xfc00 , 0x0100 , 0xff00 , 
++	0x0100 , 0x0100 , 0x0100 , 0xfc00 , 
++	0xff00 , 0x0100 , 0x0100 , 0xfe00 , 
++	0x0100 , 0xff00 , 0x0100 , 0xfc00 , 
++	0x0100 , 0x0200 , 0xff00 , 0x0100 , 
++	0xff00 , 0xff00 , 0x0200 , 0xfd00 , 
++	0xfe00 , 0x0100 , 0xff00 , 0x0100 , 
++	0xfe00 , 0x0100 , 0x0300 , 0xfe00 , 
++	0x0300 , 0xfe00 , 0xff00 , 0x0100 , 
++	0xff00 , 0x0200 , 0xfd00 , 0x0000 , 
++	0xff00 , 0x0200 , 0xff00 , 0x0200 , 
++	0xff00 , 0x0100 , 0x0000 , 0xff00 , 
++	0x0200 , 0x0100 , 0x0000 , 0xff00 , 
++	0x0100 , 0xfe00 , 0x0200 , 0xfe00 , 
++	0xfe00 , 0x0100 , 0xfe00 , 0x0100 , 
++	0xfd00 , 0xff00 , 0xff00 , 0xfe00 , 
++	0xff00 , 0xfc00 , 0x0100 , 0xfe00 , 
++	0x0100 , 0xff00 , 0xfe00 , 0xff00 , 
++	0xff00 , 0xfe00 , 0x0100 , 0xfe00 , 
++	0x0100 , 0xff00 , 0x0100 , 0xfe00 , 
++	0xff00 , 0x0200 , 0xfe00 , 0x0000 , 
++	0x0100 , 0x0200 , 0xff00 , 0x0200 , 
++	0xff00 , 0x0000 , 0x0100 , 0x0100 , 
++	0xff00 , 0x0200 , 0xfe00 , 0xff00 , 
++	0xff00 , 0xff00 , 0x0100 , 0x0000 , 
++	0xff00 , 0x0100 , 0xff00 , 0x0000 , 
++	0x0100 , 0xff00 , 0xfe00 , 0xff00 , 
++	0xff00 , 0x0100 , 0xff00 , 0x0100 , 
++	0xfe00 , 0xff00 , 0xff00 , 0xff00 , 
++	0xfe00 , 0xff00 , 0xff00 , 0x0100 , 
++	0xff00 , 0x0200 , 0xff00 , 0x0100 , 
++	0xff00 , 0xff00 };
++
++
++unsigned short alarm_data[] = {
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x7fff , 0x7fff , 0x8000 , 0x8000 , // 9 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 0
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 1
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 2
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 3
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 4
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 5
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 6
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 7
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 8
++  0x7fff , 0x7fff , 0x7fff , 0x7fff , 0x8000 , 0x8000 , 0x8000 , 0x8000 , // 9 5
++
++};
++
++
++
++
++
++#define SHARP_BUZ_TOUCHSOUND 1
++#define SHARP_BUZ_KEYSOUND 2
++#define SHARP_BUZ_ALARM 11
++#define SHARP_BUZZER_MAKESOUND 0x5680
++
++static int collie_ct_s16_buzzer(const u_char *userPtr, size_t userCount,
++			   u_char frame[], ssize_t *frameUsed,
++			   ssize_t frameLeft)
++{
++	ssize_t count, used;
++	signed short *fp = (unsigned short *) &frame[*frameUsed];
++	signed short *up = (unsigned short *) userPtr;
++
++	DPRINTK("Collie_ct_s16 begin\n");
++
++	used = count = (userCount < frameLeft) ? userCount/2 : frameLeft/4;
++
++	DPRINTK("Collie_ct_s16 begin count %d \n",count);
++	
++	while (count > 0) {
++		*fp++ =  *up;
++		*fp++ =  *up++;
++		count--;
++	}
++
++	*frameUsed+=used*4;	
++	DPRINTK("Collie_ct_s16 exit\n");
++	return used*2;
++}
++
++
++static ssize_t sq_write_buzzer(int soundid)
++{
++	const char  * src;
++	audio_stream_t *s = &output_stream;
++	u_char *dest;
++	ssize_t uUsed, bUsed, bLeft, uLeft, ret = 0;
++
++
++	if ((collie_tc_status!=NA) && (collie_tc_status!=PLAY)) 
++	    return -EPERM;
++
++	collie_tc_status=PLAY;
++
++	if (!s->buffers && sq_allocate_buffers(s)) {
++		return -ENOMEM;
++	}
++
++	
++#ifdef CONFIG_PM
++	/* Auto Power off cancel */
++//	autoPowerCancel = 0;
++#endif
++	DPRINTK("sq_write_buzzer: id:%d\n", soundid);
++
++	switch (soundid) {
++	case SHARP_BUZ_TOUCHSOUND:
++	    src=tap_data;
++	    uLeft=176*2;
++	    break;
++	case SHARP_BUZ_KEYSOUND:
++	    src=click_data;
++	    uLeft=360*2;
++	    break;
++	case SHARP_BUZ_ALARM:
++	    src=alarm_data;
++	    uLeft=3072*2;
++	    break;
++	default:
++	    return 0;
++	}
++	DPRINTK("sq_write_buzzer: uLeft=%d\n", uLeft);
++
++	collie_tc_mute_off();
++	while (uLeft > 0) {
++		audio_buf_t *b = s->buf;
++
++		ret = -ERESTARTSYS;
++		if (down_interruptible(&b->sem)) {
++			break;
++		}
++
++		dest = b->start + b->size;
++		bUsed = 0;
++		bLeft = s->fragsize - b->size;
++		uUsed = collie_ct_s16_buzzer(src, uLeft, dest, &bUsed, bLeft);
++		cpu_cache_clean_invalidate_range((unsigned long)dest,
++		    (unsigned long)(dest+(audio_fragsize)), 0);
++		
++		DPRINTK("back to sq_write_buzzer %p\n",dest);		
++
++		if (uUsed < 0) {
++			up(&b->sem);
++			return -EFAULT;
++		}
++		src += uUsed;
++		uLeft -= uUsed;
++		b->size += bUsed;
++
++		if (b->size < s->fragsize) {
++			up(&b->sem);
++			break;
++		}
++
++		/* Send current buffer to dma */
++		sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
++		 			(void *) b, b->dma_addr, b->size);
++
++		Collie_volume_set(50);
++
++		b->size = 0;    /* indicate that the buffer has been sent */
++		NEXT_BUF(s, buf);
++	}
++
++	DPRINTK("sq_write_buzzer: return\n");
++	return ret;
++}
++
++
++
++
++
++
++
+diff -Nuar linux-2.4.18/drivers/sound/collie_ssp.c linux-2.4.18p/drivers/sound/collie_ssp.c
+--- linux-2.4.18/drivers/sound/collie_ssp.c	2003-05-13 11:18:37.000000000 +0200
++++ linux-2.4.18p/drivers/sound/collie_ssp.c	2004-10-13 15:05:36.000000000 +0200
+@@ -9,6 +9,7 @@
+  *		I/F : Synchronous serial port (SSP) TI mode
+  *
+  * Copyright (C) 2001  SHARP
++ * p.nis/dolOps messed around with it too!
+  *
+  * This program is free software; you can redistribute it and/or modify
+  * it under the terms of the GNU General Public License as published by
+@@ -24,7 +25,18 @@
+  *	23-Oct-2001 SHARP
+  *		tune hardware control method
+  *	12-Nov-2001 Lineo Japan, Inc.
+- *	14-Feb-2003 Sharp Corporation 8bit , GETOSPACE
++ *
++ *	26-Dec-2002 getospace added, some unneeded things removed
++ *	
++ *	28-Dec-2002 cut out old stuff, reorder stuff
++ *
++ *	04-Jan-2003 put in getospace from lineo's collie-tc35143.c
++ *	            also added collie_record_on off, and exported these symbols
++ *
++ *	06-Jan-2003 if mixer ioctl SOUND_MIXER_READ_DEVMASK returns 0 as mask,
++ *		    than the headphone(/mic) is not connected
++ *	            
++ *
+  */
+ #include <linux/module.h>
+ #include <linux/sched.h>
+@@ -35,7 +47,7 @@
+ #include <linux/fcntl.h>
+ #include <linux/errno.h>
+ #include <linux/mm.h>
+-#include <linux/malloc.h>
++#include <linux/slab.h>
+ #include <linux/sound.h>
+ #include <linux/init.h>
+ #include <linux/delay.h>
+@@ -48,38 +60,30 @@
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+ #include <asm/dma.h>
+-#include <asm/ucb1200.h>
+ 
+ #include <linux/soundcard.h>
+ #include <asm/proc/cache.h>
+ 
+-#include <asm/arch/gpio.h>
++#include <asm/arch/hardware.h>
+ #include <asm/arch/m62332.h>
+ #include <asm/arch/tc35143.h>
+ 
+ #undef DEBUG
+-//#define DEBUG
+ #ifdef DEBUG
+ #define DPRINTK( x... )  printk( ##x )
+ #else
+ #define DPRINTK( x... )
+ #endif
+ 
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \
+-    defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV)
+-#define COLLIE_TRY_ONE
+-#else
+-#undef	COLLIE_TRY_ONE
+-#endif
++#define	COLLIE_TRY_ONE
+ 
+ #ifdef COLLIE_TRY_ONE
+ #ifndef	GPIO_REMOCON_ADC_SW
+ #define	GPIO_REMOCON_ADC_SW	GPIO_GPIO(18)
+ #endif
+ 
++static int collie_rc_irq;
+ static DECLARE_WAIT_QUEUE_HEAD(audio_on);
+-
+-
+ static inline void collie_rc_set_int_mode(void)
+ {
+ 	GPSR = GPIO_REMOCON_ADC_SW;
+@@ -91,14 +95,12 @@
+ }
+ #endif
+ 
+-
+ int collie_dmasound_irq = -1;
+-#define	COLLIE_SOUND_DMA_CHANNEL	(collie_dmasound_irq)
+ 
++#define	COLLIE_SOUND_DMA_CHANNEL	(collie_dmasound_irq)
+ #define SND_NDEVS	256	/* Number of supported devices */
+ #define SND_DEV_CTL	0	/* Control port /dev/mixer */
+-#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM
+-				   synthesizer and MIDI output) */
++#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */
+ #define SND_DEV_MIDIN	2	/* Raw midi access */
+ #define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
+ #define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
+@@ -121,142 +123,25 @@
+ #endif
+ 
+ /*** Some declarations ***********************************************/
+-#define DMASND_TT	1
+-#define DMASND_FALCON	2
+-#define DMASND_AMIGA	3
+-#define DMASND_AWACS	4
+-#define DMASND_IRIS	5
+-#define DMASND_COLLIE	6
+ 
+-#define COLLIE_WAIT_AMP_ON	1	/* 10ms */
++
+ #define COLLIE_WAIT_LCM_ACC_XEN	50	/* 500ms */
+-#ifdef MODULE
+-static int catchRadius = 0;
+-#endif
++
+ static int collie_amp_init = 0;
+ static int collie_dac_init = 0;
+-static int collie_op_shdn_on = 0;
+ static int collie_resume = 0;
+ static int collie_hard_mute = 1;
+ static int collie_soft_mute = 1;
+ static int collie_volume = 0;
++int collie_recording=0;
++static int playing=0;
++static int headphone;
+ 
+-int collie_buzzer_volume = 0;
+-
+-#if 1
+-static DECLARE_WAIT_QUEUE_HEAD(open_queue);
++#define AUDIO_NBFRAGS_DEFAULT   64
++#define AUDIO_FRAGSIZE_DEFAULT  4096
+ 
+-#define SIGNAL_RECEIVED	(signal_pending(current))
+-#define ONE_SECOND	HZ	/* in jiffies (100ths of a second) */
+-#define SLEEP(queue, time_limit) \
+-	interruptible_sleep_on_timeout((wait_queue_head_t*)&queue, (time_limit));
+-#define WAKE_UP(queue)	(wake_up_interruptible((wait_queue_head_t*)&queue))
+-#endif
+-
+-#define AUDIO_NBFRAGS_DEFAULT   8
+-#define AUDIO_FRAGSIZE_DEFAULT  8192
+-
+-
+-#define TRACE 0
+-#if TRACE
+-#define TRACE_ON	1
+-#define TRACE_SEM	0
+-#define	TRACE_SENDDATA	0
+-#define	TRACE_PM	1
+-#define TRACE_AMP	1
+-#define TRACE_DAC	1
+-#define TRACE_OP_SHDN	1
+-#define TRACE_WRITE	1
+-#define TRACE_MUTE	1
+-#define TRACE_CLOCK	1
+-#define TRACE_PAIF	1
+-#define TRACE_SSP	1
+-#define TRACE_VOLUME	1
+-#define TRACE_MIC	1
+-#define TRACE_INTERRUPT	0
+-int	cLevel = 0;
+-char	*pLevel[16] = {
+-	/*  0 */"",
+-	/*  1 */" ",
+-	/*  2 */"  ",
+-	/*  3 */"   ",
+-	/*  4 */"    ",
+-	/*  5 */"     ",
+-	/*  6 */"      ",
+-	/*  7 */"       ",
+-	/*  8 */"        ",
+-	/*  9 */"         ",
+-	/* 10 */"          ",
+-	/* 11 */"           ",
+-	/* 12 */"            ",
+-	/* 13 */"             ",
+-	/* 14 */"              ",
+-	/* 15 */"               "
+-};
+-char *
+-indent(int level)
+-{
+-  int	i;
+-  return (level < 16 ) ? pLevel[level] : pLevel[15];
+-}
+-
+-#define	P_ID	(current->tgid)
+-#define	ENTER(f,fn)	{if(f)printk("%d:%s+[%d]%s\n",jiffies,indent(cLevel),P_ID,(fn));cLevel++;}
+-#define LEAVE(f,fn)	{cLevel--;if(f>1)printk("%d:%s-[%d]%s\n",jiffies,indent(cLevel),P_ID,(fn));}
+-#else	/* ! TRACE */
+-#define	ENTER(f,fn)
+-#define LEAVE(f,fn)
+-#endif	/* end TRACE */
+ 
+-/*
+- * DAC power management
+- */
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0) || \
+-    defined(CONFIG_COLLIE_TR1) || defined(CONFIG_COLLIE_DEV)
+-#define	DAC_OFF_WITH_DEVICE_OFF		1
+-#undef	HARD_MUTE_CTRL_DISABLE		
+-#else
+-#undef	DAC_OFF_WITH_DEVICE_OFF
+ #undef	HARD_MUTE_CTRL_DISABLE		
+-#endif
+-
+-
+-#define TRY_DELAY_OFF
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.19 */
+-static DECLARE_WAIT_QUEUE_HEAD(delay_off);
+-struct semaphore df_sem;
+-/*
+- * delay execution
+- */
+-static unsigned int	DelayedFlag = 0;
+-#define DELAY_DAC_OFF		0x1
+-#define DELAY_HARD_MUTE_ON	0x2
+-
+-static inline void ResetDelayAll(void)
+-{
+-	DelayedFlag = 0;
+-}
+-
+-static inline int isDelayedExist(void)
+-{
+-	return DelayedFlag;
+-}
+-
+-static inline void SetDelay(unsigned int flag)
+-{
+-	DelayedFlag |= flag;
+-}
+-
+-static inline void ResetDelay(unsigned int flag)
+-{
+-	DelayedFlag &= ~flag;
+-}
+-
+-static inline unsigned int isDelayed(unsigned int flag)
+-{
+-	return DelayedFlag & flag;
+-}
+-#endif
+ 
+ /*
+  * Buffer Management
+@@ -268,6 +153,7 @@
+ 	dma_addr_t dma_addr;    /* physical buffer address */
+ 	struct semaphore sem;   /* down before touching the buffer */
+ 	int master;             /* master owner for buffer allocation */
++	u_int idx;		/* buffer index, so that we know which buffer was sent last*/
+ } audio_buf_t;
+ 
+ typedef struct {
+@@ -291,16 +177,6 @@
+ 
+ static volatile int audio_wr_refcount;	/* nbr of concurrent open() for playback */
+ 
+-static ssize_t (*ct_func)(const u_char *, size_t, u_char *, ssize_t *, ssize_t) = NULL;
+-
+-#ifdef MODULE
+-MODULE_PARM(catchRadius, "i");
+-#endif
+-MODULE_PARM(numBufs, "i");
+-MODULE_PARM(bufSize, "i");
+-
+-#define min(x, y)	((x) < (y) ? (x) : (y))
+-
+ #define IOCTL_IN(arg, ret) \
+ 	do { int error = get_user(ret, (int *)(arg)); \
+ 		if (error) return error; \
+@@ -310,11 +186,7 @@
+ /*
+  * SA1110 GPIO (17)
+  */
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-#define COLLIE_GPIO_OPSHDN	GPIO_GPIO (17)	/* AMP contorol        */
+-#else	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+ #define COLLIE_GPIO_MIC		GPIO_GPIO (17)	/* MIC contorol        */
+-#endif	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+ 
+ /*
+  * DAC setup data
+@@ -352,122 +224,11 @@
+ 		( LCM_ACC_XSEL1 | LCM_ACC_CLKSEL101 ) ,
+ };
+ 
++/*** "Translations" ************************************************************/
+ 
+-/* 16 bit mu-law */
+-
+-static short ulaw2dma16[] = {
+-	-32124,	-31100,	-30076,	-29052,	-28028,	-27004,	-25980,	-24956,
+-	-23932,	-22908,	-21884,	-20860,	-19836,	-18812,	-17788,	-16764,
+-	-15996,	-15484,	-14972,	-14460,	-13948,	-13436,	-12924,	-12412,
+-	-11900,	-11388,	-10876,	-10364,	-9852,	-9340,	-8828,	-8316,
+-	-7932,	-7676,	-7420,	-7164,	-6908,	-6652,	-6396,	-6140,
+-	-5884,	-5628,	-5372,	-5116,	-4860,	-4604,	-4348,	-4092,
+-	-3900,	-3772,	-3644,	-3516,	-3388,	-3260,	-3132,	-3004,
+-	-2876,	-2748,	-2620,	-2492,	-2364,	-2236,	-2108,	-1980,
+-	-1884,	-1820,	-1756,	-1692,	-1628,	-1564,	-1500,	-1436,
+-	-1372,	-1308,	-1244,	-1180,	-1116,	-1052,	-988,	-924,
+-	-876,	-844,	-812,	-780,	-748,	-716,	-684,	-652,
+-	-620,	-588,	-556,	-524,	-492,	-460,	-428,	-396,
+-	-372,	-356,	-340,	-324,	-308,	-292,	-276,	-260,
+-	-244,	-228,	-212,	-196,	-180,	-164,	-148,	-132,
+-	-120,	-112,	-104,	-96,	-88,	-80,	-72,	-64,
+-	-56,	-48,	-40,	-32,	-24,	-16,	-8,	0,
+-	32124,	31100,	30076,	29052,	28028,	27004,	25980,	24956,
+-	23932,	22908,	21884,	20860,	19836,	18812,	17788,	16764,
+-	15996,	15484,	14972,	14460,	13948,	13436,	12924,	12412,
+-	11900,	11388,	10876,	10364,	9852,	9340,	8828,	8316,
+-	7932,	7676,	7420,	7164,	6908,	6652,	6396,	6140,
+-	5884,	5628,	5372,	5116,	4860,	4604,	4348,	4092,
+-	3900,	3772,	3644,	3516,	3388,	3260,	3132,	3004,
+-	2876,	2748,	2620,	2492,	2364,	2236,	2108,	1980,
+-	1884,	1820,	1756,	1692,	1628,	1564,	1500,	1436,
+-	1372,	1308,	1244,	1180,	1116,	1052,	988,	924,
+-	876,	844,	812,	780,	748,	716,	684,	652,
+-	620,	588,	556,	524,	492,	460,	428,	396,
+-	372,	356,	340,	324,	308,	292,	276,	260,
+-	244,	228,	212,	196,	180,	164,	148,	132,
+-	120,	112,	104,	96,	88,	80,	72,	64,
+-	56,	48,	40,	32,	24,	16,	8,	0,
+-};
+-
+-/* 16 bit A-law */
+-
+-static short alaw2dma16[] = {
+-	-5504,	-5248,	-6016,	-5760,	-4480,	-4224,	-4992,	-4736,
+-	-7552,	-7296,	-8064,	-7808,	-6528,	-6272,	-7040,	-6784,
+-	-2752,	-2624,	-3008,	-2880,	-2240,	-2112,	-2496,	-2368,
+-	-3776,	-3648,	-4032,	-3904,	-3264,	-3136,	-3520,	-3392,
+-	-22016,	-20992,	-24064,	-23040,	-17920,	-16896,	-19968,	-18944,
+-	-30208,	-29184,	-32256,	-31232,	-26112,	-25088,	-28160,	-27136,
+-	-11008,	-10496,	-12032,	-11520,	-8960,	-8448,	-9984,	-9472,
+-	-15104,	-14592,	-16128,	-15616,	-13056,	-12544,	-14080,	-13568,
+-	-344,	-328,	-376,	-360,	-280,	-264,	-312,	-296,
+-	-472,	-456,	-504,	-488,	-408,	-392,	-440,	-424,
+-	-88,	-72,	-120,	-104,	-24,	-8,	-56,	-40,
+-	-216,	-200,	-248,	-232,	-152,	-136,	-184,	-168,
+-	-1376,	-1312,	-1504,	-1440,	-1120,	-1056,	-1248,	-1184,
+-	-1888,	-1824,	-2016,	-1952,	-1632,	-1568,	-1760,	-1696,
+-	-688,	-656,	-752,	-720,	-560,	-528,	-624,	-592,
+-	-944,	-912,	-1008,	-976,	-816,	-784,	-880,	-848,
+-	5504,	5248,	6016,	5760,	4480,	4224,	4992,	4736,
+-	7552,	7296,	8064,	7808,	6528,	6272,	7040,	6784,
+-	2752,	2624,	3008,	2880,	2240,	2112,	2496,	2368,
+-	3776,	3648,	4032,	3904,	3264,	3136,	3520,	3392,
+-	22016,	20992,	24064,	23040,	17920,	16896,	19968,	18944,
+-	30208,	29184,	32256,	31232,	26112,	25088,	28160,	27136,
+-	11008,	10496,	12032,	11520,	8960,	8448,	9984,	9472,
+-	15104,	14592,	16128,	15616,	13056,	12544,	14080,	13568,
+-	344,	328,	376,	360,	280,	264,	312,	296,
+-	472,	456,	504,	488,	408,	392,	440,	424,
+-	88,	72,	120,	104,	24,	8,	56,	40,
+-	216,	200,	248,	232,	152,	136,	184,	168,
+-	1376,	1312,	1504,	1440,	1120,	1056,	1248,	1184,
+-	1888,	1824,	2016,	1952,	1632,	1568,	1760,	1696,
+-	688,	656,	752,	720,	560,	528,	624,	592,
+-	944,	912,	1008,	976,	816,	784,	880,	848,
+-};
+-
+-
+-
+-/*** Translations ************************************************************/
+-
+-static ssize_t collie_ct_law(const u_char *userPtr, size_t userCount,
+-			     u_char frame[], ssize_t *frameUsed,
+-			     ssize_t frameLeft);
+-static ssize_t collie_ct_s8(const u_char *userPtr, size_t userCount,
+-			    u_char frame[], ssize_t *frameUsed,
+-			    ssize_t frameLeft);
+-static ssize_t collie_ct_u8(const u_char *userPtr, size_t userCount,
+-			    u_char frame[], ssize_t *frameUsed,
+-			    ssize_t frameLeft);
+ static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
+ 			     u_char frame[], ssize_t *frameUsed,
+ 			     ssize_t frameLeft);
+-static ssize_t collie_ct_u16(const u_char *userPtr, size_t userCount,
+-			     u_char frame[], ssize_t *frameUsed,
+-			     ssize_t frameLeft);
+-
+-/*** Machine definitions *****************************************************/
+-
+-
+-typedef struct {
+-	int type;
+-	void *(*dma_alloc)(unsigned int, int);
+-	void (*dma_free)(void *, unsigned int);
+-	int (*irqinit)(void);
+-#ifdef MODULE
+-	void (*irqcleanup)(void);
+-#endif /* MODULE */
+-	void (*init)(void);
+-	void (*silence)(void);
+-	int (*setFormat)(int);
+-	int (*setVolume)(int);
+-	int (*setBass)(int);
+-	int (*setTreble)(int);
+-	int (*setGain)(int);
+-	void (*play)(void);
+-} MACHINE;
+-
+ 
+ /*** Low level stuff *********************************************************/
+ 
+@@ -477,71 +238,28 @@
+ 	int stereo;		/* 0 = mono, 1 = stereo */
+ 	int size;		/* 8/16 bit*/
+ 	int speed;		/* speed */
++	int volume;
+ } SETTINGS;
+ 
+-typedef struct {
+-	ssize_t (*ct_ulaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-	ssize_t (*ct_alaw)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-	ssize_t (*ct_s8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-	ssize_t (*ct_u8)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-	ssize_t (*ct_s16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-	ssize_t (*ct_u16be)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-	ssize_t (*ct_s16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-	ssize_t (*ct_u16le)(const u_char *, size_t, u_char *, ssize_t *, ssize_t);
+-} TRANS;
+-
+-struct sound_settings {
+-	MACHINE mach;		/* machine dependent things */
+-	SETTINGS hard;		/* hardware settings */
+-	SETTINGS soft;		/* software settings */
+-	SETTINGS dsp;		/* /dev/dsp default settings */
+-	TRANS *trans;		/* supported translations */
+-	int volume_left;	/* volume (range is machine dependent) */
+-	int volume_right;
+-	int bass;		/* tone (range is machine dependent) */
+-	int treble;
+-	int gain;
+-	int minDev;		/* minor device number currently open */
+-};
+-
+-static struct sound_settings sound;
++static SETTINGS sound;
+ 
+ #ifdef CONFIG_PM
+-extern int autoPowerCancel;
++//extern int autoPowerCancel;
+ #endif
+-int collie_main_volume;
+-extern int collie_under_recording;      /* collie_buzzer.c */
+-#define COLLE_RECORDING	(collie_under_recording)
+ 
+ static void Collie_Set_Volume(int volume);
+ static int Collie_Get_Volume(void);
+-static void Collie_disable_sound(void);
+-#ifdef CONFIG_PM
+-#if 0
+-static void Collie_clock_stop(void);
+-static void Collie_FS8KLPF_stop(void);
+-#endif
+-#endif
+ static int CollieIrqInit(void);
+ static int CollieGetSamp(void);
+-static void Collie_OP_SHDN_on(void);
+-static void Collie_OP_SHDN_off(void);
+-static void Collie_FS8KLPF_start(void);
+-#ifdef MODULE
+-static void CollieIrqCleanUp(void);
+-#endif /* MODULE */
+-static void CollieSilence(void);
+ static void Collie_DAC_sendword(int);
+-static void CollieInit(void);
+ static int CollieSetFormat(int format);
+ static void Collie_sq_interrupt(void*, int);
+ static int sq_allocate_buffers(audio_stream_t*);
+ static void sq_release_buffers(audio_stream_t*);
++static inline void Collie_volume_init(void);
++static void Collie_volume_set(int);
+ 
+ /*** Mid level stuff *********************************************************/
+-static void sound_silence(void);
+-static void sound_init(void);
+-static int sound_set_format(int format);
+ static int sound_set_speed(int speed);
+ static int sound_set_stereo(int stereo);
+ 
+@@ -572,468 +290,122 @@
+ static long long sound_lseek(struct file *file, long long offset, int orig);
+ static inline int ioctl_return(int *addr, int value)
+ {
+-	ENTER(TRACE_ON,"ioctl_return");
+ 	if (value < 0) {
+-		LEAVE(TRACE_ON,"ioctl_return");
+ 		return(value);
+ 	}
+-
+-	LEAVE(TRACE_ON,"ioctl_return");
+ 	return put_user(value, addr)? -EFAULT: 0;
+ }
+ 
+-
+-/*** Config & Setup **********************************************************/
+-
+-
+-void dmasound_init(void);
+-void dmasound_setup(char *str, int *ints);
+-
+-
+-/*** Translations ************************************************************/
+-
+-
+-/* ++TeSche: radically changed for new expanding purposes...
+- *
+- * These two routines now deal with copying/expanding/translating the samples
+- * from user space into our buffer at the right frequency. They take care about
+- * how much data there's actually to read, how much buffer space there is and
+- * to convert samples into the right frequency/encoding. They will only work on
+- * complete samples so it may happen they leave some bytes in the input stream
+- * if the user didn't write a multiple of the current sample size. They both
+- * return the number of bytes they've used from both streams so you may detect
+- * such a situation. Luckily all programs should be able to cope with that.
+- *
+- * I think I've optimized anything as far as one can do in plain C, all
+- * variables should fit in registers and the loops are really short. There's
+- * one loop for every possible situation. Writing a more generalized and thus
+- * parameterized loop would only produce slower code. Feel free to optimize
+- * this in assembler if you like. :)
+- *
+- * I think these routines belong here because they're not yet really hardware
+- * independent, especially the fact that the Falcon can play 16bit samples
+- * only in stereo is hardcoded in both of them!
+- *
+- * ++geert: split in even more functions (one per format)
+- */
+-
+-static ssize_t collie_ct_law(const u_char *userPtr, size_t userCount,
+-			     u_char frame[], ssize_t *frameUsed,
+-			     ssize_t frameLeft)
+-{
+-	short *table = sound.soft.format == AFMT_MU_LAW ? ulaw2dma16: alaw2dma16;
+-	ssize_t count, used;
+-	short *p = (short *) &frame[*frameUsed];
+-	int val, stereo = sound.soft.stereo;
+-
+-	ENTER(TRACE_ON,"collie_ct_law");
+-	frameLeft >>= 2;
+-	if (stereo)
+-		userCount >>= 1;
+-	used = count = min(userCount, frameLeft);
+-	if (!COLLE_RECORDING) {
+-		while (count > 0) {
+-			u_char data;
+-			if (get_user(data, userPtr++)) {
+-				LEAVE(TRACE_ON,"collie_ct_law");
+-				return -EFAULT;
+-			}
+-			val = table[data];
+-			*p++ = val;		/* Left Ch. */
+-			if (stereo) {
+-				if (get_user(data, userPtr++)) {
+-				LEAVE(TRACE_ON,"collie_ct_law");
+-				return -EFAULT;
+-				}
+-				val = table[data];
+-			}
+-			*p++ = val;		/* Right Ch. */
+-			count--;
+-		}
+-	} else {
+-		while (count > 0) {
+-			u_char data;
+-			int ave;
+-			if (get_user(data, userPtr++)) {
+-				LEAVE(TRACE_ON,"collie_ct_law");
+-				return -EFAULT;
+-			}
+-			val = table[data];
+-			ave = val;		/* Left Ch. */
+-			if (stereo) {
+-				if (get_user(data, userPtr++)) {
+-					LEAVE(TRACE_ON,"collie_ct_law");
+-					return -EFAULT;
+-				}
+-				val = table[data];
+-			}
+-			ave += val;		/* Right Ch. */
+-			ave >>= 1;
+-			*p++ = 0;		/* Left Ch. */
+-			*p++ = ave;		/* Right Ch. */
+-			count--;
+-		}
+-	}
+-	*frameUsed += used * 4;
+-	LEAVE(TRACE_ON,"collie_ct_law");
+-	return stereo? used * 2: used;
+-}
+-
+-
+-static ssize_t collie_ct_s8(const u_char *userPtr, size_t userCount,
+-			  u_char frame[], ssize_t *frameUsed,
+-			  ssize_t frameLeft)
+-{
+-	ssize_t count, used;
+-	short *p = (short *) &frame[*frameUsed];
+-	int stereo = sound.soft.stereo;
+-	short val;
+-
+-	ENTER(TRACE_ON,"collie_ct_s8");
+-	frameLeft >>= 2;
+-	if (stereo)
+-		userCount >>= 1;
+-	used = count = min(userCount, frameLeft);
+-	if (!COLLE_RECORDING) {
+-		while (count > 0) {
+-			u_char data;
+-
+-			if (get_user(data, userPtr++)) {
+-				LEAVE(TRACE_ON,"collie_ct_s8");
+-				return -EFAULT;
+-			}
+-			val = ( data - 0x80 ) << 8;
+-			*p++ = val;		/* Left Ch. */
+-			if ( stereo ) {
+-				if ( get_user(data, userPtr++)) {
+-					LEAVE(TRACE_ON,"collie_ct_s8");
+-					return -EFAULT;
+-				}
+-				val = ( data - 0x80 ) << 8;
+-			}
+-			*p++ = val;		/* Right Ch. */
+-			count--;
+-		}
+-	} else {
+-		while (count > 0) {
+-			u_char data;
+-			int ave;
+-
+-			if (get_user(data, userPtr++)) {
+-				LEAVE(TRACE_ON,"collie_ct_s8");
+-				return -EFAULT;
+-			}
+-			val = ( data - 0x80 ) << 8;
+-			ave = val;		/* Left Ch. */
+-			if ( stereo ) {
+-				if ( get_user(data, userPtr++)) {
+-					LEAVE(TRACE_ON,"collie_ct_s8");
+-					return -EFAULT;
+-				}
+-				val = ( data - 0x80 ) << 8;
+-			}
+-			ave += val;		/* Right Ch. */
+-			ave >>= 1;
+-			*p++ = 0;		/* Left Ch. */
+-			*p++ = ave;		/* Right Ch. */
+-			count--;
+-		}
+-	}
+-	*frameUsed += used * 4;
+-	LEAVE(TRACE_ON,"collie_ct_s8");
+-	return stereo? used * 2: used;
+-}
+-
+-
+-static ssize_t collie_ct_u8(const u_char *userPtr, size_t userCount,
+-			  u_char frame[], ssize_t *frameUsed,
+-			  ssize_t frameLeft)
++static void wait_ms(int ten_ms)
+ {
+-	ssize_t count, used;
+-	short *p = (short *) &frame[*frameUsed];
+-	int stereo = sound.soft.stereo;
+-	short val;
+-
+-	ENTER(TRACE_ON,"collie_ct_u8");
+-	frameLeft >>= 2;
+-	if (stereo)
+-		userCount >>= 1;
+-	used = count = min(userCount, frameLeft);
+-	if (!COLLE_RECORDING) {
+-		while (count > 0) {
+-			u_char data;
+-
+-			if (get_user(data, userPtr++)) {
+-				LEAVE(TRACE_ON,"collie_ct_u8");
+-				return -EFAULT;
+-			}
+-			val = data;
+-			*p++ = (val ^ 0x80) << 8;		/* Left Ch. */
+-			if ( stereo ) {
+-				if ( get_user(data, userPtr++)) {
+-					LEAVE(TRACE_ON,"collie_ct_u8");
+-					return -EFAULT;
+-				}
+-				val = data;
+-			}
+-			*p++ = (val ^ 0x80) << 8;		/* Right Ch. */
+-			count--;
+-		}
+-	} else {
+-		while (count > 0) {
+-			u_char data;
+-			int ave;
+-
+-			if (get_user(data, userPtr++)) {
+-				LEAVE(TRACE_ON,"collie_ct_u8");
+-				return -EFAULT;
+-			}
+-			val = data;
+-			ave = (val ^ 0x80) << 8;		/* Left Ch. */
+-			if ( stereo ) {
+-				if ( get_user(data, userPtr++)) {
+-					LEAVE(TRACE_ON,"collie_ct_u8");
+-					return -EFAULT;
+-				}
+-				val = data;
+-			}
+-			ave += (val ^ 0x80) << 8;		/* Right Ch. */
+-			ave >>= 1;
+-			*p++ = 0;			/* Left Ch. */
+-			*p++ = ave;			/* Right Ch. */
+-			count--;
+-		}
+-	}
+-	*frameUsed += used * 4;
+-	LEAVE(TRACE_ON,"collie_ct_u8");
+-	return stereo? used * 2: used;
++	schedule_timeout(ten_ms);
+ }
+ 
++/*** Translation ************************************************************/
+ 
+ static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
+ 			   u_char frame[], ssize_t *frameUsed,
+ 			   ssize_t frameLeft)
+ {
+ 	ssize_t count, used;
+-	int stereo = sound.soft.stereo;
+ 	short *fp = (short *) &frame[*frameUsed];
++	short *up = (short *) userPtr;
+ 
+-	ENTER(TRACE_ON,"collie_ct_s16");
+ 	frameLeft >>= 2;
+-	userCount >>= (stereo? 2: 1);
+-	used = count = min(userCount, frameLeft);
+-	if (!stereo) {
+-		short *up = (short *) userPtr;
+-		while (count > 0) {
+-			short data;
+-			if (get_user(data, up++)) {
+-				LEAVE(TRACE_ON,"collie_ct_s16");
+-				return -EFAULT;
+-			}
+-			*fp++ = (!COLLE_RECORDING) ? data : 0;	/* Left Ch. */
+-			*fp++ = data;
+-			count--;
++	userCount >>= 2;
++	used = count = (userCount < frameLeft) ? userCount : frameLeft;
++	
++	while (count > 0) {
++
++		short data;
++		if (get_user(data, up++)) {
++			return -EFAULT;
+ 		}
+-	} else {
+-		short *up = (short *) userPtr;
+-		while (count > 0) {
+-			short data;
+-			short temp;
+-			if (get_user(data, up++)) {
+-				LEAVE(TRACE_ON,"collie_ct_s16");
+-				return -EFAULT;
+-			}
+-			if (get_user(temp, up++)) {
+-				LEAVE(TRACE_ON,"collie_ct_s16");
+-				return -EFAULT;
+-			}
+-			if (!COLLE_RECORDING) {
+-				*fp++ = data;		/* Left Ch. */
+-				*fp++ = temp;		/* Right Ch. */
+-			} else {
+-				data >>= 1;
+-				data += (temp >> 1);
+-				*fp++ = 0;		/* Left Ch. */
+-				*fp++ = data;		/* Right Ch. */
+-			}
+-			count--;
++		if (!collie_recording) *fp++ = data;		
++		else *fp++=0;
++		
++		if (get_user(data, up++)) {
++			return -EFAULT;
+ 		}
++		*fp++ = data;		
++		count--;
+ 	}
++	
+ 	*frameUsed += used * 4;
+-	LEAVE(TRACE_ON,"collie_ct_s16");
+-	return stereo? used * 4: used * 2;
++	return used * 4;
+ }
+ 
+-static ssize_t collie_ct_u16(const u_char *userPtr, size_t userCount,
+-			   u_char frame[], ssize_t *frameUsed,
+-			   ssize_t frameLeft)
+-{
+-	ssize_t count, used;
+-	int mask = (sound.soft.format == AFMT_U16_LE? 0x0080: 0x8000);
+-	int stereo = sound.soft.stereo;
+-	short *fp = (short *) &frame[*frameUsed];
+-	short *up = (short *) userPtr;
++/*** HARDWARE dependent stuff *********************************************************/
+ 
+-	ENTER(TRACE_ON,"collie_ct_u16");
+-	frameLeft >>= 2;
+-	userCount >>= (stereo? 2: 1);
+-	used = count = min(userCount, frameLeft);
+-	if (!COLLE_RECORDING) {
+-		while (count > 0) {
+-			int data;
+-			int temp;
+-			if (get_user(data, up++)) {
+-				LEAVE(TRACE_ON,"collie_ct_u16");
+-				return -EFAULT;
+-			}
+-			data ^= mask;
+-			*fp++ = data;			/* Left Ch. */
+-			if (stereo) {
+-				if (get_user(temp, up++)) {
+-					LEAVE(TRACE_ON,"collie_ct_u16");
+-					return -EFAULT;
+-				}
+-				temp ^= mask;
+-				data  = temp;
+-				data ^= mask;
+-			}
+-			*fp++ = data;			/* Right Ch. */
+-			count--;
+-		}
++static inline void Collie_DAC_sendbit(int bit_data)
++{
++	if (bit_data & 1) {
++		LCM_GPO |=  (LCM_GPIO_DAC_SDATA);
+ 	} else {
+-		while (count > 0) {
+-			int data;
+-			int temp;
+-			int ave;
+-			if (get_user(data, up++)) {
+-				LEAVE(TRACE_ON,"collie_ct_u16");
+-				return -EFAULT;
+-			}
+-			data ^= mask;
+-			ave = data;			/* Left Ch. */
+-			if (stereo) {
+-				if (get_user(temp, up++)) {
+-					LEAVE(TRACE_ON,"collie_ct_u16");
+-					return -EFAULT;
+-				}
+-				temp ^= mask;
+-				data  = temp;
+-				data ^= mask;
+-			}
+-			ave += data;
+-			ave >>= 1;
+-			*fp++ = 0;			/* Left Ch. */
+-			*fp++ = ave;			/* Right Ch. */
+-			count--;
+-		}
++		LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
+ 	}
+-	*frameUsed += used * 4;
+-	LEAVE(TRACE_ON,"collie_ct_u16");
+-	return stereo? used * 4: used * 2;
+-}
+ 
+-static TRANS transCollie = {
+-	collie_ct_law, collie_ct_law, collie_ct_s8, collie_ct_u8,
+-	collie_ct_s16, collie_ct_u16, collie_ct_s16, collie_ct_u16
+-};
++	udelay(1);
++	LCM_GPO |=  (LCM_GPIO_DAC_SCK);
+ 
+-/*** Low level stuff *********************************************************/
++	udelay(1);
++	LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
++	udelay(1);
++	LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
++	udelay(1);
++}
+ 
+-static void Collie_Set_Volume(int volume)
++static void Collie_DAC_sendword(int data)
+ {
+-	ENTER(TRACE_ON,"Collie_Set_Volume");
+-
+-	sound.volume_left = volume & 0xff;
+-	if ( sound.volume_left > 100 ) sound.volume_left = 100;
+-
+-	collie_main_volume = sound.volume_left;
+-
+-	sound.volume_right = ( volume & 0xff00 >> 8);
+-	if ( sound.volume_right > 100 ) sound.volume_right = 100;
+-	LEAVE(TRACE_ON,"Collie_Set_Volume");
++	int i;
+ 
+-	collie_buzzer_volume = sound.volume_right;
++#if defined(CONFIG_COLLIE_PCM1741)
++	
++	LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
++	udelay(1);
++	LCM_GPO |=  (LCM_GPIO_DAC_SLOAD);
++	udelay(1);
+ 
+-}
++	for (i = 0; i < 16; i++)
++		Collie_DAC_sendbit(data >> (15 - i));
+ 
++	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
++	udelay(2);
+ 
+-static int Collie_Get_Volume(void)
+-{
+-	ENTER(TRACE_ON,"Collie_Get_Volume");
+-	LEAVE(TRACE_ON,"Collie_Get_Volume");
+-	return ( sound.volume_right << 8 | sound.volume_left );
+-}
++#elif defined(CONFIG_COLLIE_PCM1717)
++	
++	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
++	udelay(1000);
++	LCM_GPO |=  (LCM_GPIO_DAC_SLOAD);
++	udelay(1000);
++	LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
++	udelay(1000);
+ 
+-static void wait_ms(int ten_ms)
+-{
+-	ENTER(TRACE_ON,"wait_ms");
+-	LEAVE(TRACE_ON,"wait_ms");
+-	schedule_timeout(ten_ms);
+-}
++	for (i = 0; i < 16; i++)
++		Collie_DAC_sendbit(data >> (15 - i));
+ 
+-static inline void Collie_AMP_off(void)
+-{
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_AMP,"Collie_AMP_off");
+-#if 0	/* OBSOLETED: power controled by only OP_SHDN */
+-	/* Set up TC35143 GPIO I/O Direction (GPIO4 output mode) */
+-	ucb1200_set_io_direction(TC35143_GPIO_AMP_ON,
+-				 TC35143_IODIR_OUTPUT);
+- 	/* AMP OFF */
+-	ucb1200_set_io(TC35143_GPIO_AMP_ON,
+-		       TC35143_IODAT_LOW);
+-	collie_amp_init = 0;
+-#endif	/* 0 */
+-	LEAVE(TRACE_AMP,"Collie_AMP_off");
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
+-}
+-
+-static inline void Collie_AMP_on(void)
+-{
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_AMP,"Collie_AMP_on");
+-//	if (!collie_amp_init) {
+-		/* Set up TC35143 GPIO I/O Direction (GPIO4 output mode) */
+-		ucb1200_set_io_direction(TC35143_GPIO_AMP_ON,
+-					 TC35143_IODIR_OUTPUT);
+-		/* AMP ON */
+-		ucb1200_set_io(TC35143_GPIO_AMP_ON, TC35143_IODAT_HIGH);
+-		SCP_REG_GPWR |= SCP_AMP_ON;
+-		wait_ms(COLLIE_WAIT_AMP_ON);
+-		collie_amp_init = 1;
+-//	}
+-	LEAVE(TRACE_AMP,"Collie_AMP_on");
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
++	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
++	udelay(1000);
++	LCM_GPO |=  (LCM_GPIO_DAC_SLOAD);
++	udelay(1000);
++	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
++	udelay(1000);
++#endif
+ }
+ 
+-static inline void Collie_AMP_init(void)
+-{
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_AMP,"Collie_AMP_init");
+-  	Collie_AMP_off();
+-	LEAVE(TRACE_AMP,"Collie_AMP_init");
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
+-}
+ 
+ static inline void Collie_DAC_off(void)
+ {
+-	ENTER(TRACE_DAC,"Collie_DAC_off");
+-	if (!COLLE_RECORDING) {
+-		/* DAC OFF */
+-		LCM_GPD &= ~(LCM_GPIO_DAC_ON);	/* set up output */
+-		LCM_GPO &= ~(LCM_GPIO_DAC_ON);
+-
+-		/* LoCoMo GPIO disable */
+-		LCM_GPE &= ~(LCM_GPIO_DAC_ON);
+-		collie_dac_init = 0;
+-	}
+-	LEAVE(TRACE_DAC,"Collie_DAC_off");
++	/* DAC OFF */
++	LCM_GPD &= ~(LCM_GPIO_DAC_ON);	/* set up output */
++	LCM_GPO &= ~(LCM_GPIO_DAC_ON);
++	/* LoCoMo GPIO disable */
++	LCM_GPE &= ~(LCM_GPIO_DAC_ON);
++	collie_dac_init = 0;
+ }
+ 
+ static inline void Collie_DAC_on(void)
+ {
+-	ENTER(TRACE_DAC,"Collie_DAC_on");
+-//	if (!collie_dac_init) {
+ 	if (!(LCM_GPO & LCM_GPIO_DAC_ON)) {
+ 		/* LoCoMo GPIO enable */
+ 		LCM_GPE &= ~LCM_GPIO_DAC_ON;
+@@ -1049,24 +421,10 @@
+ 		    schedule();
+ 		}
+ 	}
+-//	}
+-	LEAVE(TRACE_DAC,"Collie_DAC_on");
+-}
+-
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP */
+-static inline void Collie_DAC_delay_off(void)
+-{
+-	ENTER(TRACE_DAC,"Collie_DAC_deleay_off");
+-	down(&df_sem);
+-	SetDelay(DELAY_DAC_OFF);
+-	up(&df_sem);
+-	LEAVE(TRACE_DAC,"Collie_DAC_delay_off");
+ }
+-#endif
+ 
+ static inline void Collie_DAC_init(void)
+ {
+-	ENTER(TRACE_DAC,"Collie_DAC_init");
+ 	/* LoCoMo GPIO enable */
+ 	LCM_GPE &=
+ 	  ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD);
+@@ -1075,7 +433,6 @@
+ 	  ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD);
+ 
+ #if defined(CONFIG_COLLIE_PCM1741)
+-
+ 	Collie_DAC_sendword(DAC_REG16_SetupData);	/* register16 */
+ 	Collie_DAC_sendword(DAC_REG17_SetupData);	/* register17 */
+ 	Collie_DAC_sendword(DAC_REG18_SetupData);	/* register18 */
+@@ -1083,78 +440,53 @@
+ 	Collie_DAC_sendword(DAC_REG20_SetupData);	/* register20 */
+ ////	Collie_DAC_sendword(DAC_REG21_SetupData);	/* register21 */
+ 	Collie_DAC_sendword(DAC_REG22_SetupData);	/* register22 */
+-
+ #elif defined(CONFIG_COLLIE_PCM1717)
+-
+ 	Collie_DAC_sendword(DAC_MODE0_SetupData);	/* MODE0 */
+ 	Collie_DAC_sendword(DAC_MODE1_SetupData);	/* MODE1 */
+ 	Collie_DAC_sendword(DAC_MODE2_SetupData);	/* MODE2 */
+ 	Collie_DAC_sendword(DAC_MODE3_SetupData);	/* MODE3 */
+-
+ #endif
+-
+ 	/* LoCoMo GPIO disable */
+ 	LCM_GPE &=
+ 	  ~(LCM_GPIO_DAC_SDATA | LCM_GPIO_DAC_SCK | LCM_GPIO_DAC_SLOAD);
+-	LEAVE(TRACE_DAC,"Collie_DAC_init");
+ }
+ 
+ static inline void Collie_soft_DAC_on(void)
+ {
+ #if defined(CONFIG_COLLIE_PCM1741)
+-	ENTER(TRACE_DAC, "Collie_soft_DAC_on");
+ 	Collie_DAC_sendword(DAC_REG19_DACOn);	/* register19 */
+-	LEAVE(TRACE_DAC, "Collie_soft_DAC_on");
+ #endif	/* CONFIG_COLLIE_PCM1741 */
+ }
+ 
+ static inline void Collie_soft_DAC_off(void)
+ {
+ #if defined(CONFIG_COLLIE_PCM1741)
+-	ENTER(TRACE_DAC, "Collie_soft_DAC_off");
+        	Collie_DAC_sendword(DAC_REG19_DACOff);	/* register19 */
+-	LEAVE(TRACE_DAC, "Collie_soft_DAC_off");
+-#endif	/* CONFIG_COLLIE_PCM1741 */
+-}
+-
+-static inline void Collie_soft_mute_init(void)
+-{
+-#if defined(CONFIG_COLLIE_PCM1741)
+-	ENTER(TRACE_MUTE, "Collie_soft_mute_init");
+-	Collie_DAC_sendword(DAC_REG18_MuteOn);	/* register18 */
+-	collie_soft_mute = 1;
+-	LEAVE(TRACE_MUTE, "Collie_soft_mute_init");
+ #endif	/* CONFIG_COLLIE_PCM1741 */
+ }
+ 
+ static inline void Collie_soft_mute_on(void)
+ {
+ #if defined(CONFIG_COLLIE_PCM1741)
+-	ENTER(TRACE_MUTE, "Collie_soft_mute_on");
+ 	if (!collie_soft_mute) {
+ 		Collie_DAC_sendword(DAC_REG18_MuteOn);	/* register18 */
+ 		collie_soft_mute = 1;
+ 	}
+-	LEAVE(TRACE_MUTE, "Collie_soft_mute_on");
+ #endif	/* CONFIG_COLLIE_PCM1741 */
+ }
+ 
+ static inline void Collie_soft_mute_off(void)
+ {
+ #if defined(CONFIG_COLLIE_PCM1741)
+-	ENTER(TRACE_MUTE, "Collie_soft_mute_off");
+ 	if (collie_soft_mute) {
+ 		Collie_DAC_sendword(DAC_REG18_MuteOff);	/* register18 */
+ 		collie_soft_mute = 0;
+ 	}
+-	LEAVE(TRACE_MUTE, "Collie_soft_mute_off");
+ #endif	/* CONFIG_COLLIE_PCM1741 */
+ }
+ 
+ static inline void Collie_hard_mute_init(void)
+ {
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_MUTE, "Collie_hard_mute_init");
+ 	SCP_REG_GPCR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15);
+ #ifdef HARD_MUTE_CTRL_DISABLE
+ 	SCP_REG_GPWR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15);
+@@ -1162,84 +494,107 @@
+ 	SCP_REG_GPWR &= ~(SCP_GPCR_PA14 | SCP_GPCR_PA15);
+ #endif	/* HARD_MUTE_CTRL_DISABLE */
+ 	collie_hard_mute = 1;
+-#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
++
+ 	{
+ 		int time = jiffies + 5;
+ 		while (jiffies <= time)
+ 			schedule();
+ 	}
+-#endif
+-	LEAVE(TRACE_MUTE, "Collie_hard_mute_init");
+-#endif	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+ }
+ 
+ static inline void Collie_hard_mute_on(void)
+ {
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
+ #ifndef HARD_MUTE_CTRL_DISABLE
+-	ENTER(TRACE_MUTE, "Collie_hard_mute_on");
+ 	if (!collie_hard_mute) {
+ 		SCP_REG_GPWR &= ~(SCP_GPCR_PA14 | SCP_GPCR_PA15);
+ 		collie_hard_mute = 1;
+-#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
+ 		{
+ 			int time = jiffies + 5;
+ 			while (jiffies <= time)
+ 				schedule();
+ 		}
+-#endif
+ 	}
+-	LEAVE(TRACE_MUTE, "Collie_hard_mute_on");
+ #endif	/* HARD_MUTE_CTRL_DISABLE */
+-#endif	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+ }
+ 
+ static inline void Collie_hard_mute_off(void)
+ {
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
+ #ifndef HARD_MUTE_CTRL_DISABLE
+-	ENTER(TRACE_MUTE, "Collie_hard_mute_off");
+ 	if (collie_hard_mute) {
+-		if (!COLLE_RECORDING)
+ 			SCP_REG_GPWR |= (SCP_GPCR_PA14 | SCP_GPCR_PA15);
+-		else
+-			SCP_REG_GPWR |= (SCP_GPCR_PA15);
+ 		collie_hard_mute = 0;
+-#if !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
+ 		{
+ 			int i;
+ 			for (i=0; i<=1000; i++) {
+ 				udelay(1);
+ 			}
+ 		}
+-#endif
+ 	}
+-	LEAVE(TRACE_MUTE, "Collie_hard_mute_off");
+ #endif	/* HARD_MUTE_CTRL_DISABLE */
+-#endif	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+-}
+-
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.19 */
+-static inline void Collie_hard_mute_delay_on(void)
+-{
+-	ENTER(TRACE_MUTE, "Collie_hard_mute_delay_on");
+-	down(&df_sem);
+-	SetDelay(DELAY_HARD_MUTE_ON);
+-	up(&df_sem);
+-	LEAVE(TRACE_MUTE, "Collie_hard_mute_delay_on");
+ }
+-#endif
+ 
+-static inline void Collie_audio_clock_init(void)
++static inline void Collie_hard_mute_left_on(void)
++{
++#ifndef HARD_MUTE_CTRL_DISABLE
++//	if (!collie_hard_mute) {
++		SCP_REG_GPWR &= ~(SCP_GPCR_PA14);
++		{
++			int time = jiffies + 5;
++			while (jiffies <= time)
++				schedule();
++		}
++//	}
++#endif	/* HARD_MUTE_CTRL_DISABLE */
++}
++
++static inline void Collie_hard_mute_left_off(void)
++{
++#ifndef HARD_MUTE_CTRL_DISABLE
++//	if (collie_hard_mute) {
++		SCP_REG_GPWR |= (SCP_GPCR_PA14);
++		{
++			int i;
++			for (i=0; i<=1000; i++) {
++				udelay(1);
++			}
++		}
++//	}
++#endif	/* HARD_MUTE_CTRL_DISABLE */
++}
++
++
++static int CollieGetSamp(void)
++{
++	switch (sound.speed) {
++	case 8000:
++	  	return clock_set_data[7];
++	case 44100:
++	  	return clock_set_data[0];
++	case 22050:
++	  	return clock_set_data[1];
++	case 11025:
++	  	return clock_set_data[2];
++	case 48000:
++	  	return clock_set_data[3];
++	case 32000:
++	  	return clock_set_data[4];
++	case 24000:
++	  	return clock_set_data[5];
++	case 16000:
++	  	return clock_set_data[6];
++	default:
++		printk("Collie sound: Illegal sound rate %d\n", sound.speed);
++		return clock_set_data[7];
++	}
++}
++
++static inline void Collie_audio_clock_init(void)
+ {
+-	ENTER(TRACE_CLOCK, "Collie_audio_clock_init");
+ 	LCM_ACC = 0;
+-	LEAVE(TRACE_CLOCK, "Collie_audio_clock_init");
+ }
+ 
+ static inline void Collie_audio_clock_on(void)
+ {
+-	ENTER(TRACE_CLOCK, "Collie_audio_clock_on");
+ 	/* LoCoMo Audio clock on */
+ 	LCM_ACC  = CollieGetSamp();
+ 	barrier();
+@@ -1248,263 +603,58 @@
+ 	LCM_ACC |= LCM_ACC_XEN;
+ 	barrier();
+ 	LCM_ACC |= (LCM_ACC_MCLKEN | LCM_ACC_64FSEN);
+-	LEAVE(TRACE_CLOCK, "Collie_audio_clock_on");
+ }
+ 
+ static inline void Collie_audio_clock_off(void)
+ {
+-	ENTER(TRACE_CLOCK, "Collie_audio_clock_off");
+ 	/* LoCoMo Audio clock off */
+ 	LCM_ACC &= ~(LCM_ACC_XEN | LCM_ACC_MCLKEN | LCM_ACC_64FSEN);
+ 	barrier();
+ 	LCM_ACC &= ~(LCM_ACC_XON);
+-	LEAVE(TRACE_CLOCK, "Collie_audio_clock_off");
+-}
+-
+-static inline void Collie_paif_init(void)
+-{
+-	ENTER(TRACE_PAIF, "Collie_paif_init");
+-	//	LCM_PAIF  = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST);
+-	LCM_PAIF  = (LCM_PAIF_LRCRST);
+-	LEAVE(TRACE_PAIF, "Collie_paif_init");
+ }
+ 
+ static inline void Collie_paif_on(void)
+ {
+-	ENTER(TRACE_PAIF, "Collie_paif_on");
+ 	LCM_PAIF  = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST);
+ 	LCM_PAIF &= ~(LCM_PAIF_LRCRST);
+ 	LCM_PAIF |= (LCM_PAIF_SCEN | LCM_PAIF_LRCEN);
+-	LEAVE(TRACE_PAIF, "Collie_paif_on");
+ }
+ 
+ static inline void Collie_paif_off(void)
+ {
+-	ENTER(TRACE_PAIF, "Collie_paif_off");
+-	//	LCM_PAIF  = (LCM_PAIF_SCINV | LCM_PAIF_LRCRST);
+ 	LCM_PAIF  = (LCM_PAIF_LRCRST);
+-	LEAVE(TRACE_PAIF, "Collie_paif_off");
+ }
+ 
+ static inline void Collie_MIC_init(void)
+ {
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_MIC, "Collie_MIC_init");
+ 	/* MIC to GPIO 17 */
+ 	/* alternate functions for the GPIOs */
+-	GAFR &= ~( COLLIE_GPIO_MIC );
+-	
++	GAFR &= ~( COLLIE_GPIO_MIC );	
+ 	/* Set the direction: 17 output */
+ 	GPDR |= ( COLLIE_GPIO_MIC );
+-	
+-#if defined(CONFIG_COLLIE_TR1)
+-	/* Set pin level (Low) */
+-       	GPCR = ( COLLIE_GPIO_MIC );
+-#else
+ 	/* Set pin level (High) */
+        	GPSR = ( COLLIE_GPIO_MIC );
+-#endif
+-	LEAVE(TRACE_MIC, "Collie_MIC_init");
+-#endif	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+ }
+ 
+ static inline void Collie_MIC_on(void)
+ {
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_MIC, "Collie_MIC_on");
+-#if defined(CONFIG_COLLIE_TR1)
+-	GPSR = ( COLLIE_GPIO_MIC );
+-#else
+ 	GPCR = ( COLLIE_GPIO_MIC );
+-#endif
+-	LEAVE(TRACE_MIC, "Collie_MIC_on");
+-#endif	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+ }
+ 
+ static inline void Collie_MIC_off(void)
+ {
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_MIC, "Collie_MIC_off");
+-	if (!COLLE_RECORDING) {
+-#if defined(CONFIG_COLLIE_TR1)
+-	       	GPCR = ( COLLIE_GPIO_MIC );
+-#else
+-       		GPSR = ( COLLIE_GPIO_MIC );
+-#endif
+-	}
+-	LEAVE(TRACE_MIC, "Collie_MIC_off");
+-#endif	/* !CONFIG_COLLIE_TS && !CONFIG_COLLIE_TR0 */
+-}
+-
+-static inline void Collie_volume_init(void)
+-{
+-	ENTER(TRACE_VOLUME, "Collie_volume_init");
+-	m62332_senddata(0, M62332_EVR_CH);
+-	collie_volume = 0;
+-	LEAVE(TRACE_VOLUME, "Collie_volume_init");
+-}
+-
+-static inline void Collie_volume_on(void)
+-{
+-	ENTER(TRACE_VOLUME, "Collie_volume_on");
+-	if (collie_volume != sound.volume_left) {
+-		//Collie_hard_mute_on();
+-		m62332_senddata(0xff * sound.volume_left / 100, M62332_EVR_CH);
+-		//Collie_hard_mute_off();
+-		collie_volume = sound.volume_left;
+-	}
+-	LEAVE(TRACE_VOLUME, "Collie_volume_on");
+-}
+-
+-static inline void Collie_volume_off(void)
+-{
+-	ENTER(TRACE_VOLUME, "Collie_volume_off");
+-	if (collie_volume) {
+-		//Collie_hard_mute_on();
+-		m62332_senddata(0, M62332_EVR_CH);
+-		//Collie_hard_mute_off();
+-		collie_volume = 0;
+-	}
+-	LEAVE(TRACE_VOLUME, "Collie_volume_off");
+-}
+-
+-#define	VOL_THRES	40
+-static void Collie_volume_half_adjust(void)
+-{
+-	int	volume = collie_volume;
+-	ENTER(TRACE_VOLUME, "Collie_volume_half_adjust");
+-	if (collie_volume > sound.volume_left) {
+-		/* volume down */
+-		if (collie_volume > VOL_THRES) {
+-			if (sound.volume_left > VOL_THRES) {
+-				volume = (collie_volume + sound.volume_left)/2;
+-				if (volume == collie_volume) {
+-					volume = sound.volume_left;
+-				}
+-			} else {
+-				volume = (collie_volume + VOL_THRES)/2;
+-				if (volume == collie_volume) {
+-					volume = VOL_THRES;
+-				}
+-			}
+-		} else {
+-			/* we can pull down without noise */
+-			volume = sound.volume_left;
+-		}
+-	} else if (collie_volume < sound.volume_left) {
+-		/* volume up */
+-		if (sound.volume_left > VOL_THRES) {
+-			if (collie_volume < VOL_THRES) {
+-				/* we can pull up to VOL_THRES without noise */
+-				volume = VOL_THRES;;
+-			} else {
+-				volume = (collie_volume + sound.volume_left)/2;
+-				if (volume == collie_volume) {
+-					volume = sound.volume_left;
+-				}
+-			}
+-		} else {
+-			/* we can pull up without noise */
+-			volume = sound.volume_left;
+-		}
+-	}
+-	if (collie_volume != volume) {
+-		m62332_senddata(0xff * volume / 100, M62332_EVR_CH);
+-		collie_volume = volume;
+-	}
+-	LEAVE(TRACE_VOLUME, "Collie_volume_half_adjust");
+-}
+-
+-static void Collie_volume_half_off(void)
+-{
+-	int volume;
+-	int delta = 1;
+-	ENTER(TRACE_VOLUME, "Collie_volume_half_off");
+-	while (0 < collie_volume) {
+-		if (collie_volume <= VOL_THRES) {
+-			volume = 0;
+-		} else {
+-			if (collie_volume > delta) {
+-				volume = collie_volume - delta;
+-			} else {
+-				volume = 0;
+-			}
+-			if (volume && volume < VOL_THRES) {
+-				volume = VOL_THRES;
+-			}
+-			delta <<= 1;
+-		}
+-		m62332_senddata(0xff * volume / 100, M62332_EVR_CH);
+-		collie_volume = volume;
+-		udelay(100);
+-	}
+-	LEAVE(TRACE_VOLUME, "Collie_volume_half_off");
+-}
+-
+-static void Collie_OP_SHDN_on(void)
+-{
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_OP_SHDN,"Collie_OP_SHDN_on");
+-	if (!collie_op_shdn_on) {
+-		/* set volume */
+-		Collie_volume_off();
+-
+-		/* OP_SHDN to GPIO 17 */
+-		/* alternate functions for the GPIOs */
+-		GAFR &= ~( COLLIE_GPIO_OPSHDN );
+-	
+-		/* Set the direction: 17 output */
+-		GPDR |= ( COLLIE_GPIO_OPSHDN );
+-	
+-		/* Set pin level (high) */
+-		GPSR |= ( COLLIE_GPIO_OPSHDN );
+-		
+-		/* set volume */
+-		Collie_volume_on();
+-
+-		collie_op_shdn_on = 1;
+-	}
+-	LEAVE(TRACE_OP_SHDN,"Collie_OP_SHDN_on");
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
+-}
+-
+-static void Collie_OP_SHDN_off(void)
+-{
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_OP_SHDN,"Collie_OP_SHDN_off");
+-	/* OP_SHDN to GPIO 17 */
+-	/* alternate functions for the GPIOs */
+-	GAFR &= ~( COLLIE_GPIO_OPSHDN );
+-	
+-	/* Set the direction: 17 output */
+-	GPDR |= ( COLLIE_GPIO_OPSHDN );
+-	
+-	/* Clear pin level (low) */
+-	GPCR |= ( COLLIE_GPIO_OPSHDN );
+-
+-	collie_op_shdn_on = 0;
+-	LEAVE(TRACE_OP_SHDN,"Collie_OP_SHDN_off");
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
++ 	GPSR = ( COLLIE_GPIO_MIC );
+ }
+ 
+ static inline void Collie_ssp_init(void)
+ {
+-	ENTER(TRACE_SSP, "Collie_ssp_init");
+ 	/* alternate functions for the GPIOs */
+ 	/* SSP port to GPIO 10,12,13, 19 */
+ 	GAFR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM | GPIO_SSP_CLK );
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	/* SSP port to GPIO 11 */
+-	GAFR |= GPIO_SSP_RXD;
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
+ 
+ 	/* Set the direction: 10, 12, 13 output; 19 input */
+ 	GPDR |= ( GPIO_SSP_TXD | GPIO_SSP_SCLK | GPIO_SSP_SFRM );
+ 	GPDR &= ~( GPIO_SSP_CLK );
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	/* Set the direction: 11 input */
+-	GPDR &= ~( GPIO_SSP_RXD );
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
+ 
+ 	/* enable SSP pin swap */
+ 	PPAR |= PPAR_SPR;
+@@ -1516,400 +666,162 @@
+ 	/* the SSP setting */
+ 	Ser4SSCR0 = (SSCR0_DataSize(16) | SSCR0_TI | SSCR0_SerClkDiv(2));
+ 	Ser4SSCR1 = (SSCR1_SClkIactL | SSCR1_SClk1P | SSCR1_ExtClk);
+-
+-	LEAVE(TRACE_SSP, "Collie_ssp_init");
+ }
+ 
+ static inline void Collie_ssp_on(void)
+ {
+-	ENTER(TRACE_SSP, "Collie_ssp_on");
+ 	/* turn on the SSP */
+ 	Ser4SSCR0 |= ( SSCR0_SSE );
+-	LEAVE(TRACE_SSP, "Collie_ssp_on");
+ }
+ 
+ static inline void Collie_ssp_off(void)
+ {
+-	ENTER(TRACE_SSP, "Collie_ssp_off");
+ 	/* turn off the SSP */
+ 	Ser4SSCR0 &= ~( SSCR0_SSE );
+-	LEAVE(TRACE_SSP, "Collie_ssp_off");
+-}
+-
+-static inline void Collie_sound_hard_init(void)
+-{
+-	ENTER(TRACE_ON, "Collie_sound_hard_init");
+-	Collie_hard_mute_init();
+-	Collie_audio_clock_init();
+-	Collie_paif_init();
+-	Collie_volume_init();
+-	Collie_ssp_init();
+-	Collie_MIC_init();
+-
+-	Collie_FS8KLPF_start();
+-	LEAVE(TRACE_ON, "Collie_sound_hard_init");
+-}
+-
+-static inline void Collie_sound_hard_term(void)
+-{
+-	ENTER(TRACE_ON, "Collie_sound_hard_term");
+-#ifdef DAC_OFF_WITH_DEVICE_OFF
+-	/* DAC Off */
+-	Collie_DAC_off();
+-#endif
+-	LEAVE(TRACE_ON, "Collie_sound_hard_term");
+-}
+-
+-static void Collie_FS8KLPF_start(void)
+-{
+-#if defined(CONFIG_COLLIE_TS) || defined(CONFIG_COLLIE_TR0)
+-	ENTER(TRACE_ON,"Collie_FS8KLPF_start");
+-	/* Set up TC35143 GPIO I/O Direction (GPIO5 output mode) */
+-	ucb1200_set_io_direction(TC35143_GPIO_FS8KLPF,
+-				 TC35143_IODIR_OUTPUT);
+-	/* Set up TC35143 GPIO 5 (set LOW) */
+-	ucb1200_set_io(TC35143_GPIO_FS8KLPF, TC35143_IODAT_LOW);
+-	LEAVE(TRACE_ON,"Collie_FS8KLPF_start");
+-#endif	/* CONFIG_COLLIE_TS || CONFIG_COLLIE_TR0 */
+-}
+-
+-#ifdef CONFIG_PM
+-#if 0
+-static void Collie_FS8KLPF_stop(void)
+-{
+-	/* Set up TC35143 GPIO I/O Direction (GPIO5 output mode) */
+-	ucb1200_set_io_direction(TC35143_GPIO_FS8KLPF,
+-				 TC35143_IODIR_OUTPUT);
+-	/* Set up TC35143 GPIO 5 (set LOW) */
+-	ucb1200_set_io(TC35143_GPIO_FS8KLPF, TC35143_IODAT_HIGH);
+-}
+-
+-static void Collie_clock_stop(void)
+-{
+-	/* LoCoMo PCM audio interface */
+-	Collie_paif_off();
+-
+-	/* LoCoMo audio clock off */
+-	Collie_audio_clock_off();
+-}
+-#endif
+-#endif
+-
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.19 */
+-static unsigned long in_timehandle = 0;
+-static struct timer_list timer;
+-
+-static void collieDoDelayedSilence(void)
+-{
+-	ENTER(TRACE_ON,"collieDoDelayedSilence");
+-	down(&df_sem);
+-	if(isDelayed(DELAY_HARD_MUTE_ON)) {
+-		Collie_hard_mute_on();
+-	}
+-	if(isDelayed(DELAY_DAC_OFF)) {
+-		Collie_DAC_off();
+-	}
+-	ResetDelayAll();
+-	up(&df_sem);
+-	LEAVE(TRACE_ON,"colliDoDelayedSilence");
+-}
+-
+-static void collieDelayedSilence(void)
+-{
+-	ENTER(TRACE_ON,"collieDelayedSilence");
+-	while (1) {
+-		sleep_on(&delay_off);
+-		collieDoDelayedSilence();
+-	}
+-	LEAVE(TRACE_ON,"collieDelayedSilence");
+-}
+-
+-static void collieStartDelayedSilence(unsigned long data)
+-{
+-	ENTER(TRACE_ON,"collieStartDelayedSilence");
+-	in_timehandle = 0;
+-	wake_up(&delay_off);
+-	LEAVE(TRACE_ON,"collieStartDelayedSilence");
+-}
+-
+-static void collieTriggerDelayedSilence(void)
+-{
+-	ENTER(TRACE_ON,"collieTriggerDelayedSilence");
+-	in_timehandle = 1;
+-	init_timer(&timer);
+-	timer.function = collieStartDelayedSilence;
+-	timer.expires = jiffies + 5*100;
+-	add_timer(&timer);
+-	LEAVE(TRACE_ON,"collieTriggerDelayedSilence");
+-}
+-
+-static void collieCancelDelayedSilence(void)
+-{
+-	ENTER(TRACE_ON,"collieCancelDelayedSilence");
+-	down(&df_sem);
+-	ResetDelayAll();;
+-	up(&df_sem);
+-	if (in_timehandle) {
+-		del_timer(&timer);
+-		in_timehandle = 0;
+-	}
+-	LEAVE(TRACE_ON,"collieCancelDelayedSilence");
+-}
+-#endif
+-
+-static void Collie_disable_sound(void)
+-{
+-	ENTER(TRACE_ON,"Collie_disable_sound");
+-	sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
+-	sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
+-#ifndef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.18 */
+-	Collie_volume_half_off();
+-	Collie_hard_mute_on();
+-	Collie_soft_mute_on();
+-
+-	Collie_ssp_off();
+-
+-	/* Collie_clock_stop(); */
+-#endif
+-	LEAVE(TRACE_ON,"Collie_disable_sound");
+-}
+-
+-static void CollieSilence(void)
+-{
+-	ENTER(TRACE_ON,"CollieSilence");
+-	/* Disable sound & DMA */
+-	Collie_disable_sound();
+-
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.18 */
+-	Collie_volume_half_off();
+-	Collie_hard_mute_delay_on();
+-	Collie_soft_mute_on();
+-
+-	Collie_ssp_off();
+-
+-	/* Collie_clock_stop(); */
+-#endif
+-
+-#if 0	/* H.Hayami SHARP 2001.12.18 */
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \
+-    !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
+-	Collie_volume_off();
+-#endif
+-#endif
+-	Collie_OP_SHDN_off();
+-	Collie_soft_DAC_off();
+-	Collie_paif_off();
+-	Collie_audio_clock_off();
+-
+-	//Collie_MIC_on();
+-
+-#ifndef DAC_OFF_WITH_DEVICE_OFF
+-	/* DAC Off */
+-#ifdef TRY_DELAY_OFF	/* H.Hayami 2001.12.15 */
+-	Collie_DAC_delay_off();
+-#else
+-	Collie_DAC_off();
+-#endif
+-#endif	/* end DAC_OFF_WITH_DEVICE_OFF */
+-
+-	/* AMP Off */
+-	Collie_AMP_off();
+-
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.18 */
+-	collieTriggerDelayedSilence();
+-#endif
+-	LEAVE(TRACE_ON,"CollieSilence");
+-}
+-
+-static int CollieGetSamp(void)
+-{
+-	ENTER(TRACE_ON,"CollieGetSamp");
+-	switch (sound.soft.speed) {
+-	case 8000:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[7];
+-	case 44100:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[0];
+-	case 22050:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[1];
+-	case 11025:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[2];
+-	case 48000:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[3];
+-	case 32000:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[4];
+-	case 24000:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[5];
+-	case 16000:
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-	  	return clock_set_data[6];
+-	default:
+-		printk("Collie sound: Illegal sound rate %d\n", sound.soft.speed);
+-		LEAVE(TRACE_ON,"CollieGetSamp");
+-		return clock_set_data[7];
+-	}
+-}
+-
+-static inline void Collie_DAC_sendbit(int bit_data)
+-{
+-	ENTER(TRACE_SENDDATA,"Collie_DAC_sendbit");
+-	if (bit_data & 1) {
+-		LCM_GPO |=  (LCM_GPIO_DAC_SDATA);
+-	} else {
+-		LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
+-	}
+-
+-	udelay(1);
+-	LCM_GPO |=  (LCM_GPIO_DAC_SCK);
+-
+-	udelay(1);
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
+-	udelay(1);
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SDATA);
+-	udelay(1);
+-	LEAVE(TRACE_SENDDATA,"Collie_DAC_sendbit");
+-}
+-
+-static void Collie_DAC_sendword(int data)
+-{
+-	int i;
+-
+-	ENTER(TRACE_SENDDATA,"Collie_DAC_sendword");
+-#if defined(CONFIG_COLLIE_PCM1741)
+-	
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
+-	udelay(1);
+-	LCM_GPO |=  (LCM_GPIO_DAC_SLOAD);
+-	udelay(1);
+-
+-	for (i = 0; i < 16; i++)
+-		Collie_DAC_sendbit(data >> (15 - i));
+-
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
+-	udelay(2);
+-
+-#elif defined(CONFIG_COLLIE_PCM1717)
+-	
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
+-	udelay(1000);
+-	LCM_GPO |=  (LCM_GPIO_DAC_SLOAD);
+-	udelay(1000);
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SCK);
+-	udelay(1000);
+-
+-	for (i = 0; i < 16; i++)
+-		Collie_DAC_sendbit(data >> (15 - i));
+-
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
+-	udelay(1000);
+-	LCM_GPO |=  (LCM_GPIO_DAC_SLOAD);
+-	udelay(1000);
+-	LCM_GPO &= ~(LCM_GPIO_DAC_SLOAD);
+-	udelay(1000);
+-	
+-#endif
+-	LEAVE(TRACE_SENDDATA,"Collie_DAC_sendword");
+ }
+ 
+-void
+-Collie_audio_power_on(void)
++
++static inline void Collie_sound_hard_init(void)
+ {
+-	int send_data;
++	Collie_hard_mute_init();
++	Collie_audio_clock_init();
++	Collie_paif_off();
++	Collie_volume_init();
++	Collie_ssp_init();
++	Collie_MIC_init();
++	Collie_soft_mute_on();
++	Collie_DAC_on();
++}
+ 
+-	ENTER(TRACE_ON,"Collie_audio_power_on");
++void Collie_recording_on(void)
++{
++	collie_recording=1;
++	if (!playing) 
++	    Collie_DAC_on();
++	else
++	    Collie_hard_mute_left_on();
++	Collie_MIC_on();
++}
+ 
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.19 */
+-	collieCancelDelayedSilence();
+-#endif
++void Collie_recording_off(void)
++{
++	collie_recording=0;
++	Collie_MIC_off();
++	if (!playing) 
++	    Collie_DAC_off();
++	else 
++	    Collie_hard_mute_left_off();
++}
+ 
++static void Collie_audio_power_on(void)
++{
++	playing=1;
+ 	collie_amp_init = 0;
+-
+-	/* OP_SHDN off */
+-	Collie_OP_SHDN_off();
+-
+-	/* AMP on */
+-	Collie_AMP_on();
+-
+-	/* DAC ON */
+-	Collie_DAC_on();
+-
+-	Collie_MIC_off();
+-	Collie_ssp_on();
+-	
+-	/* LoCoMo Audio clock */
+-	Collie_audio_clock_off();
++	if (!collie_recording)
++	    Collie_DAC_on();
++	Collie_ssp_on();	
++	Collie_audio_clock_off();       /* LoCoMo Audio clock */
+ 	Collie_audio_clock_on();
+-
+-	/* LoCoMo PCM audio interface */
+-	Collie_paif_on();
+-
++	Collie_paif_on();		/* LoCoMo PCM audio interface */
+ 	udelay(1000);
+-
+-	/* DAC Setting */
+ 	Collie_DAC_init();
+-
+ 	Collie_soft_DAC_on();
+-	Collie_soft_mute_init();
++	Collie_soft_mute_off();
++	Collie_hard_mute_off();
++	if (collie_recording)
++	    Collie_hard_mute_left_on();
++	Collie_volume_set(sound.volume);
++}
+ 
+-	sound.hard = sound.soft;
++static void Collie_audio_power_off(void){	/* Disable sound only */
++    Collie_volume_set(0);
++    Collie_hard_mute_on();
++    Collie_soft_mute_on();
++    Collie_ssp_off();
++    Collie_soft_DAC_off();
++    Collie_paif_off();
++    Collie_audio_clock_off();
++    if (!collie_recording)
++	Collie_DAC_off();
++    playing=0;
++}
+ 
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \
+-    !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
+-	/* Volume set */
+-	Collie_volume_half_adjust();
+-	{
+-		int i;
+-		for (i=0; i<10*1000; i++) {
+-			udelay(1);
++
++static inline void Collie_volume_init(void)
++{
++	m62332_senddata(0, M62332_EVR_CH);
++	collie_volume = 0;
++}
++
++#define	VOL_THRES	10
++
++static void Collie_volume_set(int dest)
++{
++	int	chn;
++	while (dest != collie_volume) {
++		chn = dest-collie_volume;
++		if (chn>VOL_THRES)
++		    chn=VOL_THRES;    
++		else if (chn<-VOL_THRES)
++		    chn=-VOL_THRES;
++		if (chn) {
++		    collie_volume += chn;
++		    m62332_senddata(0xff * collie_volume / 100, M62332_EVR_CH);
+ 		}
++		udelay(100);
+ 	}
+-#endif
++}
+ 
+-	Collie_soft_mute_off();
+-	Collie_hard_mute_off();
++static int sound_set_speed(int speed)
++{
++	if (speed < 0) {
++		return(sound.speed);
++	}
++
++	if (speed<8000) sound.speed=8000;
++	else if (speed<=11025) sound.speed=11025;
++	else if (speed<=16000) sound.speed=16000;
++	else if (speed<=22050) sound.speed=22050;
++	else if (speed<=24000) sound.speed=24000;
++	else if (speed<=32000) sound.speed=32000;
++	else if (speed<=44100) sound.speed=44100;
++	else sound.speed=48000;
++
++	/* LoCoMo Audio clock */
++	Collie_audio_clock_off();
++	Collie_audio_clock_on();
++	return(sound.speed);
++}
+ 
+-	LEAVE(TRACE_ON,"Collie_audio_power_on");
++/*** Mid level stuff *********************************************************/
++
++static void Collie_Set_Volume(int volume)
++{
++	sound.volume = volume & 0xff;
++	sound.volume += ( volume & 0xff00 >> 8);
++	sound.volume >>=1;
++	if (sound.volume>100) sound.volume=100;	
+ }
+ 
+-static void CollieInit(void)
++static int Collie_Get_Volume(void)
+ {
+-	ENTER(TRACE_ON,"CollieInit");
+-	sound.hard = sound.soft;
+-	LEAVE(TRACE_ON,"CollieInit");
++	return ( sound.volume << 8 | sound.volume );
+ }
+ 
++
+ static void Collie_sq_interrupt(void* id, int size)
+ {
+ 	audio_buf_t *b = (audio_buf_t *) id;
+-	ENTER(TRACE_INTERRUPT,"Collie_sq_interrupt");
+-/***** DEBUG *****
+-printk("Collie_sq_interrupt: Start\n");
+-*****************/
++
+ 	/*
+ 	 * Current buffer is sent: wake up any process waiting for it.
+ 	 */
+-	ENTER(TRACE_SEM,"up sem");
+ 	up(&b->sem);
+-	LEAVE(TRACE_SEM,"up sem");
+-/***** DEBUG *****
+-printk("Collie_sq_interrupt: up End\n");
+-*****************/
+ 	/* And any process polling on write. */
+-	ENTER(TRACE_SEM,"up wait");
+-	wake_up(&b->sem.wait);
+-	LEAVE(TRACE_SEM,"up wait");
+-/***** DEBUG *****
+-printk("Collie_sq_interrupt: wake_up End\n");
+-*****************/
++	wake_up_interruptible(&b->sem.wait);
++	/* And indicate which was the last buffer sent */
+ 
+ 	DPRINTK("Collie_sq_interrupt \n");
+-	LEAVE(TRACE_INTERRUPT,"Collie_sq_interrupt");
+ }
+ 
+ 
+@@ -1917,191 +829,52 @@
+ {
+ 	int err;
+ 
+-	ENTER(TRACE_ON,"CollieIrqInit");
+ 	err = sa1100_request_dma(&collie_dmasound_irq, "dmasound",
+ 				 DMA_Ser4SSPWr);
+ 	if (err) {
+-		LEAVE(TRACE_ON,"CollieIrqInit");
+ 		return 0;
+ 	}
+-	/* printk("collie_dmasound_irq=%d\n", collie_dmasound_irq); */
++	printk("collie_dmasound_irq=%d\n", collie_dmasound_irq); 
+ 
+ 	sa1100_dma_set_callback(collie_dmasound_irq,
+ 			       (dma_callback_t)Collie_sq_interrupt);
+ 
+-
+-	/* Disable sound & DMA */
+-	Collie_disable_sound();
+-
+-	LEAVE(TRACE_ON,"CollieIrqInit");
++	sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
++	sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
++	Collie_audio_power_off();
+ 	return(1);
+-
+-}
+-
+-#ifdef MODULE
+-static void CollieIrqCleanUp(void)
+-{
+-	ENTER(TRACE_ON,"CollieIrqCleanUp");
+-	/* Disable sound & DMA */
+-	Collie_disable_sound();
+-
+-	/* release the interrupt */
+-	free_irq(IRQ_DMA, Collie_sq_interrupt);
+-	LEAVE(TRACE_ON,"CollieIrqCleanUp");
+ }
+-#endif /* MODULE */
+-
+ 
+ static int CollieSetFormat(int format)
+ {
+ 	int size;
+ 
+-	ENTER(TRACE_ON,"CollieSetFormat");
+-	/* Falcon sound DMA supports 8bit and 16bit modes */
+-
+ 	switch (format) {
+ 	case AFMT_QUERY:
+-		LEAVE(TRACE_ON,"CollieSetFormat");
+-		return(sound.soft.format);
+-	case AFMT_MU_LAW:
+-		size = 8;
+-		ct_func = sound.trans->ct_ulaw;
+-		break;
+-	case AFMT_A_LAW:
+-		size = 8;
+-		ct_func = sound.trans->ct_alaw;
+-		break;
+-	case AFMT_S8:
+-		size = 8;
+-		ct_func = sound.trans->ct_s8;
+-		break;
+-	case AFMT_U8:
+-		size = 8;
+-		ct_func = sound.trans->ct_u8;
+-		break;
+-	case AFMT_S16_BE:
+-		size = 16;
+-		ct_func = sound.trans->ct_s16be;
+-		break;
+-	case AFMT_U16_BE:
+-		size = 16;
+-		ct_func = sound.trans->ct_u16be;
+-		break;
+-	case AFMT_S16_LE:
+-		size = 16;
+-		ct_func = sound.trans->ct_s16le;
+-		break;
+-	case AFMT_U16_LE:
++		return(sound.format);
++	default: /* This is the only one supported by the hardware it seems */
+ 		size = 16;
+-		ct_func = sound.trans->ct_u16le;
+-		break;
+-	default: /* :-) */
+-		size = 8;
+-		format = AFMT_S8;
+-	}
+-
+-	sound.soft.format = format;
+-	sound.soft.size = size;
+-	if (sound.minDev == SND_DEV_DSP) {
+-		sound.dsp.format = format;
+-		sound.dsp.size = sound.soft.size;
++		format = AFMT_S16_LE;
+ 	}
++	sound.format = format;
++	sound.size = size;
+ 
+-	LEAVE(TRACE_ON,"CollieSetFormat");
+ 	return(format);
+ }
+ 
+-/*** Machine definitions *****************************************************/
+-
+-static MACHINE machCollie = {
+-	DMASND_COLLIE,		// int type
+-	NULL,			// void *dma_alloc(uint, int)
+-	NULL,			// void  dma_free(void *, uint)
+-	CollieIrqInit,		// void  irqinit(void)
+-#ifdef MODULE
+-	CollieIrqCleanUp,	// void  irqcleanup(void)
+-#endif /* MODULE */
+-	CollieInit,		// void  init(void)
+-	CollieSilence,		// void  silence(void)
+-	CollieSetFormat,	// int   setFormat(int)
+-	NULL,			// int   setVolume(int)
+-	NULL,			// int   setBass(int)
+-	NULL,			// int   setTreble(int)
+-	NULL,			// int   setGain(int)
+-	NULL			// void  play(void)
+-};
+-
+-
+-/*** Mid level stuff *********************************************************/
+-
+-
+-static void sound_silence(void)
+-{
+-	ENTER(TRACE_ON,"sound_silence");
+-	/* update hardware settings one more */
+-	//(*sound.mach.init)();
+-	(*sound.mach.silence)();
+-	LEAVE(TRACE_ON,"sound_silence");
+-
+-}
+-
+-
+-static void sound_init(void)
+-{
+-	ENTER(TRACE_ON,"sound_init");
+-	(*sound.mach.init)();
+-	LEAVE(TRACE_ON,"sound_init");
+-}
+-
+-
+-static int sound_set_format(int format)
+-{
+-	ENTER(TRACE_ON,"sound_set_format");
+-	LEAVE(TRACE_ON,"sound_set_format");
+-	return(*sound.mach.setFormat)(format);
+-}
+-
+-
+-static int sound_set_speed(int speed)
+-{
+-	ENTER(TRACE_ON,"sound_set_speed");
+-	if (speed < 0) {
+-		LEAVE(TRACE_ON,"sound_set_speed");
+-		return(sound.soft.speed);
+-	}
+-
+-	sound.soft.speed = speed;
+-	(*sound.mach.init)();
+-	if (sound.minDev == SND_DEV_DSP)
+-		sound.dsp.speed = sound.soft.speed;
+-
+-	/* LoCoMo Audio clock */
+-	Collie_audio_clock_off();
+-	Collie_audio_clock_on();
+-
+-	LEAVE(TRACE_ON,"sound_set_speed");
+-	return(sound.soft.speed);
+-}
+ 
+ 
+ static int sound_set_stereo(int stereo)
+ {
+-	ENTER(TRACE_ON,"sound_set_stereo");
++/* Only stereo is supported by hardware */
+ 	if (stereo < 0) {
+-		LEAVE(TRACE_ON,"sound_set_stereo");
+-		return(sound.soft.stereo);
++		return(sound.stereo);
+ 	}
++	return(1);
++}
+ 
+-	stereo = !!stereo;    /* should be 0 or 1 now */
+-
+-	sound.soft.stereo = stereo;
+-	if (sound.minDev == SND_DEV_DSP)
+-		sound.dsp.stereo = stereo;
+-	//(*sound.mach.init)();
+ 
+-	LEAVE(TRACE_ON,"sound_set_stereo");
+-	return(stereo);
+-}
++/* Higher level stuff ************************************************/
+ 
+ /*
+  * /dev/mixer abstraction
+@@ -2109,20 +882,15 @@
+ 
+ static int mixer_open(struct inode *inode, struct file *file)
+ {
+-	ENTER(TRACE_ON,"mixer_open");
+ 	MOD_INC_USE_COUNT;
+ 	mixer.busy = 1;
+-	LEAVE(TRACE_ON,"mixer_open");
+ 	return 0;
+ }
+ 
+-
+ static int mixer_release(struct inode *inode, struct file *file)
+ {
+-	ENTER(TRACE_ON,"mixer_release");
+ 	mixer.busy = 0;
+ 	MOD_DEC_USE_COUNT;
+-	LEAVE(TRACE_ON,"mixer_release");
+ 	return 0;
+ }
+ 
+@@ -2132,58 +900,37 @@
+ {
+ 	int data;
+ 
+-	ENTER(TRACE_ON,"mixer_ioctl");
+-	switch (sound.mach.type) {
+-	case DMASND_COLLIE:
+-	{
+-		switch (cmd) {
+-			case SOUND_MIXER_READ_DEVMASK:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, SOUND_MASK_VOLUME );
+-			case SOUND_MIXER_READ_RECMASK:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-			case SOUND_MIXER_READ_STEREODEVS:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, SOUND_MASK_VOLUME);
+-			case SOUND_MIXER_READ_CAPS:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-
+-			case SOUND_MIXER_WRITE_VOLUME:
+-				IOCTL_IN(arg, data);
+-				Collie_Set_Volume(data);
+-			case SOUND_MIXER_READ_VOLUME:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, Collie_Get_Volume());
+-
+-			case SOUND_MIXER_READ_TREBLE:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-			case SOUND_MIXER_WRITE_TREBLE:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-
+-			case SOUND_MIXER_WRITE_MIC:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-			case SOUND_MIXER_READ_MIC:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-
+-			case SOUND_MIXER_READ_SPEAKER:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-			case SOUND_MIXER_WRITE_SPEAKER:
+-				LEAVE(TRACE_ON,"mixer_ioctl");
+-				return IOCTL_OUT(arg, 0);
+-		}
+-			break;
+-	}
+-	}
+-	LEAVE(TRACE_ON,"mixer_ioctl");
++	switch (cmd) {
++		case SOUND_MIXER_READ_DEVMASK:
++			return IOCTL_OUT(arg, headphone ? SOUND_MASK_VOLUME : 0 );
++		case SOUND_MIXER_READ_RECMASK:
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_READ_STEREODEVS:
++			return IOCTL_OUT(arg, headphone ? SOUND_MASK_VOLUME : 0 );
++		case SOUND_MIXER_READ_CAPS:
++			return IOCTL_OUT(arg, 0);
++
++		case SOUND_MIXER_WRITE_VOLUME:
++			IOCTL_IN(arg, data);
++			Collie_Set_Volume(data);
++		case SOUND_MIXER_READ_VOLUME:
++			return IOCTL_OUT(arg, Collie_Get_Volume());
++		case SOUND_MIXER_READ_TREBLE:
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_WRITE_TREBLE:
++			return IOCTL_OUT(arg, 0);
++
++		case SOUND_MIXER_WRITE_MIC:
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_READ_MIC:
++			return IOCTL_OUT(arg, 0);
++
++		case SOUND_MIXER_READ_SPEAKER:
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_WRITE_SPEAKER:
++			return IOCTL_OUT(arg, 0);
++	}	
+ 	return -EINVAL;
+-
+ }
+ 
+ 
+@@ -2198,32 +945,13 @@
+ 
+ static void __init mixer_init(void)
+ {
+-#ifndef MODULE
+-	int mixer_unit;
+-#endif
+-	ENTER(TRACE_ON,"mixer_init");
+ 	mixer_unit = register_sound_mixer(&mixer_fops, -1);
+ 	if (mixer_unit < 0) {
+-		LEAVE(TRACE_ON,"mixer_init");
+ 		return;
+ 	}
+-
+ 	mixer.busy = 0;
+-	sound.treble = 0;
+-	sound.bass = 0;
+-	switch (sound.mach.type) {
+-		case DMASND_COLLIE:
+-		  //			sound.volume_left  = 0x3c;
+-		  //			sound.volume_right = 0x3c;
+-		  	sound.volume_left  = 80;
+-		  	sound.volume_right = 80;
+-			collie_main_volume = sound.volume_left;
+-			break;
+-	}
+-
+-	//	printk("mixer_init : ret \n");
+-
+-	LEAVE(TRACE_ON,"mixer_init");
++	sound.volume  = 80;
++	Collie_volume_set(sound.volume);
+ }
+ 
+ /* This function allocates the buffer structure array and buffer data space
+@@ -2237,11 +965,9 @@
+ 	char *dmabuf = 0;
+ 	dma_addr_t dmaphys = 0;
+ 
+-	ENTER(TRACE_ON,"sq_allocate_buffers");
+ 	DPRINTK("sq_allocate_buffers\n");
+ 
+ 	if (s->buffers) {
+-		LEAVE(TRACE_ON,"sq_allocate_buffers");
+ 		return -EBUSY;
+ 	}
+ 
+@@ -2279,10 +1005,8 @@
+ 
+ 		b->start = dmabuf;
+ 		b->dma_addr = dmaphys;
++		b->idx = frag;
+ 		sema_init(&b->sem, 1);
+-		DPRINTK("buf %d: start %p dma %p\n", frag, b->start,
+-			b->dma_addr);
+-
+ 		dmabuf += s->fragsize;
+ 		dmaphys += s->fragsize;
+ 		dmasize -= s->fragsize;
+@@ -2291,13 +1015,12 @@
+ 	s->buf_idx = 0;
+ 	s->buf = &s->buffers[0];
+ 
+-	LEAVE(TRACE_ON,"sq_allocate_buffers");
++
+ 	return 0;
+ 
+ err:
+ 	printk("sound driver : unable to allocate audio memory\n ");
+ 	sq_release_buffers(s);
+-	LEAVE(TRACE_ON,"sq_allocate_buffers");
+ 	return -ENOMEM;
+ }
+ 
+@@ -2307,7 +1030,6 @@
+ 
+ static void sq_release_buffers(audio_stream_t * s)
+ {
+-	ENTER(TRACE_ON,"sq_release_buffers");
+ 	DPRINTK("sq_release_buffers\n");
+ 
+ 	/* ensure DMA won't run anymore */
+@@ -2328,7 +1050,6 @@
+ 
+ 	s->buf_idx = 0;
+ 	s->buf = NULL;
+-	LEAVE(TRACE_ON,"sq_release_buffers");
+ }
+ 
+ static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
+@@ -2339,27 +1060,20 @@
+ 	u_char *dest;
+ 	ssize_t uUsed, bUsed, bLeft, ret = 0;
+ 
+-	ENTER(TRACE_WRITE,"sq_write");
+ 	DPRINTK("sq_write: uLeft=%d\n", uLeft);
+ 
+-	/* OP_SHDN on */
+-	Collie_OP_SHDN_on();
+-
+ 	switch (file->f_flags & O_ACCMODE) {
+ 	case O_WRONLY:
+ 	case O_RDWR:
+ 		break;
+ 	default: 
+-		LEAVE(TRACE_WRITE,"sq_write1");
+ 		return -EPERM;
+ 	} 
+ 
+ 	if (!s->buffers && sq_allocate_buffers(s)) {
+-		LEAVE(TRACE_WRITE,"sq_write2");
+ 		return -ENOMEM;
+ 	}
+ 
+-#if 1
+ 	if (collie_resume == 1) {
+ 		int	i;
+ 		collie_resume = 0;
+@@ -2367,10 +1081,9 @@
+ 			udelay(1);
+ 		}
+ 	}
+-#endif
+ #ifdef CONFIG_PM
+ 	/* Auto Power off cancel */
+-	autoPowerCancel = 0;
++//	autoPowerCancel = 0;
+ #endif
+ 
+ 	while (uLeft > 0) {
+@@ -2379,41 +1092,30 @@
+ 		/* Wait for a buffer to become free */
+ 		if (file->f_flags & O_NONBLOCK) {
+ 			ret = -EAGAIN;
+-			ENTER(TRACE_SEM,"down_try sem");
+ 			if (down_trylock(&b->sem)) {
+-				LEAVE(TRACE_SEM,"down_try1 sem");
+ 				break;
+ 			}
+-			LEAVE(TRACE_SEM,"down_try2 sem");
+ 		} else {
+ 			ret = -ERESTARTSYS;
+-			ENTER(TRACE_SEM,"down_int sem");
+-			//printk("### 0x%08x:%d\n", &b->sem.count, atomic_read(&b->sem.count));
+ 			if (down_interruptible(&b->sem)) {
+-				LEAVE(TRACE_SEM,"down_int1 sem");
+ 				break;
+ 			}
+-			LEAVE(TRACE_SEM,"down_int2 sem");
+ 		}
+ 
+ 		dest = b->start + b->size;
+ 		bUsed = 0;
+ 		bLeft = s->fragsize - b->size;
+ 
+-		if (ct_func) {
+-			uUsed = ct_func(src, uLeft, dest, &bUsed, bLeft);
++		if (collie_ct_s16) {
++			uUsed = collie_ct_s16(src, uLeft, dest, &bUsed, bLeft);
+ 			cpu_cache_clean_invalidate_range((unsigned long)dest,
+ 				(unsigned long)(dest+(audio_fragsize)), 0);
+ 		} else {
+-			LEAVE(TRACE_WRITE,"sq_write3");
+ 			return -EFAULT;
+ 		}
+ 
+ 		if (uUsed < 0) {
+-			ENTER(TRACE_SEM,"up sem");
+ 			up(&b->sem);
+-			LEAVE(TRACE_SEM,"up sem");
+-			LEAVE(TRACE_WRITE,"sq_write4");
+ 			return -EFAULT;
+ 		}
+ 		src += uUsed;
+@@ -2421,9 +1123,7 @@
+ 		b->size += bUsed;
+ 
+ 		if (b->size < s->fragsize) {
+-			ENTER(TRACE_SEM,"up sem");
+ 			up(&b->sem);
+-			LEAVE(TRACE_SEM,"up sem");
+ 			break;
+ 		}
+ 
+@@ -2431,7 +1131,7 @@
+ 		sa1100_dma_queue_buffer(COLLIE_SOUND_DMA_CHANNEL,
+ 		 			(void *) b, b->dma_addr, b->size);
+ 
+-		Collie_volume_half_adjust();
++		Collie_volume_set(sound.volume);
+ 
+ 		b->size = 0;    /* indicate that the buffer has been sent */
+ 		NEXT_BUF(s, buf);
+@@ -2440,7 +1140,6 @@
+ 	if ((src - buffer0))
+ 		ret = src - buffer0;
+ 	DPRINTK("sq_write: return=%d\n", ret);
+-	LEAVE(TRACE_WRITE,"sq_write0");
+ 	return ret;
+ }
+ 
+@@ -2450,7 +1149,6 @@
+ 	unsigned int mask = 0;
+ 	int i;
+ 
+-	ENTER(TRACE_ON,"sq_poll");
+ 	DPRINTK("sq_poll(): mode=%s%s\n",
+ 		(file->f_mode & FMODE_READ) ? "r" : "",
+ 		(file->f_mode & FMODE_WRITE) ? "w" : "");
+@@ -2458,12 +1156,9 @@
+ 	if (file->f_mode & FMODE_WRITE) {
+ 		if (!output_stream.buffers 
+ 		    && sq_allocate_buffers(&output_stream)) {
+-			LEAVE(TRACE_ON,"sq_poll");
+ 			return -ENOMEM;
+ 		}
+-		ENTER(TRACE_SEM,"poll_wait wait");
+ 		poll_wait(file, &output_stream.buf->sem.wait, wait);
+-		LEAVE(TRACE_SEM,"poll_wait wait");
+ 	}
+ 
+ 	if (file->f_mode & FMODE_WRITE) {
+@@ -2477,65 +1172,33 @@
+ 		(mask & POLLIN) ? "r" : "",
+ 		(mask & POLLOUT) ? "w" : "");
+ 
+-	LEAVE(TRACE_ON,"sq_poll");
+ 	return mask;
+ }
+ 
+ static int sq_open(struct inode *inode, struct file *file)
+ {
+-	ENTER(TRACE_ON,"sq_open");
+ 	DPRINTK("sq_open\n");
+ 
+ 	if (((file->f_flags & O_ACCMODE) == O_WRONLY)
+ 	 || ((file->f_flags & O_ACCMODE) == O_RDWR)) {
+-#if 0
+-		MOD_INC_USE_COUNT;
+-		while(audio_wr_refcount) {
+-			SLEEP(open_queue, ONE_SECOND);
+-			if (SIGNAL_RECEIVED) {
+-				MOD_DEC_USE_COUNT;
+-				LEAVE(TRACE_ON,"sq_open");
+-				return -EINTR;
+-			}
+-		}
+-#else
+ 		if (audio_wr_refcount) {
+ 			DPRINTK(" sq_open        EBUSY\n");
+-			LEAVE(TRACE_ON,"sq_open");
+ 			return -EBUSY;
+ 		}
+ 		MOD_INC_USE_COUNT;
+-#endif
+ 		audio_wr_refcount++;
+ 	} else {
+ 		DPRINTK(" sq_open        EINVAL\n");
+-		LEAVE(TRACE_ON,"sq_open");
+ 		return -EINVAL;
+ 	}
+ 
+-	if (audio_wr_refcount == 1) {
+-		DPRINTK("cold\n");
+-
+-		audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
+-		audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
+-		sq_release_buffers(&output_stream);
+-		sound.minDev = MINOR(inode->i_rdev) & 0x0f;
+-		sound.soft = sound.dsp;
+-		sound.hard = sound.dsp;
+-
+-		if ((MINOR(inode->i_rdev) & 0x0f) == SND_DEV_AUDIO) {
+-			sound_set_speed(8000);
+-			sound_set_stereo(0);
+-			sound_set_format(AFMT_MU_LAW);
+-		}
+-		Collie_audio_power_on();
+-	}
+ 
+-#if 0
+-	MOD_INC_USE_COUNT;
+-#endif
+-	LEAVE(TRACE_ON,"sq_open");
+-	return 0;
++	audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
++	audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
++	sq_release_buffers(&output_stream);
++	output_stream.buf_idx=0;
++	Collie_audio_power_on();
++    	return 0;
+ }
+ 
+ static int sq_fsync(struct file *filp, struct dentry *dentry)
+@@ -2543,11 +1206,9 @@
+ 	audio_stream_t *s = &output_stream;
+ 	audio_buf_t *b = s->buf;
+ 
+-	ENTER(TRACE_ON,"sq_fsync");
+ 	DPRINTK("sq_fsync\n");
+ 
+ 	if (!s->buffers) {
+-		LEAVE(TRACE_ON,"sq_fsync");
+ 		return 0;
+ 	}
+ 
+@@ -2557,12 +1218,10 @@
+ 
+ #ifdef CONFIG_PM
+ 		/* Auto Power off cancel */
+-		autoPowerCancel = 0;
++//		autoPowerCancel = 0;
+ #endif
+ 
+-		ENTER(TRACE_SEM,"down sem");
+ 		down(&b->sem);
+-		LEAVE(TRACE_SEM,"down sem");
+ 		sa1100_dma_queue_buffer(COLLIE_SOUND_DMA_CHANNEL,
+ 					(void *) b, b->dma_addr, b->size);
+ 		b->size = 0;
+@@ -2576,23 +1235,15 @@
+ 	 * - the buffer was already free thus nothing else to sync.
+ 	 */
+ 	b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags);
+-	ENTER(TRACE_SEM,"down-int sem");
+ 	if (down_interruptible(&b->sem)) {
+-		LEAVE(TRACE_SEM,"down-int sem");
+-		LEAVE(TRACE_ON,"sq_fsync");
+ 		return -EINTR;
+ 	}
+-	LEAVE(TRACE_SEM,"down-int sem");
+-	ENTER(TRACE_SEM,"up sem");
+ 	up(&b->sem);
+-	LEAVE(TRACE_SEM,"up sem");
+-	LEAVE(TRACE_ON,"sq_fsync");
+ 	return 0;
+ }
+ 
+ static int sq_release(struct inode *inode, struct file *file)
+ {
+-	ENTER(TRACE_ON,"sq_release");
+ 	DPRINTK("sq_release\n");
+ 
+ 	switch (file->f_flags & O_ACCMODE) {
+@@ -2606,24 +1257,12 @@
+ 	}       
+ 
+ 	if (!audio_wr_refcount) {
+-		sound.soft = sound.dsp;
+-		sound.hard = sound.dsp;
+-		sound_silence();
+-		Collie_OP_SHDN_off();
++		sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
++		sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
++		Collie_audio_power_off();
+ 	} 
+ 
+-#if 0
+-	switch (file->f_flags & O_ACCMODE) {
+-	case O_WRONLY:
+-	case O_RDWR:
+-		if (!audio_wr_refcount) {
+-			WAKE_UP(open_queue);
+-		}
+-	}
+-#endif
+-
+ 	MOD_DEC_USE_COUNT;
+-	LEAVE(TRACE_ON,"sq_release");
+ 	return 0;
+ }
+ 
+@@ -2634,8 +1273,8 @@
+ 	u_long fmt;
+ 	int data;
+ 	long val;
++//	audio_buf_info abinfo;
+ 
+-	ENTER(TRACE_ON,"sq_ioctl");
+ 	switch (cmd) {
+ 	case SNDCTL_DSP_RESET:
+ 		switch (file->f_flags & O_ACCMODE) {
+@@ -2643,11 +1282,9 @@
+ 		case O_RDWR:
+ 			sq_release_buffers(&output_stream);
+ 		}
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return 0;
+ 	case SNDCTL_DSP_POST:
+ 	case SNDCTL_DSP_SYNC:
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return sq_fsync(file, file->f_dentry);
+ 
+ 		/* ++TeSche: before changing any of these it's
+@@ -2656,59 +1293,34 @@
+ 	case SNDCTL_DSP_SPEED:
+ 		sq_fsync(file, file->f_dentry);
+ 		IOCTL_IN(arg, data);
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return IOCTL_OUT(arg, sound_set_speed(data));
+ 	case SNDCTL_DSP_STEREO:
+ 		sq_fsync(file, file->f_dentry);
+ 		IOCTL_IN(arg, data);
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return IOCTL_OUT(arg, sound_set_stereo(data));
+-	case SOUND_PCM_WRITE_CHANNELS:
++	case SNDCTL_DSP_CHANNELS:
+ 		sq_fsync(file, file->f_dentry);
+ 		IOCTL_IN(arg, data);
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
+ 	case SNDCTL_DSP_SETFMT:
+ 		sq_fsync(file, file->f_dentry);
+ 		IOCTL_IN(arg, data);
+-		LEAVE(TRACE_ON,"sq_ioctl");
+-		return IOCTL_OUT(arg, sound_set_format(data));
++		return IOCTL_OUT(arg, CollieSetFormat(data));
+ 	case SNDCTL_DSP_GETFMTS:
+-		fmt = 0;
+-		if (sound.trans) {
+-			if (sound.trans->ct_ulaw)
+-				fmt |= AFMT_MU_LAW;
+-			if (sound.trans->ct_alaw)
+-				fmt |= AFMT_A_LAW;
+-			if (sound.trans->ct_s8)
+-				fmt |= AFMT_S8;
+-			if (sound.trans->ct_u8)
+-				fmt |= AFMT_U8;
+-			if (sound.trans->ct_s16be)
+-				fmt |= AFMT_S16_BE;
+-			if (sound.trans->ct_u16be)
+-				fmt |= AFMT_U16_BE;
+-			if (sound.trans->ct_s16le)
+-				fmt |= AFMT_S16_LE;
+-			if (sound.trans->ct_u16le)
+-				fmt |= AFMT_U16_LE;
+-		}
+-		LEAVE(TRACE_ON,"sq_ioctl");
++		fmt = AFMT_S16_LE;
+ 		return IOCTL_OUT(arg, fmt);
+ 	case SNDCTL_DSP_GETBLKSIZE:
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return IOCTL_OUT(arg, audio_fragsize);
+ 	case SNDCTL_DSP_SUBDIVIDE:
+ 		break;
+ 	case SNDCTL_DSP_SETFRAGMENT:
+ 		if (output_stream.buffers) {
+-			LEAVE(TRACE_ON,"sq_ioctl");
+ 			return -EBUSY;
+ 		}
+ 		get_user(val, (long *) arg);
+ 		audio_fragsize = 1 << (val & 0xFFFF);
+-		if (audio_fragsize < 16)
+-			audio_fragsize = 16;
++		if (audio_fragsize < 256)
++			audio_fragsize = 256;
+ 		if (audio_fragsize > 16384)
+ 			audio_fragsize = 16384;
+ 		audio_nbfrags = (val >> 16) & 0x7FFF;
+@@ -2717,46 +1329,54 @@
+ 		if (audio_nbfrags * audio_fragsize > 128 * 1024)
+ 			audio_nbfrags = 128 * 1024 / audio_fragsize;
+ 		if (sq_allocate_buffers(&output_stream)) {
+-			LEAVE(TRACE_ON,"sq_ioctl");
+ 			return -ENOMEM;
+ 		}
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return 0;
+ 
+-#if 1 // 2003.2.14
++/*	case SNDCTL_DSP_GETOSPACE:
++		abinfo.fragsize   = audio_fragsize;
++		abinfo.fragstotal = audio_nbfrags;
++		abinfo.fragments  = lastsent-output_stream.buf_idx;
++		if (abinfo.fragments<0)
++		    abinfo.fragments += abinfo.fragstotal;		    
++		abinfo.bytes      = abinfo.fragments*abinfo.fragsize;
++		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
++*/
+ 	case SNDCTL_DSP_GETOSPACE:
+ 	    {
+-		audio_buf_info inf = { 0, };
++		audio_stream_t *s = &output_stream;
++		audio_buf_info *inf = (audio_buf_info *) arg;
++		int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
+ 		int i;
++		int frags = 0, bytes = 0;
+ 
+-		if (!(file->f_mode & FMODE_WRITE))
+-			return -EINVAL;
+-		if (!output_stream.buffers && sq_allocate_buffers(&output_stream))
+-			return -ENOMEM;
+-		for (i = 0; i < output_stream.nbfrags; i++) {
+-			if (atomic_read(&output_stream.buffers[i].sem.count) > 0) {
+-				if (output_stream.buffers[i].size == 0)
+-					inf.fragments++;
+-				inf.bytes += output_stream.fragsize - output_stream.buffers[i].size;
+-			}
++		if (err)
++			return err;
++		if (output_stream.buffers)  {
++		    for (i = 0; i < s->nbfrags; i++) {
++			if (atomic_read(&s->buffers[i].sem.count) > 0) {
++				if (s->buffers[i].size == 0) frags++;
++				bytes += s->fragsize - s->buffers[i].size;
++			}
++		    }
++		    put_user(s->nbfrags, &inf->fragstotal);
++		    put_user(s->fragsize, &inf->fragsize);
++		} else {
++		    frags=audio_nbfrags;
++		    bytes=frags*audio_fragsize;
++		    put_user(frags, &inf->fragstotal);
++		    put_user(audio_fragsize, &inf->fragsize);
+ 		}
+-		inf.fragstotal = output_stream.nbfrags;
+-		inf.fragsize = output_stream.fragsize;
+-		return copy_to_user((void *)arg, &inf, sizeof(inf));
++		put_user(frags, &inf->fragments);
++		return put_user(bytes, &inf->bytes);
+ 	    }
+-#endif
+-
+ 
+ 	default:
+-		LEAVE(TRACE_ON,"sq_ioctl");
+ 		return mixer_ioctl(inode, file, cmd, arg);
+ 	}
+-	LEAVE(TRACE_ON,"sq_ioctl");
+ 	return -EINVAL;
+ }
+ 
+-
+-
+ static struct file_operations sq_fops =
+ {
+ 	llseek: sound_lseek,
+@@ -2770,40 +1390,18 @@
+ 
+ static void __init sq_init(void)
+ {
+-#ifndef MODULE
+-	int sq_unit;
+-#endif
+-	ENTER(TRACE_ON,"sq_init");
+ 	sq_unit = register_sound_dsp(&sq_fops, -1);
+ 	if (sq_unit < 0) {
+-		LEAVE(TRACE_ON,"sq_init");
+ 		return;
+ 	}
+ 
+-	/* whatever you like as startup mode for /dev/dsp,
+-	 * (/dev/audio hasn't got a startup mode). note that
+-	 * once changed a new open() will *not* restore these!
+-	 */
+-	sound.dsp.format = AFMT_S16_LE;
+-
+-	sound.dsp.stereo = 0;
+-	sound.dsp.size = 16;
+-
+-	/* set minimum rate possible without expanding */
+-	switch (sound.mach.type) {
+-		case DMASND_COLLIE:
+-		  	sound.dsp.speed = 8000;
+-			break;
+-	}
+-
+-	/* before the first open to /dev/dsp this wouldn't be set */
+-	sound.soft = sound.dsp;
+-	sound.hard = sound.dsp;
+-	sound.trans = &transCollie;
+-
+-	CollieSetFormat(sound.dsp.format);
+-	sound_silence();
+-	LEAVE(TRACE_ON,"sq_init");
++	sound.format = AFMT_S16_LE;
++	sound.stereo = 1;
++	sound.speed = 44100;
++
++	CollieSetFormat(AFMT_S16_LE);
++	Collie_audio_power_off();
++	output_stream.buf=output_stream.buffers=NULL;
+ }
+ 
+ /*
+@@ -2816,9 +1414,7 @@
+ 	char *buffer = state.buf;
+ 	int len = 0;
+ 
+-	ENTER(TRACE_ON,"state_open");
+ 	if (state.busy) {
+-		LEAVE(TRACE_ON,"state_open");
+ 		return -EBUSY;
+ 	}
+ 
+@@ -2828,8 +1424,8 @@
+ 
+ 	len += sprintf(buffer+len, "  COLLIE DMA sound driver:\n");
+ 
+-	len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.soft.format);
+-	switch (sound.soft.format) {
++	len += sprintf(buffer+len, "\tsound.format = 0x%x", sound.format);
++	switch (sound.format) {
+ 	case AFMT_MU_LAW:
+ 		len += sprintf(buffer+len, " (mu-law)");
+ 		break;
+@@ -2857,22 +1453,19 @@
+ 	}
+ 	len += sprintf(buffer+len, "\n");
+ 	len += sprintf(buffer+len, "\tsound.speed = %dHz (phys. %dHz)\n",
+-		       sound.soft.speed, sound.hard.speed);
++		       sound.speed, sound.speed);
+ 	len += sprintf(buffer+len, "\tsound.stereo = 0x%x (%s)\n",
+-		       sound.soft.stereo,
+-		       sound.soft.stereo ? "stereo" : "mono");
++		       sound.stereo,
++		       sound.stereo ? "stereo" : "mono");
+ 	state.len = len;
+-	LEAVE(TRACE_ON,"state_open");
+ 	return 0;
+ }
+ 
+ 
+ static int state_release(struct inode *inode, struct file *file)
+ {
+-	ENTER(TRACE_ON,"state_release");
+ 	state.busy = 0;
+ 	MOD_DEC_USE_COUNT;
+-	LEAVE(TRACE_ON,"state_release");
+ 	return 0;
+ }
+ 
+@@ -2881,19 +1474,15 @@
+ 			  loff_t *ppos)
+ {
+ 	int n = state.len - state.ptr;
+-	ENTER(TRACE_ON,"state_read");
+ 	if (n > count)
+ 		n = count;
+ 	if (n <= 0) {
+-		LEAVE(TRACE_ON,"state_read");
+ 		return 0;
+ 	}
+ 	if (copy_to_user(buf, &state.buf[state.ptr], n)) {
+-		LEAVE(TRACE_ON,"state_read");
+ 		return -EFAULT;
+ 	}
+ 	state.ptr += n;
+-	LEAVE(TRACE_ON,"state_read");
+ 	return n;
+ }
+ 
+@@ -2909,20 +1498,11 @@
+ 
+ static void __init state_init(void)
+ {
+-#ifndef MODULE
+-	int state_unit;
+-#endif
+-	ENTER(TRACE_ON,"state_unit");
+ 	state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
+ 	if (state_unit < 0) {
+-		LEAVE(TRACE_ON,"state_unit");
+ 		return;
+ 	}
+ 	state.busy = 0;
+-
+-	//	printk("state_init : ret \n");
+-	LEAVE(TRACE_ON,"state_unit");
+-
+ }
+ 
+ 
+@@ -2930,8 +1510,6 @@
+ 
+ static long long sound_lseek(struct file *file, long long offset, int orig)
+ {
+-	ENTER(TRACE_ON,"sound_lseek");
+-	LEAVE(TRACE_ON,"sound_lseek");
+ 	return -ESPIPE;
+ }
+ 
+@@ -2941,96 +1519,41 @@
+ static int collie_sound_pm_callback(struct pm_dev *pm_dev,
+ 				    pm_request_t req, void *data)
+ {
+-	ENTER(TRACE_PM,"collie_sound_pm_callback");
+ 	switch (req) {
+ 	case PM_SUSPEND:
+ #ifdef COLLIE_TRY_ONE
+ 		disable_irq(IRQ_GPIO_nREMOCON_INT);
+ #endif
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.19 */
+-		collieDoDelayedSilence();
+-		collieCancelDelayedSilence();
+-#endif
+-		if (audio_wr_refcount == 1) {
+-			Collie_volume_off();
+-			Collie_hard_mute_on();
+-			Collie_soft_mute_on();
+-			sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
+-
+-#if 0	/* H.Hayami SHARP 2001.12.18 */
+-#if !defined(CONFIG_COLLIE_TS) && !defined(CONFIG_COLLIE_TR0) && \
+-    !defined(CONFIG_COLLIE_TR1) && !defined(CONFIG_COLLIE_DEV)
+-			Collie_volume_off();
+-#endif
+-#endif
+-			Collie_OP_SHDN_off();
+-			Collie_soft_DAC_off();
+-			Collie_paif_off();
+-			Collie_audio_clock_off();
+-			//Collie_MIC_on();
+-			Collie_DAC_off();
+-			Collie_AMP_off();
+-		} else {
+-			sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
+-		}
+-		Collie_sound_hard_term();
++		sa1100_dma_sleep((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
++		Collie_audio_power_off();
+ 		break;
+ 	case PM_RESUME:
+-/***** DEBUG *****g
+-printk("collie_sound_pm_callback: audio_wr_refcount=%d\n", audio_wr_refcount);
+-*****************/
++
+ #ifdef COLLIE_TRY_ONE
+ 		enable_irq(IRQ_GPIO_nREMOCON_INT);
+ #endif
+-
+-		Collie_sound_hard_init();
+-
+-		if (audio_wr_refcount == 1) {
+-			collie_resume = 1;
+-
+-			Collie_audio_power_on();
+-
+-			sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
+-#if 0	/* H.Hayami SHARP 2001.12.18 */
+-			Collie_soft_mute_off();
+-			Collie_hard_mute_off();
+-#endif
+-		} else {
++		Collie_sound_hard_init();    /* this needs to be done! */
++		collie_resume = 1;
++		Collie_audio_power_off();
++		if (audio_wr_refcount) Collie_audio_power_on();
++		if (collie_recording) Collie_recording_on();
++		sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
+ #ifdef COLLIE_TRY_ONE
+-		  if ( !( GPLR & GPIO_nREMOCON_INT ) )
++		if ( !( GPLR & GPIO_nREMOCON_INT ) )
+ 		    Collie_DAC_on();
+ #endif
+-			sa1100_dma_wakeup((dmach_t)COLLIE_SOUND_DMA_CHANNEL);
+-		}
+-
+-
+ 		break;
+-
+ 	}
+-	LEAVE(TRACE_PM,"collie_sound_pm_callback");
+ 	return 0;
+ }
+ #endif
+ 
+ 
+ #ifdef COLLIE_TRY_ONE
+-
+-static void collie_audio_on(void)
+-{
+-    while(1) {
+-      sleep_on(&audio_on);
+-
+-      /* DAC ON */
+-      Collie_DAC_on();
+-      //      printk("call audio on \n");
+-
+-    }
+-}
+-
+ void Collie_rc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
+-  //  printk("int !\n");
+-  wake_up(&audio_on);
++  headphone=!headphone;
++  printk("%s headphone \n",headphone ? "connected" : "disconnected");
+ }
+ #endif
+ 
+@@ -3038,113 +1561,85 @@
+ 
+ int __init Collie_sound_init(void)
+ {
+-	int has_sound = 0;
+-
+-
+-	ENTER(TRACE_ON,"Collie_sound_init");
+-	has_sound = 1;
+-	sound.mach = machCollie;
+-
+-	if (!has_sound) {
+-		LEAVE(TRACE_ON,"Collie_sound_init");
+-		return -1;
+-	}
+-
+-#ifdef TRY_DELAY_OFF	/* H.Hayami SHARP 2001.12.19 */
+-	sema_init(&df_sem, 1);
+-	kernel_thread(collieDelayedSilence, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
+-#endif
+-
+ 	Collie_sound_hard_init();
+-
+-	if (!sound.mach.irqinit()) {
++	if (!CollieIrqInit()) {
+ 		printk("Sound driver: Interrupt initialization failed\n");
+-		LEAVE(TRACE_ON,"Collie_sound_init");
+ 		return -1;
+ 	}
+-
+-	/* Set up sound queue, /dev/audio and /dev/dsp. */
+-
+ 	/* Set default settings. */
+ 	sq_init();
+-
+ 	/* Set up /dev/sndstat. */
+ 	state_init();
+-
+ 	/* Set up /dev/mixer. */
+ 	mixer_init();
+-
+ #ifdef MODULE
+ 	irq_installed = 1;
+ #endif
+-
+ 	printk("Collie Sound Driver Installed\n");
+-
+ #ifdef CONFIG_PM
+ 	collie_sound_pm_dev = pm_register(PM_SYS_DEV, 0,
+ 						collie_sound_pm_callback);
+ #endif
+-
+-
+ #ifdef COLLIE_TRY_ONE
+ 	/* enable int sw */
+ 	collie_rc_set_int_mode();
+-
+ 	/* GPIO15(int):IN, GPIO18(sw):OUT */
+ 	GPDR = ((GPDR)&~GPIO_nREMOCON_INT)|GPIO_REMOCON_ADC_SW;
+-
+ 	/* GPIO15,18:not Alternate */
+ 	GAFR &= ~(GPIO_nREMOCON_INT|GPIO_REMOCON_ADC_SW);
+-
++	/* Initialize headphone state */
++	headphone=!(GPLR & GPIO_nREMOCON_INT);
+ 	/* GPIO15:Falling Edge */
+-	set_GPIO_IRQ_edge(GPIO_nREMOCON_INT, GPIO_FALLING_EDGE);
+-
++	set_GPIO_IRQ_edge(GPIO_nREMOCON_INT, GPIO_BOTH_EDGES);
+ 	/* Register interrupt handler */
+ 	if ( request_irq(IRQ_GPIO_nREMOCON_INT, Collie_rc_interrupt,
+-			       SA_INTERRUPT, "INSERT-HEADPHONE", Collie_rc_interrupt))	{
+-		printk("%s: request_irq(%d) failed.\n",
+-			__FUNCTION__, IRQ_GPIO_nREMOCON_INT);
+-	}
++			       SA_INTERRUPT, "headphone", 0))	{
++		printk("headphone: request_irq failed.\n");
+ 
+-	/* Make threads */
+-	kernel_thread(collie_audio_on,  NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
++	}
++	printk("Requested irq collie_rc succesfully (headphone) \n");
++	printk("Headphone is now %s\n",headphone ? "connected" : "disconnected");
+ #endif
+ 
+-
+-	LEAVE(TRACE_ON,"Collie_sound_init");
++	Collie_audio_power_on();  // decreasing rec. noise?
++	Collie_audio_power_off();
+ 	return 0;
+ }
+ 
+-module_init(Collie_sound_init);
+-
+-
+ #ifdef MODULE
+-
+-int init_module(void)
++static int collie_ssp_init_module(void)
+ {
+-	ENTER(TRACE_ON,"init_module");
+ 	Collie_sound_init();
+-	LEAVE(TRACE_ON,"init_module");
+ 	return 0;
+ }
+ 
+-void cleanup_module(void)
++static void collie_ssp_cleanup_module(void)
+ {
+-	ENTER(TRACE_ON,"cleanup_module");
++#ifdef CONFIG_PM
++	pm_unregister(collie_sound_pm_dev);
++#endif
+ 	if (irq_installed) {
+-		sound_silence();
+-		sound.mach.irqcleanup();
++		sa1100_dma_stop(COLLIE_SOUND_DMA_CHANNEL);
++		sa1100_dma_flush_all(COLLIE_SOUND_DMA_CHANNEL);
++		Collie_audio_power_off();		
++		sa1100_free_dma(COLLIE_SOUND_DMA_CHANNEL);
+ 	}
+-
+-	sq_release_buffers();
+-
+-	if (mixer_unit >= 0)
+-		unregister_sound_mixer(mixer_unit);
+-	if (state_unit >= 0)
+-		unregister_sound_special(state_unit);
+-	if (sq_unit >= 0)
+-		unregister_sound_dsp(sq_unit);
+-	LEAVE(TRACE_ON,"cleanup_module");
+-}
+-
++#ifdef COLLIE_TRY_ONE
++	free_irq(IRQ_GPIO_nREMOCON_INT,0);
++#endif
++	unregister_sound_mixer(mixer_unit);
++	unregister_sound_special(state_unit);
++	unregister_sound_dsp(sq_unit);
++	printk("collie_ssp has to go now, see you later!\n");
++}
++
++module_init(collie_ssp_init_module);
++module_exit(collie_ssp_cleanup_module);
++MODULE_DESCRIPTION("Collie 16bit sound driver");
++MODULE_AUTHOR("SHARP");
++MODULE_LICENSE("GPL");
++EXPORT_SYMBOL(Collie_recording_off);
++EXPORT_SYMBOL(Collie_recording_on);
++EXPORT_SYMBOL(collie_recording);
+ #endif /* MODULE */
++
+diff -Nuar linux-2.4.18/drivers/sound/collie_tc35143af.c linux-2.4.18p/drivers/sound/collie_tc35143af.c
+--- linux-2.4.18/drivers/sound/collie_tc35143af.c	1970-01-01 01:00:00.000000000 +0100
++++ linux-2.4.18p/drivers/sound/collie_tc35143af.c	2004-10-13 15:26:20.336631864 +0200
+@@ -0,0 +1,1457 @@
++/*
++    TODO
++
++    buzzer compatibility is not fool proof - if an app starts sending buzzer ioctls
++    and then write or read, nothing good will happen    / but this api is obsolote anyway
++        
++    mixer_ioctls missing: write/read_mic/igain  (there are sane defaults for those)
++    
++    fixed samplerate at 22050hz (mono,s16_le), although it can be changed
++    between 8000-22050hz hardwarewise 
++
++    
++    DONE
++
++    buffers are only allocated once, and freed when module is unloaded
++    mute left channel when duplex playing & recording    
++    cleanup
++    depend on collie_ssp, and call needed functions when needed 
++    (recording noise should be gone too as a consequence)
++    lineo's getospace incorporated (getispace left alone)
++    "optimized" default fragsize and number, so there is now no clicking all the time
++    commented out scndctl_dsp_setfragment so that no application can set bad settings (eg.xmms)
++    if you start reading from this device, than it won't let you write later unless you close it first
++    (and vica-versa)    
++    speaker is muted if nothing is playing, so noise is gone
++    
++*/
++
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/poll.h>
++#include <linux/major.h>
++#include <linux/config.h>
++#include <linux/fcntl.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/sound.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++
++#include <linux/pm.h>
++
++#include <asm/system.h>
++#include <asm/irq.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/dma.h>
++
++#include <asm/ucb1200.h>
++#include <linux/soundcard.h>
++#include <asm/proc/cache.h>
++
++#include <asm/arch/hardware.h>
++#include <asm/arch/tc35143.h>
++
++#undef DEBUG
++#ifdef DEBUG
++#define DPRINTK( x... )  printk( ##x )
++#else
++#define DPRINTK( x... )
++#endif
++
++extern int collie_recording;
++extern void Collie_recording_on(void);
++extern void Collie_recording_off(void);
++
++int collie_tc35143f_irq = -1;
++int collie_tc35143f_input_irq = -1;
++
++#define	COLLIE_BUZZER_DMA_CHANNEL	(collie_tc35143f_irq)
++#define	COLLIE_BUZZER_DMA_CHANNEL_INPUT	(collie_tc35143f_input_irq)
++#define COLLIE_GPIO_MIC			GPIO_GPIO (17)
++
++#define SND_NDEVS	256	/* Number of supported devices */
++#define SND_DEV_CTL	0	/* Control port /dev/mixer */
++#define SND_DEV_SEQ	1	/* Sequencer output /dev/sequencer (FM synthesizer and MIDI output) */
++#define SND_DEV_MIDIN	2	/* Raw midi access */
++#define SND_DEV_DSP	3	/* Digitized voice /dev/dsp */
++#define SND_DEV_AUDIO	4	/* Sparc compatible /dev/audio */
++#define SND_DEV_DSP16	5	/* Like /dev/dsp but 16 bits/sample */
++#define SND_DEV_STATUS	6	/* /dev/sndstat */
++/* #7 not in use now. Was in 2.4. Free for use after v3.0. */
++#define SND_DEV_SEQ2	8	/* /dev/sequencer, level 2 interface */
++#define SND_DEV_SNDPROC 9	/* /dev/sndproc for programmable devices */
++#define SND_DEV_PSS	SND_DEV_SNDPROC
++
++#ifdef MODULE
++static int sq_unit = -1;
++static int mixer_unit = -1;
++static int state_unit = -1;
++static int irq_installed = 0;
++#endif /* MODULE */
++
++#ifdef CONFIG_PM
++static struct pm_dev* collie_sound_pm_dev;
++#endif
++
++/*** Some declarations ***********************************************/
++static int collie_buzzer_volume = 100;
++static int audio_igain = 0;
++static int audio_iamp = 0x05;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++static struct ucb1x00 * ucbstruct;
++#endif
++static int TC35143f_control_reg_a;
++static int TC35143f_control_reg_b;
++static int TC35143f_mode;
++
++#define AUDIO_NBFRAGS_DEFAULT   32
++#define AUDIO_FRAGSIZE_DEFAULT  2048
++
++typedef struct {
++	int size;               /* buffer size */
++	char *start;            /* points to actual buffer */
++	dma_addr_t dma_addr;    /* physical buffer address */
++	struct semaphore sem;   /* down before touching the buffer */
++	int master;             /* master owner for buffer allocation */
++	u_int idx;		/* buffer index, so that we know which buffer was sent last*/
++} audio_buf_t;
++
++typedef struct {
++	audio_buf_t *buffers;   /* pointer to audio buffer structures */
++	audio_buf_t *buf;       /* current buffer used by read/write */
++	u_int buf_idx;          /* index for the pointer above... */
++	u_int fragsize;         /* fragment i.e. buffer size */
++	u_int nbfrags;          /* nbr of fragments i.e. buffers */
++} audio_stream_t;
++
++static audio_stream_t output_stream, input_stream;
++
++#define NEXT_BUF(_s_,_b_) { \
++	(_s_)->_b_##_idx++; \
++	(_s_)->_b_##_idx %= (_s_)->nbfrags; \
++	(_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; }
++					
++/* Current specs for incoming audio data */
++static u_int audio_fragsize=AUDIO_FRAGSIZE_DEFAULT;
++static u_int audio_nbfrags=AUDIO_NBFRAGS_DEFAULT;
++
++static volatile int audio_refcount;	/* nbr of concurrent open() for playback */
++typedef enum { REC,PLAY,NA,BUZZ } collie_tc_status_t;
++static collie_tc_status_t collie_tc_status;
++int collie_tc_muted;
++
++#define IOCTL_IN(arg, ret) \
++	do { int error = get_user(ret, (int *)(arg)); \
++		if (error) return error; \
++	} while (0)
++#define IOCTL_OUT(arg, ret)	ioctl_return((int *)(arg), ret)
++
++/*** "Translations" ************************************************************/
++
++static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
++			     u_char frame[], ssize_t *frameUsed,
++			     ssize_t frameLeft);
++static signed short ct_out=0;
++/*** Low level stuff *********************************************************/
++
++
++typedef struct {
++	int format;		/* AFMT_* */
++	int stereo;		/* 0 = mono, 1 = stereo */
++	int size;		/* 8/16 bit*/
++	int speed;		/* speed */
++	int volume;
++} SETTINGS;
++
++static SETTINGS sound;
++
++#ifdef CONFIG_PM
++//extern int autoPowerCancel;
++#endif
++
++static void Collie_Set_Volume(int volume);
++static int Collie_Get_Volume(void);
++static int CollieIrqInit(void);
++static int CollieSetFormat(int format);
++static void Collie_sq_interrupt(void*, int);
++static int sq_allocate_buffers(audio_stream_t*);
++static void sq_release_buffers(audio_stream_t*);
++
++/*** Mid level stuff *********************************************************/
++static int sound_set_speed(int speed);
++
++/*
++ * /dev/mixer abstraction
++ */
++
++struct sound_mixer {
++    int busy;
++};
++
++static struct sound_mixer mixer;
++
++/*
++ * /dev/sndstat
++ */
++
++/*** Common stuff ********************************************************/
++
++static long long sound_lseek(struct file *file, long long offset, int orig);
++static inline int ioctl_return(int *addr, int value)
++{
++	if (value < 0) {
++		return(value);
++	}
++	return put_user(value, addr)? -EFAULT: 0;
++}
++
++static void wait_ms(int ten_ms)
++{
++	schedule_timeout(ten_ms);
++}
++
++/*** Translation ************************************************************/
++
++static ssize_t collie_ct_s16(const u_char *userPtr, size_t userCount,
++			   u_char frame[], ssize_t *frameUsed,
++			   ssize_t frameLeft)
++{
++	ssize_t count, used;
++	signed short *fp = (unsigned short *) &frame[*frameUsed];
++	signed short *up = (unsigned short *) userPtr;
++
++	frameLeft >>= 1;
++	userCount >>= 1;
++	used = count = (userCount < frameLeft) ? userCount : frameLeft;
++	
++	while (count > 0) {
++		signed short data;
++		if (get_user(data, up++)) {
++			return -EFAULT;
++		} /* lowpass filtering, not that it matters much - something is resonating inside the Zaurus at high frequencies ? */
++		*fp++ =  ct_out = (short)( ( (long)data  + (long)ct_out ) >> 1LL );
++		count--;
++	}
++	
++	*frameUsed += used * 2;
++	return used * 2;
++}
++
++/*** HARDWARE dependent stuff *********************************************************/
++#define	VOL_THRES	10
++#define	CODEC_ASD_NUMERATOR 13
++/*~ (9216000 / ( 32 * 22050 )) */
++
++static int Collie_Sampling_value(void)
++{
++  int asd = CODEC_ASD_NUMERATOR;
++  DPRINTK("Collie_Sampling_value %x\n",asd);
++  return asd;
++}
++
++static void Collie_sound_hard_init(void)
++{
++  int asd;
++
++  DPRINTK("CollieInit\n");
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++  ucb1x00_enable(ucbstruct);
++  ucb1x00_io_set_dir(ucbstruct,0, TC35143_GPIO_BUZZER_BIAS); 
++  ucb1x00_disable(ucbstruct);
++#else
++  ucb1200_set_io_direction(TC35143_GPIO_BUZZER_BIAS, TC35143_IODIR_OUTPUT); 
++#endif
++
++  DPRINTK("TC35143F Init");
++
++  // init MCP
++  asd = Collie_Sampling_value();
++  Ser4MCCR0 &= ~MCCR0_MCE;
++  Ser4MCCR0 &= ~0xff;
++  Ser4MCCR0 |= (MCCR0_ARE | MCCR0_ATE |MCCR0_ADM | MCCR0_ECS | asd);
++  Ser4MCCR0 |= MCCR0_MCE;
++  Ser4MCSR   = 0xffffffff;
++
++  DPRINTK("Init MCP %x\n",Ser4MCCR0);
++}
++
++static void Collie_audio_power_on(void)
++{
++  if ( collie_buzzer_volume > 100 ) collie_buzzer_volume = 100;
++  if ( collie_buzzer_volume < 0   ) collie_buzzer_volume = 0;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++  ucb1x00_enable(ucbstruct);
++#endif
++  TC35143f_control_reg_a = ( TC35143_VDIV_22KHZ );
++  TC35143f_control_reg_b = ( TC35143_VADMUTE | TC35143_VHSMUTE | ( 7 - collie_buzzer_volume / 13));
++  TC35143f_mode = ( TC35143_VOFFCAN | TC35143_VCOF_22_OR_16KHZ );
++  TC35143f_control_reg_a &= ~(TC35143_VINSEL_MASK | TC35143_VGAIN_MASK | TC35143_VAMP_MASK);
++  TC35143f_control_reg_a |= (TC35143_VINSEL_VBIN2 | ((audio_igain & 0x3)<<11) | ((audio_iamp & 0x0f)<<7));
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++  ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B , TC35143f_control_reg_b);
++  ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A , TC35143f_control_reg_a);
++  ucb1x00_reg_write(ucbstruct,TC35143_MODE_REG      , TC35143f_mode );
++  ucb1x00_io_write(ucbstruct, TC35143_GPIO_BUZZER_BIAS,0);
++  ucb1x00_disable(ucbstruct);
++#else
++  ucb1200_write_reg(TC35143_CONTROL_REG_B , TC35143f_control_reg_b );
++  ucb1200_write_reg(TC35143_MODE_REG      , TC35143f_mode );
++  ucb1200_write_reg(TC35143_CONTROL_REG_A , TC35143f_control_reg_a );
++  ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_HIGH);
++#endif
++  collie_tc_muted=1;
++}
++
++static void Collie_audio_power_off(void){	/* Disable sound only */
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++  ucb1x00_enable(ucbstruct);
++  ucb1x00_io_write(ucbstruct,0, TC35143_GPIO_BUZZER_BIAS);
++#else
++  ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_LOW);
++#endif
++
++  TC35143f_control_reg_a = ( TC35143_VDIV_22KHZ );
++  TC35143f_control_reg_b = ( TC35143_ALL_MUTE );
++
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++  ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B , TC35143f_control_reg_b);
++  ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A , TC35143f_control_reg_a);
++  ucb1x00_disable(ucbstruct);
++#else
++  ucb1200_write_reg(TC35143_CONTROL_REG_B , TC35143f_control_reg_b );
++  ucb1200_write_reg(TC35143_CONTROL_REG_A , TC35143f_control_reg_a );
++#endif
++}
++
++static void collie_tc_mute_on(void){
++    unsigned int reg_b;
++    unsigned int reg_a;
++
++    if (!collie_tc_muted) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++	ucb1x00_enable(ucbstruct);
++	reg_b  = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B);
++	reg_a  = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_A);
++#else
++	reg_b  = ucb1200_read_reg(TC35143_CONTROL_REG_B);
++	reg_a  = ucb1200_read_reg(TC35143_CONTROL_REG_A);
++#endif
++	reg_b &= ~TC35143_VOUT1_EN;
++	reg_a &= ~TC35143_VOUT2_EN;
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++	ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A, reg_a);
++	ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b);
++	ucb1x00_disable(ucbstruct);
++#else
++	ucb1200_write_reg(TC35143_CONTROL_REG_A, reg_a);
++	ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
++#endif
++	collie_tc_muted=1;
++    }
++}
++
++static void collie_tc_mute_off(void){
++    unsigned int reg_b;
++    unsigned int reg_a;
++
++    if (collie_tc_muted) {
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++	ucb1x00_enable(ucbstruct);
++	reg_b  = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B);
++	reg_a  = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_A);
++#else
++	reg_b  = ucb1200_read_reg(TC35143_CONTROL_REG_B);
++	reg_a  = ucb1200_read_reg(TC35143_CONTROL_REG_A);	
++#endif
++	reg_b |= TC35143_VOUT1_EN ;
++	reg_b &= ~7;
++	reg_b |= ( 7 - collie_buzzer_volume / 13);
++	reg_a |= TC35143_VOUT2_EN;
++	reg_a &= ~(TC35143_VGAIN_MASK | TC35143_VAMP_MASK);
++	reg_a |= (((audio_igain & 0x3)<<11) | ((audio_iamp & 0x0f)<<7));
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++	ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_A, reg_a);
++	ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b);
++	ucb1x00_disable(ucbstruct);
++#else
++	ucb1200_write_reg(TC35143_CONTROL_REG_A, reg_a);
++	ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
++#endif
++	collie_tc_muted=0;
++    }
++}
++
++
++static void Collie_volume_set(int dest)
++{
++    if (collie_buzzer_volume==dest) return;
++    collie_buzzer_volume=dest;
++    collie_tc_mute_on();    
++    collie_tc_mute_off();    
++}
++
++
++/*********** GENERAL stuff, same as collie_ssp *******************************/
++
++
++static void Collie_Set_Volume(int volume)
++{
++	sound.volume = volume & 0xff;
++	sound.volume += ( volume & 0xff00 >> 8);
++	sound.volume >>=1;
++	if (sound.volume>100) sound.volume=100;	
++}
++
++static int Collie_Get_Volume(void)
++{
++	return ( sound.volume << 8 | sound.volume );
++}
++
++static void Collie_sq_interrupt(void* id, int size)
++{
++	audio_buf_t *b  = (audio_buf_t *) id;
++	audio_buf_t *b2 = output_stream.buffers + ((b->idx + 1) % output_stream.nbfrags);
++
++	/* If this is the last buffer for know, let's mute the speaker */
++	if (!down_trylock(&b2->sem)) {
++		collie_tc_mute_on();
++		up(&b2->sem);
++	}
++	
++	/*
++	 * Current buffer is sent: wake up any process waiting for it.
++	 */
++	up(&b->sem);
++	/* And any process polling on write. */
++	wake_up_interruptible(&b->sem.wait);
++
++	DPRINTK("Collie_sq_interrupt \n");
++}
++
++static void Collie_sq_input_interrupt(void* id, int size)
++{
++	audio_buf_t *b = (audio_buf_t *) id;
++	/*
++	 * Current buffer is sent: wake up any process waiting for it.
++	 */
++	b->size = size;
++	up(&b->sem);
++	/* And any process polling on write. */
++	wake_up_interruptible(&b->sem.wait);
++	/* And indicate which was the last buffer sent */
++
++	DPRINTK("Collie_sq_input_interrupt \n");
++}
++
++
++static int __init CollieIrqInit(void)
++{
++	int err;
++
++	err = sa1100_request_dma(&COLLIE_BUZZER_DMA_CHANNEL, "buzzer output",
++			   DMA_Ser4MCP0Wr);
++
++	if (err) {
++		return 0;
++	}
++	printk("collie_tc35143f_irq=%d\n", collie_tc35143f_irq); 
++
++	err = sa1100_request_dma(&COLLIE_BUZZER_DMA_CHANNEL_INPUT, "buzzer input",
++			   DMA_Ser4MCP0Rd);
++
++	if (err) {
++		return 0;
++	}
++	printk("collie_tc35143f_input_irq=%d\n", collie_tc35143f_input_irq); 
++
++
++	sa1100_dma_set_callback(COLLIE_BUZZER_DMA_CHANNEL,
++			       (dma_callback_t)Collie_sq_interrupt);
++
++	sa1100_dma_set_callback(COLLIE_BUZZER_DMA_CHANNEL_INPUT,
++			       (dma_callback_t)Collie_sq_input_interrupt);
++
++
++	sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL);
++	Collie_audio_power_off();
++	sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++	sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL);
++	return(1);
++}
++
++static int CollieSetFormat(int format)
++{
++	int size;
++
++	switch (format) {
++	case AFMT_QUERY:
++		return(sound.format);
++	default: /* This is the only one supported by the hardware it seems */
++		size = 16;
++		format = AFMT_S16_LE;
++	}
++	sound.format = format;
++	sound.size = size;
++
++	return(format);
++}
++
++
++static int sound_set_speed(int speed)
++{
++	if (speed < 0) {
++		return(sound.speed);
++	}
++	sound.speed=22050;
++	return(sound.speed);
++}
++
++/* Higher level stuff ************************************************/
++
++/*
++ * /dev/mixer abstraction
++ */
++
++static int mixer_open(struct inode *inode, struct file *file)
++{
++	MOD_INC_USE_COUNT;
++	mixer.busy = 1;
++	return 0;
++}
++
++static int mixer_release(struct inode *inode, struct file *file)
++{
++	mixer.busy = 0;
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++
++static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd,
++		       u_long arg)
++{
++	int data;
++
++	DPRINTK("Got mixer ioctl \n");
++
++    	switch (cmd) {
++		case SOUND_MIXER_INFO:
++			DPRINTK("0\n");
++			return 0;
++		case SOUND_OLD_MIXER_INFO:
++			DPRINTK("0\n");
++			return 0;
++
++		case SOUND_MIXER_READ_DEVMASK:
++			DPRINTK("1\n");
++			return IOCTL_OUT(arg, SOUND_MASK_VOLUME | SOUND_MASK_MIC | SOUND_MASK_IGAIN );
++		case SOUND_MIXER_READ_RECMASK:
++			DPRINTK("2\n");
++			return IOCTL_OUT(arg, SOUND_MASK_MIC);
++		case SOUND_MIXER_READ_STEREODEVS:
++			DPRINTK("3\n");
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_READ_CAPS:
++			DPRINTK("4\n");
++			return IOCTL_OUT(arg, 0);
++
++		case SOUND_MIXER_WRITE_VOLUME:
++			IOCTL_IN(arg, data);
++			Collie_Set_Volume(data);
++			DPRINTK("mix_io returning\n");
++			return IOCTL_OUT(arg, data);
++		case SOUND_MIXER_READ_VOLUME:
++			DPRINTK("5\n");
++			return IOCTL_OUT(arg, Collie_Get_Volume());
++		case SOUND_MIXER_READ_TREBLE:
++			DPRINTK("6\n");
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_WRITE_TREBLE:
++			DPRINTK("7\n");
++			return IOCTL_OUT(arg, 0);
++
++		case SOUND_MIXER_READ_BASS:
++			DPRINTK("6b\n");
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_WRITE_BASS:
++			DPRINTK("7b\n");
++			return IOCTL_OUT(arg, 0);
++
++
++		case SOUND_MIXER_WRITE_MIC:
++		case SOUND_MIXER_WRITE_IGAIN:
++			DPRINTK("8\n");
++			return IOCTL_OUT(arg, 100);
++		case SOUND_MIXER_READ_MIC:
++		case SOUND_MIXER_READ_IGAIN:
++			DPRINTK("9\n");
++			return IOCTL_OUT(arg, 0);
++
++		case SOUND_MIXER_READ_SPEAKER:
++			DPRINTK("10\n");
++			return IOCTL_OUT(arg, 0);
++		case SOUND_MIXER_WRITE_SPEAKER:
++			DPRINTK("11\n");
++			return IOCTL_OUT(arg, 0);
++		default:
++			DPRINTK("12 %d\n",cmd);
++			return -ENOSYS;
++	}	
++	DPRINTK("EINVAL %d??\n",cmd);
++	return -EINVAL;
++}
++
++
++static struct file_operations mixer_fops =
++{
++	llseek:  sound_lseek,
++	ioctl:   mixer_ioctl,
++	open:    mixer_open,
++	release: mixer_release,
++};
++
++
++static void __init mixer_init(void)
++{
++	mixer_unit = register_sound_mixer(&mixer_fops, -1);
++	if (mixer_unit < 0) {
++		return;
++	}
++	mixer.busy = 0;
++	sound.volume  = 100;
++	Collie_volume_set(sound.volume);
++}
++
++/* This function initializes the buffer
++ */
++
++static void sq_clean_buffers(audio_stream_t * s)
++{
++	int frag;
++
++	sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL);
++	sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++
++	s->nbfrags = audio_nbfrags;
++	s->fragsize = audio_fragsize;
++
++	if (!s->buffers)
++	    goto err;
++
++	for (frag = 0; frag < s->nbfrags; frag++) {
++		audio_buf_t *b = &s->buffers[frag];
++		b->size=0;
++		sema_init(&b->sem, 1);
++	}
++	s->buf_idx = 0;
++	s->buf = &s->buffers[0];
++	return;
++
++err:
++	printk("sound driver : where did the buffer go ??\n ");
++}
++
++/* This function allocates the buffer structure array and buffer data space
++ * according to the current number of fragments and fragment size.
++ */
++ 
++static int sq_allocate_buffers(audio_stream_t * s)
++{
++	int frag;
++	int dmasize = 0;
++	char *dmabuf = 0;
++	dma_addr_t dmaphys = 0;
++
++	DPRINTK("sq_allocate_buffers\n");
++
++	if (s->buffers) {
++		return -EBUSY;
++	}
++
++	s->nbfrags = audio_nbfrags;
++	s->fragsize = audio_fragsize;
++
++	s->buffers = (audio_buf_t *)
++		kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
++	if (!s->buffers)
++	goto err;
++	memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
++
++	for (frag = 0; frag < s->nbfrags; frag++) {
++		audio_buf_t *b = &s->buffers[frag];
++
++		/*
++		 * Let's allocate non-cached memory for DMA buffers.
++		 * We try to allocate all memory at once.
++		 * If this fails (a common reason is memory fragmentation),
++		 * then we allocate more smaller buffers.
++		 */
++		if (!dmasize) {
++			dmasize = (s->nbfrags - frag) * s->fragsize;
++			do {
++				dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA,
++							  dmasize,
++							  &dmaphys);
++				if (!dmabuf)
++					dmasize -= s->fragsize;
++			} while (!dmabuf && dmasize);
++			if (!dmabuf)
++				goto err;
++			b->master = dmasize;
++		}
++
++		b->start = dmabuf;
++		b->dma_addr = dmaphys;
++		b->idx = frag;
++		sema_init(&b->sem, 1);
++		dmabuf += s->fragsize;
++		dmaphys += s->fragsize;
++		dmasize -= s->fragsize;
++	}
++
++	s->buf_idx = 0;
++	s->buf = &s->buffers[0];
++
++	return 0;
++
++err:
++	printk("sound driver : unable to allocate audio memory\n ");
++	sq_release_buffers(s);
++	return -ENOMEM;
++}
++
++/*
++ * This function frees all buffers
++ */
++
++static void sq_release_buffers(audio_stream_t * s)
++{
++	DPRINTK("sq_release_buffers\n");
++
++	/* ensure DMA won't run anymore */
++	sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL);
++	sa1100_dma_flush_all(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++
++	if (s->buffers) {
++		int frag;
++		for (frag = 0; frag < s->nbfrags; frag++) {
++			if (!s->buffers[frag].master)
++				continue;
++			consistent_free(s->buffers[frag].start,
++					s->buffers[frag].master,
++					s->buffers[frag].dma_addr);
++		}
++		kfree(s->buffers);
++		s->buffers = NULL;
++	}
++
++	s->buf_idx = 0;
++	s->buf = NULL;
++}
++
++static int audio_recording(audio_stream_t * s)
++{
++	int i;
++	unsigned int reg_b;
++
++	if (!collie_recording) {
++		/*
++		 * Set TC35143 Audio in enable
++		 */
++////		DPRINTK("audio_recording : audio in enable\n");
++////		reg_b  = ucb1200_read_reg(TC35143_CONTROL_REG_B);
++////		reg_b &= ~(TC35143_VADMUTE);
++////		reg_b |=  (TC35143_VIN_EN | TC35143_VCLP_CLR);
++////		ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
++
++		/*
++		 * We must ensure there is an output stream at any time while 
++		 * recording since this is how the TC35143 gets its clock.
++		 * So if there is no playback data to send, the output DMA will
++		 * spin with all zeroes.
++		 */
++
++		Collie_recording_on();
++		collie_tc_mute_off();  /* This is needed for good volume */
++		DPRINTK("audio_recording : sa1100_dma_set_spin\n");
++		sa1100_dma_set_spin(COLLIE_BUZZER_DMA_CHANNEL,
++					    (dma_addr_t) FLUSH_BASE_PHYS, 2048);
++
++		/* 
++		 * Since we just allocated all buffers, we must send them to
++		 * the DMA code before receiving data.
++		 */
++		DPRINTK("audio_recording : for loop\n");
++		for (i = 0; i < s->nbfrags; i++) {
++			audio_buf_t *b = s->buf;
++			down(&b->sem);
++			sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL_INPUT, (void *) b,
++						b->dma_addr, s->fragsize);
++			NEXT_BUF(s, buf);
++		}
++		DPRINTK("audio_recording : End for loop\n");
++
++		/*
++		 * Set TC35143 Audio in enable
++		 */
++		DPRINTK("audio_recording : audio in enable\n");
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++		ucb1x00_enable(ucbstruct);
++  		ucb1x00_io_write(ucbstruct, 0, TC35143_GPIO_BUZZER_BIAS);
++		reg_b  = ucb1x00_reg_read(ucbstruct,TC35143_CONTROL_REG_B);
++#else
++		ucb1200_set_io(TC35143_GPIO_BUZZER_BIAS, TC35143_IODAT_LOW);
++		reg_b  = ucb1200_read_reg(TC35143_CONTROL_REG_B);
++#endif
++		reg_b &= ~(TC35143_VADMUTE);
++		reg_b |=  (TC35143_VIN_EN | TC35143_VCLP_CLR);
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++		ucb1x00_reg_write(ucbstruct,TC35143_CONTROL_REG_B, reg_b);
++		ucb1x00_disable(ucbstruct);
++#else
++		ucb1200_write_reg(TC35143_CONTROL_REG_B, reg_b);
++#endif
++	}
++	return 0;
++}
++
++
++static int sq_read(struct file *file, char *buffer,
++		      size_t count, loff_t * ppos)
++{
++	char *buffer0 = buffer;
++	audio_stream_t *s = &input_stream;
++	int chunksize, ret = 0;
++
++	DPRINTK("audio_read: count=%d\n", count);
++
++
++	ret = audio_recording(s);
++
++	if ((collie_tc_status!=NA) && (collie_tc_status!=REC)) 
++	    return -EPERM;
++	collie_tc_status=REC;
++
++	if (ret)
++		return ret;
++
++	/* be sure to have a full sample byte count */
++	count &= ~0x03;
++
++//	DPRINTK("audio_read : Start while loop\n");
++	while (count > 0) {
++		audio_buf_t *b = s->buf;
++
++		/* Wait for a buffer to become full */
++		if (file->f_flags & O_NONBLOCK) {
++//			DPRINTK("audio_read : down_trylock\n");
++			ret = -EAGAIN;
++			if (down_trylock(&b->sem))
++				break;
++		} else {
++//			DPRINTK("audio_read : down_interruptible\n");
++			ret = -ERESTARTSYS;
++			if (down_interruptible(&b->sem))
++				break;
++		}
++
++		/* Grab data from the current buffer */
++		chunksize = b->size;
++		if (chunksize > count)
++		    chunksize = count;
++		DPRINTK("read %d from %d\n", chunksize, s->buf_idx);
++		
++		if (copy_to_user(buffer, b->start + s->fragsize - b->size, chunksize)) {
++		    up(&b->sem);
++		    DPRINTK("not copied to buffer \n");
++		    return -EFAULT;
++		}
++		DPRINTK("copied to buffer \n");
++
++		b->size -= chunksize;
++		buffer += chunksize;
++		count -= chunksize;
++		
++		if (b->size > 0) {
++			up(&b->sem);
++			break;
++		}
++
++		/* Make current buffer available for DMA again */
++		sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL_INPUT, (void *) b,
++					b->dma_addr, s->fragsize);
++		NEXT_BUF(s, buf);
++	}
++//	DPRINTK("audio_read : End while loop\n");
++
++	if ((buffer - buffer0))
++		ret = buffer - buffer0;
++//	DPRINTK("audio_read: return=%d\n", ret);
++	return ret;
++}
++
++static ssize_t sq_write(struct file *file, const char *src, size_t uLeft,
++			loff_t *ppos)
++{
++	const char *buffer0 = src;
++	audio_stream_t *s = &output_stream;
++	u_char *dest;
++	ssize_t uUsed, bUsed, bLeft, ret = 0;
++
++	DPRINTK("sq_write: uLeft=%d\n", uLeft);
++
++	if ((collie_tc_status!=NA) && (collie_tc_status!=PLAY)) 
++	    return -EPERM;
++
++	collie_tc_status=PLAY;
++
++	if (!s->buffers && sq_allocate_buffers(s)) {
++		return -ENOMEM;
++	}
++
++
++#ifdef CONFIG_PM
++	/* Auto Power off cancel */
++//	autoPowerCancel = 0;
++#endif
++
++	collie_tc_mute_off();
++	while (uLeft > 0) {
++		audio_buf_t *b = s->buf;
++
++		/* Wait for a buffer to become free */
++		if (file->f_flags & O_NONBLOCK) {
++			ret = -EAGAIN;
++			if (down_trylock(&b->sem)) {
++				break;
++			}
++		} else {
++			ret = -ERESTARTSYS;
++			if (down_interruptible(&b->sem)) {
++				break;
++			}
++		}
++
++		dest = b->start + b->size;
++		bUsed = 0;
++		bLeft = s->fragsize - b->size;
++
++		if (collie_ct_s16) {
++			uUsed = collie_ct_s16(src, uLeft, dest, &bUsed, bLeft);
++			cpu_cache_clean_invalidate_range((unsigned long)dest,
++				(unsigned long)(dest+(audio_fragsize)), 0);
++		} else {
++			return -EFAULT;
++		}
++
++		if (uUsed < 0) {
++			up(&b->sem);
++			return -EFAULT;
++		}
++		src += uUsed;
++		uLeft -= uUsed;
++		b->size += bUsed;
++
++		if (b->size < s->fragsize) {
++			up(&b->sem);
++			break;
++		}
++
++		/* Send current buffer to dma */
++		sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
++		 			(void *) b, b->dma_addr, b->size);
++
++		Collie_volume_set(sound.volume);
++
++		b->size = 0;    /* indicate that the buffer has been sent */
++		NEXT_BUF(s, buf);
++	}
++
++	if ((src - buffer0))
++		ret = src - buffer0;
++	DPRINTK("sq_write: return=%d\n", ret);
++	return ret;
++}
++
++static unsigned int sq_poll(struct file *file, 
++			       struct poll_table_struct *wait)
++{
++	unsigned int mask = 0;
++	int i,ret;
++
++	DPRINTK("sq_poll(): mode=%s%s\n",
++		(file->f_mode & FMODE_READ) ? "r" : "",
++		(file->f_mode & FMODE_WRITE) ? "w" : "");
++
++	if ((file->f_mode & FMODE_READ) && (file->f_mode & FMODE_WRITE) && (collie_tc_status==NA))
++	    return mask;
++	
++	if ((file->f_mode & FMODE_WRITE) && (collie_tc_status!=REC)) {
++		if (!output_stream.buffers 
++		    && sq_allocate_buffers(&output_stream)) {
++			return -ENOMEM;
++		}
++		poll_wait(file, &output_stream.buf->sem.wait, wait);
++	}
++
++	if ((file->f_mode & FMODE_WRITE) && (collie_tc_status!=REC)) {
++		for (i = 0; i < output_stream.nbfrags; i++) {
++			if (atomic_read(&output_stream.buffers[i].sem.count) > 0)
++				mask |= POLLOUT | POLLWRNORM;
++		}
++	}
++
++	if ((file->f_mode & FMODE_READ) && (collie_tc_status!=PLAY)) {
++		ret = audio_recording(&input_stream);
++		if (ret<0) {
++			return ret;
++		}
++		poll_wait(file, &input_stream.buf->sem.wait, wait);
++	}
++
++	if ((file->f_mode & FMODE_READ) && (collie_tc_status!=PLAY)) {
++		for (i = 0; i < input_stream.nbfrags; i++) {
++			if (atomic_read(&input_stream.buffers[i].sem.count) > 0)
++				mask |= POLLIN | POLLRDNORM;
++		}
++	}
++
++	DPRINTK("sq_poll() returned mask of %s%s\n",
++		(mask & POLLIN) ? "r" : "",
++		(mask & POLLOUT) ? "w" : "");
++
++	return mask;
++}
++
++static int sq_open(struct inode *inode, struct file *file)
++{
++	DPRINTK("sq_open\n");
++
++	if (audio_refcount) {
++		DPRINTK(" sq_open        EBUSY\n");
++		return -EBUSY;
++	}
++
++	switch (file->f_flags & O_ACCMODE) {
++	    case O_WRONLY:
++		collie_tc_status=PLAY;
++		sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++		break;
++	    case O_RDONLY:
++		collie_tc_status=REC;
++		break;
++	    case O_RDWR:
++		collie_tc_status=NA;
++		break;
++	    default:
++		DPRINTK(" sq_open        EINVAL\n");
++		return -EINVAL;
++	}
++	
++	MOD_INC_USE_COUNT;
++	audio_refcount++;
++
++	audio_fragsize = AUDIO_FRAGSIZE_DEFAULT;
++	audio_nbfrags = AUDIO_NBFRAGS_DEFAULT;
++	sq_clean_buffers(&input_stream);
++	sq_clean_buffers(&output_stream);
++	Collie_audio_power_on();
++	DPRINTK("Going back\n");
++    	return 0;
++}
++
++static int sq_post(void)
++{
++	audio_stream_t *s = &output_stream;
++	audio_buf_t *b = s->buf;
++
++	DPRINTK("sq_post\n");
++
++	if (!s->buffers) {
++		return 0;
++	}
++
++	/* Send half-full buffers */
++	if (b->size != 0) {
++		DPRINTK("half-full_buf\n");
++
++#ifdef CONFIG_PM
++		/* Auto Power off cancel */
++//		autoPowerCancel = 0;
++#endif
++
++		down(&b->sem);
++		sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
++					(void *) b, b->dma_addr, b->size);
++		b->size = 0;
++		NEXT_BUF(s, buf);
++	}
++	return 0;
++}
++
++static int sq_fsync(void)
++{
++	audio_stream_t *s = &output_stream;
++	audio_buf_t *b = s->buf;
++
++	DPRINTK("sq_fsync\n");
++
++	if (!s->buffers) {
++		return 0;
++	}
++
++	/* Send half-full buffers */
++	if (b->size != 0) {
++		DPRINTK("half-full_buf\n");
++
++#ifdef CONFIG_PM
++		/* Auto Power off cancel */
++//		autoPowerCancel = 0;
++#endif
++
++		down(&b->sem);
++		sa1100_dma_queue_buffer(COLLIE_BUZZER_DMA_CHANNEL,
++					(void *) b, b->dma_addr, b->size);
++		b->size = 0;
++		NEXT_BUF(s, buf);
++	}
++
++	/*
++	 * Let's wait for the last buffer we sent i.e. the one before the
++	 * current buf_idx.  When we acquire the semaphore, this means either:
++	 * - DMA on the buffer completed or
++	 * - the buffer was already free thus nothing else to sync.
++	 */
++	b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags);
++	if (down_interruptible(&b->sem)) {
++		return -EINTR;
++	}
++	up(&b->sem);
++	return 0;
++}
++
++static int sq_release(struct inode *inode, struct file *file)
++{
++	DPRINTK("speaker_sq_release\n");
++
++	switch (collie_tc_status) {
++
++	case REC:
++	    sa1100_dma_set_spin(COLLIE_BUZZER_DMA_CHANNEL,0,0);
++	    sq_clean_buffers(&input_stream);
++	    Collie_recording_off();
++	    break;
++	case PLAY:
++	    sq_fsync();
++	    sq_clean_buffers(&output_stream);
++	    break;
++	default:
++	    break;		
++	}       
++	audio_refcount = 0;
++	collie_tc_status=NA;
++	sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL);
++	Collie_audio_power_off();
++	sa1100_dma_stop(COLLIE_BUZZER_DMA_CHANNEL_INPUT);	
++	MOD_DEC_USE_COUNT;
++	return 0;
++}
++
++/* Buzzer compatibility */
++#include "colliebuzzer.h"   
++
++
++static int sq_ioctl(struct inode *inode, struct file *file, u_int cmd,
++		    u_long arg)
++{
++	u_long fmt;
++	int data,ret;
++//	audio_buf_info abinfo;
++
++	DPRINTK("Got ioctl %ld \n",cmd);
++	
++	switch (cmd) {
++	case 22144:
++		sq_write_buzzer(arg);
++		sq_fsync();
++		return 0;	
++	case SNDCTL_DSP_RESET:
++		switch (collie_tc_status) {
++		case REC:
++		    sq_clean_buffers(&input_stream);
++		case PLAY:
++		    sq_fsync();
++		    sq_clean_buffers(&output_stream);
++		default:
++		    break;
++		}
++		return 0;
++	case SNDCTL_DSP_POST:
++		sq_post();
++		return 0;
++	case SNDCTL_DSP_SYNC:
++		sq_fsync();
++		return 0;
++
++		/* ++TeSche: before changing any of these it's
++		 * probably wise to wait until sound playing has
++		 * settled down. */
++	case SNDCTL_DSP_SPEED:
++//		sq_fsync(file, file->f_dentry);
++		IOCTL_IN(arg, data);
++		return IOCTL_OUT(arg, sound_set_speed(data));
++
++	case SOUND_PCM_READ_RATE:
++		return 0;
++
++	case SNDCTL_DSP_STEREO:
++//		sq_fsync(file, file->f_dentry);
++		IOCTL_IN(arg, data);
++		return IOCTL_OUT(arg, 0);
++	case SNDCTL_DSP_CHANNELS:
++//		sq_fsync(file, file->f_dentry);
++		IOCTL_IN(arg, data);
++		return IOCTL_OUT(arg, 1);
++	case SNDCTL_DSP_SETFMT:
++//		sq_fsync(file, file->f_dentry);
++		IOCTL_IN(arg, data);
++		return IOCTL_OUT(arg, CollieSetFormat(data));
++	case SNDCTL_DSP_GETFMTS:
++		fmt = AFMT_S16_LE;
++		return IOCTL_OUT(arg, fmt);
++	case SNDCTL_DSP_GETBLKSIZE:
++		return IOCTL_OUT(arg, audio_fragsize);
++	case SNDCTL_DSP_SUBDIVIDE:
++		break;
++	case SNDCTL_DSP_SETFRAGMENT:
++/*		if (output_stream.buffers) {
++			return -EBUSY;
++		}
++		get_user(val, (long *) arg);
++		audio_fragsize = 1 << (val & 0xFFFF);
++		if (audio_fragsize < 256)
++			audio_fragsize = 256;
++		if (audio_fragsize > 16384)
++			audio_fragsize = 16384;
++		audio_nbfrags = (val >> 16) & 0x7FFF;
++		if (audio_nbfrags < 2)
++			audio_nbfrags = 2;
++		if (audio_nbfrags * audio_fragsize > 128 * 1024)
++			audio_nbfrags = 128 * 1024 / audio_fragsize;
++		if (sq_allocate_buffers(&output_stream)) {
++			return -ENOMEM;
++		}
++		return 0;
++	case SNDCTL_DSP_GETOSPACE:
++		abinfo.fragsize   = audio_fragsize;
++		abinfo.fragstotal = audio_nbfrags;
++		abinfo.fragments  = lastsent-output_stream.buf_idx;
++		if (abinfo.fragments<0)
++		    abinfo.fragments += abinfo.fragstotal;		    
++		abinfo.bytes      = abinfo.fragments*abinfo.fragsize;
++     		return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
++*/
++
++	case SNDCTL_DSP_GETOSPACE:
++	    {
++		audio_stream_t *s = &output_stream;
++		audio_buf_info *inf = (audio_buf_info *) arg;
++		int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
++		int i;
++		int frags = 0, bytes = 0;
++
++		if (err)
++			return err;
++		if (output_stream.buffers)  {
++		    for (i = 0; i < s->nbfrags; i++) {
++			if (atomic_read(&s->buffers[i].sem.count) > 0) {
++				if (s->buffers[i].size == 0) frags++;
++				bytes += s->fragsize - s->buffers[i].size;
++			}
++		    }
++		    put_user(s->nbfrags, &inf->fragstotal);
++		    put_user(s->fragsize, &inf->fragsize);
++		} else {
++		    frags=audio_nbfrags;
++		    bytes=frags*audio_fragsize;
++		    put_user(frags, &inf->fragstotal);
++		    put_user(audio_fragsize, &inf->fragsize);
++		}
++		put_user(frags, &inf->fragments);
++		return put_user(bytes, &inf->bytes);
++	    }
++
++	case SNDCTL_DSP_GETISPACE:
++	    {
++		audio_stream_t *s = &input_stream;
++		audio_buf_info *inf = (audio_buf_info *) arg;
++		int err = verify_area(VERIFY_WRITE, inf, sizeof(*inf));
++		int i;
++		int frags = 0, bytes = 0;
++
++		if (err)
++			return err;
++		if (input_stream.buffers) 
++		    for (i = 0; i < s->nbfrags; i++) {
++			if (atomic_read(&s->buffers[i].sem.count) > 0) {
++				if (s->buffers[i].size == s->fragsize) frags++;
++				bytes += s->buffers[i].size;
++			}
++		    }
++		else {
++		    frags=0;
++		    bytes=0;
++		}
++		put_user(frags, &inf->fragments);
++		put_user(s->nbfrags, &inf->fragstotal);
++		put_user(s->fragsize, &inf->fragsize);
++		return put_user(bytes, &inf->bytes);		
++	    }
++
++	default:
++		ret = mixer_ioctl(inode, file, cmd, arg);
++		DPRINTK("Returning after mixer_ioctl\n");
++		return ret;
++	}
++	return -EINVAL;
++}
++
++static struct file_operations sq_fops =
++{
++	llseek: sound_lseek,
++	write: sq_write,
++	read: sq_read,
++	poll: sq_poll,
++	ioctl: sq_ioctl,
++	open: sq_open,
++	release: sq_release,
++};
++
++
++static void __init sq_init(void)
++{
++	sq_unit = register_sound_dsp(&sq_fops, -1);
++	if (sq_unit < 0) {
++		return;
++	}
++
++	sound.format = AFMT_S16_LE;
++	sound.stereo = 0;
++	sound.speed = 22050;
++
++	CollieSetFormat(sound.format);
++	Collie_audio_power_off();
++	input_stream.buf=input_stream.buffers=output_stream.buf=output_stream.buffers=NULL;
++}
++
++
++/*** Common stuff ********************************************************/
++
++static long long sound_lseek(struct file *file, long long offset, int orig)
++{
++	return -ESPIPE;
++}
++
++/*** Power Management ****************************************************/
++
++#ifdef CONFIG_PM
++static int collie_sound_pm_callback(struct pm_dev *pm_dev,
++				    pm_request_t req, void *data)
++{
++	switch (req) {
++	case PM_SUSPEND:
++		if (audio_refcount == 1) {
++		        sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
++		        sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++			Collie_audio_power_off();
++		} else {
++			sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
++		        sa1100_dma_sleep((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++		}
++		break;
++	case PM_RESUME:
++		Collie_sound_hard_init();
++//		Collie_audio_power_off();
++		if (audio_refcount == 1) {
++			Collie_audio_power_on();
++			sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
++			sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++		} else {
++			sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL);
++			sa1100_dma_wakeup((dmach_t)COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++		}
++		break;
++	}
++	return 0;
++}
++#endif
++
++/*** Config & Setup ******************************************************/
++
++int __init Collie_sound_init(void)
++{
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,19))
++	ucbstruct = ucb1x00_get();
++#endif
++	if (!CollieIrqInit()) {
++	    printk("Sound driver: Interrupt initialization failed\n");
++	    return -1;
++	}
++	Ser4MCDR0 = 0; /* ucb1200_sa1100_set_mcdr0(0); */   
++
++	Collie_sound_hard_init();
++	
++	/* Set default settings. */
++	sq_init();
++	/* Set up /dev/mixer. */
++	mixer_init();
++#ifdef MODULE
++	irq_installed = 1;
++#endif
++	printk("Collie tc35143af Sound Driver Installed\n");
++#ifdef CONFIG_PM
++	collie_sound_pm_dev = pm_register(PM_SYS_DEV, 0,
++						collie_sound_pm_callback);
++#endif
++	return 0;
++}
++
++#ifdef MODULE
++static int collie_tc35143_init_module(void)
++{
++	Collie_sound_init();
++	sq_allocate_buffers(&output_stream);
++	sq_allocate_buffers(&input_stream);
++	return 0;
++}
++
++static void collie_tc35143_cleanup_module(void)
++{
++#ifdef CONFIG_PM
++	pm_unregister(collie_sound_pm_dev);
++#endif
++	if (irq_installed) {
++		sa1100_free_dma(COLLIE_BUZZER_DMA_CHANNEL);
++		sa1100_free_dma(COLLIE_BUZZER_DMA_CHANNEL_INPUT);
++	}
++
++	sq_release_buffers(&output_stream);
++	sq_release_buffers(&input_stream);
++	unregister_sound_mixer(mixer_unit);
++	unregister_sound_special(state_unit);
++	unregister_sound_dsp(sq_unit);
++	printk("collie_tc35143af has to go now, see you later!\n");
++}
++
++module_init(collie_tc35143_init_module);
++module_exit(collie_tc35143_cleanup_module);
++MODULE_DESCRIPTION("Collie tc35143af 16bit sound driver");
++MODULE_AUTHOR("SHARP");
++MODULE_LICENSE("GPL");
++#endif /* MODULE */
++
+diff -Nuar linux-2.4.18/drivers/sound/Makefile linux-2.4.18p/drivers/sound/Makefile
+--- linux-2.4.18/drivers/sound/Makefile	2003-05-13 11:18:36.000000000 +0200
++++ linux-2.4.18p/drivers/sound/Makefile	2004-10-12 23:11:29.000000000 +0200
+@@ -11,7 +11,7 @@
+ 		    msnd.o opl3.o sb_common.o sequencer_syms.o \
+ 		    sound_core.o sound_syms.o uart401.o	\
+ 		    nm256_audio.o ac97.o ac97_codec.o aci.o \
+-		    sa1100-audio.o pxa-audio.o pxa-ac97.o
++		    sa1100-audio.o pxa-audio.o pxa-ac97.o collie_ssp.o
+ 
+ # Each configuration option enables a list of files.
+ 
+@@ -78,7 +78,7 @@
+ obj-$(CONFIG_SOUND_SA1111_UDA1341) += sa1111-uda1341.o
+ obj-$(CONFIG_SOUND_SA1100SSP)	+= sa1100ssp.o
+ obj-$(CONFIG_SOUND_COLLIE_SSP)	+= collie_ssp.o
+-obj-$(CONFIG_SOUND_COLLIE_TC35143) += collie-tc35143.o
++obj-$(CONFIG_SOUND_COLLIE_TC35143) += collie_tc35143af.o
+ obj-$(CONFIG_SOUND_PXA_AC97)+= pxa-ac97.o pxa-audio.o ac97_codec.o
+ obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
+ obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
-- 
cgit v1.2.3